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 }