/*
 * 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.ATNDeserializationOptions;
import org.antlr.v4.runtime.atn.ATNDeserializer;
import org.antlr.v4.runtime.atn.ATNSimulator;
import org.antlr.v4.runtime.atn.ATNState;
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.tree.ErrorNode;
import org.antlr.v4.runtime.tree.ErrorNodeImpl;
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.TerminalNodeImpl;
import org.antlr.v4.runtime.tree.pattern.ParseTreePattern;
import org.antlr.v4.runtime.tree.pattern.ParseTreePatternMatcher;

import java.util.ArrayList;
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.
/** This is all the parsing support code essentially; most of it is error recovery stuff. */
public abstract class Parser extends Recognizer<Token, ParserATNSimulator> { 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()]); } @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(); } } }
This field maps from the serialized ATN string to the deserialized ATN with bypass alternatives.
See Also:
/** * This field maps from the serialized ATN string to the deserialized {@link ATN} with * bypass alternatives. * * @see ATNDeserializationOptions#isGenerateRuleBypassTransitions() */
private static final Map<String, ATN> bypassAltsAtnCache = new WeakHashMap<String, ATN>();
The error handling strategy for the parser. The default value is a new instance of DefaultErrorStrategy.
See Also:
/** * The error handling strategy for the parser. The default value is a new * instance of {@link DefaultErrorStrategy}. * * @see #getErrorHandler * @see #setErrorHandler */
protected ANTLRErrorStrategy _errHandler = new DefaultErrorStrategy();
The input stream.
See Also:
/** * The input stream. * * @see #getInputStream * @see #setInputStream */
protected TokenStream _input; protected final IntegerStack _precedenceStack; { _precedenceStack = new IntegerStack(); _precedenceStack.push(0); }
The ParserRuleContext object for the currently executing rule. This is always non-null during the parsing process.
/** * 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 true.
See Also:
/** * 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 setTrace(true) is called, a reference to the TraceListener is stored here so it can be easily removed in a later call to setTrace(false). The listener itself is implemented as a parser listener so this field is not directly used by other parser methods.
/** * 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 ParseTreeListener listeners registered to receive events during the parse.
See Also:
/** * The list of {@link ParseTreeListener} listeners registered to receive * events during the parse. * * @see #addParseListener */
protected List<ParseTreeListener> _parseListeners;
The number of syntax errors reported during parsing. This value is incremented each time notifyErrorListeners is called.
/** * The number of syntax errors reported during parsing. This value is * incremented each time {@link #notifyErrorListeners} is called. */
protected int _syntaxErrors;
Indicates parser has match()ed EOF token. See exitRule().
/** Indicates parser has match()ed EOF token. See {@link #exitRule()}. */
protected boolean matchedEOF; public Parser(TokenStream input) { setInputStream(input); }
reset the parser's state
/** reset the parser's state */
public void reset() { if ( getInputStream()!=null ) getInputStream().seek(0); _errHandler.reset(this); _ctx = null; _syntaxErrors = 0; matchedEOF = false; setTrace(false); _precedenceStack.clear(); _precedenceStack.push(0); ATNSimulator interpreter = getInterpreter(); if (interpreter != null) { interpreter.reset(); } }
Match current input symbol against ttype. If the symbol type matches, ANTLRErrorStrategy.reportMatch and consume are called to complete the match process.

If the symbol type does not match, ANTLRErrorStrategy.recoverInline is called on the current error strategy to attempt recovery. If getBuildParseTree is true and the token index of the symbol returned by ANTLRErrorStrategy.recoverInline is -1, the symbol is added to the parse tree by calling createErrorNode(ParserRuleContext, Token) then ParserRuleContext.addErrorNode(ErrorNode).

Params:
  • ttype – the token type to match
Throws:
  • RecognitionException – if the current input symbol did not match ttype and the error strategy could not recover from the mismatched symbol
Returns:the matched symbol
/** * 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. * * <p>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 #createErrorNode(ParserRuleContext, Token)} then * {@link ParserRuleContext#addErrorNode(ErrorNode)}.</p> * * @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 */
public Token match(int ttype) throws RecognitionException { Token t = getCurrentToken(); if ( t.getType()==ttype ) { if ( ttype==Token.EOF ) { matchedEOF = true; } _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(createErrorNode(_ctx,t)); } } return t; }
Match current input symbol as a wildcard. If the symbol type matches (i.e. has a value greater than 0), ANTLRErrorStrategy.reportMatch and consume are called to complete the match process.

If the symbol type does not match, ANTLRErrorStrategy.recoverInline is called on the current error strategy to attempt recovery. If getBuildParseTree is true and the token index of the symbol returned by ANTLRErrorStrategy.recoverInline is -1, the symbol is added to the parse tree by calling createErrorNode(ParserRuleContext, Token). then ParserRuleContext.addErrorNode(ErrorNode)

Throws:
  • RecognitionException – if the current input symbol did not match a wildcard and the error strategy could not recover from the mismatched symbol
