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 }