All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.antlr.v4.runtime.Parser Maven / Gradle / Ivy

The newest version!
/*
 * [The "BSD license"]
 *  Copyright (c) 2012 Terence Parr
 *  Copyright (c) 2012 Sam Harwell
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *  1. Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *  2. Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *  3. The name of the author may not be used to endorse or promote products
 *     derived from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 *  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 *  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 *  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package org.antlr.v4.runtime;

import org.antlr.v4.runtime.atn.ATN;
import org.antlr.v4.runtime.atn.ATNSimulator;
import org.antlr.v4.runtime.atn.ATNState;
import org.antlr.v4.runtime.atn.ParserATNSimulator;
import org.antlr.v4.runtime.atn.RuleTransition;
import org.antlr.v4.runtime.dfa.DFA;
import org.antlr.v4.runtime.misc.IntervalSet;
import org.antlr.v4.runtime.misc.Nullable;
import org.antlr.v4.runtime.tree.ErrorNode;
import org.antlr.v4.runtime.tree.ParseTreeListener;
import org.antlr.v4.runtime.tree.ParseTreeWalker;
import org.antlr.v4.runtime.tree.TerminalNode;

import java.util.ArrayList;
import java.util.List;

/** This is all the parsing support code essentially; most of it is error recovery stuff. */
public abstract class Parser extends Recognizer {
	public class TraceListener implements ParseTreeListener {
		@Override
		public void enterEveryRule(ParserRuleContext ctx) {
			System.out.println("enter   " + getRuleNames()[ctx.getRuleIndex()] +
							   ", LT(1)=" + _input.LT(1).getText());
		}

		@Override
		public void visitTerminal(TerminalNode node) {
			System.out.println("consume "+node.getSymbol()+" rule "+
							   getRuleNames()[_ctx.getRuleIndex()]+
							   " alt="+_ctx.altNum);
		}

		@Override
		public void visitErrorNode(ErrorNode node) {
		}

		@Override
		public void exitEveryRule(ParserRuleContext ctx) {
			System.out.println("exit    "+getRuleNames()[ctx.getRuleIndex()]+
							   ", LT(1)="+_input.LT(1).getText());
		}
	}

	public static class TrimToSizeListener implements ParseTreeListener {
		public static final TrimToSizeListener INSTANCE = new TrimToSizeListener();

		@Override
		public void enterEveryRule(ParserRuleContext ctx) { }

		@Override
		public void visitTerminal(TerminalNode node) { }

		@Override
		public void visitErrorNode(ErrorNode node) {	}

		@Override
		public void exitEveryRule(ParserRuleContext ctx) {
			if (ctx.children instanceof ArrayList) {
				((ArrayList)ctx.children).trimToSize();
			}
		}
	}

	protected ANTLRErrorStrategy _errHandler = new DefaultErrorStrategy();

	protected TokenStream _input;

	/** The RuleContext object for the currently executing rule. This
	 *  must be non-null during parsing, but is initially null.
	 *  When somebody calls the start rule, this gets set to the
	 *  root context.
	 */
	protected ParserRuleContext _ctx;

	protected boolean _buildParseTrees = true;

	protected TraceListener _tracer;

	/** If the listener is non-null, trigger enter and exit rule events
     *  *during* the parse. This is typically done only when not building
     *  parse trees for later visiting. We either trigger events during
     *  the parse or during tree walks later. Both could be done.
     *  Not intended for average user!!!  Most people should use
	 *  ParseTreeListener with ParseTreeWalker.
	 *  @see ParseTreeWalker
     */
    protected List _parseListeners;

	/** Did the recognizer encounter a syntax error?  Track how many. */
	protected int _syntaxErrors = 0;

	public Parser(TokenStream input) {
		setInputStream(input);
	}

	/** reset the parser's state */
	public void reset() {
		if ( getInputStream()!=null ) getInputStream().seek(0);
		_errHandler.endErrorCondition(this);
		_ctx = null;
		_syntaxErrors = 0;
		_tracer = null;
		ATNSimulator interpreter = getInterpreter();
		if (interpreter != null) {
			interpreter.reset();
		}
	}

