fixed: undefined rule refs caused exception
This commit is contained in:
parent
1916ed0626
commit
0a8e7220f8
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
grammar T;
|
grammar T;
|
||||||
|
|
||||||
s : A # X
|
s : A # X
|
||||||
| B
|
| x
|
||||||
;
|
;
|
||||||
|
|
||||||
s : A ;
|
A : C ;
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in New Issue