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