Returns:the matched symbol
/** * 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. * * <p>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 Parser#createErrorNode(ParserRuleContext, Token)}. then * {@link ParserRuleContext#addErrorNode(ErrorNode)}</p> * * @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 */
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(createErrorNode(_ctx,t)); } } return t; }
Track the ParserRuleContext objects during the parse and hook them up using the ParserRuleContext.children list so that it forms a parse tree. The 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 ParserRuleContext.children list. Contexts are then not candidates for garbage collection.

/** * 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. * * <p>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.</p> * * <p>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.</p> */
public void setBuildParseTree(boolean buildParseTrees) { this._buildParseTrees = buildParseTrees; }
Gets whether or not a complete parse tree will be constructed while parsing. This property is true for a newly constructed parser.
Returns:true if a complete parse tree will be constructed while parsing, otherwise false
/** * 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 false by default for a newly constructed parser.
Params:
/** * 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); } }
Returns:true if the ParserRuleContext.children list is trimmed using the default TrimToSizeListener during the parse process.
/** * @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); } public List<ParseTreeListener> getParseListeners() { List<ParseTreeListener> listeners = _parseListeners; if (listeners == null) { return Collections.emptyList(); } return listeners; }
Registers 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 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.
Params:
  • listener – the listener to add
Throws:
/** * Registers {@code listener} to receive events during the parsing process. * * <p>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.</p> * * <p>With the following specific exceptions, calls to listener events are * <em>deterministic</em>, i.e. for identical input the calls to listener * methods will be the same.</p> * * <ul> * <li>Alterations to the grammar used to generate code may change the * behavior of the listener calls.</li> * <li>Alterations to the command line options passed to ANTLR 4 when * generating the parser may change the behavior of the listener calls.</li> * <li>Changing the version of the ANTLR Tool used to generate the parser * may change the behavior of the listener calls.</li> * </ul> * * @param listener the listener to add * * @throws NullPointerException if {@code} listener is {@code null} */
public void addParseListener(ParseTreeListener listener) { if (listener == null) { throw new NullPointerException("listener"); } if (_parseListeners == null) { _parseListeners = new ArrayList<ParseTreeListener>(); } this._parseListeners.add(listener); }
Remove listener from the list of parse listeners.

If listener is null or has not been added as a parse listener, this method does nothing.

Params:
  • listener – the listener to remove
See Also:
/** * Remove {@code listener} from the list of parse listeners. * * <p>If {@code listener} is {@code null} or has not been added as a parse * listener, this method does nothing.</p> * * @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 Also:
  • addParseListener
/** * Remove all parse listeners. * * @see #addParseListener */
public void removeParseListeners() { _parseListeners = null; }
Notify any parse listeners of an enter rule event.
See Also:
  • addParseListener
