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 }