	/** Match current input symbol against ttype.  Attempt
	 *  single token insertion or deletion error recovery.  If
	 *  that fails, throw MismatchedTokenException.
	 */
	public Token match(int ttype) throws RecognitionException {
		Token t = getCurrentToken();
		if ( t.getType()==ttype ) {
			_errHandler.endErrorCondition(this);
			consume();
		}
		else {
			t = _errHandler.recoverInline(this);
			if ( _buildParseTrees && t.getTokenIndex()==-1 ) {
				// we must have conjured up a new token during single token insertion
				// if it's not the current symbol
				_ctx.addErrorNode(t);
			}
		}
		return t;
	}

	public Token matchWildcard() throws RecognitionException {
		Token t = getCurrentToken();
		if (t.getType() > 0) {
			_errHandler.endErrorCondition(this);
			consume();
		}
		else {
			t = _errHandler.recoverInline(this);
			if (_buildParseTrees && t.getTokenIndex() == -1) {
				// we must have conjured up a new token during single token insertion
				// if it's not the current symbol
				_ctx.addErrorNode(t);
			}
		}

		return t;
	}

	/** Track the RuleContext objects during the parse and hook them up
	 *  using the children list so that it forms a parse tree.
	 *  The RuleContext returned from the start rule represents the root
	 *  of the parse tree.
	 *
	 *  To built parse trees, all we have to do is put a hook in setState()
	 *  and enterRule(). In setState(), we add tokens to the current context
	 *  as children. By the time we get to enterRule(), we are already
	 *  in an invoked rule so we add this context as a child of the parent
	 *  (invoking) context. Simple and effective.
	 *
	 *  Note that if we are not building parse trees, rule contexts
	 *  only point upwards. When a rule exits, it returns the context
	 *  but that gets garbage collected if nobody holds a reference.
	 *  It points upwards but nobody points at it.
	 *
	 *  When we build parse trees, we are adding all of these contexts to
	 *  somebody's children list. Contexts are then not candidates
	 *  for garbage collection.
	 */
	public void setBuildParseTree(boolean buildParseTrees) {
		this._buildParseTrees = buildParseTrees;
	}

	public boolean getBuildParseTree() {
		return _buildParseTrees;
	}

	/**
	 * Trim the internal lists of the parse tree during parsing to conserve memory.
	 * This property is set to {@code false} by default for a newly constructed parser.
	 *
	 * @param trimParseTrees {@code true} to trim the capacity of the {@link ParserRuleContext#children}
	 * list to its size after a rule is parsed.
	 */
	public void setTrimParseTree(boolean trimParseTrees) {
		if (trimParseTrees) {
			if (getTrimParseTree()) return;
			addParseListener(TrimToSizeListener.INSTANCE);
		}
		else {
			removeParseListener(TrimToSizeListener.INSTANCE);
		}
	}

	/**
	 * @return {@code true} if the {@link ParserRuleContext#children} list is trimmed
	 * using the default {@link Parser.TrimToSizeListener} during the parse process.
	 */
	public boolean getTrimParseTree() {
		if (_parseListeners == null) return false;
		return _parseListeners.contains(TrimToSizeListener.INSTANCE);
	}

//	public void setTraceATNStates(boolean traceATNStates) {
//		this.traceATNStates = traceATNStates;
//	}
//
//	public boolean getTraceATNStates() {
//		return traceATNStates;
//	}

    public List getParseListeners() {
        return _parseListeners;
    }

	/** Provide a listener that gets notified about token matches,
	 *  and rule entry/exit events DURING the parse. It's a little bit
	 *  weird for left recursive rule entry events but it's
	 *  deterministic.
	 *
	 *  THIS IS ONLY FOR ADVANCED USERS. Please give your
	 *  ParseTreeListener to a ParseTreeWalker instead of giving it to
	 *  the parser!!!!
	 */
    public void addParseListener(ParseTreeListener listener) {
		if ( listener==null ) return;
		if ( _parseListeners==null ) {
			_parseListeners = new ArrayList();
		}
        this._parseListeners.add(listener);
    }

	public void removeParseListener(ParseTreeListener l) {
		if ( l==null ) return;
		if ( _parseListeners!=null ) {
			_parseListeners.remove(l);
			if (_parseListeners.isEmpty()) {
				_parseListeners = null;
			}
		}
	}

