wasn't checking soon enough for rule redef; now it sets a dead flag in

AST so no more walking dup.
  error(51): T.g:7:0: rule s redefinition (ignoring); previous at line 3
This commit is contained in:
Terence Parr 2012-11-18 09:07:30 -08:00
parent 6a345316df
commit afe2224881
7 changed files with 81 additions and 47 deletions

View File

@ -7,6 +7,9 @@ November 17, 2012
* properly check for grammar/filename difference
* if labels, don't allow set collapse for
a : A # X | B ;
* wasn't checking soon enough for rule redef; now it sets a dead flag in
AST so no more walking dup.
error(51): T.g:7:0: rule s redefinition (ignoring); previous at line 3
November 11, 2012

View File

@ -3,6 +3,5 @@ grammar T;
s : A # X
| B
;
b : A # Y
| B{}
;
s : A ;

View File

@ -62,6 +62,7 @@ import org.antlr.v4.tool.Rule;
import org.antlr.v4.tool.ast.GrammarAST;
import org.antlr.v4.tool.ast.GrammarASTErrorNode;
import org.antlr.v4.tool.ast.GrammarRootAST;
import org.antlr.v4.tool.ast.RuleAST;
import org.stringtemplate.v4.STGroup;
import java.io.BufferedWriter;
@ -387,6 +388,8 @@ public class Tool {
if ( g.ast.hasErrors ) return;
checkForRedefinedRules(g);
int prevErrors = errMgr.getNumErrors();
// MAKE SURE GRAMMAR IS SEMANTICALLY CORRECT (FILL IN GRAMMAR OBJECT)
SemanticPipeline sem = new SemanticPipeline(g);
@ -417,6 +420,32 @@ public class Tool {
}
}
/** Important enough to avoid multiple defs that we do very early,
* right after AST construction. Turn redef'd rule's AST RULE node dead
* field to true.
*/
public void checkForRedefinedRules(Grammar g) {
GrammarAST RULES = (GrammarAST)g.ast.getFirstChildWithType(ANTLRParser.RULES);
List<RuleAST> rules = (List<RuleAST>)RULES.getChildren();
Map<String, RuleAST> ruleToAST = new HashMap<String, RuleAST>();
for (RuleAST r : rules) {
GrammarAST ID = (GrammarAST)r.getChild(0);
String ruleName = ID.getText();
RuleAST prev = ruleToAST.get(ruleName);
if ( prev !=null ) {
GrammarAST prevChild = (GrammarAST)prev.getChild(0);
g.tool.errMgr.grammarError(ErrorType.RULE_REDEFINITION,
g.fileName,
ID.getToken(),
ruleName,
prevChild.getToken().getLine());
r.dead = true;
continue;
}
ruleToAST.put(ruleName, r);
}
}
public List<GrammarRootAST> sortGrammarByTokenVocab(List<String> fileNames) {
// System.out.println(fileNames);
Graph<String> g = new Graph<String>();

View File

@ -498,7 +498,8 @@ rule
@after {
exitRule($start);
}
: ^( RULE RULE_REF {currentRuleName=$RULE_REF.text; currentRuleAST=$RULE;}
: {!((RuleAST)$start).dead}?
^( RULE RULE_REF {currentRuleName=$RULE_REF.text; currentRuleAST=$RULE;}
DOC_COMMENT? (^(RULEMODIFIERS (m=ruleModifier{mods.add($m.start);})+))?
ARG_ACTION?
ret=ruleReturns?
@ -515,6 +516,20 @@ rule
ruleBlock exceptionGroup
{finishRule((RuleAST)$RULE, $RULE_REF, $ruleBlock.start); currentRuleName=null; currentRuleAST=null;}
)
| // ugly repeated alt w/o actions but needed to force ANTLR to use
// sem pred to avoid actions when rule dead
{((RuleAST)$start).dead}?
^( RULE RULE_REF
DOC_COMMENT? (^(RULEMODIFIERS (m=ruleModifier)+))?
ARG_ACTION?
ret=ruleReturns?
thr=throwsSpec?
loc=locals?
( opts=optionsSpec
| a=ruleAction
)*
ruleBlock exceptionGroup
)
;
exceptionGroup
@ -643,7 +658,7 @@ lexerOuterAlternative
finishOuterAlt((AltAST)$start);
exitLexerOuterAlternative((AltAST)$start);
}
: lexerAlternative
: lexerAlternative
;
@ -656,7 +671,7 @@ outerAlternative
finishOuterAlt((AltAST)$start);
exitOuterAlternative((AltAST)$start);
}
: alternative
: alternative
;
lexerAlternative
@ -705,7 +720,7 @@ labeledLexerElement
}
: ^((ASSIGN|PLUS_ASSIGN) ID (lexerAtom|block))
;
lexerBlock
@init {
enterLexerBlock($start);
@ -744,7 +759,7 @@ actionElement
| SEMPRED
| ^(SEMPRED elementOptions)
;
alternative
@init {
enterAlternative((AltAST)$start);
@ -778,10 +793,10 @@ lexerCommandExpr
@after {
exitLexerCommandExpr($start);
}
: ID
: ID
| INT
;
element
@init {
enterElement($start);
@ -796,7 +811,7 @@ element
| SEMPRED {sempredInAlt((PredAST)$SEMPRED);}
| ^(ACTION elementOptions) {actionInAlt((ActionAST)$ACTION);}
| ^(SEMPRED elementOptions) {sempredInAlt((PredAST)$SEMPRED);}
| ^(NOT blockSet)
| ^(NOT block)
;

View File

@ -85,43 +85,28 @@ public class SymbolChecks {
public void process() {
// methods affect fields, but no side-effects outside this object
// So, call order sensitive
//checkForImportedRuleIssues(collector.qualifiedRulerefs);
// done in sem pipe for now
checkForRuleConflicts(g.rules.values()); // sets nameToRuleMap
// So, call order sensitive
// First collect all rules for later use in checkForLabelConflict()
if ( g.rules!=null ) {
for (Rule r : g.rules.values()) nameToRuleMap.put(r.name, r);
}
checkActionRedefinitions(collector.namedActions);
//checkRuleArgs(collector.rulerefs);
checkForTokenConflicts(collector.tokenIDRefs); // sets tokenIDs
checkForLabelConflicts(g.rules.values());
}
checkForTokenConflicts(collector.tokenIDRefs); // sets tokenIDs
checkForLabelConflicts(g.rules.values());
}
public void checkForRuleConflicts(Collection<Rule> rules) {
if ( rules==null ) return;
for (Rule r : rules) {
Rule prevRule = nameToRuleMap.get(r.name);
if ( prevRule==null ) {
nameToRuleMap.put(r.name, r);
}
else {
GrammarAST idNode = (GrammarAST)r.ast.getChild(0);
errMgr.grammarError(ErrorType.RULE_REDEFINITION,
r.g.fileName, idNode.token, r.name);
}
}
}
public void checkActionRedefinitions(List<GrammarAST> actions) {
if ( actions==null ) return;
String scope = g.getDefaultActionScope();
String name;
GrammarAST nameNode;
for (GrammarAST ampersandAST : actions) {
nameNode = (GrammarAST)ampersandAST.getChild(0);
if ( ampersandAST.getChildCount()==2 ) {
name = nameNode.getText();
}
else {
scope = nameNode.getText();
public void checkActionRedefinitions(List<GrammarAST> actions) {
if ( actions==null ) return;
String scope = g.getDefaultActionScope();
String name;
GrammarAST nameNode;
for (GrammarAST ampersandAST : actions) {
nameNode = (GrammarAST)ampersandAST.getChild(0);
if ( ampersandAST.getChildCount()==2 ) {
name = nameNode.getText();
}
else {
scope = nameNode.getText();
name = ampersandAST.getChild(1).getText();
}
Set<String> scopeActions = actionScopeToActionNames.get(scope);

View File

@ -71,7 +71,7 @@ public enum ErrorType {
// Grammar errors
SYNTAX_ERROR(50, "<arg>", ErrorSeverity.ERROR),
RULE_REDEFINITION(51, "rule <arg> redefinition", ErrorSeverity.ERROR),
RULE_REDEFINITION(51, "rule <arg> redefinition (ignoring); previous at line <arg2>", ErrorSeverity.ERROR),
LEXER_RULES_NOT_ALLOWED(52, "lexer rule <arg> not allowed in parser", ErrorSeverity.ERROR),
PARSER_RULES_NOT_ALLOWED(53, "parser rule <arg> not allowed in lexer", ErrorSeverity.ERROR),
REPEATED_PREQUEL(54, "repeated grammar prequel spec (option, token, or import); please merge", ErrorSeverity.ERROR),

View File

@ -34,6 +34,9 @@ import org.antlr.runtime.tree.Tree;
import org.antlr.v4.parse.ANTLRParser;
public class RuleAST extends GrammarASTWithOptions {
/** Kill redef of rules */
public boolean dead;
public RuleAST(GrammarAST node) {
super(node);
}