1*37748cd8SNickeau<?php 2*37748cd8SNickeau 3*37748cd8SNickeaudeclare(strict_types=1); 4*37748cd8SNickeau 5*37748cd8SNickeaunamespace Antlr\Antlr4\Runtime\Dfa; 6*37748cd8SNickeau 7*37748cd8SNickeauuse Antlr\Antlr4\Runtime\Atn\ATNConfigSet; 8*37748cd8SNickeauuse Antlr\Antlr4\Runtime\Atn\LexerActionExecutor; 9*37748cd8SNickeauuse Antlr\Antlr4\Runtime\Comparison\Equality; 10*37748cd8SNickeauuse Antlr\Antlr4\Runtime\Comparison\Hashable; 11*37748cd8SNickeauuse Antlr\Antlr4\Runtime\Comparison\Hasher; 12*37748cd8SNickeau 13*37748cd8SNickeau/** 14*37748cd8SNickeau * A DFA state represents a set of possible ATN configurations. 15*37748cd8SNickeau * As Aho, Sethi, Ullman p. 117 says "The DFA uses its state 16*37748cd8SNickeau * to keep track of all possible states the ATN can be in after 17*37748cd8SNickeau * reading each input symbol. That is to say, after reading 18*37748cd8SNickeau * input a1a2..an, the DFA is in a state that represents the 19*37748cd8SNickeau * subset T of the states of the ATN that are reachable from the 20*37748cd8SNickeau * ATN's start state along some path labeled a1a2..an." 21*37748cd8SNickeau * In conventional NFA→DFA conversion, therefore, the subset T 22*37748cd8SNickeau * would be a bitset representing the set of states the 23*37748cd8SNickeau * ATN could be in. We need to track the alt predicted by each 24*37748cd8SNickeau * state as well, however. More importantly, we need to maintain 25*37748cd8SNickeau * a stack of states, tracking the closure operations as they 26*37748cd8SNickeau * jump from rule to rule, emulating rule invocations (method calls). 27*37748cd8SNickeau * I have to add a stack to simulate the proper lookahead sequences for 28*37748cd8SNickeau * the underlying LL grammar from which the ATN was derived. 29*37748cd8SNickeau * 30*37748cd8SNickeau * I use a set of ATNConfig objects not simple states. An ATNConfig 31*37748cd8SNickeau * is both a state (ala normal conversion) and a RuleContext describing 32*37748cd8SNickeau * the chain of rules (if any) followed to arrive at that state. 33*37748cd8SNickeau * 34*37748cd8SNickeau * A DFA state may have multiple references to a particular state, 35*37748cd8SNickeau * but with different ATN contexts (with same or different alts) 36*37748cd8SNickeau * meaning that state was reached via a different set of rule invocations. 37*37748cd8SNickeau */ 38*37748cd8SNickeaufinal class DFAState implements Hashable 39*37748cd8SNickeau{ 40*37748cd8SNickeau /** @var int */ 41*37748cd8SNickeau public $stateNumber; 42*37748cd8SNickeau 43*37748cd8SNickeau /** @var ATNConfigSet */ 44*37748cd8SNickeau public $configs; 45*37748cd8SNickeau 46*37748cd8SNickeau /** 47*37748cd8SNickeau * `edges[symbol]` points to target of symbol. Shift up by 1 so (-1) 48*37748cd8SNickeau * {@see Token::EOF} maps to `edges[0]`. 49*37748cd8SNickeau * 50*37748cd8SNickeau * @var \SplFixedArray<DFAState>|null 51*37748cd8SNickeau */ 52*37748cd8SNickeau public $edges; 53*37748cd8SNickeau 54*37748cd8SNickeau /** @var bool */ 55*37748cd8SNickeau public $isAcceptState = false; 56*37748cd8SNickeau 57*37748cd8SNickeau /** 58*37748cd8SNickeau * If accept state, what ttype do we match or alt do we predict? 59*37748cd8SNickeau * This is set to {@see ATN::INVALID_ALT_NUMBER)} when 60*37748cd8SNickeau * `{@see DFAState::$predicates} !== null` or {@see DFAState::$requiresFullContext}. 61*37748cd8SNickeau * 62*37748cd8SNickeau * @var int 63*37748cd8SNickeau */ 64*37748cd8SNickeau public $prediction = 0; 65*37748cd8SNickeau 66*37748cd8SNickeau /** @var LexerActionExecutor|null */ 67*37748cd8SNickeau public $lexerActionExecutor; 68*37748cd8SNickeau 69*37748cd8SNickeau /** 70*37748cd8SNickeau * Indicates that this state was created during SLL prediction that 71*37748cd8SNickeau * discovered a conflict between the configurations in the state. Future 72*37748cd8SNickeau * {@see ParserATNSimulator::execATN()} invocations immediately jumped doing 73*37748cd8SNickeau * full context prediction if this field is true. 74*37748cd8SNickeau * 75*37748cd8SNickeau * @var bool 76*37748cd8SNickeau */ 77*37748cd8SNickeau public $requiresFullContext = false; 78*37748cd8SNickeau 79*37748cd8SNickeau /** 80*37748cd8SNickeau * During SLL parsing, this is a list of predicates associated with the 81*37748cd8SNickeau * ATN configurations of the DFA state. When we have predicates, 82*37748cd8SNickeau * {@see DFAState::$requiresFullContext} is `false` since full context 83*37748cd8SNickeau * prediction evaluates predicates on-the-fly. If this is not null, then 84*37748cd8SNickeau * {@see DFAState::$prediction} is {@see ATN::INVALID_ALT_NUMBER}. 85*37748cd8SNickeau * 86*37748cd8SNickeau * We only use these for non-{@see DFAState::$requiresFullContext} bu 87*37748cd8SNickeau * conflicting states. That means we know from the context (it's $ or we 88*37748cd8SNickeau * don't dip into outer context) that it's an ambiguity not a conflict. 89*37748cd8SNickeau * 90*37748cd8SNickeau * This list is computed by {@see ParserATNSimulator::predicateDFAState()}. 91*37748cd8SNickeau * 92*37748cd8SNickeau * @var array<PredPrediction>|null 93*37748cd8SNickeau */ 94*37748cd8SNickeau public $predicates; 95*37748cd8SNickeau 96*37748cd8SNickeau public function __construct(?ATNConfigSet $configs = null, int $stateNumber = -1) 97*37748cd8SNickeau { 98*37748cd8SNickeau $this->configs = $configs ?? new ATNConfigSet(); 99*37748cd8SNickeau $this->stateNumber = $stateNumber; 100*37748cd8SNickeau } 101*37748cd8SNickeau 102*37748cd8SNickeau /** 103*37748cd8SNickeau * Two {@see DFAState} instances are equal if their ATN configuration sets 104*37748cd8SNickeau * are the same. This method is used to see if a state already exists. 105*37748cd8SNickeau * 106*37748cd8SNickeau * Because the number of alternatives and number of ATN configurations are 107*37748cd8SNickeau * finite, there is a finite number of DFA states that can be processed. 108*37748cd8SNickeau * This is necessary to show that the algorithm terminates. 109*37748cd8SNickeau * 110*37748cd8SNickeau * Cannot test the DFA state numbers here because in 111*37748cd8SNickeau * {@see ParserATNSimulator::addDFAState()} we need to know if any other state 112*37748cd8SNickeau * exists that has this exact set of ATN configurations. The 113*37748cd8SNickeau * {@see DFAState::$stateNumber} is irrelevant. 114*37748cd8SNickeau */ 115*37748cd8SNickeau public function equals(object $other) : bool 116*37748cd8SNickeau { 117*37748cd8SNickeau if ($this === $other) { 118*37748cd8SNickeau return true; 119*37748cd8SNickeau } 120*37748cd8SNickeau 121*37748cd8SNickeau if (!$other instanceof self) { 122*37748cd8SNickeau return false; 123*37748cd8SNickeau } 124*37748cd8SNickeau 125*37748cd8SNickeau // Compare set of ATN configurations in this set with other 126*37748cd8SNickeau return Equality::equals($this->configs, $other->configs); 127*37748cd8SNickeau } 128*37748cd8SNickeau 129*37748cd8SNickeau public function __toString() : string 130*37748cd8SNickeau { 131*37748cd8SNickeau $s = \sprintf('%d:%s', $this->stateNumber, (string) $this->configs); 132*37748cd8SNickeau 133*37748cd8SNickeau if ($this->isAcceptState) { 134*37748cd8SNickeau $s .= '=>'; 135*37748cd8SNickeau 136*37748cd8SNickeau if ($this->predicates !== null) { 137*37748cd8SNickeau $s .= \sprintf('[%s]', \implode(', ', $this->predicates)); 138*37748cd8SNickeau } else { 139*37748cd8SNickeau $s .= $this->prediction; 140*37748cd8SNickeau } 141*37748cd8SNickeau } 142*37748cd8SNickeau 143*37748cd8SNickeau return $s; 144*37748cd8SNickeau } 145*37748cd8SNickeau 146*37748cd8SNickeau public function hashCode() : int 147*37748cd8SNickeau { 148*37748cd8SNickeau return Hasher::hash($this->configs); 149*37748cd8SNickeau } 150*37748cd8SNickeau} 151