	public void removeParseListeners() {
		_parseListeners = null;
	}

	/** Notify any parse listeners (implemented as ParseTreeListener's)
	 *  of an enter rule event. This is not involved with
	 *  parse tree walking in any way; it's just reusing the
	 *  ParseTreeListener interface. This is not for the average user.
	 */
	public void triggerEnterRuleEvent() {
		for (ParseTreeListener l : _parseListeners) {
			l.enterEveryRule(_ctx);
			_ctx.enterRule(l);
		}
	}

	/** Notify any parse listeners (implemented as ParseTreeListener's)
	 *  of an exit rule event. This is not involved with
	 *  parse tree walking in any way; it's just reusing the
	 *  ParseTreeListener interface. This is not for the average user.
	 */
	public void triggerExitRuleEvent() {
		// reverse order walk of listeners
		for (int i = _parseListeners.size()-1; i >= 0; i--) {
			ParseTreeListener l = _parseListeners.get(i);
			_ctx.exitRule(l);
			l.exitEveryRule(_ctx);
		}
	}

    /** Get number of recognition errors (lexer, parser, tree parser).  Each
	 *  recognizer tracks its own number.  So parser and lexer each have
	 *  separate count.  Does not count the spurious errors found between
	 *  an error and next valid token match
	 *
	 *  See also reportError()
	 */
	public int getNumberOfSyntaxErrors() {
		return _syntaxErrors;
	}

	/** Tell our token source and error strategy about a new way to create tokens */
	@Override
	public void setTokenFactory(TokenFactory factory) {
		_input.getTokenSource().setTokenFactory(factory);
		_errHandler.setTokenFactory(factory);
	}

	public ANTLRErrorStrategy getErrorHandler() {
		return _errHandler;
	}

	public void setErrorHandler(ANTLRErrorStrategy handler) {
		this._errHandler = handler;
	}

	@Override
	public TokenStream getInputStream() { return getTokenStream(); }

	@Override
	public final void setInputStream(IntStream input) {
		setTokenStream((TokenStream)input);
	}

	public TokenStream getTokenStream() {
		return _input;
	}

	/** Set the token stream and reset the parser */
	public void setTokenStream(TokenStream input) {
		this._input = null;
		reset();
		this._input = input;
	}

    /** Match needs to return the current input symbol, which gets put
     *  into the label for the associated token ref; e.g., x=ID.
     */
    public Token getCurrentToken() {
		return _input.LT(1);
	}

    public void notifyErrorListeners(String msg)	{
		notifyErrorListeners(getCurrentToken(), msg, null);
	}

	public void notifyErrorListeners(Token offendingToken, String msg,
									 @Nullable RecognitionException e)
	{
		int line = -1;
		int charPositionInLine = -1;
		line = offendingToken.getLine();
		charPositionInLine = offendingToken.getCharPositionInLine();

		ANTLRErrorListener listener = getErrorListenerDispatch();
		listener.syntaxError(this, offendingToken, line, charPositionInLine, msg, e);
	}

	/** Consume the current symbol and return it. E.g., given the following
	 *  input with A being the current lookahead symbol:
	 *
	 *  	A B
	 *  	^
	 *
	 *  this function moves the cursor to B and returns A.
	 *
	 *  If the parser is creating parse trees, the current symbol
	 *  would also be added as a child to the current context (node).
     *
     *  Trigger listener events if there's a listener.
	 */
	public Token consume() {
		Token o = getCurrentToken();
		if (o.getType() != EOF) {
			getInputStream().consume();
		}
		boolean hasListener = _parseListeners != null && !_parseListeners.isEmpty();
		if (_buildParseTrees || hasListener) {
			if ( _errHandler.inErrorRecoveryMode(this) ) {
				ErrorNode node = _ctx.addErrorNode(o);
				if (_parseListeners != null) {
					for (ParseTreeListener listener : _parseListeners) {
						listener.visitErrorNode(node);
					}
				}
			}
			else {
				TerminalNode node = _ctx.addChild(o);
				if (_parseListeners != null) {
					for (ParseTreeListener listener : _parseListeners) {
						listener.visitTerminal(node);
					}
				}
			}
		}
		return o;
	}

