24
24
use Antlr \Antlr4 \Runtime \Error \Exceptions \RecognitionException ;
25
25
use Antlr \Antlr4 \Runtime \IntervalSet ;
26
26
use Antlr \Antlr4 \Runtime \IntStream ;
27
+ use Antlr \Antlr4 \Runtime \LoggerProvider ;
27
28
use Antlr \Antlr4 \Runtime \Parser ;
28
29
use Antlr \Antlr4 \Runtime \ParserRuleContext ;
29
30
use Antlr \Antlr4 \Runtime \PredictionContexts \PredictionContext ;
35
36
use Antlr \Antlr4 \Runtime \Utils \BitSet ;
36
37
use Antlr \Antlr4 \Runtime \Utils \DoubleKeyMap ;
37
38
use Antlr \Antlr4 \Runtime \Utils \Set ;
39
+ use Psr \Log \LoggerInterface as Logger ;
38
40
39
41
/**
40
42
* The embodiment of the adaptive LL(*), ALL(*), parsing strategy.
231
233
*/
232
234
final class ParserATNSimulator extends ATNSimulator
233
235
{
236
+ public static bool $ traceAtnSimulation = false ;
237
+
234
238
protected Parser $ parser ;
235
239
236
240
/** @var array<DFA> */
@@ -260,6 +264,8 @@ final class ParserATNSimulator extends ATNSimulator
260
264
261
265
protected ?DFA $ dfa = null ;
262
266
267
+ private Logger $ logger ;
268
+
263
269
/**
264
270
* @param array<DFA> $decisionToDFA
265
271
*/
@@ -273,6 +279,7 @@ public function __construct(
273
279
274
280
$ this ->parser = $ parser ;
275
281
$ this ->decisionToDFA = $ decisionToDFA ;
282
+ $ this ->logger = LoggerProvider::getLogger ();
276
283
}
277
284
278
285
public function reset (): void
@@ -296,6 +303,18 @@ public function clearDFA(): void
296
303
*/
297
304
public function adaptivePredict (TokenStream $ input , int $ decision , ParserRuleContext $ outerContext ): int
298
305
{
306
+ if (self ::$ traceAtnSimulation ) {
307
+ $ this ->logger ->debug (
308
+ 'adaptivePredict decision {decision} exec LA(1)=={token} line {line}:{pos} ' ,
309
+ [
310
+ 'decision ' => $ decision ,
311
+ 'token ' => $ this ->getTokenName ($ input ->LA (1 )),
312
+ 'line ' => $ input ->LT (1 )?->getLine(),
313
+ 'pos ' => $ input ->LT (1 )?->getCharPositionInLine(),
314
+ ],
315
+ );
316
+ }
317
+
299
318
$ this ->input = $ input ;
300
319
$ this ->startIndex = $ input ->getIndex ();
301
320
$ this ->outerContext = $ outerContext ;
@@ -404,6 +423,19 @@ public function execATN(
404
423
int $ startIndex ,
405
424
ParserRuleContext $ outerContext ,
406
425
): ?int {
426
+ if (self ::$ traceAtnSimulation ) {
427
+ $ this ->logger ->debug (
428
+ 'execATN decision {decision}, DFA state {state}, LA(1)=={token} line {line}:{pos} ' ,
429
+ [
430
+ 'decision ' => $ dfa ->decision ,
431
+ 'state ' => $ s0 ->__toString (),
432
+ 'token ' => $ this ->getTokenName ($ input ->LA (1 )),
433
+ 'line ' => $ input ->LT (1 )?->getLine(),
434
+ 'pos ' => $ input ->LT (1 )?->getCharPositionInLine(),
435
+ ],
436
+ );
437
+ }
438
+
407
439
$ previousD = $ s0 ;
408
440
409
441
$ t = $ input ->LA (1 );
@@ -655,6 +687,12 @@ protected function execATNWithFullContext(
655
687
int $ startIndex ,
656
688
ParserRuleContext $ outerContext ,
657
689
): int {
690
+ if (self ::$ traceAtnSimulation ) {
691
+ $ this ->logger ->debug ('execATNWithFullContext {state} ' , [
692
+ 'state ' => $ s0 ->__toString (),
693
+ ]);
694
+ }
695
+
658
696
$ fullCtx = true ;
659
697
$ foundExactAmbig = false ;
660
698
$ reach = null ;
@@ -890,15 +928,18 @@ protected function computeReachSet(ATNConfigSet $closure, int $t, bool $fullCtx)
890
928
* multiple alternatives are viable.*/
891
929
892
930
if ($ skippedStopStates !== null && (!$ fullCtx || !PredictionMode::hasConfigInRuleStopState ($ reach ))) {
893
- if (\count ($ skippedStopStates ) === 0 ) {
894
- throw new \LogicException ('Skipped stop states cannot be empty. ' );
895
- }
896
-
897
931
foreach ($ skippedStopStates as $ lValue ) {
898
932
$ reach ->add ($ lValue , $ this ->mergeCache );
899
933
}
900
934
}
901
935
936
+ if (self ::$ traceAtnSimulation ) {
937
+ $ this ->logger ->debug ('computeReachSet {closure} -> {reach} ' , [
938
+ 'closure ' => $ closure ->__toString (),
939
+ 'reach ' => $ reach ->__toString (),
940
+ ]);
941
+ }
942
+
902
943
if ($ reach ->isEmpty ()) {
903
944
return null ;
904
945
}
@@ -964,6 +1005,13 @@ protected function computeStartState(ATNState $p, RuleContext $ctx, bool $fullCt
964
1005
$ initialContext = PredictionContext::fromRuleContext ($ this ->atn , $ ctx );
965
1006
$ configs = new ATNConfigSet ($ fullCtx );
966
1007
1008
+ if (self ::$ traceAtnSimulation ) {
1009
+ $ this ->logger ->debug ('computeStartState from ATN state {state} initialContext={initialContext} ' , [
1010
+ 'state ' => $ p ->__toString (),
1011
+ 'initialContext ' => $ initialContext ->__toString (),
1012
+ ]);
1013
+ }
1014
+
967
1015
foreach ($ p ->getTransitions () as $ i => $ t ) {
968
1016
$ c = new ATNConfig (null , $ t ->target , $ initialContext , null , $ i + 1 );
969
1017
$ closureBusy = new Set ();
@@ -1464,6 +1512,12 @@ protected function closureCheckingStopState(
1464
1512
int $ depth ,
1465
1513
bool $ treatEofAsEpsilon ,
1466
1514
): void {
1515
+ if (self ::$ traceAtnSimulation ) {
1516
+ $ this ->logger ->debug ('closure({config}) ' , [
1517
+ 'config ' => $ config ->toString (true ),
1518
+ ]);
1519
+ }
1520
+
1467
1521
if ($ config ->state instanceof RuleStopState) {
1468
1522
// We hit rule end. If we have context info, use it run thru all possible stack tops in ctx
1469
1523
$ context = $ config ->context ;
@@ -2150,6 +2204,12 @@ protected function addDFAState(DFA $dfa, DFAState $D): DFAState
2150
2204
$ existing = $ dfa ->states ->get ($ D );
2151
2205
2152
2206
if ($ existing instanceof DFAState) {
2207
+ if (self ::$ traceAtnSimulation ) {
2208
+ $ this ->logger ->debug ('addDFAState {state} exists ' , [
2209
+ 'state ' => $ D ->__toString (),
2210
+ ]);
2211
+ }
2212
+
2153
2213
return $ existing ;
2154
2214
}
2155
2215
@@ -2160,6 +2220,12 @@ protected function addDFAState(DFA $dfa, DFAState $D): DFAState
2160
2220
$ D ->configs ->setReadonly (true );
2161
2221
}
2162
2222
2223
+ if (self ::$ traceAtnSimulation ) {
2224
+ $ this ->logger ->debug ('addDFAState new {state} ' , [
2225
+ 'state ' => $ D ->__toString (),
2226
+ ]);
2227
+ }
2228
+
2163
2229
$ dfa ->states ->add ($ D );
2164
2230
2165
2231
return $ D ;
0 commit comments