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.LL1Analyzer; 8 9 import antlr.v4.runtime.RuleContext; 10 import antlr.v4.runtime.Token; 11 import antlr.v4.runtime.TokenConstantDefinition; 12 import antlr.v4.runtime.atn.ATN; 13 import antlr.v4.runtime.atn.ATNConfig; 14 import antlr.v4.runtime.atn.ATNState; 15 import antlr.v4.runtime.atn.AbstractPredicateTransition; 16 import antlr.v4.runtime.atn.NotSetTransition; 17 import antlr.v4.runtime.atn.PredictionContext; 18 import antlr.v4.runtime.atn.RuleStopState; 19 import antlr.v4.runtime.atn.RuleTransition; 20 import antlr.v4.runtime.atn.SingletonPredictionContext; 21 import antlr.v4.runtime.atn.Transition; 22 import antlr.v4.runtime.atn.WildcardTransition; 23 import antlr.v4.runtime.misc.IntervalSet; 24 import std.container.array; 25 import std.conv; 26 import std.stdio; 27 28 /** 29 * LL1 Analyzer 30 */ 31 class LL1Analyzer 32 { 33 34 /** 35 * Special value added to the lookahead sets to indicate that we hit 36 * a predicate during analysis if {@code seeThruPreds==false}. 37 */ 38 public static const int HIT_PRED = TokenConstantDefinition.INVALID_TYPE; 39 40 public ATN atn; 41 42 public this(ATN atn) 43 { 44 this.atn = atn; 45 } 46 47 /** 48 * Calculates the SLL(1) expected lookahead set for each outgoing transition 49 * if an {@link ATNState}. The returned array has one element for each 50 * outgoing transition in {@code s}. If the closure from transition 51 * <em>i</em> leads to a semantic predicate before matching a symbol, the 52 * element at index <em>i</em> of the result will be {@code null}. 53 * 54 * @param s the ATN state 55 * @return the expected symbols for each outgoing transition of {@code s}. 56 */ 57 public IntervalSet[] getDecisionLookahead(ATNState s) 58 { 59 debug 60 writefln("LL1Analyzer: LOOK(%s)", s.stateNumber); 61 if (s is null) { 62 return null; 63 } 64 65 IntervalSet[] look = new IntervalSet[s.getNumberOfTransitions]; 66 for (int alt = 0; alt < s.getNumberOfTransitions; alt++) { 67 look[alt] = new IntervalSet(); 68 auto lookBusy = new Array!ATNConfig(); 69 bool seeThruPreds = false; // fail to get lookahead upon pred 70 _LOOK(s.transition(alt).target, null, cast(PredictionContext)PredictionContext.EMPTY, 71 look[alt], lookBusy, new Array!bool(), seeThruPreds, false); 72 // Wipe out lookahead for this alternative if we found nothing 73 // or we had a predicate when we !seeThruPreds 74 if (look[alt].size == 0 || look[alt].contains(HIT_PRED)) { 75 look[alt] = null; 76 } 77 } 78 return look; 79 } 80 81 /** 82 * Compute set of tokens that can follow {@code s} in the ATN in the 83 * specified {@code ctx}. 84 * 85 * <p>If {@code ctx} is {@code null} and the end of the rule containing 86 * {@code s} is reached, {@link Token#EPSILON} is added to the result set. 87 * If {@code ctx} is not {@code null} and the end of the outermost rule is 88 * reached, {@link Token#EOF} is added to the result set.</p> 89 * 90 * @param s the ATN state 91 * @param ctx the complete parser context, or {@code null} if the context 92 * should be ignored 93 * 94 * @return The set of tokens that can follow {@code s} in the ATN in the 95 * specified {@code ctx}. 96 */ 97 public IntervalSet LOOK(ATNState s, RuleContext ctx) 98 { 99 return LOOK(s, null, ctx); 100 } 101 102 /** 103 * Compute set of tokens that can follow {@code s} in the ATN in the 104 * specified {@code ctx}. 105 * 106 * <p>If {@code ctx} is {@code null} and the end of the rule containing 107 * {@code s} is reached, {@link Token#EPSILON} is added to the result set. 108 * If {@code ctx} is not {@code null} and the end of the outermost rule is 109 * reached, {@link Token#EOF} is added to the result set.</p> 110 * 111 * @param s the ATN state 112 * @param stopState the ATN state to stop at. This can be a 113 * {@link BlockEndState} to detect epsilon paths through a closure. 114 * @param ctx the complete parser context, or {@code null} if the context 115 * should be ignored 116 * 117 * @return The set of tokens that can follow {@code s} in the ATN in the 118 * specified {@code ctx}. 119 */ 120 public IntervalSet LOOK(ATNState s, ATNState stopState, RuleContext ctx) 121 { 122 IntervalSet r = new IntervalSet(); 123 bool seeThruPreds = true; // ignore preds; get all lookahead 124 PredictionContext lookContext = ctx !is null ? PredictionContext.fromRuleContext(s.atn, ctx) : null; 125 _LOOK(s, stopState, lookContext, 126 r, new Array!ATNConfig(), new Array!bool(), seeThruPreds, true); 127 return r; 128 } 129 130 /** 131 * Compute set of tokens that can follow {@code s} in the ATN in the 132 * specified {@code ctx}. 133 * 134 * <p>If {@code ctx} is {@code null} and {@code stopState} or the end of the 135 * rule containing {@code s} is reached, {@link Token#EPSILON} is added to 136 * the result set. If {@code ctx} is not {@code null} and {@code addEOF} is 137 * {@code true} and {@code stopState} or the end of the outermost rule is 138 * reached, {@link Token#EOF} is added to the result set.</p> 139 * 140 * @param s the ATN state. 141 * @param stopState the ATN state to stop at. This can be a 142 * {@link BlockEndState} to detect epsilon paths through a closure. 143 * @param ctx The outer context, or {@code null} if the outer context should 144 * not be used. 145 * @param look The result lookahead set. 146 * @param lookBusy A set used for preventing epsilon closures in the ATN 147 * from causing a stack overflow. Outside code should pass 148 * {@code new HashSet<ATNConfig>} for this argument. 149 * @param calledRuleStack A set used for preventing left recursion in the 150 * ATN from causing a stack overflow. Outside code should pass 151 * {@code new BitSet()} for this argument. 152 * @param seeThruPreds {@code true} to true semantic predicates as 153 * implicitly {@code true} and "see through them", otherwise {@code false} 154 * to treat semantic predicates as opaque and add {@link #HIT_PRED} to the 155 * result if one is encountered. 156 * @param addEOF Add {@link Token#EOF} to the result if the end of the 157 * outermost context is reached. This parameter has no effect if {@code ctx} 158 * is {@code null}. 159 */ 160 protected void _LOOK(ATNState s, ATNState stopState, PredictionContext ctx, ref IntervalSet look, 161 Array!ATNConfig* lookBusy, Array!bool* calledRuleStack, bool seeThruPreds, bool addEOF) 162 { 163 debug 164 writefln("LL1Analyzer: _LOOK(%s, ctx=%s), look = %s", s.stateNumber, 165 ctx, look.intervals); 166 ATNConfig c = new ATNConfig(s, 0, ctx); 167 foreach (lb; *lookBusy) 168 if (lb == c) 169 return; 170 *lookBusy = *lookBusy ~ c; 171 if (s == stopState) { 172 if (ctx is null) { 173 look.add(TokenConstantDefinition.EPSILON); 174 return; 175 } 176 else if (ctx.isEmpty && addEOF) { 177 look.add(TokenConstantDefinition.EOF); 178 return; 179 } 180 } 181 if (cast(RuleStopState)s) { 182 if (ctx is null ) { 183 look.add(TokenConstantDefinition.EPSILON); 184 return; 185 } 186 else if (ctx.isEmpty && addEOF) { 187 look.add(TokenConstantDefinition.EOF); 188 return; 189 } 190 191 if (ctx != PredictionContext.EMPTY) { 192 // run thru all possible stack tops in ctx 193 bool removed = (*calledRuleStack).length && (*calledRuleStack)[s.ruleIndex]; 194 try { 195 if ((*calledRuleStack).length <= s.ruleIndex) 196 (*calledRuleStack).length = s.ruleIndex+1; 197 calledRuleStack.opIndexAssign(false, s.ruleIndex); 198 for (int i = 0; i < ctx.size(); i++) { 199 ATNState returnState = atn.states[ctx.getReturnState(i)]; 200 debug { 201 import std.stdio; 202 writefln("popping back to %s", returnState); 203 } 204 _LOOK(returnState, stopState, ctx.getParent(i), look, lookBusy, calledRuleStack, seeThruPreds, addEOF); 205 } 206 } 207 finally { 208 if (removed) { 209 calledRuleStack.opIndexAssign(true, s.ruleIndex); 210 } 211 } 212 return; 213 } 214 } 215 216 int n = s.getNumberOfTransitions; 217 for (int i=0; i<n; i++) { 218 Transition t = s.transition(i); 219 if (t.classinfo == RuleTransition.classinfo) { 220 if (calledRuleStack.length > 221 (cast(RuleTransition)t).target.ruleIndex && 222 (*calledRuleStack)[(cast(RuleTransition)t).target.ruleIndex]) { 223 continue; 224 } 225 PredictionContext newContext = 226 SingletonPredictionContext.create(ctx, (cast(RuleTransition)t).followState.stateNumber); 227 try { 228 if (calledRuleStack.length <= (cast(RuleTransition)t).target.ruleIndex) 229 calledRuleStack.length = (cast(RuleTransition)t).target.ruleIndex +1; 230 calledRuleStack.opIndexAssign(true, (cast(RuleTransition)t).target.ruleIndex); 231 _LOOK(t.target, stopState, newContext, look, lookBusy, calledRuleStack, seeThruPreds, addEOF); 232 } 233 finally { 234 calledRuleStack.opIndexAssign(false, (cast(RuleTransition)t).target.ruleIndex); 235 } 236 } 237 else if (cast(AbstractPredicateTransition)t) { 238 if ( seeThruPreds ) { 239 _LOOK(t.target, stopState, ctx, look, lookBusy, calledRuleStack, seeThruPreds, addEOF); 240 } 241 else { 242 look.add(HIT_PRED); 243 } 244 } 245 else if ( t.isEpsilon() ) { 246 _LOOK(t.target, stopState, ctx, look, lookBusy, calledRuleStack, seeThruPreds, addEOF); 247 } 248 else if (t.classinfo == WildcardTransition.classinfo) { 249 look.addAll( IntervalSet.of(TokenConstantDefinition.MIN_USER_TOKEN_TYPE, atn.maxTokenType) ); 250 } 251 else { 252 debug 253 writeln("LL1Analyzer: adding " ~ to!string(t)); 254 IntervalSet set = t.label(); 255 if (set) { 256 if (cast(NotSetTransition)t) { 257 set = set.complement(IntervalSet.of(TokenConstantDefinition.MIN_USER_TOKEN_TYPE, atn.maxTokenType)); 258 } 259 look.addAll(set); 260 debug 261 writefln("LL1Analyzer: look %s", look); 262 } 263 } 264 } 265 } 266 267 }