	protected void addContextToParseTree() {
		ParserRuleContext parent = (ParserRuleContext)_ctx.parent;
		// add current context to parent if we have a parent
		if ( parent!=null )	{
			parent.addChild(_ctx);
		}
	}

	/** Always called by generated parsers upon entry to a rule.
	 *  This occurs after the new context has been pushed. Access field
	 *  _ctx get the current context.
	 *
	 *  This is flexible because users do not have to regenerate parsers
	 *  to get trace facilities.
	 */
	public void enterRule(ParserRuleContext localctx, int state, int ruleIndex) {
		setState(state);
		_ctx = localctx;
		_ctx.start = _input.LT(1);
		if (_buildParseTrees) addContextToParseTree();
        if ( _parseListeners != null) triggerEnterRuleEvent();
	}

    public void exitRule() {
		_ctx.stop = _input.LT(-1);
        // trigger event on _ctx, before it reverts to parent
        if ( _parseListeners != null) triggerExitRuleEvent();
		setState(_ctx.invokingState);
		_ctx = (ParserRuleContext)_ctx.parent;
    }

	public void enterOuterAlt(ParserRuleContext localctx, int altNum) {
		// if we have new localctx, make sure we replace existing ctx
		// that is previous child of parse tree
		if ( _buildParseTrees && _ctx != localctx ) {
			ParserRuleContext parent = (ParserRuleContext)_ctx.parent;
			if ( parent!=null )	{
				parent.removeLastChild();
				parent.addChild(localctx);
			}
		}
		_ctx = localctx;
		_ctx.altNum = altNum;
	}

	public void enterRecursionRule(ParserRuleContext localctx, int ruleIndex) {
		_ctx = localctx;
		_ctx.start = _input.LT(1);
		if (_parseListeners != null) {
			triggerEnterRuleEvent(); // simulates rule entry for left-recursive rules
		}
	}

	/* like enterRule but for recursive rules */
	public void pushNewRecursionContext(ParserRuleContext localctx, int state, int ruleIndex) {
		ParserRuleContext previous = _ctx;
		previous.parent = localctx;
		previous.invokingState = state;
		previous.stop = _input.LT(-1);

		_ctx = localctx;
		_ctx.start = previous.start;
		if (_buildParseTrees) {
			_ctx.addChild(previous);
		}

		if ( _parseListeners != null ) {
			triggerEnterRuleEvent(); // simulates rule entry for left-recursive rules
		}
	}

	public void unrollRecursionContexts(ParserRuleContext _parentctx) {
		_ctx.stop = _input.LT(-1);
		ParserRuleContext retctx = _ctx; // save current ctx (return value)

		// unroll so _ctx is as it was before call to recursive method
		if ( _parseListeners != null ) {
			while ( _ctx != _parentctx ) {
				triggerExitRuleEvent();
				_ctx = (ParserRuleContext)_ctx.parent;
			}
		}
		else {
			_ctx = _parentctx;
		}
		// hook into tree
		retctx.parent = _parentctx;
		if (_buildParseTrees) _parentctx.addChild(retctx); // add return ctx into invoking rule's tree
	}

	public ParserRuleContext getInvokingContext(int ruleIndex) {
		ParserRuleContext p = _ctx;
		while ( p!=null ) {
			if ( p.getRuleIndex() == ruleIndex ) return p;
			p = (ParserRuleContext)p.parent;
		}
		return null;
	}

	public ParserRuleContext getContext() {
		return _ctx;
	}

	public boolean inContext(String context) {
		// TODO: useful in parser?
		return false;
	}

    public boolean isExpectedToken(int symbol) {
//   		return getInterpreter().atn.nextTokens(_ctx);
        ATN atn = getInterpreter().atn;
		ParserRuleContext ctx = _ctx;
        ATNState s = atn.states.get(getState());
        IntervalSet following = atn.nextTokens(s);
        if (following.contains(symbol)) {
            return true;
        }
//        System.out.println("following "+s+"="+following);
        if ( !following.contains(Token.EPSILON) ) return false;

        while ( ctx!=null && ctx.invokingState>=0 && following.contains(Token.EPSILON) ) {
            ATNState invokingState = atn.states.get(ctx.invokingState);
            RuleTransition rt = (RuleTransition)invokingState.transition(0);
            following = atn.nextTokens(rt.followState);
            if (following.contains(symbol)) {
                return true;
            }

            ctx = (ParserRuleContext)ctx.parent;
        }

        if ( following.contains(Token.EPSILON) && symbol == Token.EOF ) {
            return true;
        }

        return false;
    }

