LL1Analyzer adds EOF to expected tokens set if closure reaches end of start rule.
This commit is contained in:
parent
a62775c4ba
commit
68b9798d6f
|
@ -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) );
|
||||||
|
|
Loading…
Reference in New Issue