1 /* 2 * Copyright (c) 2012-2018 The ANTLR Project. All rights reserved. 3 * Use of this file is governed by the BSD 3-clause license that 4 * can be found in the LICENSE.txt file in the project root. 5 */ 6 7 module antlr.v4.runtime.atn.ATN; 8 9 import std.conv; 10 import antlr.v4.runtime.IllegalArgumentException; 11 import antlr.v4.runtime.RuleContext; 12 import antlr.v4.runtime.atn.ATNState; 13 import antlr.v4.runtime.atn.ATNType; 14 import antlr.v4.runtime.atn.DecisionState; 15 import antlr.v4.runtime.atn.RuleStartState; 16 import antlr.v4.runtime.atn.RuleStopState; 17 import antlr.v4.runtime.atn.LL1Analyzer; 18 import antlr.v4.runtime.atn.RuleTransition; 19 import antlr.v4.runtime.Token; 20 import antlr.v4.runtime.TokenConstantDefinition; 21 import antlr.v4.runtime.atn.TokensStartState; 22 import antlr.v4.runtime.atn.LexerAction; 23 import antlr.v4.runtime.misc.IntervalSet; 24 25 // Class ATN 26 /** 27 * Class implementation adapted from Java code 28 */ 29 class ATN 30 { 31 32 public static immutable int INVALID_ALT_NUMBER = 0; 33 34 public ATNState[] states; 35 36 /** 37 * @uml 38 * Each subrule/rule is a decision point and we must track them so we 39 * can go back later and build DFA predictors for them. This includes 40 * all the rules, subrules, optional blocks, ()+, ()* etc... 41 */ 42 public DecisionState[] decisionToState; 43 44 /** 45 * @uml 46 * Maps from rule index to starting state number. 47 */ 48 public RuleStartState[] ruleToStartState; 49 50 /** 51 * @uml 52 * Maps from rule index to stop state number. 53 */ 54 public RuleStopState[] ruleToStopState; 55 56 public TokensStartState[string] modeNameToStartState; 57 58 /** 59 * @uml 60 * The type of the ATN. 61 */ 62 public ATNType grammarType; 63 64 /** 65 * @uml 66 * The maximum value for any symbol recognized by a transition in the ATN. 67 */ 68 public int maxTokenType; 69 70 /** 71 * @uml 72 * For lexer ATNs, this maps the rule index to the resulting token type. 73 * For parser ATNs, this maps the rule index to the generated bypass token 74 * type if the 75 * {@link ATNDeserializationOptions#isGenerateRuleBypassTransitions} 76 * deserialization option was specified; otherwise, this is {@code null}. 77 */ 78 public int[] ruleToTokenType; 79 80 /** 81 * @uml 82 * For lexer ATNs, this is an array of {@link LexerAction} objects which may 83 * be referenced by action transitions in the ATN. 84 */ 85 public LexerAction[] lexerActions; 86 87 public TokensStartState[] modeToStartState; 88 89 /** 90 * @uml 91 * Used for runtime deserialization of ATNs from strings 92 */ 93 public this(ATNType grammarType, int maxTokenType) 94 { 95 this.grammarType = grammarType; 96 this.maxTokenType = maxTokenType; 97 } 98 99 /** 100 * @uml 101 * Compute the set of valid tokens that can occur starting in state {@code s}. 102 * If {@code ctx} is null, the set of tokens will not include what can follow 103 * the rule surrounding {@code s}. In other words, the set will be 104 * restricted to tokens reachable staying within {@code s}'s rule. 105 */ 106 public IntervalSet nextTokens(ATNState s, RuleContext ctx) 107 { 108 LL1Analyzer anal = new LL1Analyzer(this); 109 IntervalSet next = anal.LOOK(s, ctx); 110 return next; 111 } 112 113 /** 114 * @uml 115 * Compute the set of valid tokens that can occur starting in {@code s} and 116 * staying in same rule. {@link Token#EPSILON} is in set if we reach end of 117 * rule. 118 */ 119 public IntervalSet nextTokens(ATNState s) 120 { 121 debug { 122 import std.stdio; 123 writefln("ATN: nextTokens(ATNState s) %s", s); 124 } 125 if (s.nextTokenWithinRule !is null ) { 126 return s.nextTokenWithinRule; 127 } 128 s.nextTokenWithinRule = nextTokens(s, null); 129 s.nextTokenWithinRule.setReadonly(true); 130 return s.nextTokenWithinRule; 131 } 132 133 public void addState(ATNState state) 134 { 135 if (state !is null) { 136 state.atn = this; 137 state.stateNumber = to!int(states.length); 138 } 139 states ~= state; 140 } 141 142 public void removeState(ATNState state) 143 { 144 states[state.stateNumber] = null; // just free mem, don't shift states in list 145 } 146 147 public int defineDecisionState(DecisionState s) 148 { 149 decisionToState ~= s; 150 s.decision = to!int(decisionToState.length)-1; 151 return s.decision; 152 } 153 154 public DecisionState getDecisionState(int decision) 155 { 156 if (decisionToState.length > 0) { 157 return decisionToState[decision]; 158 } 159 return null; 160 } 161 162 public int getNumberOfDecisions() 163 { 164 return to!int(decisionToState.length); 165 } 166 167 /** 168 * @uml 169 * Computes the set of input symbols which could follow ATN state number 170 * {@code stateNumber} in the specified full {@code context}. This method 171 * considers the complete parser context, but does not evaluate semantic 172 * predicates (i.e. all predicates encountered during the calculation are 173 * assumed true). If a path in the ATN exists from the starting state to the 174 * {@link RuleStopState} of the outermost context without matching any 175 * symbols, {@link Token#EOF} is added to the returned set. 176 * 177 * <p>If {@code context} is {@code null}, it is treated as 178 * {@link ParserRuleContext#EMPTY}.</p> 179 * 180 * @param stateNumber the ATN state number 181 * @param context the full parse context 182 * @return The set of potentially valid input symbols which could follow the 183 * specified state in the specified context. 184 * @throws IllegalArgumentException if the ATN does not contain a state with 185 * number {@code stateNumber} 186 */ 187 public IntervalSet getExpectedTokens(int stateNumber, RuleContext context) 188 { 189 if (stateNumber < 0 || stateNumber >= states.length) { 190 throw new IllegalArgumentException("Invalid state number."); 191 } 192 193 RuleContext ctx = context; 194 ATNState s = states[stateNumber]; 195 IntervalSet following = nextTokens(s); 196 if (!following.contains(TokenConstantDefinition.EPSILON)) { 197 return following; 198 } 199 200 IntervalSet expected = new IntervalSet(); 201 expected.addAll(following); 202 expected.remove(TokenConstantDefinition.EPSILON); 203 while (ctx !is null && ctx.invokingState >= 0 && following.contains(TokenConstantDefinition.EPSILON)) { 204 ATNState invokingState = states[ctx.invokingState]; 205 RuleTransition rt = cast(RuleTransition)invokingState.transition(0); 206 following = nextTokens(rt.followState); 207 expected.addAll(following); 208 expected.remove(TokenConstantDefinition.EPSILON); 209 ctx = ctx.parent; 210 } 211 212 if (following.contains(TokenConstantDefinition.EPSILON)) { 213 expected.add(TokenConstantDefinition.EOF); 214 } 215 216 return expected; 217 } 218 219 }