1/* 2 * [The "BSD licence"] 3 * Copyright (c) 2005-2008 Terence Parr 4 * All rights reserved. 5 * 6 * Conversion to C#: 7 * Copyright (c) 2008-2009 Sam Harwell, Pixel Mine, Inc. 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33namespace Antlr.Runtime.Debug 34{ 35 using System.Collections.Generic; 36 using ParseTree = Antlr.Runtime.Tree.ParseTree; 37 38 /** <summary> 39 * This parser listener tracks rule entry/exit and token matches 40 * to build a simple parse tree using ParseTree nodes. 41 * </summary> 42 */ 43 public class ParseTreeBuilder : BlankDebugEventListener 44 { 45 public const string EPSILON_PAYLOAD = "<epsilon>"; 46 47 Stack<ParseTree> callStack = new Stack<ParseTree>(); 48 List<IToken> hiddenTokens = new List<IToken>(); 49 int backtracking = 0; 50 51 public ParseTreeBuilder( string grammarName ) 52 { 53 ParseTree root = Create( "<grammar " + grammarName + ">" ); 54 callStack.Push( root ); 55 } 56 57 public virtual ParseTree Tree 58 { 59 get 60 { 61 return callStack.Peek(); 62 } 63 } 64 65 /** <summary> 66 * What kind of node to create. You might want to override 67 * so I factored out creation here. 68 * </summary> 69 */ 70 public virtual ParseTree Create( object payload ) 71 { 72 return new ParseTree( payload ); 73 } 74 75 public virtual ParseTree EpsilonNode() 76 { 77 return Create( EPSILON_PAYLOAD ); 78 } 79 80 /** <summary>Backtracking or cyclic DFA, don't want to add nodes to tree</summary> */ 81 public override void EnterDecision( int d, bool couldBacktrack ) 82 { 83 backtracking++; 84 } 85 public override void ExitDecision( int i ) 86 { 87 backtracking--; 88 } 89 90 public override void EnterRule( string filename, string ruleName ) 91 { 92 if ( backtracking > 0 ) 93 return; 94 ParseTree parentRuleNode = callStack.Peek(); 95 ParseTree ruleNode = Create( ruleName ); 96 parentRuleNode.AddChild( ruleNode ); 97 callStack.Push( ruleNode ); 98 } 99 100 public override void ExitRule( string filename, string ruleName ) 101 { 102 if ( backtracking > 0 ) 103 return; 104 ParseTree ruleNode = callStack.Peek(); 105 if ( ruleNode.ChildCount == 0 ) 106 { 107 ruleNode.AddChild( EpsilonNode() ); 108 } 109 callStack.Pop(); 110 } 111 112 public override void ConsumeToken( IToken token ) 113 { 114 if ( backtracking > 0 ) 115 return; 116 ParseTree ruleNode = callStack.Peek(); 117 ParseTree elementNode = Create( token ); 118 elementNode.hiddenTokens = this.hiddenTokens; 119 this.hiddenTokens = new List<IToken>(); 120 ruleNode.AddChild( elementNode ); 121 } 122 123 public override void ConsumeHiddenToken( IToken token ) 124 { 125 if ( backtracking > 0 ) 126 return; 127 hiddenTokens.Add( token ); 128 } 129 130 public override void RecognitionException( RecognitionException e ) 131 { 132 if ( backtracking > 0 ) 133 return; 134 ParseTree ruleNode = callStack.Peek(); 135 ParseTree errorNode = Create( e ); 136 ruleNode.AddChild( errorNode ); 137 } 138 } 139} 140