blob: ff053491372ba3e69de4bc4a82956e664e64f86a [file] [log] [blame] [edit]
/* 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.
*/
using System;
using System.IO;
using System.Text;
using System.Collections.Generic;
using Antlr4.Runtime.Atn;
using Antlr4.Runtime.Dfa;
using Antlr4.Runtime.Misc;
using Antlr4.Runtime.Sharpen;
using Antlr4.Runtime.Tree;
using Antlr4.Runtime.Tree.Pattern;
namespace Antlr4.Runtime
{
/// <summary>This is all the parsing support code essentially; most of it is error recovery stuff.</summary>
/// <remarks>This is all the parsing support code essentially; most of it is error recovery stuff.</remarks>
public abstract class Parser : Recognizer<IToken, ParserATNSimulator>
{
public class TraceListener : IParseTreeListener
{
public TraceListener(TextWriter output,Parser enclosing) {
_output = output;
_enclosing = enclosing;
}
public virtual void EnterEveryRule(ParserRuleContext ctx)
{
_output.WriteLine("enter " + this._enclosing.RuleNames[ctx.RuleIndex] + ", LT(1)=" + this._enclosing._input.LT(1).Text);
}
public virtual void ExitEveryRule(ParserRuleContext ctx)
{
_output.WriteLine("exit " + this._enclosing.RuleNames[ctx.RuleIndex] + ", LT(1)=" + this._enclosing._input.LT(1).Text);
}
public virtual void VisitErrorNode(IErrorNode node)
{
}
public virtual void VisitTerminal(ITerminalNode node)
{
ParserRuleContext parent = (ParserRuleContext)((IRuleNode)node.Parent).RuleContext;
IToken token = node.Symbol;
_output.WriteLine("consume " + token + " rule " + this._enclosing.RuleNames[parent.RuleIndex]);
}
internal TraceListener(Parser _enclosing)
{
this._enclosing = _enclosing;
_output = Console.Out;
}
private readonly Parser _enclosing;
private readonly TextWriter _output;
}
public class TrimToSizeListener : IParseTreeListener
{
public static readonly Parser.TrimToSizeListener Instance = new Parser.TrimToSizeListener();
public virtual void VisitTerminal(ITerminalNode node)
{
}
public virtual void VisitErrorNode(IErrorNode node)
{
}
public virtual void EnterEveryRule(ParserRuleContext ctx)
{
}
public virtual void ExitEveryRule(ParserRuleContext ctx)
{
if (ctx.children is List<IParseTree>)
{
((List<IParseTree>)ctx.children).TrimExcess();
}
}
}
/// <summary>
/// This field maps from the serialized ATN string to the deserialized
/// <see cref="Antlr4.Runtime.Atn.ATN"/>
/// with
/// bypass alternatives.
/// </summary>
/// <seealso cref="Antlr4.Runtime.Atn.ATNDeserializationOptions.GenerateRuleBypassTransitions()"/>
// private static readonly IDictionary<string, ATN> bypassAltsAtnCache = new Dictionary<string, ATN>();
private ATN bypassAltsAtnCache;
/// <summary>The error handling strategy for the parser.</summary>
/// <remarks>
/// The error handling strategy for the parser. The default value is a new
/// instance of
/// <see cref="DefaultErrorStrategy"/>
/// .
/// </remarks>
/// <seealso cref="ErrorHandler"/>
[NotNull]
private IAntlrErrorStrategy _errHandler = new DefaultErrorStrategy();
/// <summary>The input stream.</summary>
/// <remarks>The input stream.</remarks>
/// <seealso cref="InputStream()"/>
private ITokenStream _input;
private readonly List<int> _precedenceStack = new List<int> { 0 };
/// <summary>
/// The
/// <see cref="ParserRuleContext"/>
/// object for the currently executing rule.
/// This is always non-null during the parsing process.
/// </summary>
private ParserRuleContext _ctx;
/// <summary>
/// Specifies whether or not the parser should construct a parse tree during
/// the parsing process.
/// </summary>
/// <remarks>
/// Specifies whether or not the parser should construct a parse tree during
/// the parsing process. The default value is
/// <see langword="true"/>
/// .
/// </remarks>
/// <seealso cref="BuildParseTree"/>
private bool _buildParseTrees = true;
/// <summary>
/// When
/// <see cref="Trace"/>
/// <c>(true)</c>
/// is called, a reference to the
/// <see cref="TraceListener"/>
/// is stored here so it can be easily removed in a
/// later call to
/// <see cref="Trace"/>
/// <c>(false)</c>
/// . The listener itself is
/// implemented as a parser listener so this field is not directly used by
/// other parser methods.
/// </summary>
private Parser.TraceListener _tracer;
/// <summary>
/// The list of
/// <see cref="Antlr4.Runtime.Tree.IParseTreeListener"/>
/// listeners registered to receive
/// events during the parse.
/// </summary>
/// <seealso cref="AddParseListener(Antlr4.Runtime.Tree.IParseTreeListener)"/>
[Nullable]
private IList<IParseTreeListener> _parseListeners;
/// <summary>The number of syntax errors reported during parsing.</summary>
/// <remarks>
/// The number of syntax errors reported during parsing. This value is
/// incremented each time
/// <see cref="NotifyErrorListeners(string)"/>
/// is called.
/// </remarks>
private int _syntaxErrors;
protected readonly TextWriter Output;
protected readonly TextWriter ErrorOutput;
public Parser(ITokenStream input) : this(input, Console.Out, Console.Error) { }
public Parser(ITokenStream input, TextWriter output, TextWriter errorOutput)
{
TokenStream = input;
Output = output;
ErrorOutput = errorOutput;
}
/// <summary>reset the parser's state</summary>
public virtual void Reset()
{
if (((ITokenStream)InputStream) != null)
{
((ITokenStream)InputStream).Seek(0);
}
_errHandler.Reset(this);
_ctx = null;
_syntaxErrors = 0;
Trace = false;
_precedenceStack.Clear();
_precedenceStack.Add(0);
ATNSimulator interpreter = Interpreter;
if (interpreter != null)
{
interpreter.Reset();
}
}
/// <summary>
/// Match current input symbol against
/// <paramref name="ttype"/>
/// . If the symbol type
/// matches,
/// <see cref="IAntlrErrorStrategy.ReportMatch(Parser)"/>
/// and
/// <see cref="Consume()"/>
/// are
/// called to complete the match process.
/// <p>If the symbol type does not match,
/// <see cref="IAntlrErrorStrategy.RecoverInline(Parser)"/>
/// is called on the current error
/// strategy to attempt recovery. If
/// <see cref="BuildParseTree()"/>
/// is
/// <see langword="true"/>
/// and the token index of the symbol returned by
/// <see cref="IAntlrErrorStrategy.RecoverInline(Parser)"/>
/// is -1, the symbol is added to
/// the parse tree by calling
/// <see cref="ParserRuleContext.AddErrorNode(IToken)"/>
/// .</p>
/// </summary>
/// <param name="ttype">the token type to match</param>
/// <returns>the matched symbol</returns>
/// <exception cref="RecognitionException">
/// if the current input symbol did not match
/// <paramref name="ttype"/>
/// and the error strategy could not recover from the
/// mismatched symbol
/// </exception>
/// <exception cref="Antlr4.Runtime.RecognitionException"/>
[return: NotNull]
public virtual IToken Match(int ttype)
{
IToken t = CurrentToken;
if (t.Type == ttype)
{
_errHandler.ReportMatch(this);
Consume();
}
else
{
t = _errHandler.RecoverInline(this);
if (_buildParseTrees && t.TokenIndex == -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;
}
/// <summary>Match current input symbol as a wildcard.</summary>
/// <remarks>
/// Match current input symbol as a wildcard. If the symbol type matches
/// (i.e. has a value greater than 0),
/// <see cref="IAntlrErrorStrategy.ReportMatch(Parser)"/>
/// and
/// <see cref="Consume()"/>
/// are called to complete the match process.
/// <p>If the symbol type does not match,
/// <see cref="IAntlrErrorStrategy.RecoverInline(Parser)"/>
/// is called on the current error
/// strategy to attempt recovery. If
/// <see cref="BuildParseTree()"/>
/// is
/// <see langword="true"/>
/// and the token index of the symbol returned by
/// <see cref="IAntlrErrorStrategy.RecoverInline(Parser)"/>
/// is -1, the symbol is added to
/// the parse tree by calling
/// <see cref="ParserRuleContext.AddErrorNode(IToken)"/>
/// .</p>
/// </remarks>
/// <returns>the matched symbol</returns>
/// <exception cref="RecognitionException">
/// if the current input symbol did not match
/// a wildcard and the error strategy could not recover from the mismatched
/// symbol
/// </exception>
/// <exception cref="Antlr4.Runtime.RecognitionException"/>
[return: NotNull]
public virtual IToken MatchWildcard()
{
IToken t = CurrentToken;
if (t.Type > 0)
{
_errHandler.ReportMatch(this);
Consume();
}
else
{
t = _errHandler.RecoverInline(this);
if (_buildParseTrees && t.TokenIndex == -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;
}
/// <summary>
/// Track the
/// <see cref="ParserRuleContext"/>
/// objects during the parse and hook
/// them up using the
/// <see cref="ParserRuleContext.children"/>
/// list so that it
/// forms a parse tree. The
/// <see cref="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
/// <see cref="ParserRuleContext.children"/>
/// list. Contexts are then not candidates
/// for garbage collection.</p>
/// </summary>
/// <summary>
/// Gets whether or not a complete parse tree will be constructed while
/// parsing.
/// </summary>
/// <remarks>
/// Gets whether or not a complete parse tree will be constructed while
/// parsing. This property is
/// <see langword="true"/>
/// for a newly constructed parser.
/// </remarks>
/// <returns>
///
/// <see langword="true"/>
/// if a complete parse tree will be constructed while
/// parsing, otherwise
/// <see langword="false"/>
/// </returns>
public virtual bool BuildParseTree
{
get
{
return _buildParseTrees;
}
set
{
this._buildParseTrees = value;
}
}
/// <summary>Trim the internal lists of the parse tree during parsing to conserve memory.</summary>
/// <remarks>
/// Trim the internal lists of the parse tree during parsing to conserve memory.
/// This property is set to
/// <see langword="false"/>
/// by default for a newly constructed parser.
/// </remarks>
/// <value>
///
/// <see langword="true"/>
/// to trim the capacity of the
/// <see cref="ParserRuleContext.children"/>
/// list to its size after a rule is parsed.
/// </value>
/// <returns>
///
/// <see langword="true"/>
/// if the
/// <see cref="ParserRuleContext.children"/>
/// list is trimmed
/// using the default
/// <see cref="TrimToSizeListener"/>
/// during the parse process.
/// </returns>
public virtual bool TrimParseTree
{
get
{
return ParseListeners.Contains(Parser.TrimToSizeListener.Instance);
}
set
{
bool trimParseTrees = value;
if (trimParseTrees)
{
if (TrimParseTree)
{
return;
}
AddParseListener(Parser.TrimToSizeListener.Instance);
}
else
{
RemoveParseListener(Parser.TrimToSizeListener.Instance);
}
}
}
public virtual IList<IParseTreeListener> ParseListeners
{
get
{
IList<IParseTreeListener> listeners = _parseListeners;
if (listeners == null)
{
return Sharpen.Collections.EmptyList<IParseTreeListener>();
}
return listeners;
}
}
/// <summary>
/// Registers
/// <paramref name="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
/// <see cref="Antlr4.Runtime.Tree.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>
/// </summary>
/// <param name="listener">the listener to add</param>
/// <exception cref="System.ArgumentNullException">
/// if
/// <c/>
/// listener is
/// <see langword="null"/>
/// </exception>
public virtual void AddParseListener(IParseTreeListener listener)
{
if (listener == null)
{
throw new ArgumentNullException("listener");
}
if (_parseListeners == null)
{
_parseListeners = new List<IParseTreeListener>();
}
this._parseListeners.Add(listener);
}
/// <summary>
/// Remove
/// <paramref name="listener"/>
/// from the list of parse listeners.
/// <p>If
/// <paramref name="listener"/>
/// is
/// <see langword="null"/>
/// or has not been added as a parse
/// listener, this method does nothing.</p>
/// </summary>
/// <seealso cref="AddParseListener(Antlr4.Runtime.Tree.IParseTreeListener)"/>
/// <param name="listener">the listener to remove</param>
public virtual void RemoveParseListener(IParseTreeListener listener)
{
if (_parseListeners != null)
{
if (_parseListeners.Remove(listener))
{
if (_parseListeners.Count == 0)
{
_parseListeners = null;
}
}
}
}
/// <summary>Remove all parse listeners.</summary>
/// <remarks>Remove all parse listeners.</remarks>
/// <seealso cref="AddParseListener(Antlr4.Runtime.Tree.IParseTreeListener)"/>
public virtual void RemoveParseListeners()
{
_parseListeners = null;
}
/// <summary>Notify any parse listeners of an enter rule event.</summary>
/// <remarks>Notify any parse listeners of an enter rule event.</remarks>
/// <seealso cref="AddParseListener(Antlr4.Runtime.Tree.IParseTreeListener)"/>
protected internal virtual void TriggerEnterRuleEvent()
{
foreach (IParseTreeListener listener in _parseListeners)
{
listener.EnterEveryRule(_ctx);
_ctx.EnterRule(listener);
}
}
/// <summary>Notify any parse listeners of an exit rule event.</summary>
/// <remarks>Notify any parse listeners of an exit rule event.</remarks>
/// <seealso cref="AddParseListener(Antlr4.Runtime.Tree.IParseTreeListener)"/>
protected internal virtual void TriggerExitRuleEvent()
{
// reverse order walk of listeners
if (_parseListeners != null) {
for (int i = _parseListeners.Count - 1; i >= 0; i--) {
IParseTreeListener listener = _parseListeners [i];
_ctx.ExitRule (listener);
listener.ExitEveryRule (_ctx);
}
}
}
/// <summary>Gets the number of syntax errors reported during parsing.</summary>
/// <remarks>
/// Gets the number of syntax errors reported during parsing. This value is
/// incremented each time
/// <see cref="NotifyErrorListeners(string)"/>
/// is called.
/// </remarks>
/// <seealso cref="NotifyErrorListeners(string)"/>
public virtual int NumberOfSyntaxErrors
{
get
{
return _syntaxErrors;
}
}
public virtual ITokenFactory TokenFactory
{
get
{
return _input.TokenSource.TokenFactory;
}
}
/// <summary>
/// The ATN with bypass alternatives is expensive to create so we create it
/// lazily.
/// </summary>
/// <remarks>
/// The ATN with bypass alternatives is expensive to create so we create it
/// lazily.
/// </remarks>
/// <exception cref="System.NotSupportedException">
/// if the current parser does not
/// implement the
/// <see cref="Recognizer{Symbol, ATNInterpreter}.SerializedAtn()"/>
/// method.
/// </exception>
[return: NotNull]
public virtual ATN GetATNWithBypassAlts()
{
int[] serializedAtn = SerializedAtn;
if (serializedAtn == null)
{
throw new NotSupportedException("The current parser does not support an ATN with bypass alternatives.");
}
lock (this)
{
if ( bypassAltsAtnCache!=null ) {
return bypassAltsAtnCache;
}
ATNDeserializationOptions deserializationOptions = new ATNDeserializationOptions();
deserializationOptions.GenerateRuleBypassTransitions = true;
bypassAltsAtnCache = new ATNDeserializer(deserializationOptions).Deserialize(serializedAtn);
return bypassAltsAtnCache;
}
}
/// <summary>The preferred method of getting a tree pattern.</summary>
/// <remarks>
/// 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>
/// </remarks>
public virtual ParseTreePattern CompileParseTreePattern(string pattern, int patternRuleIndex)
{
if (((ITokenStream)InputStream) != null)
{
ITokenSource tokenSource = ((ITokenStream)InputStream).TokenSource;
if (tokenSource is Lexer)
{
Lexer lexer = (Lexer)tokenSource;
return CompileParseTreePattern(pattern, patternRuleIndex, lexer);
}
}
throw new NotSupportedException("Parser can't discover a lexer to use");
}
/// <summary>
/// The same as
/// <see cref="CompileParseTreePattern(string, int)"/>
/// but specify a
/// <see cref="Lexer"/>
/// rather than trying to deduce it from this parser.
/// </summary>
public virtual ParseTreePattern CompileParseTreePattern(string pattern, int patternRuleIndex, Lexer lexer)
{
ParseTreePatternMatcher m = new ParseTreePatternMatcher(lexer, this);
return m.Compile(pattern, patternRuleIndex);
}
public virtual IAntlrErrorStrategy ErrorHandler
{
get
{
return _errHandler;
}
set
{
IAntlrErrorStrategy handler = value;
this._errHandler = handler;
}
}
public override IIntStream InputStream
{
get
{
return _input;
}
}
public ITokenStream TokenStream
{
get
{
return _input;
}
set
{
this._input = null;
Reset ();
this._input = value;
}
}
/// <summary>
/// Match needs to return the current input symbol, which gets put
/// into the label for the associated token ref; e.g., x=ID.
/// </summary>
/// <remarks>
/// Match needs to return the current input symbol, which gets put
/// into the label for the associated token ref; e.g., x=ID.
/// </remarks>
public virtual IToken CurrentToken
{
get
{
return _input.LT(1);
}
}
public void NotifyErrorListeners(string msg)
{
NotifyErrorListeners(CurrentToken, msg, null);
}
public virtual void NotifyErrorListeners(IToken offendingToken, string msg, RecognitionException e)
{
_syntaxErrors++;
int line = -1;
int charPositionInLine = -1;
if (offendingToken != null)
{
line = offendingToken.Line;
charPositionInLine = offendingToken.Column;
}
IAntlrErrorListener<IToken> listener = ((IParserErrorListener)ErrorListenerDispatch);
listener.SyntaxError(ErrorOutput, this, offendingToken, line, charPositionInLine, msg, e);
}
/// <summary>
/// Consume and return the
/// <linkplain>
/// #getCurrentToken
/// current symbol
/// </linkplain>
/// .
/// <p>E.g., given the following input with
/// <c>A</c>
/// being the current
/// lookahead symbol, this function moves the cursor to
/// <c>B</c>
/// and returns
/// <c>A</c>
/// .</p>
/// <pre>
/// A B
/// ^
/// </pre>
/// If the parser is not in error recovery mode, the consumed symbol is added
/// to the parse tree using
/// <see cref="ParserRuleContext.AddChild(IToken)"/>
/// , and
/// <see cref="Antlr4.Runtime.Tree.IParseTreeListener.VisitTerminal(Antlr4.Runtime.Tree.ITerminalNode)"/>
/// 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
/// <see cref="ParserRuleContext.AddErrorNode(IToken)"/>
/// , and
/// <see cref="Antlr4.Runtime.Tree.IParseTreeListener.VisitErrorNode(Antlr4.Runtime.Tree.IErrorNode)"/>
/// is called on any parse
/// listeners.
/// </summary>
public virtual IToken Consume()
{
IToken o = CurrentToken;
if (o.Type != Eof)
{
((ITokenStream)InputStream).Consume();
}
bool hasListener = _parseListeners != null && _parseListeners.Count != 0;
if (_buildParseTrees || hasListener)
{
if (_errHandler.InErrorRecoveryMode(this))
{
IErrorNode node = _ctx.AddErrorNode(o);
if (_parseListeners != null)
{
foreach (IParseTreeListener listener in _parseListeners)
{
listener.VisitErrorNode(node);
}
}
}
else
{
ITerminalNode node = _ctx.AddChild(o);
if (_parseListeners != null)
{
foreach (IParseTreeListener listener in _parseListeners)
{
listener.VisitTerminal(node);
}
}
}
}
return o;
}
protected internal virtual void AddContextToParseTree()
{
ParserRuleContext parent = (ParserRuleContext)_ctx.Parent;
// add current context to parent if we have a parent
if (parent != null)
{
parent.AddChild(_ctx);
}
}
/// <summary>Always called by generated parsers upon entry to a rule.</summary>
/// <remarks>
/// Always called by generated parsers upon entry to a rule. Access field
/// <see cref="_ctx"/>
/// get the current context.
/// </remarks>
public virtual void EnterRule(ParserRuleContext localctx, int state, int ruleIndex)
{
State = state;
_ctx = localctx;
_ctx.Start = _input.LT(1);
if (_buildParseTrees)
{
AddContextToParseTree();
}
if (_parseListeners != null)
{
TriggerEnterRuleEvent();
}
}
public virtual void EnterLeftFactoredRule(ParserRuleContext localctx, int state, int ruleIndex)
{
State = state;
if (_buildParseTrees)
{
ParserRuleContext factoredContext = (ParserRuleContext)_ctx.GetChild(_ctx.ChildCount - 1);
_ctx.RemoveLastChild();
factoredContext.Parent = localctx;
localctx.AddChild(factoredContext);
}
_ctx = localctx;
_ctx.Start = _input.LT(1);
if (_buildParseTrees)
{
AddContextToParseTree();
}
if (_parseListeners != null)
{
TriggerEnterRuleEvent();
}
}
public virtual void ExitRule()
{
_ctx.Stop = _input.LT(-1);
// trigger event on _ctx, before it reverts to parent
if (_parseListeners != null)
{
TriggerExitRuleEvent();
}
State = _ctx.invokingState;
_ctx = (ParserRuleContext)_ctx.Parent;
}
public virtual 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;
}
/// <summary>Get the precedence level for the top-most precedence rule.</summary>
/// <remarks>Get the precedence level for the top-most precedence rule.</remarks>
/// <returns>
/// The precedence level for the top-most precedence rule, or -1 if
/// the parser context is not nested within a precedence rule.
/// </returns>
public int Precedence
{
get
{
if (_precedenceStack.Count == 0)
{
return -1;
}
return _precedenceStack[_precedenceStack.Count - 1];
}
}
[Obsolete(@"UseEnterRecursionRule(ParserRuleContext, int, int, int) instead.")]
public virtual void EnterRecursionRule(ParserRuleContext localctx, int ruleIndex)
{
EnterRecursionRule(localctx, Atn.ruleToStartState[ruleIndex].stateNumber, ruleIndex, 0);
}
public virtual void EnterRecursionRule(ParserRuleContext localctx, int state, int ruleIndex, int precedence)
{
State = state;
_precedenceStack.Add(precedence);
_ctx = localctx;
_ctx.Start = _input.LT(1);
if (_parseListeners != null)
{
TriggerEnterRuleEvent();
}
}
// simulates rule entry for left-recursive rules
/// <summary>
/// Like
/// <see cref="EnterRule(ParserRuleContext, int, int)"/>
/// but for recursive rules.
/// </summary>
public virtual 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 virtual void UnrollRecursionContexts(ParserRuleContext _parentctx)
{
_precedenceStack.RemoveAt(_precedenceStack.Count - 1);
_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 virtual ParserRuleContext GetInvokingContext(int ruleIndex)
{
ParserRuleContext p = _ctx;
while (p != null)
{
if (p.RuleIndex == ruleIndex)
{
return p;
}
p = (ParserRuleContext)p.Parent;
}
return null;
}
public virtual ParserRuleContext Context
{
get
{
return _ctx;
}
set
{
ParserRuleContext ctx = value;
_ctx = ctx;
}
}
public override bool Precpred(RuleContext localctx, int precedence)
{
return precedence >= _precedenceStack[_precedenceStack.Count - 1];
}
public new IParserErrorListener ErrorListenerDispatch
{
get
{
return new ProxyParserErrorListener(ErrorListeners);
}
}
public virtual bool InContext(string context)
{
// TODO: useful in parser?
return false;
}
/// <summary>
/// Checks whether or not
/// <paramref name="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>
/// </summary>
/// <param name="symbol">the symbol type to check</param>
/// <returns>
///
/// <see langword="true"/>
/// if
/// <paramref name="symbol"/>
/// can follow the current state in
/// the ATN, otherwise
/// <see langword="false"/>
/// .
/// </returns>
public virtual bool IsExpectedToken(int symbol)
{
// return getInterpreter().atn.nextTokens(_ctx);
ATN atn = Interpreter.atn;
ParserRuleContext ctx = _ctx;
ATNState s = atn.states[State];
IntervalSet following = atn.NextTokens(s);
if (following.Contains(symbol))
{
return true;
}
// System.out.println("following "+s+"="+following);
if (!following.Contains(TokenConstants.EPSILON))
{
return false;
}
while (ctx != null && ctx.invokingState >= 0 && following.Contains(TokenConstants.EPSILON))
{
ATNState invokingState = atn.states[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(TokenConstants.EPSILON) && symbol == TokenConstants.EOF)
{
return true;
}
return false;
}
/// <summary>
/// Computes the set of input symbols which could follow the current parser
/// state and context, as given by
/// <see cref="Recognizer{Symbol, ATNInterpreter}.State()"/>
/// and
/// <see cref="Context()"/>
/// ,
/// respectively.
/// </summary>
/// <seealso cref="Antlr4.Runtime.Atn.ATN.GetExpectedTokens(int, RuleContext)"/>
[return: NotNull]
public virtual IntervalSet GetExpectedTokens()
{
return Atn.GetExpectedTokens(State, Context);
}
[return: NotNull]
public virtual IntervalSet GetExpectedTokensWithinCurrentRule()
{
ATN atn = Interpreter.atn;
ATNState s = atn.states[State];
return atn.NextTokens(s);
}
/// <summary>
/// Get a rule's index (i.e.,
/// <c>RULE_ruleName</c>
/// field) or -1 if not found.
/// </summary>
public virtual int GetRuleIndex(string ruleName)
{
int ruleIndex;
if (RuleIndexMap.TryGetValue(ruleName, out ruleIndex))
{
return ruleIndex;
}
return -1;
}
public virtual ParserRuleContext RuleContext
{
get
{
return _ctx;
}
}
/// <summary>
/// Return List&lt;String&gt; of the rule names in your parser instance
/// leading up to a call to the current rule.
/// </summary>
/// <remarks>
/// 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.
/// </remarks>
public virtual IList<string> GetRuleInvocationStack()
{
return GetRuleInvocationStack(_ctx);
}
public virtual string GetRuleInvocationStackAsString()
{
StringBuilder sb = new StringBuilder ("[");
foreach (string s in GetRuleInvocationStack()) {
sb.Append (s);
sb.Append (", ");
}
sb.Length = sb.Length - 2;
sb.Append ("]");
return sb.ToString ();
}
public virtual IList<string> GetRuleInvocationStack(RuleContext p)
{
string[] ruleNames = RuleNames;
IList<string> stack = new List<string>();
while (p != null)
{
// compute what follows who invoked us
int ruleIndex = p.RuleIndex;
if (ruleIndex < 0)
{
stack.Add("n/a");
}
else
{
stack.Add(ruleNames[ruleIndex]);
}
p = p.Parent;
}
return stack;
}
/// <summary>For debugging and other purposes.</summary>
/// <remarks>For debugging and other purposes.</remarks>
public virtual IList<string> GetDFAStrings()
{
IList<string> s = new List<string>();
for (int d = 0; d < Interpreter.atn.decisionToDFA.Length; d++)
{
DFA dfa = Interpreter.atn.decisionToDFA[d];
s.Add(dfa.ToString(Vocabulary));
}
return s;
}
/// <summary>For debugging and other purposes.</summary>
/// <remarks>For debugging and other purposes.</remarks>
public virtual void DumpDFA()
{
bool seenOne = false;
for (int d = 0; d < Interpreter.decisionToDFA.Length; d++)
{
DFA dfa = Interpreter.decisionToDFA[d];
if (dfa.states.Count>0)
{
if (seenOne)
{
Output.WriteLine();
}
Output.WriteLine("Decision " + dfa.decision + ":");
Output.Write(dfa.ToString(Vocabulary));
seenOne = true;
}
}
}
public virtual string SourceName
{
get
{
return _input.SourceName;
}
}
public override ParseInfo ParseInfo
{
get
{
ParserATNSimulator interp = Interpreter;
if (interp is ProfilingATNSimulator)
{
return new ParseInfo((ProfilingATNSimulator)interp);
}
return null;
}
}
/// <since>4.3</since>
public virtual bool Profile
{
set
{
bool profile = value;
ParserATNSimulator interp = Interpreter;
if (profile)
{
if (!(interp is ProfilingATNSimulator))
{
Interpreter = new ProfilingATNSimulator(this);
}
}
else
{
if (interp is ProfilingATNSimulator)
{
Interpreter = new ParserATNSimulator(this, Atn, null, null);
}
}
}
}
/// <summary>
/// During a parse is sometimes useful to listen in on the rule entry and exit
/// events as well as token matches.
/// </summary>
/// <remarks>
/// 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.
/// </remarks>
public virtual bool Trace
{
get
{
foreach (object o in ParseListeners)
{
if (o is Parser.TraceListener)
{
return true;
}
}
return false;
}
set
{
bool trace = value;
if (!trace)
{
RemoveParseListener(_tracer);
_tracer = null;
}
else
{
if (_tracer != null)
{
RemoveParseListener(_tracer);
}
else
{
_tracer = new Parser.TraceListener(this);
}
AddParseListener(_tracer);
}
}
}
}
}