1/*
2 [The "BSD license"]
3 Copyright (c) 2005-2009 Terence Parr
4 All rights reserved.
5
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
8 are met:
9 1. Redistributions of source code must retain the above copyright
10     notice, this list of conditions and the following disclaimer.
11 2. Redistributions in binary form must reproduce the above copyright
12     notice, this list of conditions and the following disclaimer in the
13     documentation and/or other materials provided with the distribution.
14 3. The name of the author may not be used to endorse or promote products
15     derived from this software without specific prior written permission.
16
17 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28package org.antlr.runtime.tree;
29
30import org.antlr.runtime.Token;
31import org.antlr.runtime.CommonToken;
32
33public class TreePatternParser {
34	protected TreePatternLexer tokenizer;
35	protected int ttype;
36	protected TreeWizard wizard;
37	protected TreeAdaptor adaptor;
38
39	public TreePatternParser(TreePatternLexer tokenizer, TreeWizard wizard, TreeAdaptor adaptor) {
40		this.tokenizer = tokenizer;
41		this.wizard = wizard;
42		this.adaptor = adaptor;
43		ttype = tokenizer.nextToken(); // kickstart
44	}
45
46	public Object pattern() {
47		if ( ttype==TreePatternLexer.BEGIN ) {
48			return parseTree();
49		}
50		else if ( ttype==TreePatternLexer.ID ) {
51			Object node = parseNode();
52			if ( ttype==TreePatternLexer.EOF ) {
53				return node;
54			}
55			return null; // extra junk on end
56		}
57		return null;
58	}
59
60	public Object parseTree() {
61		if ( ttype != TreePatternLexer.BEGIN ) {
62			throw new RuntimeException("no BEGIN");
63		}
64		ttype = tokenizer.nextToken();
65		Object root = parseNode();
66		if ( root==null ) {
67			return null;
68		}
69		while ( ttype==TreePatternLexer.BEGIN ||
70				ttype==TreePatternLexer.ID ||
71				ttype==TreePatternLexer.PERCENT ||
72				ttype==TreePatternLexer.DOT )
73		{
74			if ( ttype==TreePatternLexer.BEGIN ) {
75				Object subtree = parseTree();
76				adaptor.addChild(root, subtree);
77			}
78			else {
79				Object child = parseNode();
80				if ( child==null ) {
81					return null;
82				}
83				adaptor.addChild(root, child);
84			}
85		}
86		if ( ttype != TreePatternLexer.END ) {
87			throw new RuntimeException("no END");
88		}
89		ttype = tokenizer.nextToken();
90		return root;
91	}
92
93	public Object parseNode() {
94		// "%label:" prefix
95		String label = null;
96		if ( ttype == TreePatternLexer.PERCENT ) {
97			ttype = tokenizer.nextToken();
98			if ( ttype != TreePatternLexer.ID ) {
99				return null;
100			}
101			label = tokenizer.sval.toString();
102			ttype = tokenizer.nextToken();
103			if ( ttype != TreePatternLexer.COLON ) {
104				return null;
105			}
106			ttype = tokenizer.nextToken(); // move to ID following colon
107		}
108
109		// Wildcard?
110		if ( ttype == TreePatternLexer.DOT ) {
111			ttype = tokenizer.nextToken();
112			Token wildcardPayload = new CommonToken(0, ".");
113			TreeWizard.TreePattern node =
114				new TreeWizard.WildcardTreePattern(wildcardPayload);
115			if ( label!=null ) {
116				node.label = label;
117			}
118			return node;
119		}
120
121		// "ID" or "ID[arg]"
122		if ( ttype != TreePatternLexer.ID ) {
123			return null;
124		}
125		String tokenName = tokenizer.sval.toString();
126		ttype = tokenizer.nextToken();
127		if ( tokenName.equals("nil") ) {
128			return adaptor.nil();
129		}
130		String text = tokenName;
131		// check for arg
132		String arg = null;
133		if ( ttype == TreePatternLexer.ARG ) {
134			arg = tokenizer.sval.toString();
135			text = arg;
136			ttype = tokenizer.nextToken();
137		}
138
139		// create node
140		int treeNodeType = wizard.getTokenType(tokenName);
141		if ( treeNodeType==Token.INVALID_TOKEN_TYPE ) {
142			return null;
143		}
144		Object node;
145		node = adaptor.create(treeNodeType, text);
146		if ( label!=null && node.getClass()==TreeWizard.TreePattern.class ) {
147			((TreeWizard.TreePattern)node).label = label;
148		}
149		if ( arg!=null && node.getClass()==TreeWizard.TreePattern.class ) {
150			((TreeWizard.TreePattern)node).hasTextArg = true;
151		}
152		return node;
153	}
154}
155