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