1 /*
2  * Copyright (c) 2012-2017 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.dfa.DFAState;
8 
9 import std.conv;
10 import std.array;
11 import antlr.v4.runtime.misc.MurmurHash;
12 import antlr.v4.runtime.atn.ATNConfig;
13 import antlr.v4.runtime.atn.ATNConfigSet;
14 import antlr.v4.runtime.atn.LexerActionExecutor;
15 import antlr.v4.runtime.dfa.PredPrediction;
16 
17 // Class DFAState
18 /**
19  * A DFA state represents a set of possible ATN configurations.
20  * As Aho, Sethi, Ullman p. 117 says "The DFA uses its state
21  * to keep track of all possible states the ATN can be in after
22  * reading each input symbol.  That is to say, after reading
23  * input a1a2..an, the DFA is in a state that represents the
24  * subset T of the states of the ATN that are reachable from the
25  * ATN's start state along some path labeled a1a2..an."
26  * In conventional NFA→DFA conversion, therefore, the subset T
27  * would be a bitset representing the set of states the
28  * ATN could be in.  We need to track the alt predicted by each
29  * state as well, however.  More importantly, we need to maintain
30  * a stack of states, tracking the closure operations as they
31  * jump from rule to rule, emulating rule invocations (method calls).
32  * I have to add a stack to simulate the proper lookahead sequences for
33  * the underlying LL grammar from which the ATN was derived.
34  *
35  * <p>I use a set of ATNConfig objects not simple states.  An ATNConfig
36  * is both a state (ala normal conversion) and a RuleContext describing
37  * the chain of rules (if any) followed to arrive at that state.</p>
38  *
39  * <p>A DFA state may have multiple references to a particular state,
40  * but with different ATN contexts (with same or different alts)
41  * meaning that state was reached via a different set of rule invocations.</p>
42  */
43 class DFAState
44 {
45 
46     public int stateNumber = -1;
47 
48     public ATNConfigSet configs = new ATNConfigSet;
49 
50     /**
51      * {@code edges[symbol]} points to target of symbol. Shift up by 1 so (-1)
52      * {@link Token#EOF} maps to {@code edges[0]}.
53      */
54     public DFAState[] edges;
55 
56     public bool isAcceptState = false;
57 
58     /**
59      * if accept state, what ttype do we match or alt do we predict?
60      * This is set to {@link ATN#INVALID_ALT_NUMBER} when {@link #predicates}{@code !=null} or
61      * {@link #requiresFullContext}.
62      */
63     public int prediction;
64 
65     public LexerActionExecutor lexerActionExecutor;
66 
67     /**
68      * Indicates that this state was created during SLL prediction that
69      * discovered a conflict between the configurations in the state. Future
70      * {@link ParserATNSimulator#execATN} invocations immediately jumped doing
71      * full context prediction if this field is true.
72      */
73     public bool requiresFullContext;
74 
75     /**
76      * During SLL parsing, this is a list of predicates associated with the
77      * ATN configurations of the DFA state. When we have predicates,
78      * {@link #requiresFullContext} is {@code false} since full context prediction evaluates predicates
79      * on-the-fly. If this is not null, then {@link #prediction} is
80      * {@link ATN#INVALID_ALT_NUMBER}.
81      * 	 *
82      * <p>We only use these for non-{@link #requiresFullContext} but conflicting states. That
83      * means we know from the context (it's $ or we don't dip into outer
84      * context) that it's an ambiguity not a conflict.</p>
85      *
86      * <p>This list is computed by {@link ParserATNSimulator#predicateDFAState}.</p>
87      */
88     public PredPrediction[] predicates;
89 
90     public this()
91     {
92     }
93 
94     public this(int stateNumber)
95     {
96         this.stateNumber = stateNumber;
97     }
98 
99     public this(ATNConfigSet configs)
100     {
101         this.configs = configs;
102     }
103 
104     /**
105      * Get the set of all alts mentioned by all ATN configurations in the
106      * DFA state.
107      */
108     public int[] getAltSet()
109     {
110         int[] alts;
111         if (configs) {
112             foreach (ATNConfig c; configs.configs) {
113                 alts ~= c.alt;
114             }
115         }
116         if (alts.length == 0) return null;
117         return alts;
118     }
119 
120     /**
121      * @uml
122      * @override
123      * @safe
124      * @nothrow
125      */
126     public override size_t toHash() @safe nothrow
127     {
128 	size_t hash = MurmurHash.initialize(7);
129         hash = MurmurHash.update(hash, configs.toHash());
130         hash = MurmurHash.finish(hash, 1);
131         return hash;
132     }
133 
134     /**
135      * Two {@link DFAState} instances are equal if their ATN configuration sets
136      * are the same. This method is used to see if a state already exists.
137      *
138      * <p>Because the number of alternatives and number of ATN configurations are
139      * finite, there is a finite number of DFA states that can be processed.
140      * This is necessary to show that the algorithm terminates.</p>
141      *
142      * <p>Cannot test the DFA state numbers here because in
143      * {@link ParserATNSimulator#addDFAState} we need to know if any other state
144      * exists that has this exact set of ATN configurations. The
145      * {@link #stateNumber} is irrelevant.</p>
146      * @uml
147      * @override
148      */
149     public override bool opEquals(Object o)
150     {
151         //if (o is null) return false;
152         if (this is o) {
153             return true;
154         }
155         if (!cast(DFAState)o) {
156              return false;
157         }
158         // compare set of ATN configurations in this set with other
159         DFAState other = cast(DFAState)o;
160         // TODO: what to do when configs==null?
161         bool sameSet = ATNConfigSet.equals(this.configs, other.configs);
162         debug(DFAState)
163             {
164                 import std.stdio;
165                 writefln("DFAState.equals: configs %s same %s other.configs %s", configs,
166                          (sameSet?"==":"!="), other.configs);
167             }
168         return sameSet;
169     }
170 
171     /**
172      * @uml
173      * @override
174      */
175     public override string toString()
176     {
177         auto buf = appender!string;
178         buf.put(to!string(stateNumber));
179         buf.put(":");
180         buf.put(configs.toString);
181         if (isAcceptState) {
182             buf.put("=>");
183             if (predicates !is null) {
184                 buf.put(to!string(predicates));
185             }
186             else {
187                 buf.put(to!string(prediction));
188             }
189         }
190         return buf.data;
191     }
192 
193 }