/** * 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 Also:
  • addParseListener
/** * 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 notifyErrorListeners is called.
See Also:
/** * 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; } @Override public TokenFactory<?> getTokenFactory() { return _input.getTokenSource().getTokenFactory(); }
Tell our token source and error strategy about a new way to create tokens.
/** Tell our token source and error strategy about a new way to create tokens. */
@Override public void setTokenFactory(TokenFactory<?> factory) { _input.getTokenSource().setTokenFactory(factory); }
The ATN with bypass alternatives is expensive to create so we create it lazily.
Throws:
/** * 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. */
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");
/** * The preferred method of getting a tree pattern. For example, here's a * sample use: * * <pre> * ParseTree t = parser.expr(); * ParseTreePattern p = parser.compileParseTreePattern("&lt;ID&gt;+0", MyParser.RULE_expr); * ParseTreeMatch m = p.match(t); * String id = m.get("ID"); * </pre> */
public ParseTreePattern compileParseTreePattern(String pattern, int patternRuleIndex) { if ( getTokenStream()!=null ) { TokenSource tokenSource = getTokenStream().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 compileParseTreePattern(String, int) but specify a Lexer rather than trying to deduce it from this parser.
/** * 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); } 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.
/** 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.
/** 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 final void notifyErrorListeners(String msg) { notifyErrorListeners(getCurrentToken(), msg, null); } public void notifyErrorListeners(Token offendingToken, String msg, RecognitionException e) { _syntaxErrors++; int line = -1; int charPositionInLine = -1; line = offendingToken.getLine(); charPositionInLine = offendingToken.getCharPositionInLine(); ANTLRErrorListener listener = getErrorListenerDispatch(); listener.syntaxError(this, offendingToken, line, charPositionInLine, msg, e); }
Consume and return the current symbol.

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

 A B
 ^
If the parser is not in error recovery mode, the consumed symbol is added to the parse tree using ParserRuleContext.addChild(TerminalNode), and 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 createErrorNode(ParserRuleContext, Token) then ParserRuleContext.addErrorNode(ErrorNode) and ParseTreeListener.visitErrorNode is called on any parse listeners.
/** * Consume and return the {@linkplain #getCurrentToken current symbol}. * * <p>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}.</p> * * <pre> * A B * ^ * </pre> * * If the parser is not in error recovery mode, the consumed symbol is added * to the parse tree using {@link ParserRuleContext#addChild(TerminalNode)}, and * {@link ParseTreeListener#visitTerminal} is called on any parse listeners. * If the parser <em>is</em> in error recovery mode, the consumed symbol is * added to the parse tree using {@link #createErrorNode(ParserRuleContext, Token)} then * {@link ParserRuleContext#addErrorNode(ErrorNode)} 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(createErrorNode(_ctx,o)); if (_parseListeners != null) { for (ParseTreeListener listener : _parseListeners) { listener.visitErrorNode(node); } } } else { TerminalNode node = _ctx.addChild(createTerminalNode(_ctx,o)); if (_parseListeners != null) { for (ParseTreeListener listener : _parseListeners) { listener.visitTerminal(node); } } } } return o; }
How to create a token leaf node associated with a parent. Typically, the terminal node to create is not a function of the parent.
Since:4.7
/** How to create a token leaf node associated with a parent. * Typically, the terminal node to create is not a function of the parent. * * @since 4.7 */
public TerminalNode createTerminalNode(ParserRuleContext parent, Token t) { return new TerminalNodeImpl(t); }
How to create an error node, given a token, associated with a parent. Typically, the error node to create is not a function of the parent.
Since:4.7
/** How to create an error node, given a token, associated with a parent. * Typically, the error node to create is not a function of the parent. * * @since 4.7 */
public ErrorNode createErrorNode(ParserRuleContext parent, Token t) { return new ErrorNodeImpl(t); } 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 _ctx get the current context.
/** * Always called by generated parsers upon entry to a rule. Access field * {@link #_ctx} get the current context. */
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() { if ( matchedEOF ) { // if we have matched EOF, it cannot consume past EOF so we use LT(1) here _ctx.stop = _input.LT(1); // LT(1) will be end of file } else { _ctx.stop = _input.LT(-1); // stop node is what we just matched } // 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) { localctx.setAltNumber(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.
Returns:The precedence level for the top-most precedence rule, or -1 if the parser context is not nested within a precedence rule.
/** * 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 enterRecursionRule(ParserRuleContext, int, int, int) instead.
/** * @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 enterRule but for recursive rules. Make the current context the child of the incoming localctx.
/** 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(RuleContext localctx, int precedence) { return precedence >= _precedenceStack.peek(); } public boolean inContext(String context) { // TODO: useful in parser? return false; }
Checks whether or not 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);
Params:
  • symbol – the symbol type to check
Returns:true if symbol can follow the current state in the ATN, otherwise false.
/** * 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. * * <pre> * return getExpectedTokens().contains(symbol); * </pre> * * @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; } public boolean isMatchedEOF() { return matchedEOF; }
Computes the set of input symbols which could follow the current parser state and context, as given by Recognizer<Token,ParserATNSimulator>.getState and getContext, respectively.
See Also:
/** * 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) */
public IntervalSet getExpectedTokens() { return getATN().getExpectedTokens(getState(), getContext()); } public IntervalSet getExpectedTokensWithinCurrentRule() { ATN atn = getInterpreter().atn; ATNState s = atn.states.get(getState()); return atn.nextTokens(s); }
Get a rule's index (i.e., RULE_ruleName field) or -1 if not found.
/** 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.
/** Return List&lt;String&gt; 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<String> getRuleInvocationStack() { return getRuleInvocationStack(_ctx); } public List<String> getRuleInvocationStack(RuleContext p) { String[] ruleNames = getRuleNames(); List<String> stack = new ArrayList<String>(); 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.
/** For debugging and other purposes. */
public List<String> getDFAStrings() { synchronized (_interp.decisionToDFA) { List<String> s = new ArrayList<String>(); for (int d = 0; d < _interp.decisionToDFA.length; d++) { DFA dfa = _interp.decisionToDFA[d]; s.add( dfa.toString(getVocabulary()) ); } return s; } }
For debugging and other purposes.
/** 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.states.isEmpty() ) { if ( seenOne ) System.out.println(); System.out.println("Decision " + dfa.decision + ":"); System.out.print(dfa.toString(getVocabulary())); 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
/** * @since 4.3 */
public void setProfile(boolean profile) { ParserATNSimulator interp = getInterpreter(); PredictionMode saveMode = interp.getPredictionMode(); if ( profile ) { if ( !(interp instanceof ProfilingATNSimulator) ) { setInterpreter(new ProfilingATNSimulator(this)); } } else if ( interp instanceof ProfilingATNSimulator ) { ParserATNSimulator sim = new ParserATNSimulator(this, getATN(), interp.decisionToDFA, interp.getSharedContextCache()); setInterpreter(sim); } getInterpreter().setPredictionMode(saveMode); }
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.
/** 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 TraceListener is registered as a parse listener for the parser.
See Also:
/** * Gets whether a {@link TraceListener} is registered as a parse listener * for the parser. * * @see #setTrace(boolean) */
public boolean isTrace() { return _tracer != null; } }