/** Override this method so that we can record which alternative
* was taken at each decision point. For non-left recursive rules,
* it's simple. Set decisionStatesThatSetOuterAltNumInContext
* indicates which decision states should set the outer alternative number.
*
* <p>Left recursive rules are much more complicated to deal with:
* there is typically a decision for the primary alternatives and a
* decision to choose between the recursive operator alternatives.
* For example, the following left recursive rule has two primary and 2
* recursive alternatives.</p>
*
* e : e '*' e
| '-' INT
| e '+' e
| ID
| ;
|
* <p>ANTLR rewrites that rule to be</p>
*
* e[int precedence]
* : ('-' INT | ID)
* ( {...}? '*' e[5]
| {...}? '+' e[3]
| )*
| ;
|
*
* <p>So, there are two decisions associated with picking the outermost alt.
* This complicates our tracking significantly. The outermost alternative number
* is a function of the decision (ATN state) within a left recursive rule and the
* predicted alternative coming back from adaptivePredict().</p>
*
* We use stateToAltsMap as a cache to avoid expensive calls to
* getRecursiveOpAlts().
*/
protected override int VisitDecisionState(DecisionState p)
{
int predictedAlt = base.VisitDecisionState(p);
if (p.NumberOfTransitions > 1)
{
// System.out.println("decision "+p.decision+": "+predictedAlt);
if (p.decision == this.overrideDecision &&
this._input.Index == this.overrideDecisionInputIndex)
{
overrideDecisionRoot = (GrammarInterpreterRuleContext)Context;
}
}
GrammarInterpreterRuleContext ctx = (GrammarInterpreterRuleContext)_ctx;
if (decisionStatesThatSetOuterAltNumInContext.Get(p.stateNumber))
{
ctx.OuterAlternative = predictedAlt;
Rule r = g.GetRule(p.ruleIndex);
if (atn.ruleToStartState[r.index].isPrecedenceRule)
{
int[] alts = stateToAltsMap[p.stateNumber];
LeftRecursiveRule lr = (LeftRecursiveRule)g.GetRule(p.ruleIndex);
if (p.StateType == StateType.BlockStart)
{
if (alts == null)
{
alts = lr.GetPrimaryAlts();
stateToAltsMap[p.stateNumber] = alts; // cache it
}
}
else if (p.StateType == StateType.StarBlockStart)
{
if (alts == null)
{
alts = lr.GetRecursiveOpAlts();
stateToAltsMap[p.stateNumber] = alts; // cache it
}
}
ctx.OuterAlternative = alts[predictedAlt];
}
}
return(predictedAlt);
}