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 }