fixed: undefined rule refs caused exception

This commit is contained in:
Terence Parr 2012-11-18 09:33:11 -08:00
parent 1916ed0626
commit 0a8e7220f8
4 changed files with 36 additions and 12 deletions

View File

@ -10,6 +10,7 @@ November 17, 2012
* wasn't checking soon enough for rule redef; now it sets a dead flag in * wasn't checking soon enough for rule redef; now it sets a dead flag in
AST so no more walking dup. AST so no more walking dup.
error(51): T.g:7:0: rule s redefinition (ignoring); previous at line 3 error(51): T.g:7:0: rule s redefinition (ignoring); previous at line 3
* fixed: undefined rule refs caused exception
November 11, 2012 November 11, 2012

View File

@ -1,7 +1,7 @@
grammar T; grammar T;
s : A # X s : A # X
| B | x
; ;
s : A ; A : C ;

View File

@ -44,6 +44,7 @@ import org.antlr.v4.misc.Graph;
import org.antlr.v4.parse.ANTLRLexer; import org.antlr.v4.parse.ANTLRLexer;
import org.antlr.v4.parse.ANTLRParser; import org.antlr.v4.parse.ANTLRParser;
import org.antlr.v4.parse.GrammarASTAdaptor; import org.antlr.v4.parse.GrammarASTAdaptor;
import org.antlr.v4.parse.GrammarTreeVisitor;
import org.antlr.v4.parse.ToolANTLRParser; import org.antlr.v4.parse.ToolANTLRParser;
import org.antlr.v4.runtime.misc.LogManager; import org.antlr.v4.runtime.misc.LogManager;
import org.antlr.v4.runtime.misc.Nullable; import org.antlr.v4.runtime.misc.Nullable;
@ -59,10 +60,12 @@ import org.antlr.v4.tool.Grammar;
import org.antlr.v4.tool.GrammarTransformPipeline; import org.antlr.v4.tool.GrammarTransformPipeline;
import org.antlr.v4.tool.LexerGrammar; import org.antlr.v4.tool.LexerGrammar;
import org.antlr.v4.tool.Rule; import org.antlr.v4.tool.Rule;
import org.antlr.v4.tool.ast.ActionAST;
import org.antlr.v4.tool.ast.GrammarAST; import org.antlr.v4.tool.ast.GrammarAST;
import org.antlr.v4.tool.ast.GrammarASTErrorNode; import org.antlr.v4.tool.ast.GrammarASTErrorNode;
import org.antlr.v4.tool.ast.GrammarRootAST; import org.antlr.v4.tool.ast.GrammarRootAST;
import org.antlr.v4.tool.ast.RuleAST; import org.antlr.v4.tool.ast.RuleAST;
import org.antlr.v4.tool.ast.TerminalAST;
import org.stringtemplate.v4.STGroup; import org.stringtemplate.v4.STGroup;
import java.io.BufferedWriter; import java.io.BufferedWriter;
@ -388,7 +391,8 @@ public class Tool {
if ( g.ast.hasErrors ) return; if ( g.ast.hasErrors ) return;
checkForRedefinedRules(g); boolean ruleFail = checkForRuleIssues(g);
if ( ruleFail ) return;
int prevErrors = errMgr.getNumErrors(); int prevErrors = errMgr.getNumErrors();
// MAKE SURE GRAMMAR IS SEMANTICALLY CORRECT (FILL IN GRAMMAR OBJECT) // MAKE SURE GRAMMAR IS SEMANTICALLY CORRECT (FILL IN GRAMMAR OBJECT)
@ -422,12 +426,14 @@ public class Tool {
/** Important enough to avoid multiple defs that we do very early, /** Important enough to avoid multiple defs that we do very early,
* right after AST construction. Turn redef'd rule's AST RULE node dead * right after AST construction. Turn redef'd rule's AST RULE node dead
* field to true. * field to true. Also check for undefined rules in parser/lexer to
* avoid exceptions later. Return true if we find an undefined rule.
*/ */
public void checkForRedefinedRules(Grammar g) { public boolean checkForRuleIssues(final Grammar g) {
// check for redefined rules
GrammarAST RULES = (GrammarAST)g.ast.getFirstChildWithType(ANTLRParser.RULES); GrammarAST RULES = (GrammarAST)g.ast.getFirstChildWithType(ANTLRParser.RULES);
List<RuleAST> rules = (List<RuleAST>)RULES.getChildren(); List<RuleAST> rules = (List<RuleAST>)RULES.getChildren();
Map<String, RuleAST> ruleToAST = new HashMap<String, RuleAST>(); final Map<String, RuleAST> ruleToAST = new HashMap<String, RuleAST>();
for (RuleAST r : rules) { for (RuleAST r : rules) {
GrammarAST ID = (GrammarAST)r.getChild(0); GrammarAST ID = (GrammarAST)r.getChild(0);
String ruleName = ID.getText(); String ruleName = ID.getText();
@ -444,6 +450,29 @@ public class Tool {
} }
ruleToAST.put(ruleName, r); ruleToAST.put(ruleName, r);
} }
// check for undefined rules
class UndefChecker extends GrammarTreeVisitor {
public boolean undefined = false;
@Override
public void tokenRef(TerminalAST ref) {
if ( g.isLexer() ) ruleRef(ref, null);
}
@Override
public void ruleRef(GrammarAST ref, ActionAST arg) {
RuleAST ruleAST = ruleToAST.get(ref.getText());
if ( ruleAST==null ) {
undefined = true;
errMgr.grammarError(ErrorType.UNDEFINED_RULE_REF,
g.fileName, ref.token, ref.getText());
}
}
}
UndefChecker chk = new UndefChecker();
chk.visitGrammar(g.ast);
return chk.undefined; // no problem
} }
public List<GrammarRootAST> sortGrammarByTokenVocab(List<String> fileNames) { public List<GrammarRootAST> sortGrammarByTokenVocab(List<String> fileNames) {

View File

@ -29,7 +29,6 @@
package org.antlr.v4.semantics; package org.antlr.v4.semantics;
import org.antlr.v4.parse.ANTLRParser;
import org.antlr.v4.tool.Alternative; import org.antlr.v4.tool.Alternative;
import org.antlr.v4.tool.ErrorManager; import org.antlr.v4.tool.ErrorManager;
import org.antlr.v4.tool.ErrorType; import org.antlr.v4.tool.ErrorType;
@ -218,11 +217,6 @@ public class SymbolChecks {
for (GrammarAST ref : rulerefs) { for (GrammarAST ref : rulerefs) {
String ruleName = ref.getText(); String ruleName = ref.getText();
Rule r = g.getRule(ruleName); Rule r = g.getRule(ruleName);
if ( r==null && !ref.hasAncestor(ANTLRParser.DOT)) {
// only give error for unqualified rule refs now
errMgr.grammarError(ErrorType.UNDEFINED_RULE_REF,
g.fileName, ref.token, ruleName);
}
GrammarAST arg = (GrammarAST)ref.getChild(0); GrammarAST arg = (GrammarAST)ref.getChild(0);
if ( arg!=null && (r==null || r.args==null) ) { if ( arg!=null && (r==null || r.args==null) ) {
errMgr.grammarError(ErrorType.RULE_HAS_NO_ARGS, errMgr.grammarError(ErrorType.RULE_HAS_NO_ARGS,