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