org.antlr.v4.runtime.ParserInterpreter.java Source code

Java tutorial

Introduction

Here is the source code for org.antlr.v4.runtime.ParserInterpreter.java

Source

/*
 * Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
 * Use of this file is governed by the BSD 3-clause license that
 * can be found in the LICENSE.txt file in the project root.
 */

package org.antlr.v4.runtime;

import org.antlr.v4.runtime.atn.ATN;
import org.antlr.v4.runtime.atn.ATNState;
import org.antlr.v4.runtime.atn.ActionTransition;
import org.antlr.v4.runtime.atn.AtomTransition;
import org.antlr.v4.runtime.atn.DecisionState;
import org.antlr.v4.runtime.atn.LoopEndState;
import org.antlr.v4.runtime.atn.ParserATNSimulator;
import org.antlr.v4.runtime.atn.PrecedencePredicateTransition;
import org.antlr.v4.runtime.atn.PredicateTransition;
import org.antlr.v4.runtime.atn.PredictionContextCache;
import org.antlr.v4.runtime.atn.RuleStartState;
import org.antlr.v4.runtime.atn.RuleTransition;
import org.antlr.v4.runtime.atn.StarLoopEntryState;
import org.antlr.v4.runtime.atn.Transition;
import org.antlr.v4.runtime.dfa.DFA;
import org.antlr.v4.runtime.misc.Pair;

import java.util.ArrayDeque;
import java.util.Collection;
import java.util.Deque;

/** A parser simulator that mimics what ANTLR's generated
 *  parser code does. A ParserATNSimulator is used to make
 *  predictions via adaptivePredict but this class moves a pointer through the
 *  ATN to simulate parsing. ParserATNSimulator just
 *  makes us efficient rather than having to backtrack, for example.
 *
 *  This properly creates parse trees even for left recursive rules.
 *
 *  We rely on the left recursive rule invocation and special predicate
 *  transitions to make left recursive rules work.
 *
 *  See TestParserInterpreter for examples.
 */
public class ParserInterpreter extends Parser {
    protected final String grammarFileName;
    protected final ATN atn;

    protected final DFA[] decisionToDFA; // not shared like it is for generated parsers
    protected final PredictionContextCache sharedContextCache = new PredictionContextCache();

    @Deprecated
    protected final String[] tokenNames;
    protected final String[] ruleNames;

    private final Vocabulary vocabulary;

    /** This stack corresponds to the _parentctx, _parentState pair of locals
     *  that would exist on call stack frames with a recursive descent parser;
     *  in the generated function for a left-recursive rule you'd see:
     *
     *  private EContext e(int _p) throws RecognitionException {
     *      ParserRuleContext _parentctx = _ctx;    // Pair.a
     *      int _parentState = getState();          // Pair.b
     *      ...
     *  }
     *
     *  Those values are used to create new recursive rule invocation contexts
     *  associated with left operand of an alt like "expr '*' expr".
     */
    protected final Deque<Pair<ParserRuleContext, Integer>> _parentContextStack = new ArrayDeque<Pair<ParserRuleContext, Integer>>();

    /** We need a map from (decision,inputIndex)->forced alt for computing ambiguous
     *  parse trees. For now, we allow exactly one override.
     */
    protected int overrideDecision = -1;
    protected int overrideDecisionInputIndex = -1;
    protected int overrideDecisionAlt = -1;
    protected boolean overrideDecisionReached = false; // latch and only override once; error might trigger infinite loop

    /** What is the current context when we override a decisions?  This tells
     *  us what the root of the parse tree is when using override
     *  for an ambiguity/lookahead check.
     */
    protected InterpreterRuleContext overrideDecisionRoot = null;

    protected InterpreterRuleContext rootContext;

    /**
     * @deprecated Use {@link #ParserInterpreter(String, Vocabulary, Collection, ATN, TokenStream)} instead.
     */
    @Deprecated
    public ParserInterpreter(String grammarFileName, Collection<String> tokenNames, Collection<String> ruleNames,
            ATN atn, TokenStream input) {
        this(grammarFileName, VocabularyImpl.fromTokenNames(tokenNames.toArray(new String[tokenNames.size()])),
                ruleNames, atn, input);
    }

    public ParserInterpreter(String grammarFileName, Vocabulary vocabulary, Collection<String> ruleNames, ATN atn,
            TokenStream input) {
        super(input);
        this.grammarFileName = grammarFileName;
        this.atn = atn;
        this.tokenNames = new String[atn.maxTokenType];
        for (int i = 0; i < tokenNames.length; i++) {
            tokenNames[i] = vocabulary.getDisplayName(i);
        }

        this.ruleNames = ruleNames.toArray(new String[ruleNames.size()]);
        this.vocabulary = vocabulary;

        // init decision DFA
        int numberOfDecisions = atn.getNumberOfDecisions();
        this.decisionToDFA = new DFA[numberOfDecisions];
        for (int i = 0; i < numberOfDecisions; i++) {
            DecisionState decisionState = atn.getDecisionState(i);
            decisionToDFA[i] = new DFA(decisionState, i);
        }

        // get atn simulator that knows how to do predictions
        setInterpreter(new ParserATNSimulator(this, atn, decisionToDFA, sharedContextCache));
    }

