fix LL1 analyzer

This commit is contained in:
parrt 2016-12-09 18:07:47 -08:00
parent 3a6ffafec3
commit 0eb27279de
4 changed files with 54 additions and 15 deletions

View File

@ -150,7 +150,8 @@ public class LL1Analyzer {
if (ctx == null) { if (ctx == null) {
look.add(Token.EPSILON); look.add(Token.EPSILON);
return; return;
} else if (ctx.isEmpty() && addEOF) { }
else if (ctx.isEmpty() && addEOF) {
look.add(Token.EOF); look.add(Token.EOF);
return; return;
} }
@ -160,26 +161,26 @@ public class LL1Analyzer {
if ( ctx==null ) { if ( ctx==null ) {
look.add(Token.EPSILON); look.add(Token.EPSILON);
return; return;
} else if (ctx.isEmpty() && addEOF) { }
else if (ctx.isEmpty() && addEOF) {
look.add(Token.EOF); look.add(Token.EOF);
return; return;
} }
if ( ctx != PredictionContext.EMPTY ) { if ( ctx != PredictionContext.EMPTY ) {
// run thru all possible stack tops in ctx // run thru all possible stack tops in ctx
for (int i = 0; i < ctx.size(); i++) { boolean removed = calledRuleStack.get(s.ruleIndex);
ATNState returnState = atn.states.get(ctx.getReturnState(i)); try {
// System.out.println("popping back to "+retState); calledRuleStack.clear(s.ruleIndex);
for (int i = 0; i < ctx.size(); i++) {
boolean removed = calledRuleStack.get(returnState.ruleIndex); ATNState returnState = atn.states.get(ctx.getReturnState(i));
try { // System.out.println("popping back to "+retState);
calledRuleStack.clear(returnState.ruleIndex);
_LOOK(returnState, stopState, ctx.getParent(i), look, lookBusy, calledRuleStack, seeThruPreds, addEOF); _LOOK(returnState, stopState, ctx.getParent(i), look, lookBusy, calledRuleStack, seeThruPreds, addEOF);
} }
finally { }
if (removed) { finally {
calledRuleStack.set(returnState.ruleIndex); if (removed) {
} calledRuleStack.set(s.ruleIndex);
} }
} }
return; return;

View File

@ -317,6 +317,40 @@ public class TestToolSyntaxErrors extends BaseJavaToolTest {
super.testErrors(pair, true); super.testErrors(pair, true);
} }
// Test for https://github.com/antlr/antlr4/issues/1203
@Test public void testEpsilonNestedClosureAnalysis() {
String grammar =
"grammar T;\n"+
"s : (a a)* ;\n"+
"a : 'foo'* ;\n";
String expected =
"error(" + ErrorType.EPSILON_CLOSURE.code + "): T.g4:2:0: rule s contains a closure with at least one alternative that can match an empty string\n";
String[] pair = new String[] {
grammar,
expected
};
super.testErrors(pair, true);
}
// Test for https://github.com/antlr/antlr4/issues/1203
@Test public void testEpsilonOptionalAndClosureAnalysis() {
String grammar =
"grammar T;\n"+
"s : (a a)? ;\n"+
"a : 'foo'* ;\n";
String expected =
"warning(" + ErrorType.EPSILON_OPTIONAL.code + "): T.g4:2:0: rule s contains an optional block with at least one alternative that can match an empty string\n";
String[] pair = new String[] {
grammar,
expected
};
super.testErrors(pair, true);
}
@Test public void testEpsilonOptionalAnalysis() { @Test public void testEpsilonOptionalAnalysis() {
String grammar = String grammar =
"grammar A;\n" "grammar A;\n"

View File

@ -34,7 +34,8 @@ public class AnalysisPipeline {
if (g.isLexer()) { if (g.isLexer()) {
processLexer(); processLexer();
} else { }
else {
// BUILD DFA FOR EACH DECISION // BUILD DFA FOR EACH DECISION
processParser(); processParser();
} }

View File

@ -113,7 +113,10 @@ public class ParserATNFactory implements ATNFactory {
for (Triple<Rule, ATNState, ATNState> pair : preventEpsilonClosureBlocks) { for (Triple<Rule, ATNState, ATNState> pair : preventEpsilonClosureBlocks) {
LL1Analyzer analyzer = new LL1Analyzer(atn); LL1Analyzer analyzer = new LL1Analyzer(atn);
if (analyzer.LOOK(pair.b, pair.c, null).contains(org.antlr.v4.runtime.Token.EPSILON)) { ATNState blkStart = pair.b;
ATNState blkStop = pair.c;
IntervalSet lookahead = analyzer.LOOK(blkStart, blkStop, null);
if ( lookahead.contains(org.antlr.v4.runtime.Token.EPSILON)) {
ErrorType errorType = pair.a instanceof LeftRecursiveRule ? ErrorType.EPSILON_LR_FOLLOW : ErrorType.EPSILON_CLOSURE; ErrorType errorType = pair.a instanceof LeftRecursiveRule ? ErrorType.EPSILON_LR_FOLLOW : ErrorType.EPSILON_CLOSURE;
g.tool.errMgr.grammarError(errorType, g.fileName, ((GrammarAST)pair.a.ast.getChild(0)).getToken(), pair.a.name); g.tool.errMgr.grammarError(errorType, g.fileName, ((GrammarAST)pair.a.ast.getChild(0)).getToken(), pair.a.name);
} }