13447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein/*
23447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein [The "BSD license"]
33447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein Copyright (c) 2005-2009 Terence Parr
43447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein All rights reserved.
53447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
63447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein Redistribution and use in source and binary forms, with or without
73447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein modification, are permitted provided that the following conditions
83447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein are met:
93447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein 1. Redistributions of source code must retain the above copyright
103447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein     notice, this list of conditions and the following disclaimer.
113447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein 2. Redistributions in binary form must reproduce the above copyright
123447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein     notice, this list of conditions and the following disclaimer in the
133447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein     documentation and/or other materials provided with the distribution.
143447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein 3. The name of the author may not be used to endorse or promote products
153447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein     derived from this software without specific prior written permission.
163447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
173447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
183447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
193447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
203447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
213447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
223447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
233447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
243447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
253447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
263447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
273447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein */
283447a5916aa62f44de24cc441fc9987116ddff52Andrew Sappersteinpackage org.antlr.runtime.tree;
293447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
303447a5916aa62f44de24cc441fc9987116ddff52Andrew Sappersteinimport org.antlr.runtime.*;
313447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
323447a5916aa62f44de24cc441fc9987116ddff52Andrew Sappersteinimport java.util.regex.Matcher;
33324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverimport java.util.regex.Pattern;
343447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
353447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein/** A parser for a stream of tree nodes.  "tree grammars" result in a subclass
363447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein *  of this.  All the error reporting and recovery is shared with Parser via
373447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein *  the BaseRecognizer superclass.
383447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein*/
393447a5916aa62f44de24cc441fc9987116ddff52Andrew Sappersteinpublic class TreeParser extends BaseRecognizer {
403447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	public static final int DOWN = Token.DOWN;
413447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	public static final int UP = Token.UP;
423447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
433447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein    // precompiled regex used by inContext
443447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein    static String dotdot = ".*[^.]\\.\\.[^.].*";
453447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein    static String doubleEtc = ".*\\.\\.\\.\\s+\\.\\.\\..*";
463447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein    static Pattern dotdotPattern = Pattern.compile(dotdot);
473447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein    static Pattern doubleEtcPattern = Pattern.compile(doubleEtc);
483447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
493447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	protected TreeNodeStream input;
503447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
513447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	public TreeParser(TreeNodeStream input) {
523447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		super(); // highlight that we go to super to set state object
533447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		setTreeNodeStream(input);
543447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	}
553447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
563447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	public TreeParser(TreeNodeStream input, RecognizerSharedState state) {
573447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		super(state); // share the state object with another parser
583447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		setTreeNodeStream(input);
593447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein    }
603447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
613447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	public void reset() {
623447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		super.reset(); // reset all recognizer state variables
633447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		if ( input!=null ) {
643447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			input.seek(0); // rewind the input
653447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		}
663447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	}
673447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
683447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	/** Set the input stream */
693447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	public void setTreeNodeStream(TreeNodeStream input) {
703447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		this.input = input;
713447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	}
723447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
733447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	public TreeNodeStream getTreeNodeStream() {
743447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		return input;
753447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	}
763447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
773447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	public String getSourceName() {
783447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		return input.getSourceName();
793447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	}
803447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
813447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	protected Object getCurrentInputSymbol(IntStream input) {
823447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		return ((TreeNodeStream)input).LT(1);
833447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	}
843447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
853447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	protected Object getMissingSymbol(IntStream input,
863447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein									  RecognitionException e,
873447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein									  int expectedTokenType,
883447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein									  BitSet follow)
893447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	{
903447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		String tokenText =
913447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			"<missing "+getTokenNames()[expectedTokenType]+">";
923447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein        TreeAdaptor adaptor = ((TreeNodeStream)e.input).getTreeAdaptor();
933447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein        return adaptor.create(new CommonToken(expectedTokenType, tokenText));
943447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	}
953447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
963447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein    /** Match '.' in tree parser has special meaning.  Skip node or
973447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 *  entire tree if node has children.  If children, scan until
983447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 *  corresponding UP node.
993447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 */
1003447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	public void matchAny(IntStream ignore) { // ignore stream, copy of input
1013447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		state.errorRecovery = false;
1023447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		state.failed = false;
1033447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		Object look = input.LT(1);
1043447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		if ( input.getTreeAdaptor().getChildCount(look)==0 ) {
1053447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			input.consume(); // not subtree, consume 1 node and return
1063447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			return;
1073447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		}
1083447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		// current node is a subtree, skip to corresponding UP.
1093447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		// must count nesting level to get right UP
1103447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		int level=0;
1113447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		int tokenType = input.getTreeAdaptor().getType(look);
1123447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		while ( tokenType!=Token.EOF && !(tokenType==UP && level==0) ) {
1133447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			input.consume();
1143447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			look = input.LT(1);
1153447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			tokenType = input.getTreeAdaptor().getType(look);
1163447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			if ( tokenType == DOWN ) {
1173447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein				level++;
1183447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			}
1193447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			else if ( tokenType == UP ) {
1203447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein				level--;
1213447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			}
1223447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		}
1233447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		input.consume(); // consume UP
1243447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	}
1253447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
1263447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein    /** We have DOWN/UP nodes in the stream that have no line info; override.
1273447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 *  plus we want to alter the exception type.  Don't try to recover
1283447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 *  from tree parser errors inline...
1293447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein     */
1303447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein    protected Object recoverFromMismatchedToken(IntStream input,
1313447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein                                                int ttype,
1323447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein                                                BitSet follow)
1333447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein        throws RecognitionException
1343447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein    {
1353447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein        throw new MismatchedTreeNodeException(ttype, (TreeNodeStream)input);
1363447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein    }
1373447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
1383447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein    /** Prefix error message with the grammar name because message is
1393447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 *  always intended for the programmer because the parser built
1403447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 *  the input tree not the user.
1413447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 */
1423447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	public String getErrorHeader(RecognitionException e) {
1433447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		return getGrammarFileName()+": node from "+
1443447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			   (e.approximateLineInfo?"after ":"")+"line "+e.line+":"+e.charPositionInLine;
1453447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	}
1463447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
1473447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	/** Tree parsers parse nodes they usually have a token object as
1483447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 *  payload. Set the exception token and do the default behavior.
1493447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 */
1503447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	public String getErrorMessage(RecognitionException e, String[] tokenNames) {
1513447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		if ( this instanceof TreeParser ) {
1523447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			TreeAdaptor adaptor = ((TreeNodeStream)e.input).getTreeAdaptor();
1533447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			e.token = adaptor.getToken(e.node);
1543447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			if ( e.token==null ) { // could be an UP/DOWN node
1553447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein				e.token = new CommonToken(adaptor.getType(e.node),
1563447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein										  adaptor.getText(e.node));
1573447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			}
1583447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		}
1593447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		return super.getErrorMessage(e, tokenNames);
1603447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	}
1613447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
162324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	/** Check if current node in input has a context.  Context means sequence
163324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 *  of nodes towards root of tree.  For example, you might say context
164324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 *  is "MULT" which means my parent must be MULT.  "CLASS VARDEF" says
165324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 *  current node must be child of a VARDEF and whose parent is a CLASS node.
166324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 *  You can use "..." to mean zero-or-more nodes.  "METHOD ... VARDEF"
167324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 *  means my parent is VARDEF and somewhere above that is a METHOD node.
168324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 *  The first node in the context is not necessarily the root.  The context
169324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 *  matcher stops matching and returns true when it runs out of context.
170324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 *  There is no way to force the first node to be the root.
171324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 */
172324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	public boolean inContext(String context) {
173324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		return inContext(input.getTreeAdaptor(), getTokenNames(), input.LT(1), context);
174324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	}
175324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
176324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	/** The worker for inContext.  It's static and full of parameters for
177324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 *  testing purposes.
178324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 */
179324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	public static boolean inContext(TreeAdaptor adaptor,
180324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver									String[] tokenNames,
181324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver									Object t,
182324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver									String context)
183324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	{
184324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		Matcher dotdotMatcher = dotdotPattern.matcher(context);
185324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		Matcher doubleEtcMatcher = doubleEtcPattern.matcher(context);
186324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		if ( dotdotMatcher.find() ) { // don't allow "..", must be "..."
187324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			throw new IllegalArgumentException("invalid syntax: ..");
188324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		}
189324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		if ( doubleEtcMatcher.find() ) { // don't allow double "..."
190324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			throw new IllegalArgumentException("invalid syntax: ... ...");
191324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		}
192324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		context = context.replaceAll("\\.\\.\\.", " ... "); // ensure spaces around ...
193324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		context = context.trim();
194324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		String[] nodes = context.split("\\s+");
195324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		int ni = nodes.length-1;
196324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		t = adaptor.getParent(t);
197324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		while ( ni>=0 && t!=null ) {
198324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			if ( nodes[ni].equals("...") ) {
199324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver				// walk upwards until we see nodes[ni-1] then continue walking
200324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver				if ( ni==0 ) return true; // ... at start is no-op
201324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver				String goal = nodes[ni-1];
202324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver				Object ancestor = getAncestor(adaptor, tokenNames, t, goal);
203324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver				if ( ancestor==null ) return false;
204324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver				t = ancestor;
205324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver				ni--;
206324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			}
207324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			String name = tokenNames[adaptor.getType(t)];
208324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			if ( !name.equals(nodes[ni]) ) {
209324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver				//System.err.println("not matched: "+nodes[ni]+" at "+t);
210324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver				return false;
211324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			}
212324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			// advance to parent and to previous element in context node list
213324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			ni--;
214324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			t = adaptor.getParent(t);
215324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		}
216324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
217324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		if ( t==null && ni>=0 ) return false; // at root but more nodes to match
218324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		return true;
219324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	}
220324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
221324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	/** Helper for static inContext */
222324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	protected static Object getAncestor(TreeAdaptor adaptor, String[] tokenNames, Object t, String goal) {
223324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		while ( t!=null ) {
224324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			String name = tokenNames[adaptor.getType(t)];
225324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			if ( name.equals(goal) ) return t;
226324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			t = adaptor.getParent(t);
227324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		}
228324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		return null;
229324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	}
230324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
2313447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	public void traceIn(String ruleName, int ruleIndex)  {
2323447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		super.traceIn(ruleName, ruleIndex, input.LT(1));
2333447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	}
2343447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
2353447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	public void traceOut(String ruleName, int ruleIndex)  {
2363447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		super.traceOut(ruleName, ruleIndex, input.LT(1));
2373447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	}
2383447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein}
239