Java tutorial
/* * 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. */ 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 {@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 {@link DefaultErrorStrategy}. * * @see #getErrorHandler * @see #setErrorHandler */ 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 */ protected List<ParseTreeListener> _parseListeners; /** * 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 {@link #exitRule()}. */ protected boolean matchedEOF; 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; matchedEOF = false; 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. * * <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), {@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 {@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 {@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); } public List<ParseTreeListener> getParseListeners() { List<ParseTreeListener> listeners = _parseListeners; if (listeners == null) { return Collections.emptyList(); } return listeners; } /** * 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 {@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 #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; } @Override public TokenFactory<?> getTokenFactory() { return _input.getTokenSource().getTokenFactory(); } /** 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 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: * * <pre> * ParseTree t = parser.expr(); * ParseTreePattern p = parser.compileParseTreePattern("<ID>+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 {@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. */ 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 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 {@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 */ 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 */ 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 * {@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. * * @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(RuleContext localctx, int precedence) { return precedence >= _precedenceStack.peek(); } public boolean inContext(String context) { // TODO: useful in parser? return 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 {@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., {@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<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. */ 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. */ 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 */ 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. */ 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; } }