ParseTreeBuilder.cs revision 324c4644fee44b9898524c09511bd33c3f12e2df
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    using System.Collections.Generic;
35    using ParseTree = Antlr.Runtime.Tree.ParseTree;
36
37    /** <summary>
38     *  This parser listener tracks rule entry/exit and token matches
39     *  to build a simple parse tree using ParseTree nodes.
40     *  </summary>
41     */
42    public class ParseTreeBuilder : BlankDebugEventListener {
43        public const string EPSILON_PAYLOAD = "<epsilon>";
44
45        Stack<ParseTree> callStack = new Stack<ParseTree>();
46        List<IToken> hiddenTokens = new List<IToken>();
47        int backtracking = 0;
48
49        public ParseTreeBuilder(string grammarName) {
50            ParseTree root = Create("<grammar " + grammarName + ">");
51            callStack.Push(root);
52        }
53
54        public virtual ParseTree GetTree() {
55            var enumerator = callStack.GetEnumerator();
56            enumerator.MoveNext();
57            return enumerator.Current;
58        }
59
60        /** <summary>
61         *  What kind of node to create.  You might want to override
62         *  so I factored out creation here.
63         *  </summary>
64         */
65        public virtual ParseTree Create(object payload) {
66            return new ParseTree(payload);
67        }
68
69        public virtual ParseTree EpsilonNode() {
70            return Create(EPSILON_PAYLOAD);
71        }
72
73        /** <summary>Backtracking or cyclic DFA, don't want to add nodes to tree</summary> */
74        public override void EnterDecision(int d, bool couldBacktrack) {
75            backtracking++;
76        }
77        public override void ExitDecision(int i) {
78            backtracking--;
79        }
80
81        public override void EnterRule(string filename, string ruleName) {
82            if (backtracking > 0)
83                return;
84            ParseTree parentRuleNode = callStack.Peek();
85            ParseTree ruleNode = Create(ruleName);
86            parentRuleNode.AddChild(ruleNode);
87            callStack.Push(ruleNode);
88        }
89
90        public override void ExitRule(string filename, string ruleName) {
91            if (backtracking > 0)
92                return;
93            ParseTree ruleNode = callStack.Peek();
94            if (ruleNode.ChildCount == 0) {
95                ruleNode.AddChild(EpsilonNode());
96            }
97            callStack.Pop();
98        }
99
100        public override void ConsumeToken(IToken token) {
101            if (backtracking > 0)
102                return;
103            ParseTree ruleNode = callStack.Peek();
104            ParseTree elementNode = Create(token);
105            elementNode.hiddenTokens = this.hiddenTokens;
106            this.hiddenTokens = new List<IToken>();
107            ruleNode.AddChild(elementNode);
108        }
109
110        public override void ConsumeHiddenToken(IToken token) {
111            if (backtracking > 0)
112                return;
113            hiddenTokens.Add(token);
114        }
115
116        public override void RecognitionException(RecognitionException e) {
117            if (backtracking > 0)
118                return;
119            ParseTree ruleNode = callStack.Peek();
120            ParseTree errorNode = Create(e);
121            ruleNode.AddChild(errorNode);
122        }
123    }
124}
125