1 /* 2 * Copyright (c) 2012-2019 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 /** 42 * "dup" of ParserInterpreter 43 */ 44 class LexerATNSimulator : ATNSimulator 45 { 46 47 public static immutable int MIN_DFA_EDGE = 0; 48 49 public static immutable int MAX_DFA_EDGE = 127; 50 51 protected Lexer recog; 52 53 /** 54 * @uml 55 * The current token's starting index into the character stream. 56 * Shared across DFA to ATN simulation in case the ATN fails and the 57 * DFA did not have a previous accept state. In this case, we use the 58 * ATN-generated exception object. 59 */ 60 protected int startIndex = -1; 61 62 /** 63 * @uml 64 * line number 1..n within the input 65 */ 66 protected int line = 1; 67 68 /** 69 * @uml 70 * The index of the character relative to the beginning of the line 0..n-1 71 */ 72 protected int charPositionInLine = 0; 73 74 public DFA[] decisionToDFA; 75 76 protected int mode = Lexer.DEFAULT_MODE; 77 78 protected SimState prevAccept; 79 80 public static int match_calls = 0; 81 82 public this(ATN atn, DFA[] decisionToDFA, PredictionContextCache sharedContextCache) 83 { 84 this(null, atn, decisionToDFA,sharedContextCache); 85 } 86 87 public this(Lexer recog, ATN atn, DFA[] decisionToDFA, PredictionContextCache sharedContextCache) 88 { 89 super(atn, sharedContextCache); 90 this.decisionToDFA = decisionToDFA; 91 this.recog = recog; 92 } 93 94 public void copyState(LexerATNSimulator simulator) 95 { 96 this.charPositionInLine = simulator.charPositionInLine; 97 this.line = simulator.line; 98 this.mode = simulator.mode; 99 this.startIndex = simulator.startIndex; 100 } 101 102 public int match(CharStream input, int mode) 103 { 104 match_calls++; 105 this.mode = mode; 106 int mark = input.mark; 107 try { 108 this.startIndex = input.index; 109 this.prevAccept.reset; 110 DFA dfa = decisionToDFA[mode]; 111 if (dfa.s0 is null) { 112 return matchATN(input); 113 } 114 else { 115 return execATN(input, dfa.s0); 116 } 117 } 118 finally { 119 input.release(mark); 120 } 121 } 122 123 /** 124 * @uml 125 * @override 126 */ 127 public override void reset() 128 { 129 prevAccept.reset(); 130 startIndex = -1; 131 line = 1; 132 charPositionInLine = 0; 133 mode = Lexer.DEFAULT_MODE; 134 } 135 136 /** 137 * @uml 138 * @override 139 */ 140 public override void clearDFA() 141 { 142 for (int d = 0; d < decisionToDFA.length; d++) { 143 decisionToDFA[d] = new DFA(atn.getDecisionState(d), d); 144 } 145 } 146 147 protected int matchATN(CharStream input) 148 { 149 ATNState startState = atn.modeToStartState[mode]; 150 int old_mode = mode; 151 ATNConfigSet s0_closure = computeStartState(input, startState); 152 bool suppressEdge = s0_closure.hasSemanticContext; 153 s0_closure.hasSemanticContext = false; 154 DFAState next = addDFAState(s0_closure); 155 if (!suppressEdge) { 156 decisionToDFA[mode].s0 = next; 157 } 158 int predict = execATN(input, next); 159 160 debug(LexerATNSimulator) 161 writefln("DFA after matchATN:\n%1$s\n", decisionToDFA[old_mode].toLexerString()); 162 return predict; 163 } 164 165 protected int execATN(CharStream input, DFAState ds0) 166 { 167 debug(LexerATNSimulator) { 168 writefln("enter exec index %s from %s", input.index, ds0.configs); 169 } 170 171 if (ds0.isAcceptState) { 172 // allow zero-length tokens 173 captureSimState(prevAccept, input, ds0); 174 } 175 int t = input.LA(1); 176 DFAState s = ds0; // s is current/from DFA state 177 178 while (true) { // while more work 179 debug(LexerATNSimulator) { 180 writefln("execATN loop starting closure: %s\n", s.configs); 181 } 182 // As we move src->trg, src->trg, we keep track of the previous trg to 183 // avoid looking up the DFA state again, which is expensive. 184 // If the previous target was already part of the DFA, we might 185 // be able to avoid doing a reach operation upon t. If s!=null, 186 // it means that semantic predicates didn't prevent us from 187 // creating a DFA state. Once we know s!=null, we check to see if 188 // the DFA state has an edge already for t. If so, we can just reuse 189 // it's configuration set; there's no point in re-computing it. 190 // This is kind of like doing DFA simulation within the ATN 191 // simulation because DFA simulation is really just a way to avoid 192 // computing reach/closure sets. Technically, once we know that 193 // we have a previously added DFA state, we could jump over to 194 // the DFA simulator. But, that would mean popping back and forth 195 // a lot and making things more complicated algorithmically. 196 // This optimization makes a lot of sense for loops within DFA. 197 // A character will take us back to an existing DFA state 198 // that already has lots of edges out of it. e.g., .* in comments. 199 DFAState target = getExistingTargetState(s, t); 200 if (target is null) { 201 target = computeTargetState(input, s, t); 202 } 203 if (target == ERROR) { 204 break; 205 } 206 // If this is a consumable input element, make sure to consume before 207 // capturing the accept state so the input index, line, and char 208 // position accurately reflect the state of the interpreter at the 209 // end of the token. 210 if (t != IntStreamConstant.EOF) { 211 consume(input); 212 } 213 214 if (target.isAcceptState) { 215 captureSimState(prevAccept, input, target); 216 if (t == IntStreamConstant.EOF) { 217 break; 218 } 219 } 220 t = input.LA(1); 221 s = target; // flip; current DFA target becomes new src/from state 222 } 223 return failOrAccept(prevAccept, input, s.configs, t); 224 } 225 226 /** 227 * @uml 228 * Get an existing target state for an edge in the DFA. If the target state 229 * for the edge has not yet been computed or is otherwise not available, 230 * this method returns {@code null}. 231 * 232 * @param s The current DFA state 233 * @param t The next input symbol 234 * @return The existing target DFA state for the given input symbol 235 * {@code t}, or {@code null} if the target state for this edge is not 236 * already cached 237 */ 238 public DFAState getExistingTargetState(DFAState s, int t) 239 { 240 if (s.edges is null || t < MIN_DFA_EDGE || t > MAX_DFA_EDGE) { 241 return null; 242 } 243 244 DFAState target = s.edges[t - MIN_DFA_EDGE]; 245 if (target !is null) 246 debug(LexerATNSimulator) { 247 writefln("reuse state %1$s"~ 248 " edge to %2$s", s.stateNumber, target.stateNumber); 249 } 250 251 return target; 252 } 253 254 /** 255 * @uml 256 * Compute a target state for an edge in the DFA, and attempt to add the 257 * computed state and corresponding edge to the DFA. 258 * 259 * @param input The input stream 260 * @param s The current DFA state 261 * @param t The next input symbol 262 * 263 * @return The computed target DFA state for the given input symbol 264 * {@code t}. If {@code t} does not lead to a valid DFA state, this method 265 * returns {@link #ERROR}. 266 */ 267 protected DFAState computeTargetState(CharStream input, DFAState s, int t) 268 { 269 ATNConfigSet reach = new OrderedATNConfigSet(); 270 271 // if we don't find an existing DFA state 272 // Fill reach starting from closure, following t transitions 273 getReachableConfigSet(input, s.configs, reach, t); 274 275 if (reach.isEmpty()) { // we got nowhere on t from s 276 if (!reach.hasSemanticContext) { 277 // we got nowhere on t, don't throw out this knowledge; it'd 278 // cause a failover from DFA later. 279 addDFAEdge(s, t, ERROR); 280 } 281 282 // stop when we can't match any more char 283 return ERROR; 284 } 285 286 // Add an edge from s to target DFA found/created for reach 287 return addDFAEdge(s, t, reach); 288 } 289 290 protected int failOrAccept(SimState prevAccept, CharStream input, ATNConfigSet reach, 291 int t) 292 { 293 if (prevAccept.dfaState !is null) { 294 LexerActionExecutor lexerActionExecutor = prevAccept.dfaState.lexerActionExecutor; 295 accept(input, lexerActionExecutor, startIndex, 296 prevAccept.index, prevAccept.line, prevAccept.charPos); 297 return prevAccept.dfaState.prediction; 298 } 299 else { 300 // if no accept and EOF is first char, return EOF 301 if (t==IntStreamConstant.EOF && input.index() == startIndex) { 302 return TokenConstantDefinition.EOF; 303 } 304 throw new LexerNoViableAltException(recog, input, startIndex, reach); 305 } 306 } 307 308 /** 309 * @uml 310 * Given a starting configuration set, figure out all ATN configurations 311 * we can reach upon input {@code t}. Parameter {@code reach} is a return 312 * parameter. 313 */ 314 protected void getReachableConfigSet(CharStream input, ATNConfigSet closureATNConfigSet, ATNConfigSet reach, 315 int t) 316 { 317 // this is used to skip processing for configs which have a lower priority 318 // than a config that already reached an accept state for the same rule 319 int skipAlt = ATN.INVALID_ALT_NUMBER; 320 foreach (ATNConfig c; closureATNConfigSet.configs) { 321 bool currentAltReachedAcceptState = c.alt == skipAlt; 322 if (currentAltReachedAcceptState && (cast(LexerATNConfig)c).hasPassedThroughNonGreedyDecision()) { 323 continue; 324 } 325 326 debug(LexerATNSimulator) { 327 writefln("testing %s at %s\n", getTokenName(t), c.toString(recog, true)); 328 } 329 330 int n = c.state.getNumberOfTransitions(); 331 for (int ti=0; ti<n; ti++) { // for each transition 332 Transition trans = c.state.transition(ti); 333 ATNState target = getReachableTarget(trans, t); 334 if (target !is null) { 335 LexerActionExecutor lexerActionExecutor = (cast(LexerATNConfig)c).getLexerActionExecutor(); 336 if (lexerActionExecutor !is null) { 337 lexerActionExecutor = lexerActionExecutor.fixOffsetBeforeMatch(input.index() - startIndex); 338 } 339 340 bool treatEofAsEpsilon = t == IntStreamConstant.EOF; 341 if (closure(input, new LexerATNConfig(cast(LexerATNConfig)c, target, lexerActionExecutor), 342 reach, currentAltReachedAcceptState, true, treatEofAsEpsilon)) { 343 // any remaining configs for this alt have a lower priority than 344 // the one that just reached an accept state. 345 skipAlt = c.alt; 346 break; 347 } 348 } 349 } 350 } 351 352 } 353 354 protected void accept(CharStream input, LexerActionExecutor lexerActionExecutor, int startIndex, 355 int index, int line, int charPos) 356 { 357 debug(LexerATNSimulator) { 358 writefln("ACTION %s\n", lexerActionExecutor); 359 } 360 361 // seek to after last char in token 362 input.seek(index); 363 this.line = line; 364 this.charPositionInLine = charPos; 365 366 if (lexerActionExecutor !is null && recog !is null) { 367 lexerActionExecutor.execute(recog, input, startIndex); 368 } 369 } 370 371 protected ATNState getReachableTarget(Transition trans, int t) 372 { 373 if (trans.matches(t, 0, 0xfffe)) { 374 return trans.target; 375 } 376 377 return null; 378 } 379 380 protected ATNConfigSet computeStartState(CharStream input, ATNState p) 381 { 382 PredictionContext initialContext = cast(PredictionContext)PredictionContext.EMPTY; 383 ATNConfigSet configs = new OrderedATNConfigSet(); 384 for (int i=0; i<p.getNumberOfTransitions(); i++) { 385 ATNState target = p.transition(i).target; 386 LexerATNConfig c = new LexerATNConfig(target, i+1, initialContext); 387 closure(input, c, configs, false, false, false); 388 } 389 return configs; 390 } 391 392 /** 393 * @uml 394 * Since the alternatives within any lexer decision are ordered by 395 * preference, this method stops pursuing the closure as soon as an accept 396 * state is reached. After the first accept state is reached by depth-first 397 * search from {@code config}, all other (potentially reachable) states for 398 * this rule would have a lower priority. 399 * 400 * @return {@code true} if an accept state is reached, otherwise 401 * {@code false}. 402 */ 403 protected bool closure(CharStream input, LexerATNConfig config, ATNConfigSet configs, 404 bool currentAltReachedAcceptState, bool speculative, bool treatEofAsEpsilon) 405 { 406 debug(LexerATNSimulator) 407 writefln("closure(\"%s\")", config); 408 if (cast(RuleStopState)config.state) { 409 debug(LexerATNSimulator) { 410 if (recog !is null) { 411 writefln("closure at %1$s rule stop %2$s\n", recog.getRuleNames()[config.state.ruleIndex], config); 412 } 413 else { 414 writefln("closure at rule stop %s\n", config); 415 } 416 } 417 418 if (config.context is null || config.context.hasEmptyPath()) { 419 if (config.context is null || config.context.isEmpty()) { 420 configs.add(config); 421 return true; 422 } 423 else { 424 configs.add(new LexerATNConfig(config, 425 config.state, 426 cast(PredictionContext)PredictionContext.EMPTY)); 427 currentAltReachedAcceptState = true; 428 } 429 } 430 if (config.context !is null && !config.context.isEmpty() ) { 431 for (auto i = 0; i < config.context.size; i++) { 432 if (config.context.getReturnState(i) != PredictionContext.EMPTY_RETURN_STATE) { 433 PredictionContext newContext = config.context.getParent(i); // "pop" return state 434 ATNState returnState = atn.states[config.context.getReturnState(i)]; 435 LexerATNConfig c = new LexerATNConfig(config, returnState, newContext); 436 currentAltReachedAcceptState = closure(input, c, configs, currentAltReachedAcceptState, 437 speculative, treatEofAsEpsilon); 438 } 439 } 440 } 441 442 return currentAltReachedAcceptState; 443 } 444 445 // optimization 446 if (!config.state.onlyHasEpsilonTransitions) { 447 if (!currentAltReachedAcceptState || !config.hasPassedThroughNonGreedyDecision()) { 448 configs.add(config); 449 } 450 } 451 452 ATNState p = config.state; 453 for (int i=0; i<p.getNumberOfTransitions(); i++) { 454 Transition t = p.transition(i); 455 LexerATNConfig c = getEpsilonTarget(input, config, t, configs, speculative, treatEofAsEpsilon); 456 if (c !is null) { 457 currentAltReachedAcceptState = closure(input, c, configs, currentAltReachedAcceptState, 458 speculative, treatEofAsEpsilon); 459 } 460 } 461 return currentAltReachedAcceptState; 462 } 463 464 /** 465 * side-effect: can alter configs.hasSemanticContext 466 */ 467 protected LexerATNConfig getEpsilonTarget(CharStream input, LexerATNConfig config, Transition t, 468 ref ATNConfigSet configs, bool speculative, bool treatEofAsEpsilon) 469 { 470 debug(LexerATNSimulator) { 471 import std.stdio; 472 writefln("LexerATNSimulator getEpsilonTarget t = %s, serType = %s", t, t.getSerializationType); 473 } 474 LexerATNConfig c = null; 475 switch (t.getSerializationType) { 476 case TransitionStates.RULE: 477 RuleTransition ruleTransition = cast(RuleTransition)t; 478 PredictionContext newContext = 479 SingletonPredictionContext.create(config.context, ruleTransition.followState.stateNumber); 480 c = new LexerATNConfig(config, t.target, newContext); 481 break; 482 case TransitionStates.PRECEDENCE: 483 throw new UnsupportedOperationException("Precedence predicates are not supported in lexers."); 484 case TransitionStates.PREDICATE: 485 /* Track traversing semantic predicates. If we traverse, 486 we cannot add a DFA state for this "reach" computation 487 because the DFA would not test the predicate again in the 488 future. Rather than creating collections of semantic predicates 489 like v3 and testing them on prediction, v4 will test them on the 490 fly all the time using the ATN not the DFA. This is slower but 491 semantically it's not used that often. One of the key elements to 492 this predicate mechanism is not adding DFA states that see 493 predicates immediately afterwards in the ATN. For example, 494 495 a : ID {p1}? | ID {p2}? ; 496 497 should create the start state for rule 'a' (to save start state 498 competition), but should not create target of ID state. The 499 collection of ATN states the following ID references includes 500 states reached by traversing predicates. Since this is when we 501 test them, we cannot cash the DFA state target of ID. 502 */ 503 PredicateTransition pt = cast(PredicateTransition)t; 504 debug(LexerATNSimulator) { 505 writefln("EVAL rule %1$s:%2$s", pt.ruleIndex, pt.predIndex); 506 } 507 configs.hasSemanticContext = true; 508 if (evaluatePredicate(input, pt.ruleIndex, pt.predIndex, speculative)) { 509 c = new LexerATNConfig(config, t.target); 510 } 511 break; 512 513 case TransitionStates.ACTION: 514 if (config.context is null || config.context.hasEmptyPath()) { 515 // execute actions anywhere in the start rule for a token. 516 // 517 // TODO: if the entry rule is invoked recursively, some 518 // actions may be executed during the recursive call. The 519 // problem can appear when hasEmptyPath() is true but 520 // isEmpty() is false. In this case, the config needs to be 521 // split into two contexts - one with just the empty path 522 // and another with everything but the empty path. 523 // Unfortunately, the current algorithm does not allow 524 // getEpsilonTarget to return two configurations, so 525 // additional modifications are needed before we can support 526 // the split operation. 527 LexerActionExecutor lexerActionExecutor = LexerActionExecutor.append(config.getLexerActionExecutor(), atn.lexerActions[(cast(ActionTransition)t).actionIndex]); 528 c = new LexerATNConfig(config, t.target, lexerActionExecutor); 529 break; 530 } 531 else { 532 // ignore actions in referenced rules 533 c = new LexerATNConfig(config, t.target); 534 break; 535 } 536 537 case TransitionStates.EPSILON: 538 c = new LexerATNConfig(config, t.target); 539 break; 540 541 case TransitionStates.ATOM: 542 case TransitionStates.RANGE: 543 case TransitionStates.SET: 544 if (treatEofAsEpsilon) { 545 if (t.matches(IntStreamConstant.EOF, 0, 0xfffe)) { 546 c = new LexerATNConfig(config, t.target); 547 break; 548 } 549 } 550 551 break; 552 default: {} 553 } 554 555 return c; 556 } 557 558 /** 559 * Evaluate a predicate specified in the lexer. 560 * 561 * 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}). 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 }