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

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

There is a newer version: 4.9.0
Show 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.ATNDeserializationOptions;
import org.antlr.v4.runtime.atn.ATNDeserializer;
import org.antlr.v4.runtime.atn.ATNSerializer;
import org.antlr.v4.runtime.atn.ATNSimulator;
import org.antlr.v4.runtime.atn.ATNState;
import org.antlr.v4.runtime.atn.AmbiguityInfo;
import org.antlr.v4.runtime.atn.ParseInfo;
import org.antlr.v4.runtime.atn.ParserATNSimulator;
import org.antlr.v4.runtime.atn.PredictionMode;
import org.antlr.v4.runtime.atn.ProfilingATNSimulator;
import org.antlr.v4.runtime.atn.RuleTransition;
import org.antlr.v4.runtime.dfa.DFA;
import org.antlr.v4.runtime.misc.IntegerStack;
import org.antlr.v4.runtime.misc.IntervalSet;
import org.antlr.v4.runtime.misc.NotNull;
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 org.antlr.v4.runtime.tree.Trees;
import org.antlr.v4.runtime.tree.pattern.ParseTreePattern;
import org.antlr.v4.runtime.tree.pattern.ParseTreePatternMatcher;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;

/** 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 exitEveryRule(ParserRuleContext ctx) {
			System.out.println("exit    "+getRuleNames()[ctx.getRuleIndex()]+
							   ", LT(1)="+_input.LT(1).getText());
		}

		@Override
		public void visitErrorNode(ErrorNode node) {
		}

		@Override
		public void visitTerminal(TerminalNode node) {
			ParserRuleContext parent = (ParserRuleContext)node.getParent().getRuleContext();
			Token token = node.getSymbol();
			System.out.println("consume "+token+" rule "+
							   getRuleNames()[parent.getRuleIndex()]);
		}
	}

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

		@Override
		public void visitTerminal(TerminalNode node) {
		}

		@Override
		public void visitErrorNode(ErrorNode node) {
		}

		@Override
		public void enterEveryRule(ParserRuleContext ctx) {
		}

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

	/**
	 * This field maps from the serialized ATN string to the deserialized {@link ATN} with
	 * bypass alternatives.
	 *
	 * @see ATNDeserializationOptions#isGenerateRuleBypassTransitions()
	 */
	private static final Map bypassAltsAtnCache =
		new WeakHashMap();

	/**
	 * The error handling strategy for the parser. The default value is a new
	 * instance of {@link DefaultErrorStrategy}.
	 *
	 * @see #getErrorHandler
	 * @see #setErrorHandler
	 */
	@NotNull
	protected ANTLRErrorStrategy _errHandler = new DefaultErrorStrategy();

	/**
	 * The input stream.
	 *
	 * @see #getInputStream
	 * @see #setInputStream
	 */
	protected TokenStream _input;

	protected final IntegerStack _precedenceStack;
	{
		_precedenceStack = new IntegerStack();
		_precedenceStack.push(0);
	}
	/**
	 * The {@link ParserRuleContext} object for the currently executing rule.
	 * This is always non-null during the parsing process.
	 */
	protected ParserRuleContext _ctx;

	/**
	 * Specifies whether or not the parser should construct a parse tree during
	 * the parsing process. The default value is {@code true}.
	 *
	 * @see #getBuildParseTree
	 * @see #setBuildParseTree
	 */
	protected boolean _buildParseTrees = true;


	/**
	 * When {@link #setTrace}{@code (true)} is called, a reference to the
	 * {@link TraceListener} is stored here so it can be easily removed in a
	 * later call to {@link #setTrace}{@code (false)}. The listener itself is
	 * implemented as a parser listener so this field is not directly used by
	 * other parser methods.
	 */
	private TraceListener _tracer;

	/**
	 * The list of {@link ParseTreeListener} listeners registered to receive
	 * events during the parse.
	 *
	 * @see #addParseListener
	 */
	@Nullable
	protected List _parseListeners;

	/**
	 * The number of syntax errors reported during parsing. This value is
	 * incremented each time {@link #notifyErrorListeners} is called.
	 */
	protected int _syntaxErrors;

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

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

	/**
	 * Match current input symbol against {@code ttype}. If the symbol type
	 * matches, {@link ANTLRErrorStrategy#reportMatch} and {@link #consume} are
	 * called to complete the match process.
	 *
	 * 

If the symbol type does not match, * {@link ANTLRErrorStrategy#recoverInline} is called on the current error * strategy to attempt recovery. If {@link #getBuildParseTree} is * {@code true} and the token index of the symbol returned by * {@link ANTLRErrorStrategy#recoverInline} is -1, the symbol is added to * the parse tree by calling {@link ParserRuleContext#addErrorNode}.

* * @param ttype the token type to match * @return the matched symbol * @throws RecognitionException if the current input symbol did not match * {@code ttype} and the error strategy could not recover from the * mismatched symbol */ @NotNull public Token match(int ttype) throws RecognitionException { Token t = getCurrentToken(); if ( t.getType()==ttype ) { _errHandler.reportMatch(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; } /** * Match current input symbol as a wildcard. If the symbol type matches * (i.e. has a value greater than 0), {@link ANTLRErrorStrategy#reportMatch} * and {@link #consume} are called to complete the match process. * *

If the symbol type does not match, * {@link ANTLRErrorStrategy#recoverInline} is called on the current error * strategy to attempt recovery. If {@link #getBuildParseTree} is * {@code true} and the token index of the symbol returned by * {@link ANTLRErrorStrategy#recoverInline} is -1, the symbol is added to * the parse tree by calling {@link ParserRuleContext#addErrorNode}.

* * @return the matched symbol * @throws RecognitionException if the current input symbol did not match * a wildcard and the error strategy could not recover from the mismatched * symbol */ @NotNull public Token matchWildcard() throws RecognitionException { Token t = getCurrentToken(); if (t.getType() > 0) { _errHandler.reportMatch(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 {@link ParserRuleContext} objects during the parse and hook * them up using the {@link ParserRuleContext#children} list so that it * forms a parse tree. The {@link ParserRuleContext} returned from the start * rule represents the root of the parse tree. * *

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 * {@link ParserRuleContext#children} list. Contexts are then not candidates * for garbage collection.

*/ public void setBuildParseTree(boolean buildParseTrees) { this._buildParseTrees = buildParseTrees; } /** * Gets whether or not a complete parse tree will be constructed while * parsing. This property is {@code true} for a newly constructed parser. * * @return {@code true} if a complete parse tree will be constructed while * parsing, otherwise {@code false} */ 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() { return getParseListeners().contains(TrimToSizeListener.INSTANCE); } @NotNull public List getParseListeners() { List listeners = _parseListeners; if (listeners == null) { return Collections.emptyList(); } return listeners; } /** * Registers {@code listener} to receive events during the parsing process. * *

To support output-preserving grammar transformations (including but not * limited to left-recursion removal, automated left-factoring, and * optimized code generation), calls to listener methods during the parse * may differ substantially from calls made by * {@link ParseTreeWalker#DEFAULT} used after the parse is complete. In * particular, rule entry and exit events may occur in a different order * during the parse than after the parser. In addition, calls to certain * rule entry methods may be omitted.

* *

With the following specific exceptions, calls to listener events are * deterministic, i.e. for identical input the calls to listener * methods will be the same.

* *
    *
  • Alterations to the grammar used to generate code may change the * behavior of the listener calls.
  • *
  • Alterations to the command line options passed to ANTLR 4 when * generating the parser may change the behavior of the listener calls.
  • *
  • Changing the version of the ANTLR Tool used to generate the parser * may change the behavior of the listener calls.
  • *
* * @param listener the listener to add * * @throws NullPointerException if {@code} listener is {@code null} */ public void addParseListener(@NotNull ParseTreeListener listener) { if (listener == null) { throw new NullPointerException("listener"); } if (_parseListeners == null) { _parseListeners = new ArrayList(); } this._parseListeners.add(listener); } /** * Remove {@code listener} from the list of parse listeners. * *

If {@code listener} is {@code null} or has not been added as a parse * listener, this method does nothing.

* * @see #addParseListener * * @param listener the listener to remove */ public void removeParseListener(ParseTreeListener listener) { if (_parseListeners != null) { if (_parseListeners.remove(listener)) { if (_parseListeners.isEmpty()) { _parseListeners = null; } } } } /** * Remove all parse listeners. * * @see #addParseListener */ public void removeParseListeners() { _parseListeners = null; } /** * Notify any parse listeners of an enter rule event. * * @see #addParseListener */ protected void triggerEnterRuleEvent() { for (ParseTreeListener listener : _parseListeners) { listener.enterEveryRule(_ctx); _ctx.enterRule(listener); } } /** * Notify any parse listeners of an exit rule event. * * @see #addParseListener */ protected void triggerExitRuleEvent() { // reverse order walk of listeners for (int i = _parseListeners.size()-1; i >= 0; i--) { ParseTreeListener listener = _parseListeners.get(i); _ctx.exitRule(listener); listener.exitEveryRule(_ctx); } } /** * Gets the number of syntax errors reported during parsing. This value is * incremented each time {@link #notifyErrorListeners} is called. * * @see #notifyErrorListeners */ public int getNumberOfSyntaxErrors() { return _syntaxErrors; } public TokenFactory getTokenFactory() { return _input.getTokenSource().getTokenFactory(); } /** * The ATN with bypass alternatives is expensive to create so we create it * lazily. * * @throws UnsupportedOperationException if the current parser does not * implement the {@link #getSerializedATN()} method. */ @NotNull public ATN getATNWithBypassAlts() { String serializedAtn = getSerializedATN(); if (serializedAtn == null) { throw new UnsupportedOperationException("The current parser does not support an ATN with bypass alternatives."); } synchronized (bypassAltsAtnCache) { ATN result = bypassAltsAtnCache.get(serializedAtn); if (result == null) { ATNDeserializationOptions deserializationOptions = new ATNDeserializationOptions(); deserializationOptions.setGenerateRuleBypassTransitions(true); result = new ATNDeserializer(deserializationOptions).deserialize(serializedAtn.toCharArray()); bypassAltsAtnCache.put(serializedAtn, result); } return result; } } /** * The preferred method of getting a tree pattern. For example, here's a * sample use: * *
	 * ParseTree t = parser.expr();
	 * ParseTreePattern p = parser.compileParseTreePattern("<ID>+0", MyParser.RULE_expr);
	 * ParseTreeMatch m = p.match(t);
	 * String id = m.get("ID");
	 * 
*/ public ParseTreePattern compileParseTreePattern(String pattern, int patternRuleIndex) { if ( getInputStream()!=null ) { TokenSource tokenSource = getInputStream().getTokenSource(); if ( tokenSource instanceof Lexer ) { Lexer lexer = (Lexer)tokenSource; return compileParseTreePattern(pattern, patternRuleIndex, lexer); } } throw new UnsupportedOperationException("Parser can't discover a lexer to use"); } /** * The same as {@link #compileParseTreePattern(String, int)} but specify a * {@link Lexer} rather than trying to deduce it from this parser. */ public ParseTreePattern compileParseTreePattern(String pattern, int patternRuleIndex, Lexer lexer) { ParseTreePatternMatcher m = new ParseTreePatternMatcher(lexer, this); return m.compile(pattern, patternRuleIndex); } @NotNull public ANTLRErrorStrategy getErrorHandler() { return _errHandler; } public void setErrorHandler(@NotNull ANTLRErrorStrategy handler) { this._errHandler = handler; } @Override public TokenStream getInputStream() { return _input; } /** Set the token stream and reset the parser. */ public void setInputStream(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. */ @NotNull public Token getCurrentToken() { return _input.LT(1); } public final void notifyErrorListeners(@NotNull String msg) { notifyErrorListeners(getCurrentToken(), msg, null); } public void notifyErrorListeners(@NotNull Token offendingToken, @NotNull String msg, @Nullable RecognitionException e) { _syntaxErrors++; int line = -1; int charPositionInLine = -1; if (offendingToken != null) { line = offendingToken.getLine(); charPositionInLine = offendingToken.getCharPositionInLine(); } ANTLRErrorListener listener = getErrorListenerDispatch(); listener.syntaxError(this, offendingToken, line, charPositionInLine, msg, e); } /** * Consume and return the {@linkplain #getCurrentToken current symbol}. * *

E.g., given the following input with {@code A} being the current * lookahead symbol, this function moves the cursor to {@code B} and returns * {@code A}.

* *
	 *  A B
	 *  ^
	 * 
* * If the parser is not in error recovery mode, the consumed symbol is added * to the parse tree using {@link ParserRuleContext#addChild(Token)}, and * {@link ParseTreeListener#visitTerminal} is called on any parse listeners. * If the parser is in error recovery mode, the consumed symbol is * added to the parse tree using * {@link ParserRuleContext#addErrorNode(Token)}, and * {@link ParseTreeListener#visitErrorNode} is called on any parse * listeners. */ 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. Access field * {@link #_ctx} get the current context. */ public void enterRule(@NotNull ParserRuleContext localctx, int state, int ruleIndex) { setState(state); _ctx = localctx; _ctx.start = _input.LT(1); if (_buildParseTrees) addContextToParseTree(); if ( _parseListeners != null) triggerEnterRuleEvent(); } public void enterLeftFactoredRule(ParserRuleContext localctx, int state, int ruleIndex) { setState(state); if (_buildParseTrees) { ParserRuleContext factoredContext = (ParserRuleContext)_ctx.getChild(_ctx.getChildCount() - 1); _ctx.removeLastChild(); factoredContext.parent = localctx; localctx.addChild(factoredContext); } _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; } /** * Get the precedence level for the top-most precedence rule. * * @return The precedence level for the top-most precedence rule, or -1 if * the parser context is not nested within a precedence rule. */ public final int getPrecedence() { if (_precedenceStack.isEmpty()) { return -1; } return _precedenceStack.peek(); } /** * @deprecated Use * {@link #enterRecursionRule(ParserRuleContext, int, int, int)} instead. */ @Deprecated public void enterRecursionRule(ParserRuleContext localctx, int ruleIndex) { enterRecursionRule(localctx, getATN().ruleToStartState[ruleIndex].stateNumber, ruleIndex, 0); } public void enterRecursionRule(ParserRuleContext localctx, int state, int ruleIndex, int precedence) { setState(state); _precedenceStack.push(precedence); _ctx = localctx; _ctx.start = _input.LT(1); if (_parseListeners != null) { triggerEnterRuleEvent(); // simulates rule entry for left-recursive rules } } /** Like {@link #enterRule} but for recursive rules. * Make the current context the child of the incoming localctx. */ 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) { _precedenceStack.pop(); _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 != null) { // add return ctx into invoking rule's tree _parentctx.addChild(retctx); } } 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 void setContext(ParserRuleContext ctx) { _ctx = ctx; } @Override public boolean precpred(@Nullable RuleContext localctx, int precedence) { return precedence >= _precedenceStack.peek(); } @Override public ParserErrorListener getErrorListenerDispatch() { return new ProxyParserErrorListener(getErrorListeners()); } public boolean inContext(String context) { // TODO: useful in parser? return false; } /** Given an AmbiguityInfo object that contains information about an * ambiguous decision event, return the list of ambiguous parse trees. * An ambiguity occurs when a specific token sequence can be recognized * in more than one way by the grammar. These ambiguities are detected only * at decision points. * * The list of trees includes the actual interpretation (that for * the minimum alternative number) and all ambiguous alternatives. * * This method reuses the same physical input token stream used to * detect the ambiguity by the original parser in the first place. * This method resets/seeks within but does not alter originalParser. * The input position is restored upon exit from this method. * Parsers using a {@link UnbufferedTokenStream} may not be able to * perform the necessary save index() / seek(saved_index) operation. * * The trees are rooted at the node whose start..stop token indices * include the start and stop indices of this ambiguity event. That is, * the trees returns will always include the complete ambiguous subphrase * identified by the ambiguity event. * * Be aware that this method does NOT notify error or parse listeners as * it would trigger duplicate or otherwise unwanted events. * * This uses a temporary ParserATNSimulator and a ParserInterpreter * so we don't mess up any statistics, event lists, etc... * The parse tree constructed while identifying/making ambiguityInfo is * not affected by this method as it creates a new parser interp to * get the ambiguous interpretations. * * Nodes in the returned ambig trees are independent of the original parse * tree (constructed while identifying/creating ambiguityInfo). * * @param originalParser The parser used to create ambiguityInfo; it * is not modified by this routine and can be either * a generated or interpreted parser. It's token * stream *is* reset/seek()'d. * @param ambiguityInfo The information about an ambiguous decision event * for which you want ambiguous parse trees. * * @throws RecognitionException Throws upon syntax error while matching * ambig input. * * @since 4.5 */ public static List getAmbiguousParseTrees(@NotNull Parser originalParser, @NotNull AmbiguityInfo ambiguityInfo, int startRuleIndex) { List trees = new ArrayList(); int saveTokenInputPosition = originalParser.getInputStream().index(); try { // Create a new parser interpreter to parse the ambiguous subphrase ParserInterpreter parser; if ( originalParser instanceof ParserInterpreter ) { parser = new ParserInterpreter((ParserInterpreter) originalParser); } else { char[] serializedAtn = ATNSerializer.getSerializedAsChars(originalParser.getATN(), Arrays.asList(originalParser.getRuleNames())); ATN deserialized = new ATNDeserializer().deserialize(serializedAtn); parser = new ParserInterpreter(originalParser.getGrammarFileName(), originalParser.getVocabulary(), Arrays.asList(originalParser.getRuleNames()), deserialized, originalParser.getInputStream()); } // Make sure that we don't get any error messages from using this temporary parser parser.removeErrorListeners(); parser.removeParseListeners(); parser.getInterpreter().setPredictionMode(PredictionMode.LL_EXACT_AMBIG_DETECTION); // get ambig trees int alt = ambiguityInfo.getAmbiguousAlternatives().nextSetBit(0); while ( alt>=0 ) { // re-parse input for all ambiguous alternatives // (don't have to do first as it's been parsed, but do again for simplicity // using this temp parser.) parser.reset(); parser.getInputStream().seek(ambiguityInfo.startIndex); parser.overrideDecision = ambiguityInfo.decision; parser.overrideDecisionInputIndex = ambiguityInfo.startIndex; parser.overrideDecisionAlt = alt; ParserRuleContext t = parser.parse(startRuleIndex); ParserRuleContext ambigSubTree = Trees.getRootOfSubtreeEnclosingRegion(t, ambiguityInfo.startIndex, ambiguityInfo.stopIndex); trees.add(ambigSubTree); alt = ambiguityInfo.getAmbiguousAlternatives().nextSetBit(alt+1); } } finally { originalParser.getInputStream().seek(saveTokenInputPosition); } return trees; } /** * Checks whether or not {@code symbol} can follow the current state in the * ATN. The behavior of this method is equivalent to the following, but is * implemented such that the complete context-sensitive follow set does not * need to be explicitly constructed. * *
	 * return getExpectedTokens().contains(symbol);
	 * 
* * @param symbol the symbol type to check * @return {@code true} if {@code symbol} can follow the current state in * the ATN, otherwise {@code 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; } /** * Computes the set of input symbols which could follow the current parser * state and context, as given by {@link #getState} and {@link #getContext}, * respectively. * * @see ATN#getExpectedTokens(int, RuleContext) */ @NotNull public IntervalSet getExpectedTokens() { return getATN().getExpectedTokens(getState(), getContext()); } @NotNull public IntervalSet getExpectedTokensWithinCurrentRule() { ATN atn = getInterpreter().atn; ATNState s = atn.states.get(getState()); return atn.nextTokens(s); } /** Get a rule's index (i.e., {@code RULE_ruleName} field) or -1 if not found. */ public int getRuleIndex(String ruleName) { Integer ruleIndex = getRuleIndexMap().get(ruleName); if ( ruleIndex!=null ) return ruleIndex; return -1; } public ParserRuleContext getRuleContext() { return _ctx; } /** Return List<String> 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() { List s = new ArrayList(); for (int d = 0; d < _interp.atn.decisionToDFA.length; d++) { DFA dfa = _interp.atn.decisionToDFA[d]; s.add( dfa.toString(getVocabulary(), getRuleNames()) ); } return s; } /** For debugging and other purposes. */ public void dumpDFA() { boolean seenOne = false; for (int d = 0; d < _interp.atn.decisionToDFA.length; d++) { DFA dfa = _interp.atn.decisionToDFA[d]; if ( !dfa.isEmpty() ) { if ( seenOne ) System.out.println(); System.out.println("Decision " + dfa.decision + ":"); System.out.print(dfa.toString(getVocabulary(), getRuleNames())); seenOne = true; } } } public String getSourceName() { return _input.getSourceName(); } @Override public ParseInfo getParseInfo() { ParserATNSimulator interp = getInterpreter(); if (interp instanceof ProfilingATNSimulator) { return new ParseInfo((ProfilingATNSimulator)interp); } return null; } /** * @since 4.3 */ public void setProfile(boolean profile) { ParserATNSimulator interp = getInterpreter(); if ( profile ) { if (!(interp instanceof ProfilingATNSimulator)) { setInterpreter(new ProfilingATNSimulator(this)); } } else if (interp instanceof ProfilingATNSimulator) { setInterpreter(new ParserATNSimulator(this, getATN())); } getInterpreter().setPredictionMode(interp.getPredictionMode()); } /** During a parse is sometimes useful to listen in on the rule entry and exit * events as well as token matches. This is for quick and dirty debugging. */ public void setTrace(boolean trace) { if ( !trace ) { removeParseListener(_tracer); _tracer = null; } else { if ( _tracer!=null ) removeParseListener(_tracer); else _tracer = new TraceListener(); addParseListener(_tracer); } } /** * Gets whether a {@link TraceListener} is registered as a parse listener * for the parser. * * @see #setTrace(boolean) */ public boolean isTrace() { return _tracer != null; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy