LL1Analyzer adds EOF to expected tokens set if closure reaches end of start rule.

This commit is contained in:
Sam Harwell 2012-11-04 13:32:45 -06:00
parent a62775c4ba
commit 68b9798d6f
1 changed files with 23 additions and 12 deletions

View File

@ -29,6 +29,7 @@
package org.antlr.v4.runtime.atn; package org.antlr.v4.runtime.atn;
import org.antlr.v4.runtime.IntStream;
import org.antlr.v4.runtime.RuleContext; import org.antlr.v4.runtime.RuleContext;
import org.antlr.v4.runtime.Token; import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.misc.IntervalSet; import org.antlr.v4.runtime.misc.IntervalSet;
@ -63,7 +64,7 @@ public class LL1Analyzer {
boolean seeThruPreds = false; // fail to get lookahead upon pred boolean seeThruPreds = false; // fail to get lookahead upon pred
_LOOK(s.transition(alt - 1).target, _LOOK(s.transition(alt - 1).target,
PredictionContext.EMPTY, PredictionContext.EMPTY,
look[alt], lookBusy, seeThruPreds); look[alt], lookBusy, seeThruPreds, false);
// Wipe out lookahead for this alternative if we found nothing // Wipe out lookahead for this alternative if we found nothing
// or we had a predicate when we !seeThruPreds // or we had a predicate when we !seeThruPreds
if ( look[alt].size()==0 || look[alt].contains(HIT_PRED) ) { if ( look[alt].size()==0 || look[alt].contains(HIT_PRED) ) {
@ -73,15 +74,21 @@ public class LL1Analyzer {
return look; return look;
} }
/** Get lookahead, using ctx if we reach end of rule. If ctx is EMPTY, don't chase FOLLOW. /**
* If ctx is null, EPSILON is in set if we can reach end of rule. * Get lookahead, using {@code ctx} if we reach end of rule. If {@code ctx}
*/ * is {@code null} or {@link RuleContext#EMPTY EMPTY}, don't chase FOLLOW.
* If {@code ctx} is {@code null}, {@link Token#EPSILON EPSILON} is in set
* if we can reach end of rule. If {@code ctx} is
* {@link RuleContext#EMPTY EMPTY}, {@link IntStream#EOF EOF} is in set if
* we can reach end of rule.
*/
@NotNull @NotNull
public IntervalSet LOOK(@NotNull ATNState s, @Nullable RuleContext ctx) { public IntervalSet LOOK(@NotNull ATNState s, @Nullable RuleContext ctx) {
IntervalSet r = new IntervalSet(); IntervalSet r = new IntervalSet();
boolean seeThruPreds = true; // ignore preds; get all lookahead boolean seeThruPreds = true; // ignore preds; get all lookahead
_LOOK(s, PredictionContext.fromRuleContext(s.atn, ctx), PredictionContext lookContext = ctx != null ? PredictionContext.fromRuleContext(s.atn, ctx) : null;
r, new HashSet<ATNConfig>(), seeThruPreds); _LOOK(s, lookContext,
r, new HashSet<ATNConfig>(), seeThruPreds, true);
return r; return r;
} }
@ -95,7 +102,7 @@ public class LL1Analyzer {
protected void _LOOK(@NotNull ATNState s, @Nullable PredictionContext ctx, protected void _LOOK(@NotNull ATNState s, @Nullable PredictionContext ctx,
@NotNull IntervalSet look, @NotNull IntervalSet look,
@NotNull Set<ATNConfig> lookBusy, @NotNull Set<ATNConfig> lookBusy,
boolean seeThruPreds) boolean seeThruPreds, boolean addEOF)
{ {
// System.out.println("_LOOK("+s.stateNumber+", ctx="+ctx); // System.out.println("_LOOK("+s.stateNumber+", ctx="+ctx);
ATNConfig c = new ATNConfig(s, 0, ctx); ATNConfig c = new ATNConfig(s, 0, ctx);
@ -105,13 +112,17 @@ public class LL1Analyzer {
if ( ctx==null ) { if ( ctx==null ) {
look.add(Token.EPSILON); look.add(Token.EPSILON);
return; return;
} } else if (ctx.isEmpty() && addEOF) {
look.add(Token.EOF);
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 (SingletonPredictionContext p : ctx) { for (SingletonPredictionContext p : ctx) {
ATNState returnState = atn.states.get(p.returnState); ATNState returnState = atn.states.get(p.returnState);
// System.out.println("popping back to "+retState); // System.out.println("popping back to "+retState);
_LOOK(returnState, p.parent, look, lookBusy, seeThruPreds); _LOOK(returnState, p.parent, look, lookBusy, seeThruPreds, addEOF);
} }
return; return;
} }
@ -123,18 +134,18 @@ public class LL1Analyzer {
if ( t.getClass() == RuleTransition.class ) { if ( t.getClass() == RuleTransition.class ) {
PredictionContext newContext = PredictionContext newContext =
SingletonPredictionContext.create(ctx, ((RuleTransition)t).followState.stateNumber); SingletonPredictionContext.create(ctx, ((RuleTransition)t).followState.stateNumber);
_LOOK(t.target, newContext, look, lookBusy, seeThruPreds); _LOOK(t.target, newContext, look, lookBusy, seeThruPreds, addEOF);
} }
else if ( t instanceof PredicateTransition ) { else if ( t instanceof PredicateTransition ) {
if ( seeThruPreds ) { if ( seeThruPreds ) {
_LOOK(t.target, ctx, look, lookBusy, seeThruPreds); _LOOK(t.target, ctx, look, lookBusy, seeThruPreds, addEOF);
} }
else { else {
look.add(HIT_PRED); look.add(HIT_PRED);
} }
} }
else if ( t.isEpsilon() ) { else if ( t.isEpsilon() ) {
_LOOK(t.target, ctx, look, lookBusy, seeThruPreds); _LOOK(t.target, ctx, look, lookBusy, seeThruPreds, addEOF);
} }
else if ( t.getClass() == WildcardTransition.class ) { else if ( t.getClass() == WildcardTransition.class ) {
look.addAll( IntervalSet.of(Token.MIN_USER_TOKEN_TYPE, atn.maxTokenType) ); look.addAll( IntervalSet.of(Token.MIN_USER_TOKEN_TYPE, atn.maxTokenType) );