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.LexerATNSimulator; 8 9 import std.conv; 10 import std.format; 11 import std.stdio; 12 import antlr.v4.runtime.atn.ATNSimulator; 13 import antlr.v4.runtime.IntStreamConstant; 14 import antlr.v4.runtime.Lexer; 15 import antlr.v4.runtime.UnsupportedOperationException; 16 import antlr.v4.runtime.dfa.DFA; 17 import antlr.v4.runtime.dfa.DFAState; 18 import antlr.v4.runtime.atn.ATN; 19 import antlr.v4.runtime.atn.ATNState; 20 import antlr.v4.runtime.atn.ATNConfigSet; 21 import antlr.v4.runtime.atn.ATNConfig; 22 import antlr.v4.runtime.atn.LexerActionExecutor; 23 import antlr.v4.runtime.atn.LexerATNConfig; 24 import antlr.v4.runtime.atn.PredictionContext; 25 import antlr.v4.runtime.atn.RuleTransition; 26 import antlr.v4.runtime.atn.RuleStopState; 27 import antlr.v4.runtime.atn.PredictionContextCache; 28 import antlr.v4.runtime.atn.SimState; 29 import antlr.v4.runtime.atn.SingletonPredictionContext; 30 import antlr.v4.runtime.atn.PredicateTransition; 31 import antlr.v4.runtime.atn.Transition; 32 import antlr.v4.runtime.atn.TransitionStates; 33 import antlr.v4.runtime.atn.ActionTransition; 34 import antlr.v4.runtime.atn.OrderedATNConfigSet; 35 import antlr.v4.runtime.CharStream; 36 import antlr.v4.runtime.LexerNoViableAltException; 37 import antlr.v4.runtime.Token; 38 import antlr.v4.runtime.TokenConstantDefinition; 39 import antlr.v4.runtime.misc; 40 41 // Class LexerATNSimulator 42 /** 43 * "dup" of ParserInterpreter 44 */ 45 class LexerATNSimulator : ATNSimulator 46 { 47 48 public static immutable int MIN_DFA_EDGE = 0; 49 50 public static immutable int MAX_DFA_EDGE = 127; 51 52 protected Lexer recog; 53 54 /** 55 * @uml 56 * The current token's starting index into the character stream. 57 * Shared across DFA to ATN simulation in case the ATN fails and the 58 * DFA did not have a previous accept state. In this case, we use the 59 * ATN-generated exception object. 60 */ 61 protected int startIndex = -1; 62 63 /** 64 * @uml 65 * line number 1..n within the input 66 */ 67 protected int line = 1; 68 69 /** 70 * @uml 71 * The index of the character relative to the beginning of the line 0..n-1 72 */ 73 protected int charPositionInLine = 0; 74 75 public DFA[] decisionToDFA; 76 77 protected int mode = Lexer.DEFAULT_MODE; 78 79 protected SimState prevAccept; 80 81 public static int match_calls = 0; 82 83 public this(ATN atn, DFA[] decisionToDFA, PredictionContextCache sharedContextCache) 84 { 85 this(null, atn, decisionToDFA,sharedContextCache); 86 } 87 88 public this(Lexer recog, ATN atn, DFA[] decisionToDFA, PredictionContextCache sharedContextCache) 89 { 90 super(atn, sharedContextCache); 91 this.decisionToDFA = decisionToDFA; 92 this.recog = recog; 93 } 94 95 public void copyState(LexerATNSimulator simulator) 96 { 97 this.charPositionInLine = simulator.charPositionInLine; 98 this.line = simulator.line; 99 this.mode = simulator.mode; 100 this.startIndex = simulator.startIndex; 101 } 102 103 public int match(CharStream input, int mode) 104 { 105 match_calls++; 106 this.mode = mode; 107 int mark = input.mark; 108 try { 109 this.startIndex = input.index; 110 this.prevAccept.reset; 111 DFA dfa = decisionToDFA[mode]; 112 if (dfa.s0 is null) { 113 return matchATN(input); 114 } 115 else { 116 return execATN(input, dfa.s0); 117 } 118 } 119 finally { 120 input.release(mark); 121 } 122 } 123 124 /** 125 * @uml 126 * @override 127 */ 128 public override void reset() 129 { 130 prevAccept.reset(); 131 startIndex = -1; 132 line = 1; 133 charPositionInLine = 0; 134 mode = Lexer.DEFAULT_MODE; 135 } 136 137 /** 138 * @uml 139 * @override 140 */ 141 public override void clearDFA() 142 { 143 for (int d = 0; d < decisionToDFA.length; d++) { 144 decisionToDFA[d] = new DFA(atn.getDecisionState(d), d); 145 } 146 } 147 148 protected int matchATN(CharStream input) 149 { 150 ATNState startState = atn.modeToStartState[mode]; 151 int old_mode = mode; 152 ATNConfigSet s0_closure = computeStartState(input, startState); 153 bool suppressEdge = s0_closure.hasSemanticContext; 154 s0_closure.hasSemanticContext = false; 155 DFAState next = addDFAState(s0_closure); 156 if (!suppressEdge) { 157 decisionToDFA[mode].s0 = next; 158 } 159 int predict = execATN(input, next); 160 161 debug(LexerATNSimulator) 162 writefln("DFA after matchATN:\n%1$s\n", decisionToDFA[old_mode].toLexerString()); 163 return predict; 164 } 165 166 protected int execATN(CharStream input, DFAState ds0) 167 { 168 debug(LexerATNSimulator) { 169 writefln("enter exec index %s from %s", input.index, ds0.configs); 170 } 171 172 if (ds0.isAcceptState) { 173 // allow zero-length tokens 174 captureSimState(prevAccept, input, ds0); 175 } 176 int t = input.LA(1); 177 DFAState s = ds0; // s is current/from DFA state 178 179 while (true) { // while more work 180 debug(LexerATNSimulator) { 181 writefln("execATN loop starting closure: %s\n", s.configs); 182 } 183 // As we move src->trg, src->trg, we keep track of the previous trg to 184 // avoid looking up the DFA state again, which is expensive. 185 // If the previous target was already part of the DFA, we might 186 // be able to avoid doing a reach operation upon t. If s!=null, 187 // it means that semantic predicates didn't prevent us from 188 // creating a DFA state. Once we know s!=null, we check to see if 189 // the DFA state has an edge already for t. If so, we can just reuse 190 // it's configuration set; there's no point in re-computing it. 191 // This is kind of like doing DFA simulation within the ATN 192 // simulation because DFA simulation is really just a way to avoid 193 // computing reach/closure sets. Technically, once we know that 194 // we have a previously added DFA state, we could jump over to 195 // the DFA simulator. But, that would mean popping back and forth 196 // a lot and making things more complicated algorithmically. 197 // This optimization makes a lot of sense for loops within DFA. 198 // A character will take us back to an existing DFA state 199 // that already has lots of edges out of it. e.g., .* in comments. 200 DFAState target = getExistingTargetState(s, t); 201 if (target is null) { 202 target = computeTargetState(input, s, t); 203 } 204 if (target == ERROR) { 205 break; 206 } 207 // If this is a consumable input element, make sure to consume before 208 // capturing the accept state so the input index, line, and char 209 // position accurately reflect the state of the interpreter at the 210 // end of the token. 211 if (t != IntStreamConstant.EOF) { 212 consume(input); 213 } 214 215 if (target.isAcceptState) { 216 captureSimState(prevAccept, input, target); 217 if (t == IntStreamConstant.EOF) { 218 break; 219 } 220 } 221 t = input.LA(1); 222 s = target; // flip; current DFA target becomes new src/from state 223 } 224 return failOrAccept(prevAccept, input, s.configs, t); 225 } 226 227 /** 228 * @uml 229 * Get an existing target state for an edge in the DFA. If the target state 230 * for the edge has not yet been computed or is otherwise not available, 231 * this method returns {@code null}. 232 * 233 * @param s The current DFA state 234 * @param t The next input symbol 235 * @return The existing target DFA state for the given input symbol 236 * {@code t}, or {@code null} if the target state for this edge is not 237 * already cached 238 */ 239 public DFAState getExistingTargetState(DFAState s, int t) 240 { 241 if (s.edges is null || t < MIN_DFA_EDGE || t > MAX_DFA_EDGE) { 242 return null; 243 } 244 245 DFAState target = s.edges[t - MIN_DFA_EDGE]; 246 if (target !is null) 247 debug(LexerATNSimulator) { 248 writefln("reuse state %1$s"~ 249 " edge to %2$s", s.stateNumber, target.stateNumber); 250 } 251 252 return target; 253 } 254 255 /** 256 * @uml 257 * Compute a target state for an edge in the DFA, and attempt to add the 258 * computed state and corresponding edge to the DFA. 259 * 260 * @param input The input stream 261 * @param s The current DFA state 262 * @param t The next input symbol 263 * 264 * @return The computed target DFA state for the given input symbol 265 * {@code t}. If {@code t} does not lead to a valid DFA state, this method 266 * returns {@link #ERROR}. 267 */ 268 protected DFAState computeTargetState(CharStream input, DFAState s, int t) 269 { 270 ATNConfigSet reach = new OrderedATNConfigSet(); 271 272 // if we don't find an existing DFA state 273 // Fill reach starting from closure, following t transitions 274 getReachableConfigSet(input, s.configs, reach, t); 275 276 if (reach.isEmpty()) { // we got nowhere on t from s 277 if (!reach.hasSemanticContext) { 278 // we got nowhere on t, don't throw out this knowledge; it'd 279 // cause a failover from DFA later. 280 addDFAEdge(s, t, ERROR); 281 } 282 283 // stop when we can't match any more char 284 return ERROR; 285 } 286 287 // Add an edge from s to target DFA found/created for reach 288 return addDFAEdge(s, t, reach); 289 } 290 291 protected int failOrAccept(SimState prevAccept, CharStream input, ATNConfigSet reach, 292 int t) 293 { 294 if (prevAccept.dfaState !is null) { 295 LexerActionExecutor lexerActionExecutor = prevAccept.dfaState.lexerActionExecutor; 296 accept(input, lexerActionExecutor, startIndex, 297 prevAccept.index, prevAccept.line, prevAccept.charPos); 298 return prevAccept.dfaState.prediction; 299 } 300 else { 301 // if no accept and EOF is first char, return EOF 302 if (t==IntStreamConstant.EOF && input.index() == startIndex) { 303 return TokenConstantDefinition.EOF; 304 } 305 throw new LexerNoViableAltException(recog, input, startIndex, reach); 306 } 307 } 308 309 /** 310 * @uml 311 * Given a starting configuration set, figure out all ATN configurations 312 * we can reach upon input {@code t}. Parameter {@code reach} is a return 313 * parameter. 314 */ 315 protected void getReachableConfigSet(CharStream input, ATNConfigSet closureATNConfigSet, ATNConfigSet reach, 316 int t) 317 { 318 // this is used to skip processing for configs which have a lower priority 319 // than a config that already reached an accept state for the same rule 320 int skipAlt = ATN.INVALID_ALT_NUMBER; 321 foreach (ATNConfig c; closureATNConfigSet.configs) { 322 bool currentAltReachedAcceptState = c.alt == skipAlt; 323 if (currentAltReachedAcceptState && (cast(LexerATNConfig)c).hasPassedThroughNonGreedyDecision()) { 324 continue; 325 } 326 327 debug(LexerATNSimulator) { 328 writefln("testing %s at %s\n", getTokenName(t), c.toString(recog, true)); 329 } 330 331 int n = c.state.getNumberOfTransitions(); 332 for (int ti=0; ti<n; ti++) { // for each transition 333 Transition trans = c.state.transition(ti); 334 ATNState target = getReachableTarget(trans, t); 335 if (target !is null) { 336 LexerActionExecutor lexerActionExecutor = (cast(LexerATNConfig)c).getLexerActionExecutor(); 337 if (lexerActionExecutor !is null) { 338 lexerActionExecutor = lexerActionExecutor.fixOffsetBeforeMatch(input.index() - startIndex); 339 } 340 341 bool treatEofAsEpsilon = t == IntStreamConstant.EOF; 342 if (closure(input, new LexerATNConfig(cast(LexerATNConfig)c, target, lexerActionExecutor), 343 reach, currentAltReachedAcceptState, true, treatEofAsEpsilon)) { 344 // any remaining configs for this alt have a lower priority than 345 // the one that just reached an accept state. 346 skipAlt = c.alt; 347 break; 348 } 349 } 350 } 351 } 352 353 } 354 355 protected void accept(CharStream input, LexerActionExecutor lexerActionExecutor, int startIndex, 356 int index, int line, int charPos) 357 { 358 debug(LexerATNSimulator) { 359 writefln("ACTION %s\n", lexerActionExecutor); 360 } 361 362 // seek to after last char in token 363 input.seek(index); 364 this.line = line; 365 this.charPositionInLine = charPos; 366 367 if (lexerActionExecutor !is null && recog !is null) { 368 lexerActionExecutor.execute(recog, input, startIndex); 369 } 370 } 371 372 protected ATNState getReachableTarget(Transition trans, int t) 373 { 374 if (trans.matches(t, 0, 0xfffe)) { 375 return trans.target; 376 } 377 378 return null; 379 } 380 381 protected ATNConfigSet computeStartState(CharStream input, ATNState p) 382 { 383 PredictionContext initialContext = cast(PredictionContext)PredictionContext.EMPTY; 384 ATNConfigSet configs = new OrderedATNConfigSet(); 385 for (int i=0; i<p.getNumberOfTransitions(); i++) { 386 ATNState target = p.transition(i).target; 387 LexerATNConfig c = new LexerATNConfig(target, i+1, initialContext); 388 closure(input, c, configs, false, false, false); 389 } 390 return configs; 391 } 392 393 /** 394 * @uml 395 * Since the alternatives within any lexer decision are ordered by 396 * preference, this method stops pursuing the closure as soon as an accept 397 * state is reached. After the first accept state is reached by depth-first 398 * search from {@code config}, all other (potentially reachable) states for 399 * this rule would have a lower priority. 400 * 401 * @return {@code true} if an accept state is reached, otherwise 402 * {@code false}. 403 */ 404 protected bool closure(CharStream input, LexerATNConfig config, ATNConfigSet configs, 405 bool currentAltReachedAcceptState, bool speculative, bool treatEofAsEpsilon) 406 { 407 if (cast(RuleStopState)config.state) { 408 debug(LexerATNSimulator) { 409 if (recog !is null) { 410 writefln("closure at %1$s rule stop %2$s\n", recog.getRuleNames()[config.state.ruleIndex], config); 411 } 412 else { 413 writefln("closure at rule stop %s\n", config); 414 } 415 } 416 417 if (config.context is null || config.context.hasEmptyPath()) { 418 if (config.context is null || config.context.isEmpty()) { 419 configs.add(config); 420 return true; 421 } 422 else { 423 configs.add(new LexerATNConfig(config, 424 config.state, 425 cast(PredictionContext)PredictionContext.EMPTY)); 426 currentAltReachedAcceptState = true; 427 } 428 } 429 if (config.context !is null && !config.context.isEmpty() ) { 430 for (auto i = 0; i < config.context.size; i++) { 431 if (config.context.getReturnState(i) != PredictionContext.EMPTY_RETURN_STATE) { 432 PredictionContext newContext = config.context.getParent(i); // "pop" return state 433 ATNState returnState = atn.states[config.context.getReturnState(i)]; 434 LexerATNConfig c = new LexerATNConfig(config, returnState, newContext); 435 currentAltReachedAcceptState = closure(input, c, configs, currentAltReachedAcceptState, 436 speculative, treatEofAsEpsilon); 437 } 438 } 439 } 440 441 return currentAltReachedAcceptState; 442 } 443 444 // optimization 445 if (!config.state.onlyHasEpsilonTransitions) { 446 if (!currentAltReachedAcceptState || !config.hasPassedThroughNonGreedyDecision()) { 447 configs.add(config); 448 } 449 } 450 451 ATNState p = config.state; 452 for (int i=0; i<p.getNumberOfTransitions(); i++) { 453 Transition t = p.transition(i); 454 LexerATNConfig c = getEpsilonTarget(input, config, t, configs, speculative, treatEofAsEpsilon); 455 if (c !is null) { 456 currentAltReachedAcceptState = closure(input, c, configs, currentAltReachedAcceptState, 457 speculative, treatEofAsEpsilon); 458 } 459 } 460 return currentAltReachedAcceptState; 461 } 462 463 /** 464 * side-effect: can alter configs.hasSemanticContext 465 */ 466 protected LexerATNConfig getEpsilonTarget(CharStream input, LexerATNConfig config, Transition t, 467 ref ATNConfigSet configs, bool speculative, bool treatEofAsEpsilon) 468 { 469 debug(LexerATNSimulator) { 470 import std.stdio; 471 writefln("LexerATNSimulator getEpsilonTarget t = %s, serType = %s", t, t.getSerializationType); 472 } 473 LexerATNConfig c = null; 474 switch (t.getSerializationType) { 475 case TransitionStates.RULE: 476 RuleTransition ruleTransition = cast(RuleTransition)t; 477 PredictionContext newContext = 478 SingletonPredictionContext.create(config.context, ruleTransition.followState.stateNumber); 479 c = new LexerATNConfig(config, t.target, newContext); 480 break; 481 case TransitionStates.PRECEDENCE: 482 throw new UnsupportedOperationException("Precedence predicates are not supported in lexers."); 483 case TransitionStates.PREDICATE: 484 /* Track traversing semantic predicates. If we traverse, 485 we cannot add a DFA state for this "reach" computation 486 because the DFA would not test the predicate again in the 487 future. Rather than creating collections of semantic predicates 488 like v3 and testing them on prediction, v4 will test them on the 489 fly all the time using the ATN not the DFA. This is slower but 490 semantically it's not used that often. One of the key elements to 491 this predicate mechanism is not adding DFA states that see 492 predicates immediately afterwards in the ATN. For example, 493 494 a : ID {p1}? | ID {p2}? ; 495 496 should create the start state for rule 'a' (to save start state 497 competition), but should not create target of ID state. The 498 collection of ATN states the following ID references includes 499 states reached by traversing predicates. Since this is when we 500 test them, we cannot cash the DFA state target of ID. 501 */ 502 PredicateTransition pt = cast(PredicateTransition)t; 503 debug(LexerATNSimulator) { 504 writefln("EVAL rule %1$s:%2$s", pt.ruleIndex, pt.predIndex); 505 } 506 configs.hasSemanticContext = true; 507 if (evaluatePredicate(input, pt.ruleIndex, pt.predIndex, speculative)) { 508 c = new LexerATNConfig(config, t.target); 509 } 510 break; 511 512 case TransitionStates.ACTION: 513 if (config.context is null || config.context.hasEmptyPath()) { 514 // execute actions anywhere in the start rule for a token. 515 // 516 // TODO: if the entry rule is invoked recursively, some 517 // actions may be executed during the recursive call. The 518 // problem can appear when hasEmptyPath() is true but 519 // isEmpty() is false. In this case, the config needs to be 520 // split into two contexts - one with just the empty path 521 // and another with everything but the empty path. 522 // Unfortunately, the current algorithm does not allow 523 // getEpsilonTarget to return two configurations, so 524 // additional modifications are needed before we can support 525 // the split operation. 526 LexerActionExecutor lexerActionExecutor = LexerActionExecutor.append(config.getLexerActionExecutor(), atn.lexerActions[(cast(ActionTransition)t).actionIndex]); 527 c = new LexerATNConfig(config, t.target, lexerActionExecutor); 528 break; 529 } 530 else { 531 // ignore actions in referenced rules 532 c = new LexerATNConfig(config, t.target); 533 break; 534 } 535 536 case TransitionStates.EPSILON: 537 c = new LexerATNConfig(config, t.target); 538 break; 539 540 case TransitionStates.ATOM: 541 case TransitionStates.RANGE: 542 case TransitionStates.SET: 543 if (treatEofAsEpsilon) { 544 if (t.matches(IntStreamConstant.EOF, 0, 0xfffe)) { 545 c = new LexerATNConfig(config, t.target); 546 break; 547 } 548 } 549 550 break; 551 default: {} 552 } 553 554 return c; 555 } 556 557 /** 558 * @uml 559 * Evaluate a predicate specified in the lexer. 560 * 561 * <p>If {@code speculative} is {@code true}, this method was called before 562 * {@link #consume} for the matched character. This method should call 563 * {@link #consume} before evaluating the predicate to ensure position 564 * sensitive values, including {@link Lexer#getText}, {@link Lexer#getLine}, 565 * and {@link Lexer#getCharPositionInLine}, properly reflect the current 566 * lexer state. This method should restore {@code input} and the simulator 567 * to the original state before returning (i.e. undo the actions made by the 568 * call to {@link #consume}.</p> 569 * 570 * @param input The input stream. 571 * @param ruleIndex The rule containing the predicate. 572 * @param predIndex The index of the predicate within the rule. 573 * @param speculative {@code true} if the current index in {@code input} is 574 * one character before the predicate's location. 575 * 576 * @return {@code true} if the specified predicate evaluates to 577 * {@code true}. 578 */ 579 protected bool evaluatePredicate(CharStream input, int ruleIndex, int predIndex, bool speculative) 580 { 581 // assume true if no recognizer was provided 582 if (recog is null) { 583 return true; 584 } 585 586 if (!speculative) { 587 return recog.sempred(null, ruleIndex, predIndex); 588 } 589 590 int savedCharPositionInLine = charPositionInLine; 591 int savedLine = line; 592 int index = input.index(); 593 int marker = input.mark(); 594 try { 595 consume(input); 596 return recog.sempred(null, ruleIndex, predIndex); 597 } 598 finally { 599 charPositionInLine = savedCharPositionInLine; 600 line = savedLine; 601 input.seek(index); 602 input.release(marker); 603 } 604 } 605 606 public void captureSimState(ref SimState settings, CharStream input, DFAState dfaState) 607 { 608 settings.index = input.index; 609 settings.line = line; 610 settings.charPos = charPositionInLine; 611 settings.dfaState = dfaState; 612 } 613 614 protected DFAState addDFAEdge(DFAState from, int t, ATNConfigSet q) 615 { 616 /* leading to this call, ATNConfigSet.hasSemanticContext is used as a 617 * marker indicating dynamic predicate evaluation makes this edge 618 * dependent on the specific input sequence, so the static edge in the 619 * DFA should be omitted. The target DFAState is still created since 620 * execATN has the ability to resynchronize with the DFA state cache 621 * following the predicate evaluation step. 622 * 623 * TJP notes: next time through the DFA, we see a pred again and eval. 624 * If that gets us to a previously created (but dangling) DFA 625 * state, we can continue in pure DFA mode from there. 626 */ 627 bool suppressEdge = q.hasSemanticContext; 628 q.hasSemanticContext = false; 629 630 DFAState to = addDFAState(q); 631 632 if (suppressEdge) { 633 return to; 634 } 635 636 addDFAEdge(from, t, to); 637 return to; 638 } 639 640 protected void addDFAEdge(DFAState p, int t, DFAState q) 641 { 642 if (t < MIN_DFA_EDGE || t > MAX_DFA_EDGE) { 643 // Only track edges within the DFA bounds 644 return; 645 } 646 647 debug(LexerATNSimulator) { 648 writefln("EDGE %1$s -> %2$s upon %3$s", p, q, t); 649 } 650 651 synchronized (p) { 652 if (p.edges is null) { 653 // make room for tokens 1..n and -1 masquerading as index 0 654 p.edges = new DFAState[MAX_DFA_EDGE-MIN_DFA_EDGE+1]; 655 } 656 p.edges[t - MIN_DFA_EDGE] = q; // connect 657 } 658 } 659 660 /** 661 * Add a new DFA state if there isn't one with this set of 662 * configurations already. This method also detects the first 663 * configuration containing an ATN rule stop state. Later, when 664 * traversing the DFA, we will know which rule to accept. 665 */ 666 protected DFAState addDFAState(ATNConfigSet configs) 667 { 668 /* the lexer evaluates predicates on-the-fly; by this point configs 669 * should not contain any configurations with unevaluated predicates. 670 */ 671 assert(!configs.hasSemanticContext); 672 DFAState proposed = new DFAState(configs); 673 ATNConfig firstConfigWithRuleStopState; 674 foreach (ATNConfig c; configs.configs) { 675 if (cast(RuleStopState)c.state) { 676 firstConfigWithRuleStopState = c; 677 break; 678 } 679 } 680 if (firstConfigWithRuleStopState) { 681 proposed.isAcceptState = true; 682 proposed.lexerActionExecutor = (cast(LexerATNConfig)firstConfigWithRuleStopState).getLexerActionExecutor(); 683 proposed.prediction = atn.ruleToTokenType[firstConfigWithRuleStopState.state.ruleIndex]; 684 } 685 DFA dfa = decisionToDFA[mode]; 686 //DFAState existing = dfa.states[proposed]; 687 if (proposed in dfa.states) 688 return dfa.states[proposed]; 689 DFAState newState = proposed; 690 newState.stateNumber = to!int(dfa.states.length); 691 configs.readonly(true); 692 newState.configs = configs; 693 dfa.states[newState] = newState; 694 return newState; 695 } 696 697 public DFA getDFA(int mode) 698 { 699 return decisionToDFA[mode]; 700 } 701 702 public string getText(CharStream input) 703 { 704 // index is first lookahead char, don't include. 705 return input.getText(Interval.of(startIndex, input.index()-1)); 706 } 707 708 public int getLine() 709 { 710 return line; 711 } 712 713 public void setLine(int line) 714 { 715 this.line = line; 716 } 717 718 public int getCharPositionInLine() 719 { 720 return charPositionInLine; 721 } 722 723 public void setCharPositionInLine(int charPositionInLine) 724 { 725 this.charPositionInLine = charPositionInLine; 726 } 727 728 public void consume(CharStream input) 729 { 730 int curChar = input.LA(1); 731 if (curChar == '\n') { 732 line++; 733 charPositionInLine=0; 734 } else { 735 charPositionInLine++; 736 } 737 input.consume(); 738 } 739 740 public string getTokenName(int t) 741 { 742 if (t == -1) return "EOF"; 743 //if ( atn.g!=null ) return atn.g.getTokenDisplayName(t); 744 return format("'%s'", t); 745 } 746 747 }