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.Parser; 8 9 import std.stdio; 10 import std.algorithm; 11 import std.conv; 12 import antlr.v4.runtime.ANTLRErrorStrategy; 13 import antlr.v4.runtime.ANTLRErrorListener; 14 import antlr.v4.runtime.DefaultErrorStrategy; 15 import antlr.v4.runtime.Lexer; 16 import antlr.v4.runtime.IntStream; 17 import antlr.v4.runtime.InterfaceRuleContext; 18 import antlr.v4.runtime.RuleContext; 19 import antlr.v4.runtime.ParserRuleContext; 20 import antlr.v4.runtime.Recognizer; 21 import antlr.v4.runtime.RecognitionException; 22 import antlr.v4.runtime.UnsupportedOperationException; 23 import antlr.v4.runtime.Token; 24 import antlr.v4.runtime.CommonToken; 25 import antlr.v4.runtime.TokenFactory; 26 import antlr.v4.runtime.TokenConstantDefinition; 27 import antlr.v4.runtime.TokenStream; 28 import antlr.v4.runtime.TokenSource; 29 import antlr.v4.runtime.InterfaceParser; 30 import antlr.v4.runtime.atn.ATN; 31 import antlr.v4.runtime.atn.ATNSimulator; 32 import antlr.v4.runtime.atn.ParserATNSimulator; 33 import antlr.v4.runtime.atn.ParseInfo; 34 import antlr.v4.runtime.atn.PredictionMode; 35 import antlr.v4.runtime.atn.RuleTransition; 36 import antlr.v4.runtime.atn.ATNDeserializer; 37 import antlr.v4.runtime.atn.ATNDeserializationOptions; 38 import antlr.v4.runtime.atn.ATNState; 39 import antlr.v4.runtime.atn.ProfilingATNSimulator; 40 import antlr.v4.runtime.dfa.DFA; 41 import antlr.v4.runtime.tree.pattern.ParseTreePattern; 42 import antlr.v4.runtime.tree.pattern.ParseTreePatternMatcher; 43 import antlr.v4.runtime.tree.ParseTreeListener; 44 import antlr.v4.runtime.tree.ErrorNode; 45 import antlr.v4.runtime.tree.TerminalNode; 46 import antlr.v4.runtime.misc.IntegerStack; 47 import antlr.v4.runtime.misc.IntervalSet; 48 49 // Class Parser 50 /** 51 * TODO add class description 52 */ 53 abstract class Parser : Recognizer!(Token, ParserATNSimulator), InterfaceParser 54 { 55 // Class TraceListener 56 /** 57 * TODO add class description 58 */ 59 class TraceListener : ParseTreeListener 60 { 61 62 public void enterEveryRule(ParserRuleContext ctx) 63 { 64 writeln("enter " ~ getRuleNames()[ctx.getRuleIndex()] ~ 65 ", LT(1)=" ~ _input.LT(1).getText()); 66 } 67 68 public void visitTerminal(TerminalNode node) 69 { 70 writeln("consume " ~ node.getSymbol().getText ~ " rule " ~ 71 getRuleNames()[ctx_.getRuleIndex()]); 72 } 73 74 public void visitErrorNode(ErrorNode node) 75 { 76 } 77 78 /** 79 * @uml 80 * @override 81 */ 82 public override void exitEveryRule(ParserRuleContext ctx) 83 { 84 writeln("exit " ~ getRuleNames()[ctx.getRuleIndex()] ~ 85 ", LT(1)=" ~ _input.LT(1).getText()); 86 } 87 88 } 89 90 // Singleton TrimToSizeListener 91 /** 92 * TODO add class description 93 */ 94 static class TrimToSizeListener : ParseTreeListener 95 { 96 97 /** 98 * The single instance of TrimToSizeListener. 99 */ 100 private static __gshared Parser.TrimToSizeListener instance_; 101 102 public void enterEveryRule(ParserRuleContext ctx) 103 { 104 } 105 106 public void visitTerminal(TerminalNode node) 107 { 108 } 109 110 public void visitErrorNode(ErrorNode node) 111 { 112 } 113 114 public void exitEveryRule(ParserRuleContext ctx) 115 { 116 // if (ctx.children.classinfo == ArrayList.classinfo) { 117 // ((ArrayList<?>)ctx.children).trimToSize(); 118 // } 119 } 120 121 /** 122 * Creates the single instance of TrimToSizeListener. 123 */ 124 private shared static this() 125 { 126 instance_ = new TrimToSizeListener; 127 } 128 129 /** 130 * Returns: A single instance of TrimToSizeListener. 131 */ 132 public static TrimToSizeListener instance() 133 { 134 return instance_; 135 } 136 137 } 138 139 /** 140 * @uml 141 * This field maps from the serialized ATN string to the deserialized {@link ATN} with 142 * bypass alternatives. 143 * 144 * @see ATNDeserializationOptions#isGenerateRuleBypassTransitions() 145 */ 146 private ATN[wstring] bypassAltsAtnCache; 147 148 protected ANTLRErrorStrategy _errHandler; 149 150 protected TokenStream _input; 151 152 public IntegerStack _precedenceStack; 153 154 /** 155 * @uml 156 * The {@link ParserRuleContext} object for the currently executing rule. 157 * This is always non-null during the parsing process. 158 * @read 159 * @write 160 */ 161 public ParserRuleContext ctx_; 162 163 /** 164 * @uml 165 * Specifies whether or not the parser should construct a parse tree during 166 * the parsing process. The default value is {@code true}. 167 * 168 * @see #getBuildParseTree 169 * @see #setBuildParseTree 170 */ 171 protected bool _buildParseTrees = true; 172 173 public TraceListener _tracer; 174 175 /** 176 * @uml 177 * The list of {@link ParseTreeListener} listeners registered to receive 178 * events during the parse. 179 * 180 * @see #addParseListener 181 */ 182 public ParseTreeListener[] _parseListeners; 183 184 /** 185 * @uml 186 * The number of syntax errors reported during parsing. This value is 187 * incremented each time {@link #notifyErrorListeners} is called. 188 */ 189 public int _syntaxErrors; 190 191 /** 192 * @uml 193 * Indicates parser has match()ed EOF token. See {@link #exitRule()}. 194 */ 195 public bool matchedEOF; 196 197 public this() 198 { 199 } 200 201 public this(TokenStream input) 202 { 203 setInputStream(input); 204 } 205 206 /** 207 * @uml 208 * reset the parser's state 209 */ 210 public void reset() 211 { 212 if (getInputStream() !is null) 213 getInputStream().seek(0); 214 _errHandler = new DefaultErrorStrategy; 215 _errHandler.reset(this); 216 ctx_ = null; 217 _syntaxErrors = 0; 218 matchedEOF = false; 219 _precedenceStack = new IntegerStack(); 220 _precedenceStack.clear; 221 _precedenceStack.push(0); 222 ATNSimulator interpreter = getInterpreter(); 223 if (interpreter !is null) { 224 interpreter.reset(); 225 } 226 } 227 228 /** 229 * @uml 230 * Match current input symbol against {@code ttype}. If the symbol type 231 * matches, {@link ANTLRErrorStrategy#reportMatch} and {@link #consume} are 232 * called to complete the match process. 233 * 234 * <p>If the symbol type does not match, 235 * {@link ANTLRErrorStrategy#recoverInline} is called on the current error 236 * strategy to attempt recovery. If {@link #getBuildParseTree} is 237 * {@code true} and the token index of the symbol returned by 238 * {@link ANTLRErrorStrategy#recoverInline} is -1, the symbol is added to 239 * the parse tree by calling {@link ParserRuleContext#addErrorNode}.</p> 240 * 241 * @param ttype the token type to match 242 * @return the matched symbol 243 * @throws RecognitionException if the current input symbol did not match 244 * {@code ttype} and the error strategy could not recover from the 245 * mismatched symbol 246 */ 247 public Token match(int ttype) 248 { 249 Token t = getCurrentToken; 250 251 debug(Parser) { 252 import std.stdio; 253 writefln("Parser: match %s, currentToken = %s", ttype, t); 254 } 255 256 if (t.getType == ttype) { 257 if (ttype == TokenConstantDefinition.EOF) 258 { 259 matchedEOF = true; 260 } 261 _errHandler.reportMatch(this); 262 consume(); 263 } 264 else { 265 t = _errHandler.recoverInline(this); 266 if (_buildParseTrees && t.getTokenIndex == -1) { 267 // we must have conjured up a new token during single token insertion 268 // if it's not the current symbol 269 ctx_.addErrorNode(t); 270 } 271 } 272 return t; 273 } 274 275 /** 276 * @uml 277 * Match current input symbol as a wildcard. If the symbol type matches 278 * (i.e. has a value greater than 0), {@link ANTLRErrorStrategy#reportMatch} 279 * and {@link #consume} are called to complete the match process. 280 * 281 * <p>If the symbol type does not match, 282 * {@link ANTLRErrorStrategy#recoverInline} is called on the current error 283 * strategy to attempt recovery. If {@link #getBuildParseTree} is 284 * {@code true} and the token index of the symbol returned by 285 * {@link ANTLRErrorStrategy#recoverInline} is -1, the symbol is added to 286 * the parse tree by calling {@link ParserRuleContext#addErrorNode}.</p> 287 * 288 * @return the matched symbol 289 * @throws RecognitionException if the current input symbol did not match 290 * a wildcard and the error strategy could not recover from the mismatched 291 * symbol 292 */ 293 public Token matchWildcard() 294 { 295 Token t = getCurrentToken(); 296 if (t.getType() > 0) { 297 _errHandler.reportMatch(this); 298 consume(); 299 } 300 else { 301 t = _errHandler.recoverInline(this); 302 if (_buildParseTrees && t.getTokenIndex() == -1) { 303 // we must have conjured up a new token during single token insertion 304 // if it's not the current symbol 305 ctx_.addErrorNode(t); 306 } 307 } 308 return t; 309 } 310 311 /** 312 * @uml 313 * Track the {@link ParserRuleContext} objects during the parse and hook 314 * them up using the {@link ParserRuleContext#children} list so that it 315 * forms a parse tree. The {@link ParserRuleContext} returned from the start 316 * rule represents the root of the parse tree. 317 * 318 * <p>Note that if we are not building parse trees, rule contexts only point 319 * upwards. When a rule exits, it returns the context but that gets garbage 320 * collected if nobody holds a reference. It points upwards but nobody 321 * points at it.</p> 322 * 323 * <p>When we build parse trees, we are adding all of these contexts to 324 * {@link ParserRuleContext#children} list. Contexts are then not candidates 325 * for garbage collection.</p> 326 */ 327 public void setBuildParseTree(bool buildParseTrees) 328 { 329 this._buildParseTrees = buildParseTrees; 330 } 331 332 /** 333 * @uml 334 * Gets whether or not a complete parse tree will be constructed while 335 * parsing. This property is {@code true} for a newly constructed parser. 336 * 337 * @return {@code true} if a complete parse tree will be constructed while 338 * parsing, otherwise {@code false} 339 */ 340 public bool getBuildParseTree() 341 { 342 return _buildParseTrees; 343 } 344 345 /** 346 * @uml 347 * Trim the internal lists of the parse tree during parsing to conserve memory. 348 * This property is set to {@code false} by default for a newly constructed parser. 349 * 350 * @param trimParseTrees {@code true} to trim the capacity of the {@link ParserRuleContext#children} 351 * list to its size after a rule is parsed. 352 */ 353 public void setTrimParseTree(bool trimParseTrees) 354 { 355 if (trimParseTrees) { 356 if (getTrimParseTree()) return; 357 addParseListener(TrimToSizeListener.instance); 358 } 359 else { 360 removeParseListener(TrimToSizeListener.instance); 361 } 362 } 363 364 /** 365 * @uml 366 * The @return {@code true} if the {@link ParserRuleContext#children} list is trimed 367 * using the default {@link Parser.TrimToSizeListener} during the parse process. 368 */ 369 public bool getTrimParseTree() 370 { 371 return canFind(getParseListeners(), TrimToSizeListener.instance); 372 } 373 374 public ParseTreeListener[] getParseListeners() 375 { 376 ParseTreeListener[] listeners = _parseListeners; 377 if (listeners is null) { 378 return []; 379 } 380 381 return listeners; 382 } 383 384 /** 385 * @uml 386 * Registers {@code listener} to receive events during the parsing process. 387 * 388 * <p>To support output-preserving grammar transformations (including but not 389 * limited to left-recursion removal, automated left-factoring, and 390 * optimized code generation), calls to listener methods during the parse 391 * may differ substantially from calls made by 392 * {@link ParseTreeWalker#DEFAULT} used after the parse is complete. In 393 * particular, rule entry and exit events may occur in a different order 394 * during the parse than after the parser. In addition, calls to certain 395 * rule entry methods may be omitted.</p> 396 * 397 * <p>With the following specific exceptions, calls to listener events are 398 * <em>deterministic</em>, i.e. for identical input the calls to listener 399 * methods will be the same.</p> 400 * 401 * <ul> 402 * <li>Alterations to the grammar used to generate code may change the 403 * behavior of the listener calls.</li> 404 * <li>Alterations to the command line options passed to ANTLR 4 when 405 * generating the parser may change the behavior of the listener calls.</li> 406 * <li>Changing the version of the ANTLR Tool used to generate the parser 407 * may change the behavior of the listener calls.</li> 408 * </ul> 409 * 410 * @param listener the listener to add 411 * 412 * @throws NullPointerException if {@code} listener is {@code null} 413 */ 414 public void addParseListener(ParseTreeListener listener) 415 { 416 assert (listener !is null, "NullPointerException(listener)"); 417 _parseListeners ~= listener; 418 } 419 420 public void removeParseListener(ParseTreeListener listener) 421 { 422 ParseTreeListener[] new_parseListeners; 423 foreach (li; _parseListeners) { 424 if ( li != listener) new_parseListeners ~= li; 425 } 426 _parseListeners = new_parseListeners; 427 } 428 429 /** 430 * @uml 431 * Remove all parse listeners. 432 * 433 * @see #addParseListener 434 */ 435 public void removeParseListeners() 436 { 437 _parseListeners.length = 0; 438 } 439 440 /** 441 * @uml 442 * Notify any parse listeners of an enter rule event. 443 * 444 * @see #addParseListener 445 */ 446 protected void triggerEnterRuleEvent() 447 { 448 foreach (listener; _parseListeners) { 449 listener.enterEveryRule(ctx_); 450 ctx_.enterRule(listener); 451 } 452 } 453 454 /** 455 * @uml 456 * Notify any parse listeners of an exit rule event. 457 * 458 * @see #addParseListener 459 */ 460 protected void triggerExitRuleEvent() 461 { 462 // reverse order walk of listeners 463 for (auto i = _parseListeners.length-1; i >= 0; i--) { 464 ParseTreeListener listener = _parseListeners[i]; 465 ctx_.exitRule(listener); 466 listener.exitEveryRule(ctx_); 467 } 468 } 469 470 /** 471 * @uml 472 * Gets the number of syntax errors reported during parsing. This value is 473 * incremented each time {@link #notifyErrorListeners} is called. 474 * 475 * @see #notifyErrorListeners 476 */ 477 public int getNumberOfSyntaxErrors() 478 { 479 return _syntaxErrors; 480 } 481 482 /** 483 * @uml 484 * @override 485 */ 486 public override TokenFactory!CommonToken tokenFactory() 487 { 488 return _input.getTokenSource().tokenFactory(); 489 } 490 491 /** 492 * Tell our token source and error strategy about a new way to create tokens. 493 * @uml 494 * @override 495 */ 496 public override void tokenFactory(TokenFactory!CommonToken factory) 497 { 498 _input.getTokenSource().tokenFactory(factory); 499 } 500 501 /** 502 * @uml 503 * The ATN with bypass alternatives is expensive to create so we create it 504 * lazily. 505 * 506 * @throws UnsupportedOperationException if the current parser does not 507 * implement the {@link #getSerializedATN()} method. 508 */ 509 public ATN getATNWithBypassAlts() 510 { 511 wstring serializedAtn = getSerializedATN(); 512 if (serializedAtn is null) { 513 throw new UnsupportedOperationException("The current parser does not support an ATN with bypass alternatives."); 514 } 515 if (serializedAtn in bypassAltsAtnCache) { 516 return bypassAltsAtnCache[serializedAtn]; 517 } 518 ATN result; 519 ATNDeserializationOptions deserializationOptions = new ATNDeserializationOptions(); 520 deserializationOptions.generateRuleBypassTransitions(true); 521 result = new ATNDeserializer(deserializationOptions).deserialize(serializedAtn); 522 bypassAltsAtnCache[serializedAtn] = result; 523 return result; 524 } 525 526 public ParseTreePattern compileParseTreePattern(string pattern, int patternRuleIndex) 527 { 528 if (getTokenStream() !is null) { 529 TokenSource tokenSource = getTokenStream().getTokenSource(); 530 if (tokenSource.classinfo == Lexer.classinfo) { 531 Lexer lexer = cast(Lexer)tokenSource; 532 return compileParseTreePattern(pattern, patternRuleIndex, lexer); 533 } 534 } 535 throw new UnsupportedOperationException("Parser can't discover a lexer to use"); 536 } 537 538 /** 539 * @uml 540 * The same as {@link #compileParseTreePattern(String, int)} but specify a 541 * {@link Lexer} rather than trying to deduce it from this parser. 542 */ 543 public ParseTreePattern compileParseTreePattern(string pattern, int patternRuleIndex, 544 Lexer lexer) 545 { 546 ParseTreePatternMatcher m = new ParseTreePatternMatcher(lexer, this); 547 return m.compile(pattern, patternRuleIndex); 548 } 549 550 public auto getErrorHandler() 551 { 552 return _errHandler; 553 } 554 555 public void setErrorHandler(ANTLRErrorStrategy handler) 556 { 557 } 558 559 /** 560 * @uml 561 * @override 562 */ 563 public override TokenStream getInputStream() 564 { 565 return getTokenStream(); 566 } 567 568 /** 569 * @uml 570 * @override 571 */ 572 public override void setInputStream(IntStream input) 573 { 574 setTokenStream(cast(TokenStream)input); 575 } 576 577 public TokenStream getTokenStream() 578 { 579 return _input; 580 } 581 582 /** 583 * @uml 584 * Set the token stream and reset the parser. 585 */ 586 public void setTokenStream(TokenStream input) 587 { 588 this._input = null; 589 reset(); 590 this._input = input; 591 } 592 593 /** 594 * @uml 595 * Match needs to return the current input symbol, which gets put 596 * into the label for the associated token ref; e.g., x=ID. 597 */ 598 public Token getCurrentToken() 599 { 600 return _input.LT(1); 601 } 602 603 /** 604 * @uml 605 * @final 606 */ 607 public final void notifyErrorListeners(string msg) 608 { 609 notifyErrorListeners(getCurrentToken(), msg, null); 610 } 611 612 public void notifyErrorListeners(Token offendingToken, string msg, RecognitionException e) 613 { 614 _syntaxErrors++; 615 int line = -1; 616 int charPositionInLine = -1; 617 line = offendingToken.getLine(); 618 charPositionInLine = offendingToken.getCharPositionInLine(); 619 ANTLRErrorListener!(Token, ParserATNSimulator) listener = getErrorListenerDispatch(); 620 listener.syntaxError(this, cast(Object)offendingToken, line, charPositionInLine, msg, e); 621 } 622 623 /** 624 * @uml 625 * Consume and return the {@linkplain #getCurrentToken current symbol}. 626 * 627 * <p>E.g., given the following input with {@code A} being the current 628 * lookahead symbol, this function moves the cursor to {@code B} and returns 629 * {@code A}.</p> 630 * 631 * <pre> 632 * A B 633 * ^ 634 * </pre> 635 * 636 * If the parser is not in error recovery mode, the consumed symbol is added 637 * to the parse tree using {@link ParserRuleContext#addChild(Token)}, and 638 * {@link ParseTreeListener#visitTerminal} is called on any parse listeners. 639 * If the parser <em>is</em> in error recovery mode, the consumed symbol is 640 * added to the parse tree using 641 * {@link ParserRuleContext#addErrorNode(Token)}, and 642 * {@link ParseTreeListener#visitErrorNode} is called on any parse 643 * listeners. 644 */ 645 public Token consume() 646 { 647 Token o = getCurrentToken(); 648 if (o.getType() != EOF) { 649 getInputStream().consume(); 650 } 651 652 bool hasListener = _parseListeners !is null && _parseListeners.length; 653 if (_buildParseTrees || hasListener) { 654 if (_errHandler.inErrorRecoveryMode(this)) { 655 ErrorNode node = ctx_.addErrorNode(o); 656 if (_parseListeners !is null) { 657 foreach (ParseTreeListener listener; _parseListeners) { 658 listener.visitErrorNode(node); 659 } 660 } 661 } 662 else { 663 TerminalNode node = ctx_.addChild(o); 664 if (_parseListeners !is null) { 665 foreach (ParseTreeListener listener; _parseListeners) { 666 listener.visitTerminal(node); 667 } 668 } 669 } 670 } 671 return o; 672 } 673 674 protected void addContextToParseTree() 675 { 676 ParserRuleContext parent = cast(ParserRuleContext)ctx_.parent; 677 // add current context to parent if we have a parent 678 if (parent !is null) { 679 parent.addChild(ctx_); 680 } 681 } 682 683 public void enterRule(ParserRuleContext localctx, int state, int ruleIndex) 684 { 685 setState(state); 686 ctx_ = localctx; 687 ctx_.start = _input.LT(1); 688 if (_buildParseTrees) addContextToParseTree(); 689 if (_parseListeners !is null) 690 triggerEnterRuleEvent(); 691 } 692 693 public void exitRule() 694 { 695 if (matchedEOF) { 696 // if we have matched EOF, it cannot consume past EOF so we use LT(1) here 697 ctx_.stop = _input.LT(1); // LT(1) will be end of file 698 } 699 else { 700 ctx_.stop = _input.LT(-1); // stop node is what we just matched 701 } 702 // trigger event on ctx_, before it reverts to parent 703 if (_parseListeners !is null) 704 triggerExitRuleEvent(); 705 setState(ctx_.invokingState); 706 ctx_ = cast(ParserRuleContext)ctx_.parent; 707 } 708 709 public void enterOuterAlt(ParserRuleContext localctx, int altNum) 710 { 711 localctx.setAltNumber(altNum); 712 // if we have new localctx, make sure we replace existing ctx 713 // that is previous child of parse tree 714 if (_buildParseTrees && ctx_ != localctx) { 715 ParserRuleContext parent = cast(ParserRuleContext)ctx_.parent; 716 if (parent !is null) 717 { 718 parent.removeLastChild(); 719 parent.addChild(localctx); 720 } 721 } 722 ctx_ = localctx; 723 } 724 725 /** 726 * @uml 727 * Get the precedence level for the top-most precedence rule. 728 * 729 * @return The precedence level for the top-most precedence rule, or -1 if 730 * the parser context is not nested within a precedence rule. 731 * @final 732 */ 733 public final int getPrecedence() 734 { 735 if (_precedenceStack.isEmpty) { 736 return -1; 737 } 738 return _precedenceStack.peek(); 739 } 740 741 /** 742 * @uml 743 * . @deprecated Use 744 * {@link #enterRecursionRule(ParserRuleContext, int, int, int)} instead. 745 */ 746 public void enterRecursionRule(ParserRuleContext localctx, int ruleIndex) 747 { 748 enterRecursionRule(localctx, getATN().ruleToStartState[ruleIndex].stateNumber, ruleIndex, 0); 749 } 750 751 public void enterRecursionRule(ParserRuleContext localctx, int state, int ruleIndex, 752 int precedence) 753 { 754 setState(state); 755 _precedenceStack.push(precedence); 756 ctx_ = localctx; 757 ctx_.start = _input.LT(1); 758 if(_parseListeners !is null) { 759 triggerEnterRuleEvent(); // simulates rule entry for left-recursive rules 760 } 761 } 762 763 /** 764 * @uml 765 * Like {@link #enterRule} but for recursive rules. 766 * Make the current context the child of the incoming localctx. 767 */ 768 public void pushNewRecursionContext(ParserRuleContext localctx, int state, int ruleIndex) 769 { 770 ParserRuleContext previous = ctx_; 771 previous.parent = localctx; 772 previous.invokingState = state; 773 previous.stop = _input.LT(-1); 774 775 ctx_ = localctx; 776 ctx_.start = previous.start; 777 if (_buildParseTrees) { 778 ctx_.addChild(previous); 779 } 780 781 if (_parseListeners !is null) { 782 triggerEnterRuleEvent(); // simulates rule entry for left-recursive rules 783 } 784 } 785 786 public void unrollRecursionContexts(ParserRuleContext _parentctx) 787 { 788 _precedenceStack.pop(); 789 ctx_.stop = _input.LT(-1); 790 ParserRuleContext retctx = ctx_; // save current ctx (return value) 791 792 // unroll so ctx_ is as it was before call to recursive method 793 if (_parseListeners !is null) { 794 while (ctx_ !is _parentctx) { 795 triggerExitRuleEvent(); 796 ctx_ = cast(ParserRuleContext)ctx_.parent; 797 } 798 } 799 else { 800 ctx_ = _parentctx; 801 } 802 803 // hook into tree 804 retctx.parent = _parentctx; 805 806 if (_buildParseTrees && _parentctx !is null) { 807 // add return ctx into invoking rule's tree 808 _parentctx.addChild(retctx); 809 } 810 } 811 812 public ParserRuleContext getInvokingContext(int ruleIndex) 813 { 814 ParserRuleContext p = ctx_; 815 while (p !is null ) { 816 if ( p.getRuleIndex() == ruleIndex ) return p; 817 p = cast(ParserRuleContext)p.parent; 818 } 819 return null; 820 } 821 822 /** 823 * @uml 824 * @override 825 */ 826 public override bool precpred(InterfaceRuleContext localctx, int precedence) 827 { 828 return precedence >= _precedenceStack.peek(); 829 } 830 831 public bool inContext(string context) 832 { 833 // TODO: useful in parser? 834 return false; 835 } 836 837 /** 838 * @uml 839 * Checks whether or not {@code symbol} can follow the current state in the 840 * ATN. The behavior of this method is equivalent to the following, but is 841 * implemented such that the complete context-sensitive follow set does not 842 * need to be explicitly constructed. 843 * 844 * <pre> 845 * return getExpectedTokens().contains(symbol); 846 * </pre> 847 * 848 * @param symbol the symbol type to check 849 * @return {@code true} if {@code symbol} can follow the current state in 850 * the ATN, otherwise {@code false}. 851 */ 852 public bool isExpectedToken(int symbol) 853 { 854 ATN atn = getInterpreter().atn; 855 ParserRuleContext ctx = ctx_; 856 ATNState s = atn.states[getState]; 857 IntervalSet following = atn.nextTokens(s); 858 if (following.contains(symbol)) { 859 return true; 860 } 861 // System.out.println("following "+s+"="+following); 862 if (!following.contains(TokenConstantDefinition.EPSILON)) 863 return false; 864 865 while (ctx !is null && ctx.invokingState>=0 && following.contains(TokenConstantDefinition.EPSILON) ) { 866 ATNState invokingState = atn.states[ctx.invokingState]; 867 RuleTransition rt = cast(RuleTransition)invokingState.transition(0); 868 following = atn.nextTokens(rt.followState); 869 if (following.contains(symbol)) { 870 return true; 871 } 872 873 ctx = cast(ParserRuleContext)ctx.parent; 874 } 875 if (following.contains(TokenConstantDefinition.EPSILON) && symbol == TokenConstantDefinition.EOF) { 876 return true; 877 } 878 879 return false; 880 } 881 882 public bool isMatchedEOF() 883 { 884 return matchedEOF; 885 } 886 887 /** 888 * @uml 889 * Computes the set of input symbols which could follow the current parser 890 * state and context, as given by {@link #getState} and {@link #getContext}, 891 * espectively. 892 * 893 * @see ATN#getExpectedTokens(int, RuleContext) 894 */ 895 public IntervalSet getExpectedTokens() 896 { 897 return getATN().getExpectedTokens(getState(), ctx_); 898 } 899 900 public IntervalSet getExpectedTokensWithinCurrentRule() 901 { 902 ATN atn = getInterpreter().atn; 903 ATNState s = atn.states[getState]; 904 return atn.nextTokens(s); 905 } 906 907 /** 908 * @uml 909 * Get a rule's index (i.e., {@code RULE_ruleName} field) or -1 if not found. 910 */ 911 public int getRuleIndex(string ruleName) 912 { 913 if (ruleName in getRuleIndexMap) 914 return getRuleIndexMap[ruleName]; 915 return -1; 916 } 917 918 public ParserRuleContext getRuleContext() 919 { 920 return ctx_; 921 } 922 923 /** 924 * @uml 925 * Return List<String> of the rule names in your parser instance 926 * leading up to a call to the current rule. You could override if 927 * you want more details such as the file/line info of where 928 * in the ATN a rule is invoked. 929 * 930 * This is very useful for error messages. 931 */ 932 public string[] getRuleInvocationStack() 933 { 934 return getRuleInvocationStack(ctx_); 935 } 936 937 public string[] getRuleInvocationStack(RuleContext p) 938 { 939 string[] ruleNames = getRuleNames(); 940 string[] stack; 941 while (p) { 942 // compute what follows who invoked us 943 int ruleIndex = p.getRuleIndex(); 944 if (ruleIndex < 0) 945 stack ~= "n/a"; 946 else 947 stack ~= ruleNames[ruleIndex]; 948 p = p.getParent; 949 } 950 return stack; 951 } 952 953 /** 954 * @uml 955 * For debugging and other purposes. 956 */ 957 public string[] getDFAStrings() 958 { 959 string[] s; 960 for (int d = 0; d < _interp.decisionToDFA.length; d++) { 961 DFA dfa = _interp.decisionToDFA[d]; 962 s ~= dfa.toString(getVocabulary()); 963 } 964 return s; 965 } 966 967 /** 968 * @uml 969 * For debugging and other purposes. 970 */ 971 public void dumpDFA() 972 { 973 bool seenOne = false; 974 for (int d = 0; d < _interp.decisionToDFA.length; d++) { 975 DFA dfa = _interp.decisionToDFA[d]; 976 if (dfa.states.length) { 977 if (seenOne) writeln(); 978 writefln("Decision %1$s:", dfa.decision); 979 writefln(dfa.toString(getVocabulary())); 980 seenOne = true; 981 } 982 } 983 } 984 985 public string getSourceName() 986 { 987 return _input.getSourceName(); 988 } 989 990 /** 991 * @uml 992 * @override 993 */ 994 public override ParseInfo getParseInfo() 995 { 996 ParserATNSimulator interp = getInterpreter(); 997 if (interp.classinfo == ProfilingATNSimulator.classinfo) { 998 return new ParseInfo(cast(ProfilingATNSimulator)interp); 999 } 1000 return null; 1001 } 1002 1003 public void setProfile(bool profile) 1004 { 1005 ParserATNSimulator interp = getInterpreter(); 1006 auto saveMode = interp.getPredictionMode(); 1007 if (profile) { 1008 if (interp.classinfo != ProfilingATNSimulator.classinfo) { 1009 setInterpreter(new ProfilingATNSimulator(this)); 1010 } 1011 } 1012 else if (interp.classinfo == ProfilingATNSimulator.classinfo) { 1013 ParserATNSimulator sim = 1014 new ParserATNSimulator(this, getATN(), interp.decisionToDFA, interp.getSharedContextCache()); 1015 setInterpreter(sim); 1016 } 1017 getInterpreter().setPredictionMode(saveMode); 1018 } 1019 1020 public void setTrace(bool trace) 1021 { 1022 if (!trace) { 1023 removeParseListener(_tracer); 1024 _tracer = null; 1025 } 1026 else { 1027 if (_tracer !is null ) removeParseListener(_tracer); 1028 else _tracer = new TraceListener(); 1029 addParseListener(_tracer); 1030 } 1031 } 1032 1033 /** 1034 * @uml 1035 * Gets whether a {@link TraceListener} is registered as a parse listener 1036 * for the parser. 1037 * 1038 * @see #setTrace(boolean) 1039 */ 1040 public bool isTrace() 1041 { 1042 return _tracer !is null; 1043 } 1044 1045 public final ParserRuleContext ctx() 1046 { 1047 return this.ctx_; 1048 } 1049 1050 public final void ctx(ParserRuleContext ctx) 1051 { 1052 this.ctx_ = ctx; 1053 } 1054 1055 }