	/** Compute the set of valid tokens reachable from the current
	 *  position in the parse.
	 */
    public IntervalSet getExpectedTokens() {
        ATN atn = getInterpreter().atn;
		ParserRuleContext ctx = _ctx;
        ATNState s = atn.states.get(getState());
        IntervalSet following = atn.nextTokens(s);
//        System.out.println("following "+s+"="+following);
        if ( !following.contains(Token.EPSILON) ) return following;
        IntervalSet expected = new IntervalSet();
        expected.addAll(following);
        expected.remove(Token.EPSILON);
        while ( ctx!=null && ctx.invokingState>=0 && following.contains(Token.EPSILON) ) {
            ATNState invokingState = atn.states.get(ctx.invokingState);
            RuleTransition rt = (RuleTransition)invokingState.transition(0);
            following = atn.nextTokens(rt.followState);
            expected.addAll(following);
            expected.remove(Token.EPSILON);
            ctx = (ParserRuleContext)ctx.parent;
        }
        if ( following.contains(Token.EPSILON) ) {
            expected.add(Token.EOF);
        }
        return expected;
   	}

    public IntervalSet getExpectedTokensWithinCurrentRule() {
        ATN atn = getInterpreter().atn;
        ATNState s = atn.states.get(getState());
   		return atn.nextTokens(s);
   	}

//	/** Compute the set of valid tokens reachable from the current
//	 *  position in the parse.
//	 */
//	public IntervalSet nextTokens(@NotNull RuleContext ctx) {
//		ATN atn = getInterpreter().atn;
//		ATNState s = atn.states.get(ctx.s);
//		if ( s == null ) return null;
//		return atn.nextTokens(s, ctx);
//	}

	public ParserRuleContext getRuleContext() { return _ctx; }

	/** Return List of the rule names in your parser instance
	 *  leading up to a call to the current rule.  You could override if
	 *  you want more details such as the file/line info of where
	 *  in the ATN a rule is invoked.
	 *
	 *  This is very useful for error messages.
	 */
	public List getRuleInvocationStack() {
		return getRuleInvocationStack(_ctx);
	}

	public List getRuleInvocationStack(RuleContext p) {
		String[] ruleNames = getRuleNames();
		List stack = new ArrayList();
		while ( p!=null ) {
			// compute what follows who invoked us
			int ruleIndex = p.getRuleIndex();
			if ( ruleIndex<0 ) stack.add("n/a");
			else stack.add(ruleNames[ruleIndex]);
			p = p.parent;
		}
		return stack;
	}

    /** For debugging and other purposes */
	public List getDFAStrings() {
		synchronized (_interp.decisionToDFA) {
			List s = new ArrayList();
			for (int d = 0; d < _interp.decisionToDFA.length; d++) {
				DFA dfa = _interp.decisionToDFA[d];
				s.add( dfa.toString(getTokenNames()) );
			}
			return s;
		}
    }

	/** For debugging and other purposes */
	public void dumpDFA() {
		synchronized (_interp.decisionToDFA) {
			boolean seenOne = false;
			for (int d = 0; d < _interp.decisionToDFA.length; d++) {
				DFA dfa = _interp.decisionToDFA[d];
				if ( dfa!=null ) {
					if ( seenOne ) System.out.println();
					System.out.println("Decision " + dfa.decision + ":");
					System.out.print(dfa.toString(getTokenNames()));
					seenOne = true;
				}
			}
		}
    }

	public String getSourceName() {
		return _input.getSourceName();
	}

	/** A convenience method for use most often with template rewrites.
	 *  Convert a List to List
	 */
	public List toStrings(List tokens) {
		if ( tokens==null ) return null;
		List strings = new ArrayList(tokens.size());
		for (int i=0; i




© 2015 - 2025 Weber Informatics LLC | Privacy Policy