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