use of org.antlr.v4.runtime.atn.ATNState in project antlr4 by tunnelvisionlabs.
the class LeftRecursionDetector method check.
public void check() {
for (RuleStartState start : atn.ruleToStartState) {
// System.out.print("check "+start.rule.name);
rulesVisitedPerRuleCheck.clear();
rulesVisitedPerRuleCheck.add(start);
// FASerializer ser = new FASerializer(atn.g, start);
// System.out.print(":\n"+ser+"\n");
check(g.getRule(start.ruleIndex), start, new HashSet<ATNState>());
}
// System.out.println("cycles="+listOfRecursiveCycles);
if (!listOfRecursiveCycles.isEmpty()) {
g.tool.errMgr.leftRecursionCycles(g.fileName, listOfRecursiveCycles);
}
}
use of org.antlr.v4.runtime.atn.ATNState in project antlr4 by tunnelvisionlabs.
the class ParserATNSimulator method computeStartState.
@NotNull
protected SimulatorState computeStartState(DFA dfa, ParserRuleContext globalContext, boolean useContext) {
DFAState s0 = dfa.isPrecedenceDfa() ? dfa.getPrecedenceStartState(parser.getPrecedence(), useContext) : useContext ? dfa.s0full.get() : dfa.s0.get();
if (s0 != null) {
if (!useContext) {
return new SimulatorState(globalContext, s0, useContext, globalContext);
}
s0.setContextSensitive(atn);
}
final int decision = dfa.decision;
@NotNull final ATNState p = dfa.atnStartState;
int previousContext = 0;
ParserRuleContext remainingGlobalContext = globalContext;
// always at least the implicit call to start rule
PredictionContext initialContext = useContext ? PredictionContext.EMPTY_FULL : PredictionContext.EMPTY_LOCAL;
PredictionContextCache contextCache = new PredictionContextCache();
if (useContext) {
if (!enable_global_context_dfa) {
while (remainingGlobalContext != null) {
if (remainingGlobalContext.isEmpty()) {
previousContext = PredictionContext.EMPTY_FULL_STATE_KEY;
remainingGlobalContext = null;
} else {
previousContext = getReturnState(remainingGlobalContext);
initialContext = initialContext.appendContext(previousContext, contextCache);
remainingGlobalContext = remainingGlobalContext.getParent();
}
}
}
while (s0 != null && s0.isContextSensitive() && remainingGlobalContext != null) {
DFAState next;
remainingGlobalContext = skipTailCalls(remainingGlobalContext);
if (remainingGlobalContext.isEmpty()) {
next = s0.getContextTarget(PredictionContext.EMPTY_FULL_STATE_KEY);
previousContext = PredictionContext.EMPTY_FULL_STATE_KEY;
remainingGlobalContext = null;
} else {
previousContext = getReturnState(remainingGlobalContext);
next = s0.getContextTarget(previousContext);
initialContext = initialContext.appendContext(previousContext, contextCache);
remainingGlobalContext = remainingGlobalContext.getParent();
}
if (next == null) {
break;
}
s0 = next;
}
}
if (s0 != null && !s0.isContextSensitive()) {
return new SimulatorState(globalContext, s0, useContext, remainingGlobalContext);
}
ATNConfigSet configs = new ATNConfigSet();
while (true) {
ATNConfigSet reachIntermediate = new ATNConfigSet();
int n = p.getNumberOfTransitions();
for (int ti = 0; ti < n; ti++) {
// for each transition
ATNState target = p.transition(ti).target;
reachIntermediate.add(ATNConfig.create(target, ti + 1, initialContext));
}
boolean hasMoreContext = remainingGlobalContext != null;
if (!hasMoreContext) {
configs.setOutermostConfigSet(true);
}
final boolean collectPredicates = true;
closure(reachIntermediate, configs, collectPredicates, hasMoreContext, contextCache, false);
boolean stepIntoGlobal = configs.getDipsIntoOuterContext();
DFAState next;
if (useContext && !enable_global_context_dfa) {
s0 = addDFAState(dfa, configs, contextCache);
break;
} else if (s0 == null) {
if (!dfa.isPrecedenceDfa()) {
AtomicReference<DFAState> reference = useContext ? dfa.s0full : dfa.s0;
next = addDFAState(dfa, configs, contextCache);
if (!reference.compareAndSet(null, next)) {
next = reference.get();
}
} else {
/* If this is a precedence DFA, we use applyPrecedenceFilter
* to convert the computed start state to a precedence start
* state. We then use DFA.setPrecedenceStartState to set the
* appropriate start state for the precedence level rather
* than simply setting DFA.s0.
*/
configs = applyPrecedenceFilter(configs, globalContext, contextCache);
next = addDFAState(dfa, configs, contextCache);
dfa.setPrecedenceStartState(parser.getPrecedence(), useContext, next);
}
} else {
if (dfa.isPrecedenceDfa()) {
configs = applyPrecedenceFilter(configs, globalContext, contextCache);
}
next = addDFAState(dfa, configs, contextCache);
s0.setContextTarget(previousContext, next);
}
s0 = next;
if (!useContext || !stepIntoGlobal) {
break;
}
// TODO: make sure it distinguishes empty stack states
next.setContextSensitive(atn);
configs.clear();
remainingGlobalContext = skipTailCalls(remainingGlobalContext);
int nextContextElement = getReturnState(remainingGlobalContext);
if (remainingGlobalContext.isEmpty()) {
remainingGlobalContext = null;
} else {
remainingGlobalContext = remainingGlobalContext.getParent();
}
if (nextContextElement != PredictionContext.EMPTY_FULL_STATE_KEY) {
initialContext = initialContext.appendContext(nextContextElement, contextCache);
}
previousContext = nextContextElement;
}
return new SimulatorState(globalContext, s0, useContext, remainingGlobalContext);
}
use of org.antlr.v4.runtime.atn.ATNState in project antlr4 by tunnelvisionlabs.
the class Parser method getExpectedTokensWithinCurrentRule.
@NotNull
public IntervalSet getExpectedTokensWithinCurrentRule() {
ATN atn = getInterpreter().atn;
ATNState s = atn.states.get(getState());
return atn.nextTokens(s);
}
use of org.antlr.v4.runtime.atn.ATNState in project antlr4 by tunnelvisionlabs.
the class ParserInterpreter method visitState.
protected void visitState(ATNState p) {
int predictedAlt = 1;
if (p.getNumberOfTransitions() > 1) {
predictedAlt = visitDecisionState((DecisionState) p);
}
Transition transition = p.transition(predictedAlt - 1);
switch(transition.getSerializationType()) {
case Transition.EPSILON:
if (pushRecursionContextStates.get(p.stateNumber) && !(transition.target instanceof LoopEndState)) {
// We are at the start of a left recursive rule's (...)* loop
// and we're not taking the exit branch of loop.
InterpreterRuleContext localctx = createInterpreterRuleContext(_parentContextStack.peek().getItem1(), _parentContextStack.peek().getItem2(), _ctx.getRuleIndex());
pushNewRecursionContext(localctx, atn.ruleToStartState[p.ruleIndex].stateNumber, _ctx.getRuleIndex());
}
break;
case Transition.ATOM:
match(((AtomTransition) transition).label);
break;
case Transition.RANGE:
case Transition.SET:
case Transition.NOT_SET:
if (!transition.matches(_input.LA(1), Token.MIN_USER_TOKEN_TYPE, 65535)) {
recoverInline();
}
matchWildcard();
break;
case Transition.WILDCARD:
matchWildcard();
break;
case Transition.RULE:
RuleStartState ruleStartState = (RuleStartState) transition.target;
int ruleIndex = ruleStartState.ruleIndex;
InterpreterRuleContext newctx = createInterpreterRuleContext(_ctx, p.stateNumber, ruleIndex);
if (ruleStartState.isPrecedenceRule) {
enterRecursionRule(newctx, ruleStartState.stateNumber, ruleIndex, ((RuleTransition) transition).precedence);
} else {
enterRule(newctx, transition.target.stateNumber, ruleIndex);
}
break;
case Transition.PREDICATE:
PredicateTransition predicateTransition = (PredicateTransition) transition;
if (!sempred(_ctx, predicateTransition.ruleIndex, predicateTransition.predIndex)) {
throw new FailedPredicateException(this);
}
break;
case Transition.ACTION:
ActionTransition actionTransition = (ActionTransition) transition;
action(_ctx, actionTransition.ruleIndex, actionTransition.actionIndex);
break;
case Transition.PRECEDENCE:
if (!precpred(_ctx, ((PrecedencePredicateTransition) transition).precedence)) {
throw new FailedPredicateException(this, String.format("precpred(_ctx, %d)", ((PrecedencePredicateTransition) transition).precedence));
}
break;
default:
throw new UnsupportedOperationException("Unrecognized ATN transition type.");
}
setState(transition.target.stateNumber);
}
use of org.antlr.v4.runtime.atn.ATNState in project antlr4 by tunnelvisionlabs.
the class DefaultErrorStrategy method getErrorRecoverySet.
/* Compute the error recovery set for the current rule. During
* rule invocation, the parser pushes the set of tokens that can
* follow that rule reference on the stack; this amounts to
* computing FIRST of what follows the rule reference in the
* enclosing rule. See LinearApproximator.FIRST().
* This local follow set only includes tokens
* from within the rule; i.e., the FIRST computation done by
* ANTLR stops at the end of a rule.
*
* EXAMPLE
*
* When you find a "no viable alt exception", the input is not
* consistent with any of the alternatives for rule r. The best
* thing to do is to consume tokens until you see something that
* can legally follow a call to r *or* any rule that called r.
* You don't want the exact set of viable next tokens because the
* input might just be missing a token--you might consume the
* rest of the input looking for one of the missing tokens.
*
* Consider grammar:
*
* a : '[' b ']'
* | '(' b ')'
* ;
* b : c '^' INT ;
* c : ID
* | INT
* ;
*
* At each rule invocation, the set of tokens that could follow
* that rule is pushed on a stack. Here are the various
* context-sensitive follow sets:
*
* FOLLOW(b1_in_a) = FIRST(']') = ']'
* FOLLOW(b2_in_a) = FIRST(')') = ')'
* FOLLOW(c_in_b) = FIRST('^') = '^'
*
* Upon erroneous input "[]", the call chain is
*
* a -> b -> c
*
* and, hence, the follow context stack is:
*
* depth follow set start of rule execution
* 0 <EOF> a (from main())
* 1 ']' b
* 2 '^' c
*
* Notice that ')' is not included, because b would have to have
* been called from a different context in rule a for ')' to be
* included.
*
* For error recovery, we cannot consider FOLLOW(c)
* (context-sensitive or otherwise). We need the combined set of
* all context-sensitive FOLLOW sets--the set of all tokens that
* could follow any reference in the call chain. We need to
* resync to one of those tokens. Note that FOLLOW(c)='^' and if
* we resync'd to that token, we'd consume until EOF. We need to
* sync to context-sensitive FOLLOWs for a, b, and c: {']','^'}.
* In this case, for input "[]", LA(1) is ']' and in the set, so we would
* not consume anything. After printing an error, rule c would
* return normally. Rule b would not find the required '^' though.
* At this point, it gets a mismatched token error and throws an
* exception (since LA(1) is not in the viable following token
* set). The rule exception handler tries to recover, but finds
* the same recovery set and doesn't consume anything. Rule b
* exits normally returning to rule a. Now it finds the ']' (and
* with the successful match exits errorRecovery mode).
*
* So, you can see that the parser walks up the call chain looking
* for the token that was a member of the recovery set.
*
* Errors are not generated in errorRecovery mode.
*
* ANTLR's error recovery mechanism is based upon original ideas:
*
* "Algorithms + Data Structures = Programs" by Niklaus Wirth
*
* and
*
* "A note on error recovery in recursive descent parsers":
* http://portal.acm.org/citation.cfm?id=947902.947905
*
* Later, Josef Grosch had some good ideas:
*
* "Efficient and Comfortable Error Recovery in Recursive Descent
* Parsers":
* ftp://www.cocolab.com/products/cocktail/doca4.ps/ell.ps.zip
*
* Like Grosch I implement context-sensitive FOLLOW sets that are combined
* at run-time upon error to avoid overhead during parsing.
*/
@NotNull
protected IntervalSet getErrorRecoverySet(@NotNull Parser recognizer) {
ATN atn = recognizer.getInterpreter().atn;
RuleContext ctx = recognizer._ctx;
IntervalSet recoverSet = new IntervalSet();
while (ctx != null && ctx.invokingState >= 0) {
// compute what follows who invoked us
ATNState invokingState = atn.states.get(ctx.invokingState);
RuleTransition rt = (RuleTransition) invokingState.transition(0);
IntervalSet follow = atn.nextTokens(rt.followState);
recoverSet.addAll(follow);
ctx = ctx.parent;
}
recoverSet.remove(Token.EPSILON);
// System.out.println("recover set "+recoverSet.toString(recognizer.getTokenNames()));
return recoverSet;
}
Aggregations