    @Override
    public void reset() {
        super.reset();
        overrideDecisionReached = false;
        overrideDecisionRoot = null;
    }

    @Override
    public ATN getATN() {
        return atn;
    }

    @Override
    @Deprecated
    public String[] getTokenNames() {
        return tokenNames;
    }

    @Override
    public Vocabulary getVocabulary() {
        return vocabulary;
    }

    @Override
    public String[] getRuleNames() {
        return ruleNames;
    }

    @Override
    public String getGrammarFileName() {
        return grammarFileName;
    }

    /** Begin parsing at startRuleIndex */
    public ParserRuleContext parse(int startRuleIndex) {
        RuleStartState startRuleStartState = atn.ruleToStartState[startRuleIndex];

        rootContext = createInterpreterRuleContext(null, ATNState.INVALID_STATE_NUMBER, startRuleIndex);
        if (startRuleStartState.isLeftRecursiveRule) {
            enterRecursionRule(rootContext, startRuleStartState.stateNumber, startRuleIndex, 0);
        } else {
            enterRule(rootContext, startRuleStartState.stateNumber, startRuleIndex);
        }

        while (true) {
            ATNState p = getATNState();
            switch (p.getStateType()) {
            case ATNState.RULE_STOP:
                // pop; return from rule
                if (_ctx.isEmpty()) {
                    if (startRuleStartState.isLeftRecursiveRule) {
                        ParserRuleContext result = _ctx;
                        Pair<ParserRuleContext, Integer> parentContext = _parentContextStack.pop();
                        unrollRecursionContexts(parentContext.a);
                        return result;
                    } else {
                        exitRule();
                        return rootContext;
                    }
                }

                visitRuleStopState(p);
                break;

            default:
                try {
                    visitState(p);
                } catch (RecognitionException e) {
                    setState(atn.ruleToStopState[p.ruleIndex].stateNumber);
                    getContext().exception = e;
                    getErrorHandler().reportError(this, e);
                    recover(e);
                }

                break;
            }
        }
    }

    @Override
    public void enterRecursionRule(ParserRuleContext localctx, int state, int ruleIndex, int precedence) {
        Pair<ParserRuleContext, Integer> pair = new Pair<ParserRuleContext, Integer>(_ctx, localctx.invokingState);
        _parentContextStack.push(pair);
        super.enterRecursionRule(localctx, state, ruleIndex, precedence);
    }

    protected ATNState getATNState() {
        return atn.states.get(getState());
    }

