| /* 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.Collections.Concurrent; |
| using System.Collections.Generic; |
| using Antlr4.Runtime; |
| using Antlr4.Runtime.Atn; |
| using Antlr4.Runtime.Dfa; |
| using Antlr4.Runtime.Misc; |
| using Antlr4.Runtime.Sharpen; |
| |
| namespace Antlr4.Runtime.Atn |
| { |
| public class ATN |
| { |
| public const int INVALID_ALT_NUMBER = 0; |
| |
| [NotNull] |
| public readonly IList<ATNState> states = new List<ATNState>(); |
| |
| /// <summary> |
| /// Each subrule/rule is a decision point and we must track them so we |
| /// can go back later and build DFA predictors for them. |
| /// </summary> |
| /// <remarks> |
| /// Each subrule/rule is a decision point and we must track them so we |
| /// can go back later and build DFA predictors for them. This includes |
| /// all the rules, subrules, optional blocks, ()+, ()* etc... |
| /// </remarks> |
| [NotNull] |
| public readonly IList<DecisionState> decisionToState = new List<DecisionState>(); |
| |
| /// <summary>Maps from rule index to starting state number.</summary> |
| /// <remarks>Maps from rule index to starting state number.</remarks> |
| public RuleStartState[] ruleToStartState; |
| |
| /// <summary>Maps from rule index to stop state number.</summary> |
| /// <remarks>Maps from rule index to stop state number.</remarks> |
| public RuleStopState[] ruleToStopState; |
| |
| [NotNull] |
| public readonly IDictionary<string, TokensStartState> modeNameToStartState = new Dictionary<string, TokensStartState>(); |
| |
| /// <summary>The type of the ATN.</summary> |
| /// <remarks>The type of the ATN.</remarks> |
| public readonly ATNType grammarType; |
| |
| /// <summary>The maximum value for any symbol recognized by a transition in the ATN.</summary> |
| /// <remarks>The maximum value for any symbol recognized by a transition in the ATN.</remarks> |
| public readonly int maxTokenType; |
| |
| /// <summary>For lexer ATNs, this maps the rule index to the resulting token type.</summary> |
| /// <remarks> |
| /// For lexer ATNs, this maps the rule index to the resulting token type. |
| /// For parser ATNs, this maps the rule index to the generated bypass token |
| /// type if the |
| /// <see cref="ATNDeserializationOptions.GenerateRuleBypassTransitions()"/> |
| /// deserialization option was specified; otherwise, this is |
| /// <see langword="null"/> |
| /// . |
| /// </remarks> |
| public int[] ruleToTokenType; |
| |
| /// <summary> |
| /// For lexer ATNs, this is an array of |
| /// <see cref="ILexerAction"/> |
| /// objects which may |
| /// be referenced by action transitions in the ATN. |
| /// </summary> |
| public ILexerAction[] lexerActions; |
| |
| [NotNull] |
| public readonly IList<TokensStartState> modeToStartState = new List<TokensStartState>(); |
| |
| private readonly PredictionContextCache contextCache = new PredictionContextCache(); |
| |
| [NotNull] |
| public DFA[] decisionToDFA = new DFA[0]; |
| |
| [NotNull] |
| public DFA[] modeToDFA = new DFA[0]; |
| |
| protected internal readonly ConcurrentDictionary<int, int> LL1Table = new ConcurrentDictionary<int, int>(); |
| |
| /// <summary>Used for runtime deserialization of ATNs from strings</summary> |
| public ATN(ATNType grammarType, int maxTokenType) |
| { |
| this.grammarType = grammarType; |
| this.maxTokenType = maxTokenType; |
| } |
| |
| |
| public virtual PredictionContext GetCachedContext(PredictionContext context) |
| { |
| return PredictionContext.GetCachedContext(context, contextCache, new PredictionContext.IdentityHashMap()); |
| } |
| |
| /// <summary> |
| /// Compute the set of valid tokens that can occur starting in state |
| /// <paramref name="s"/> |
| /// . |
| /// If |
| /// <paramref name="ctx"/> |
| /// is |
| /// <see cref="EmptyPredictionContext.Instance"/> |
| /// , the set of tokens will not include what can follow |
| /// the rule surrounding |
| /// <paramref name="s"/> |
| /// . In other words, the set will be |
| /// restricted to tokens reachable staying within |
| /// <paramref name="s"/> |
| /// 's rule. |
| /// </summary> |
| [return: NotNull] |
| public virtual IntervalSet NextTokens(ATNState s, RuleContext ctx) |
| { |
| LL1Analyzer anal = new LL1Analyzer(this); |
| IntervalSet next = anal.Look(s, ctx); |
| return next; |
| } |
| |
| /// <summary> |
| /// Compute the set of valid tokens that can occur starting in |
| /// <paramref name="s"/> |
| /// and |
| /// staying in same rule. |
| /// <see cref="TokenConstants.EPSILON"/> |
| /// is in set if we reach end of |
| /// rule. |
| /// </summary> |
| [return: NotNull] |
| public virtual IntervalSet NextTokens(ATNState s) |
| { |
| if (s.nextTokenWithinRule != null) |
| { |
| return s.nextTokenWithinRule; |
| } |
| s.nextTokenWithinRule = NextTokens(s, null); |
| s.nextTokenWithinRule.SetReadonly(true); |
| return s.nextTokenWithinRule; |
| } |
| |
| public virtual void AddState(ATNState state) |
| { |
| if (state != null) |
| { |
| state.atn = this; |
| state.stateNumber = states.Count; |
| } |
| states.Add(state); |
| } |
| |
| public virtual void RemoveState(ATNState state) |
| { |
| states[state.stateNumber] = null; |
| } |
| |
| // just free mem, don't shift states in list |
| public virtual void DefineMode(string name, TokensStartState s) |
| { |
| modeNameToStartState[name] = s; |
| modeToStartState.Add(s); |
| modeToDFA = Arrays.CopyOf(modeToDFA, modeToStartState.Count); |
| modeToDFA[modeToDFA.Length - 1] = new DFA(s); |
| DefineDecisionState(s); |
| } |
| |
| public virtual int DefineDecisionState(DecisionState s) |
| { |
| decisionToState.Add(s); |
| s.decision = decisionToState.Count - 1; |
| decisionToDFA = Arrays.CopyOf(decisionToDFA, decisionToState.Count); |
| decisionToDFA[decisionToDFA.Length - 1] = new DFA(s, s.decision); |
| return s.decision; |
| } |
| |
| public virtual DecisionState GetDecisionState(int decision) |
| { |
| if (decisionToState.Count != 0) |
| { |
| return decisionToState[decision]; |
| } |
| return null; |
| } |
| |
| public virtual int NumberOfDecisions |
| { |
| get |
| { |
| return decisionToState.Count; |
| } |
| } |
| |
| /// <summary> |
| /// Computes the set of input symbols which could follow ATN state number |
| /// <paramref name="stateNumber"/> |
| /// in the specified full |
| /// <paramref name="context"/> |
| /// . This method |
| /// considers the complete parser context, but does not evaluate semantic |
| /// predicates (i.e. all predicates encountered during the calculation are |
| /// assumed true). If a path in the ATN exists from the starting state to the |
| /// <see cref="RuleStopState"/> |
| /// of the outermost context without matching any |
| /// symbols, |
| /// <see cref="TokenConstants.EOF"/> |
| /// is added to the returned set. |
| /// <p>If |
| /// <paramref name="context"/> |
| /// is |
| /// <see langword="null"/> |
| /// , it is treated as |
| /// <see cref="ParserRuleContext.EmptyContext"/> |
| /// .</p> |
| /// </summary> |
| /// <param name="stateNumber">the ATN state number</param> |
| /// <param name="context">the full parse context</param> |
| /// <returns> |
| /// The set of potentially valid input symbols which could follow the |
| /// specified state in the specified context. |
| /// </returns> |
| /// <exception cref="System.ArgumentException"> |
| /// if the ATN does not contain a state with |
| /// number |
| /// <paramref name="stateNumber"/> |
| /// </exception> |
| [return: NotNull] |
| public virtual IntervalSet GetExpectedTokens(int stateNumber, RuleContext context) |
| { |
| if (stateNumber < 0 || stateNumber >= states.Count) |
| { |
| throw new ArgumentException("Invalid state number."); |
| } |
| RuleContext ctx = context; |
| ATNState s = states[stateNumber]; |
| IntervalSet following = NextTokens(s); |
| if (!following.Contains(TokenConstants.EPSILON)) |
| { |
| return following; |
| } |
| IntervalSet expected = new IntervalSet(); |
| expected.AddAll(following); |
| expected.Remove(TokenConstants.EPSILON); |
| while (ctx != null && ctx.invokingState >= 0 && following.Contains(TokenConstants.EPSILON)) |
| { |
| ATNState invokingState = states[ctx.invokingState]; |
| RuleTransition rt = (RuleTransition)invokingState.Transition(0); |
| following = NextTokens(rt.followState); |
| expected.AddAll(following); |
| expected.Remove(TokenConstants.EPSILON); |
| ctx = ctx.Parent; |
| } |
| if (following.Contains(TokenConstants.EPSILON)) |
| { |
| expected.Add(TokenConstants.EOF); |
| } |
| return expected; |
| } |
| } |
| } |