    protected void visitState(ATNState p) {
        //      System.out.println("visitState "+p.stateNumber);
        int predictedAlt = 1;
        if (p instanceof DecisionState) {
            predictedAlt = visitDecisionState((DecisionState) p);
        }

        Transition transition = p.transition(predictedAlt - 1);
        switch (transition.getSerializationType()) {
        case Transition.EPSILON:
            if (p.getStateType() == ATNState.STAR_LOOP_ENTRY && ((StarLoopEntryState) p).isPrecedenceDecision
                    && !(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().a,
                        _parentContextStack.peek().b, _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.isLeftRecursiveRule) {
                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);
    }

    /** Method visitDecisionState() is called when the interpreter reaches
     *  a decision state (instance of DecisionState). It gives an opportunity
     *  for subclasses to track interesting things.
     */
    protected int visitDecisionState(DecisionState p) {
        int predictedAlt = 1;
        if (p.getNumberOfTransitions() > 1) {
            getErrorHandler().sync(this);
            int decision = p.decision;
            if (decision == overrideDecision && _input.index() == overrideDecisionInputIndex
                    && !overrideDecisionReached) {
                predictedAlt = overrideDecisionAlt;
                overrideDecisionReached = true;
            } else {
                predictedAlt = getInterpreter().adaptivePredict(_input, decision, _ctx);
            }
        }
        return predictedAlt;
    }

    /** Provide simple "factory" for InterpreterRuleContext's.
     *  @since 4.5.1
     */
    protected InterpreterRuleContext createInterpreterRuleContext(ParserRuleContext parent, int invokingStateNumber,
            int ruleIndex) {
        return new InterpreterRuleContext(parent, invokingStateNumber, ruleIndex);
    }

    protected void visitRuleStopState(ATNState p) {
        RuleStartState ruleStartState = atn.ruleToStartState[p.ruleIndex];
        if (ruleStartState.isLeftRecursiveRule) {
            Pair<ParserRuleContext, Integer> parentContext = _parentContextStack.pop();
            unrollRecursionContexts(parentContext.a);
            setState(parentContext.b);
        } else {
            exitRule();
        }

        RuleTransition ruleTransition = (RuleTransition) atn.states.get(getState()).transition(0);
        setState(ruleTransition.followState.stateNumber);
    }

    /** Override this parser interpreters normal decision-making process
     *  at a particular decision and input token index. Instead of
     *  allowing the adaptive prediction mechanism to choose the
     *  first alternative within a block that leads to a successful parse,
     *  force it to take the alternative, 1..n for n alternatives.
     *
     *  As an implementation limitation right now, you can only specify one
     *  override. This is sufficient to allow construction of different
     *  parse trees for ambiguous input. It means re-parsing the entire input
     *  in general because you're never sure where an ambiguous sequence would
     *  live in the various parse trees. For example, in one interpretation,
     *  an ambiguous input sequence would be matched completely in expression
     *  but in another it could match all the way back to the root.
     *
     *  s : e '!'? ;
     *  e : ID
     *    | ID '!'
     *    ;
     *
     *  Here, x! can be matched as (s (e ID) !) or (s (e ID !)). In the first
     *  case, the ambiguous sequence is fully contained only by the root.
     *  In the second case, the ambiguous sequences fully contained within just
     *  e, as in: (e ID !).
     *
     *  Rather than trying to optimize this and make
     *  some intelligent decisions for optimization purposes, I settled on
     *  just re-parsing the whole input and then using
     *  {link Trees#getRootOfSubtreeEnclosingRegion} to find the minimal
     *  subtree that contains the ambiguous sequence. I originally tried to
     *  record the call stack at the point the parser detected and ambiguity but
     *  left recursive rules create a parse tree stack that does not reflect
     *  the actual call stack. That impedance mismatch was enough to make
     *  it it challenging to restart the parser at a deeply nested rule
     *  invocation.
     *
     *  Only parser interpreters can override decisions so as to avoid inserting
     *  override checking code in the critical ALL(*) prediction execution path.
     *
     *  @since 4.5.1
     */
    public void addDecisionOverride(int decision, int tokenIndex, int forcedAlt) {
        overrideDecision = decision;
        overrideDecisionInputIndex = tokenIndex;
        overrideDecisionAlt = forcedAlt;
    }

    public InterpreterRuleContext getOverrideDecisionRoot() {
        return overrideDecisionRoot;
    }

    /** Rely on the error handler for this parser but, if no tokens are consumed
     *  to recover, add an error node. Otherwise, nothing is seen in the parse
     *  tree.
     */
    protected void recover(RecognitionException e) {
        int i = _input.index();
        getErrorHandler().recover(this, e);
        if (_input.index() == i) {
            // no input consumed, better add an error node
            if (e instanceof InputMismatchException) {
                InputMismatchException ime = (InputMismatchException) e;
                Token tok = e.getOffendingToken();
                int expectedTokenType = Token.INVALID_TYPE;
                if (!ime.getExpectedTokens().isNil()) {
                    expectedTokenType = ime.getExpectedTokens().getMinElement(); // get any element
                }
                Token errToken = getTokenFactory().create(
                        new Pair<TokenSource, CharStream>(tok.getTokenSource(),
                                tok.getTokenSource().getInputStream()),
                        expectedTokenType, tok.getText(), Token.DEFAULT_CHANNEL, -1, -1, // invalid start/stop
                        tok.getLine(), tok.getCharPositionInLine());
                _ctx.addErrorNode(createErrorNode(_ctx, errToken));
            } else { // NoViableAlt
                Token tok = e.getOffendingToken();
                Token errToken = getTokenFactory().create(
                        new Pair<TokenSource, CharStream>(tok.getTokenSource(),
                                tok.getTokenSource().getInputStream()),
                        Token.INVALID_TYPE, tok.getText(), Token.DEFAULT_CHANNEL, -1, -1, // invalid start/stop
                        tok.getLine(), tok.getCharPositionInLine());
                _ctx.addErrorNode(createErrorNode(_ctx, errToken));
            }
        }
    }

    protected Token recoverInline() {
        return _errHandler.recoverInline(this);
    }

    /** Return the root of the parse, which can be useful if the parser
     *  bails out. You still can access the top node. Note that,
     *  because of the way left recursive rules add children, it's possible
     *  that the root will not have any children if the start rule immediately
     *  called and left recursive rule that fails.
     *
     * @since 4.5.1
     */
    public InterpreterRuleContext getRootContext() {
        return rootContext;
    }
}