Uploading antlr runtime for doclava use.

Change-Id: Iea8a6dd3a2c46dd3c13a81da6aa94e01bf98b854
diff --git a/Android.mk b/Android.mk
new file mode 100644
index 0000000..efe3a09
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1,32 @@
+# Copyright (C) 2011 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := antlr
+#LOCAL_SDK_VERSION := 8
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_HOST_JAVA_LIBRARY)
+
+# Also build a host-side library
+# include $(CLEAR_VARS)
+# 
+# LOCAL_SRC_FILES := $(call all-java-files-under, src)
+# LOCAL_MODULE := antlrlib
+# 
+# include $(BUILD_HOST_JAVA_LIBRARY)
+
diff --git a/src/org/antlr/runtime/ANTLRFileStream.java b/src/org/antlr/runtime/ANTLRFileStream.java
new file mode 100755
index 0000000..27ef58b
--- /dev/null
+++ b/src/org/antlr/runtime/ANTLRFileStream.java
@@ -0,0 +1,78 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime;
+
+import java.io.*;
+
+/** This is a char buffer stream that is loaded from a file
+ *  all at once when you construct the object.  This looks very
+ *  much like an ANTLReader or ANTLRInputStream, but it's a special case
+ *  since we know the exact size of the object to load.  We can avoid lots
+ *  of data copying. 
+ */
+public class ANTLRFileStream extends ANTLRStringStream {
+	protected String fileName;
+
+	public ANTLRFileStream(String fileName) throws IOException {
+		this(fileName, null);
+	}
+
+	public ANTLRFileStream(String fileName, String encoding) throws IOException {
+		this.fileName = fileName;
+		load(fileName, encoding);
+	}
+
+	public void load(String fileName, String encoding)
+		throws IOException
+	{
+		if ( fileName==null ) {
+			return;
+		}
+		File f = new File(fileName);
+		int size = (int)f.length();
+		InputStreamReader isr;
+		FileInputStream fis = new FileInputStream(fileName);
+		if ( encoding!=null ) {
+			isr = new InputStreamReader(fis, encoding);
+		}
+		else {
+			isr = new InputStreamReader(fis);
+		}
+		try {
+			data = new char[size];
+			super.n = isr.read(data);
+		}
+		finally {
+			isr.close();
+		}
+	}
+
+	public String getSourceName() {
+		return fileName;
+	}
+}
diff --git a/src/org/antlr/runtime/ANTLRInputStream.java b/src/org/antlr/runtime/ANTLRInputStream.java
new file mode 100755
index 0000000..e544aae
--- /dev/null
+++ b/src/org/antlr/runtime/ANTLRInputStream.java
@@ -0,0 +1,70 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime;
+
+import java.io.*;
+
+/** A kind of ReaderStream that pulls from an InputStream.
+ *  Useful for reading from stdin and specifying file encodings etc...
+  */
+public class ANTLRInputStream extends ANTLRReaderStream {
+	public ANTLRInputStream() {
+	}
+
+	public ANTLRInputStream(InputStream input) throws IOException {
+		this(input, null);
+	}
+
+	public ANTLRInputStream(InputStream input, int size) throws IOException {
+		this(input, size, null);
+	}
+
+	public ANTLRInputStream(InputStream input, String encoding) throws IOException {
+		this(input, INITIAL_BUFFER_SIZE, encoding);
+	}
+
+	public ANTLRInputStream(InputStream input, int size, String encoding) throws IOException {
+		this(input, size, READ_BUFFER_SIZE, encoding);
+	}
+
+	public ANTLRInputStream(InputStream input,
+							int size,
+							int readBufferSize,
+							String encoding)
+		throws IOException
+	{
+		InputStreamReader isr;
+		if ( encoding!=null ) {
+			isr = new InputStreamReader(input, encoding);
+		}
+		else {
+			isr = new InputStreamReader(input);
+		}
+		load(isr, size, readBufferSize);
+	}
+}
diff --git a/src/org/antlr/runtime/ANTLRReaderStream.java b/src/org/antlr/runtime/ANTLRReaderStream.java
new file mode 100755
index 0000000..24d51ad
--- /dev/null
+++ b/src/org/antlr/runtime/ANTLRReaderStream.java
@@ -0,0 +1,95 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime;
+
+import java.io.*;
+
+/** Vacuum all input from a Reader and then treat it like a StringStream.
+ *  Manage the buffer manually to avoid unnecessary data copying.
+ *
+ *  If you need encoding, use ANTLRInputStream.
+ */
+public class ANTLRReaderStream extends ANTLRStringStream {
+	public static final int READ_BUFFER_SIZE = 1024;
+	public static final int INITIAL_BUFFER_SIZE = 1024;
+
+	public ANTLRReaderStream() {
+	}
+
+	public ANTLRReaderStream(Reader r) throws IOException {
+		this(r, INITIAL_BUFFER_SIZE, READ_BUFFER_SIZE);
+	}
+
+	public ANTLRReaderStream(Reader r, int size) throws IOException {
+		this(r, size, READ_BUFFER_SIZE);
+	}
+
+	public ANTLRReaderStream(Reader r, int size, int readChunkSize) throws IOException {
+		load(r, size, readChunkSize);
+	}
+
+	public void load(Reader r, int size, int readChunkSize)
+		throws IOException
+	{
+		if ( r==null ) {
+			return;
+		}
+		if ( size<=0 ) {
+			size = INITIAL_BUFFER_SIZE;
+		}
+		if ( readChunkSize<=0 ) {
+			readChunkSize = READ_BUFFER_SIZE;
+		}
+		// System.out.println("load "+size+" in chunks of "+readChunkSize);
+		try {
+			// alloc initial buffer size.
+			data = new char[size];
+			// read all the data in chunks of readChunkSize
+			int numRead=0;
+			int p = 0;
+			do {
+				if ( p+readChunkSize > data.length ) { // overflow?
+					// System.out.println("### overflow p="+p+", data.length="+data.length);
+					char[] newdata = new char[data.length*2]; // resize
+					System.arraycopy(data, 0, newdata, 0, data.length);
+					data = newdata;
+				}
+				numRead = r.read(data, p, readChunkSize);
+				// System.out.println("read "+numRead+" chars; p was "+p+" is now "+(p+numRead));
+				p += numRead;
+			} while (numRead!=-1); // while not EOF
+			// set the actual size of the data available;
+			// EOF subtracted one above in p+=numRead; add one back
+			super.n = p+1;
+			//System.out.println("n="+n);
+		}
+		finally {
+			r.close();
+		}
+	}
+}
diff --git a/src/org/antlr/runtime/ANTLRStringStream.java b/src/org/antlr/runtime/ANTLRStringStream.java
new file mode 100755
index 0000000..17af23c
--- /dev/null
+++ b/src/org/antlr/runtime/ANTLRStringStream.java
@@ -0,0 +1,230 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/** A pretty quick CharStream that pulls all data from an array
+ *  directly.  Every method call counts in the lexer.  Java's
+ *  strings aren't very good so I'm avoiding.
+ */
+public class ANTLRStringStream implements CharStream {
+	/** The data being scanned */
+	protected char[] data;
+
+	/** How many characters are actually in the buffer */
+	protected int n;
+
+	/** 0..n-1 index into string of next char */
+	protected int p=0;
+
+	/** line number 1..n within the input */
+	protected int line = 1;
+
+	/** The index of the character relative to the beginning of the line 0..n-1 */
+	protected int charPositionInLine = 0;
+
+	/** tracks how deep mark() calls are nested */
+	protected int markDepth = 0;
+
+	/** A list of CharStreamState objects that tracks the stream state
+	 *  values line, charPositionInLine, and p that can change as you
+	 *  move through the input stream.  Indexed from 1..markDepth.
+     *  A null is kept @ index 0.  Create upon first call to mark().
+	 */
+	protected List markers;
+
+	/** Track the last mark() call result value for use in rewind(). */
+	protected int lastMarker;
+
+	/** What is name or source of this char stream? */
+	public String name;
+
+	public ANTLRStringStream() {
+	}
+
+	/** Copy data in string to a local char array */
+	public ANTLRStringStream(String input) {
+		this();
+		this.data = input.toCharArray();
+		this.n = input.length();
+	}
+
+	/** This is the preferred constructor as no data is copied */
+	public ANTLRStringStream(char[] data, int numberOfActualCharsInArray) {
+		this();
+		this.data = data;
+		this.n = numberOfActualCharsInArray;
+	}
+
+	/** Reset the stream so that it's in the same state it was
+	 *  when the object was created *except* the data array is not
+	 *  touched.
+	 */
+	public void reset() {
+		p = 0;
+		line = 1;
+		charPositionInLine = 0;
+		markDepth = 0;
+	}
+
+    public void consume() {
+		//System.out.println("prev p="+p+", c="+(char)data[p]);
+        if ( p < n ) {
+			charPositionInLine++;
+			if ( data[p]=='\n' ) {
+				/*
+				System.out.println("newline char found on line: "+line+
+								   "@ pos="+charPositionInLine);
+				*/
+				line++;
+				charPositionInLine=0;
+			}
+            p++;
+			//System.out.println("p moves to "+p+" (c='"+(char)data[p]+"')");
+        }
+    }
+
+    public int LA(int i) {
+		if ( i==0 ) {
+			return 0; // undefined
+		}
+		if ( i<0 ) {
+			i++; // e.g., translate LA(-1) to use offset i=0; then data[p+0-1]
+			if ( (p+i-1) < 0 ) {
+				return CharStream.EOF; // invalid; no char before first char
+			}
+		}
+
+		if ( (p+i-1) >= n ) {
+            //System.out.println("char LA("+i+")=EOF; p="+p);
+            return CharStream.EOF;
+        }
+        //System.out.println("char LA("+i+")="+(char)data[p+i-1]+"; p="+p);
+		//System.out.println("LA("+i+"); p="+p+" n="+n+" data.length="+data.length);
+		return data[p+i-1];
+    }
+
+	public int LT(int i) {
+		return LA(i);
+	}
+
+	/** Return the current input symbol index 0..n where n indicates the
+     *  last symbol has been read.  The index is the index of char to
+	 *  be returned from LA(1).
+     */
+    public int index() {
+        return p;
+    }
+
+	public int size() {
+		return n;
+	}
+
+	public int mark() {
+        if ( markers==null ) {
+            markers = new ArrayList();
+            markers.add(null); // depth 0 means no backtracking, leave blank
+        }
+        markDepth++;
+		CharStreamState state = null;
+		if ( markDepth>=markers.size() ) {
+			state = new CharStreamState();
+			markers.add(state);
+		}
+		else {
+			state = (CharStreamState)markers.get(markDepth);
+		}
+		state.p = p;
+		state.line = line;
+		state.charPositionInLine = charPositionInLine;
+		lastMarker = markDepth;
+		return markDepth;
+    }
+
+    public void rewind(int m) {
+		CharStreamState state = (CharStreamState)markers.get(m);
+		// restore stream state
+		seek(state.p);
+		line = state.line;
+		charPositionInLine = state.charPositionInLine;
+		release(m);
+	}
+
+	public void rewind() {
+		rewind(lastMarker);
+	}
+
+	public void release(int marker) {
+		// unwind any other markers made after m and release m
+		markDepth = marker;
+		// release this marker
+		markDepth--;
+	}
+
+	/** consume() ahead until p==index; can't just set p=index as we must
+	 *  update line and charPositionInLine.
+	 */
+	public void seek(int index) {
+		if ( index<=p ) {
+			p = index; // just jump; don't update stream state (line, ...)
+			return;
+		}
+		// seek forward, consume until p hits index
+		while ( p<index ) {
+			consume();
+		}
+	}
+
+	public String substring(int start, int stop) {
+		return new String(data,start,stop-start+1);
+	}
+
+	public int getLine() {
+		return line;
+	}
+
+	public int getCharPositionInLine() {
+		return charPositionInLine;
+	}
+
+	public void setLine(int line) {
+		this.line = line;
+	}
+
+	public void setCharPositionInLine(int pos) {
+		this.charPositionInLine = pos;
+	}
+
+	public String getSourceName() {
+		return name;
+	}
+
+    public String toString() { return new String(data); }
+}
diff --git a/src/org/antlr/runtime/BaseRecognizer.java b/src/org/antlr/runtime/BaseRecognizer.java
new file mode 100755
index 0000000..667664d
--- /dev/null
+++ b/src/org/antlr/runtime/BaseRecognizer.java
@@ -0,0 +1,886 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/** A generic recognizer that can handle recognizers generated from
+ *  lexer, parser, and tree grammars.  This is all the parsing
+ *  support code essentially; most of it is error recovery stuff and
+ *  backtracking.
+ */
+public abstract class BaseRecognizer {
+	public static final int MEMO_RULE_FAILED = -2;
+	public static final int MEMO_RULE_UNKNOWN = -1;
+	public static final int INITIAL_FOLLOW_STACK_SIZE = 100;
+
+	// copies from Token object for convenience in actions
+	public static final int DEFAULT_TOKEN_CHANNEL = Token.DEFAULT_CHANNEL;
+	public static final int HIDDEN = Token.HIDDEN_CHANNEL;
+
+	public static final String NEXT_TOKEN_RULE_NAME = "nextToken";
+
+	/** State of a lexer, parser, or tree parser are collected into a state
+	 *  object so the state can be shared.  This sharing is needed to
+	 *  have one grammar import others and share same error variables
+	 *  and other state variables.  It's a kind of explicit multiple
+	 *  inheritance via delegation of methods and shared state.
+	 */
+	protected RecognizerSharedState state;
+
+	public BaseRecognizer() {
+		state = new RecognizerSharedState();
+	}
+
+	public BaseRecognizer(RecognizerSharedState state) {
+		if ( state==null ) {
+			state = new RecognizerSharedState();
+		}
+		this.state = state;
+	}
+
+	/** reset the parser's state; subclasses must rewinds the input stream */
+	public void reset() {
+		// wack everything related to error recovery
+		if ( state==null ) {
+			return; // no shared state work to do
+		}
+		state._fsp = -1;
+		state.errorRecovery = false;
+		state.lastErrorIndex = -1;
+		state.failed = false;
+		state.syntaxErrors = 0;
+		// wack everything related to backtracking and memoization
+		state.backtracking = 0;
+		for (int i = 0; state.ruleMemo!=null && i < state.ruleMemo.length; i++) { // wipe cache
+			state.ruleMemo[i] = null;
+		}
+	}
+
+
+	/** Match current input symbol against ttype.  Attempt
+	 *  single token insertion or deletion error recovery.  If
+	 *  that fails, throw MismatchedTokenException.
+	 *
+	 *  To turn off single token insertion or deletion error
+	 *  recovery, override recoverFromMismatchedToken() and have it
+     *  throw an exception. See TreeParser.recoverFromMismatchedToken().
+     *  This way any error in a rule will cause an exception and
+     *  immediate exit from rule.  Rule would recover by resynchronizing
+     *  to the set of symbols that can follow rule ref.
+	 */
+	public Object match(IntStream input, int ttype, BitSet follow)
+		throws RecognitionException
+	{
+		//System.out.println("match "+((TokenStream)input).LT(1));
+		Object matchedSymbol = getCurrentInputSymbol(input);
+		if ( input.LA(1)==ttype ) {
+			input.consume();
+			state.errorRecovery = false;
+			state.failed = false;
+			return matchedSymbol;
+		}
+		if ( state.backtracking>0 ) {
+			state.failed = true;
+			return matchedSymbol;
+		}
+		matchedSymbol = recoverFromMismatchedToken(input, ttype, follow);
+		return matchedSymbol;
+	}
+
+	/** Match the wildcard: in a symbol */
+	public void matchAny(IntStream input) {
+		state.errorRecovery = false;
+		state.failed = false;
+		input.consume();
+	}
+
+	public boolean mismatchIsUnwantedToken(IntStream input, int ttype) {
+		return input.LA(2)==ttype;
+	}
+
+	public boolean mismatchIsMissingToken(IntStream input, BitSet follow) {
+		if ( follow==null ) {
+			// we have no information about the follow; we can only consume
+			// a single token and hope for the best
+			return false;
+		}
+		// compute what can follow this grammar element reference
+		if ( follow.member(Token.EOR_TOKEN_TYPE) ) {
+			BitSet viableTokensFollowingThisRule = computeContextSensitiveRuleFOLLOW();
+			follow = follow.or(viableTokensFollowingThisRule);
+            if ( state._fsp>=0 ) { // remove EOR if we're not the start symbol
+                follow.remove(Token.EOR_TOKEN_TYPE);
+            }
+		}
+		// if current token is consistent with what could come after set
+		// then we know we're missing a token; error recovery is free to
+		// "insert" the missing token
+
+		//System.out.println("viable tokens="+follow.toString(getTokenNames()));
+		//System.out.println("LT(1)="+((TokenStream)input).LT(1));
+
+		// BitSet cannot handle negative numbers like -1 (EOF) so I leave EOR
+		// in follow set to indicate that the fall of the start symbol is
+		// in the set (EOF can follow).
+		if ( follow.member(input.LA(1)) || follow.member(Token.EOR_TOKEN_TYPE) ) {
+			//System.out.println("LT(1)=="+((TokenStream)input).LT(1)+" is consistent with what follows; inserting...");
+			return true;
+		}
+		return false;
+	}
+
+	/** Report a recognition problem.
+	 *
+	 *  This method sets errorRecovery to indicate the parser is recovering
+	 *  not parsing.  Once in recovery mode, no errors are generated.
+	 *  To get out of recovery mode, the parser must successfully match
+	 *  a token (after a resync).  So it will go:
+	 *
+	 * 		1. error occurs
+	 * 		2. enter recovery mode, report error
+	 * 		3. consume until token found in resynch set
+	 * 		4. try to resume parsing
+	 * 		5. next match() will reset errorRecovery mode
+	 *
+	 *  If you override, make sure to update syntaxErrors if you care about that.
+	 */
+	public void reportError(RecognitionException e) {
+		// if we've already reported an error and have not matched a token
+		// yet successfully, don't report any errors.
+		if ( state.errorRecovery ) {
+			//System.err.print("[SPURIOUS] ");
+			return;
+		}
+		state.syntaxErrors++; // don't count spurious
+		state.errorRecovery = true;
+
+		displayRecognitionError(this.getTokenNames(), e);
+	}
+
+	public void displayRecognitionError(String[] tokenNames,
+										RecognitionException e)
+	{
+		String hdr = getErrorHeader(e);
+		String msg = getErrorMessage(e, tokenNames);
+		emitErrorMessage(hdr+" "+msg);
+	}
+
+	/** What error message should be generated for the various
+	 *  exception types?
+	 *
+	 *  Not very object-oriented code, but I like having all error message
+	 *  generation within one method rather than spread among all of the
+	 *  exception classes. This also makes it much easier for the exception
+	 *  handling because the exception classes do not have to have pointers back
+	 *  to this object to access utility routines and so on. Also, changing
+	 *  the message for an exception type would be difficult because you
+	 *  would have to subclassing exception, but then somehow get ANTLR
+	 *  to make those kinds of exception objects instead of the default.
+	 *  This looks weird, but trust me--it makes the most sense in terms
+	 *  of flexibility.
+	 *
+	 *  For grammar debugging, you will want to override this to add
+	 *  more information such as the stack frame with
+	 *  getRuleInvocationStack(e, this.getClass().getName()) and,
+	 *  for no viable alts, the decision description and state etc...
+	 *
+	 *  Override this to change the message generated for one or more
+	 *  exception types.
+	 */
+	public String getErrorMessage(RecognitionException e, String[] tokenNames) {
+		String msg = e.getMessage();
+		if ( e instanceof UnwantedTokenException ) {
+			UnwantedTokenException ute = (UnwantedTokenException)e;
+			String tokenName="<unknown>";
+			if ( ute.expecting== Token.EOF ) {
+				tokenName = "EOF";
+			}
+			else {
+				tokenName = tokenNames[ute.expecting];
+			}
+			msg = "extraneous input "+getTokenErrorDisplay(ute.getUnexpectedToken())+
+				" expecting "+tokenName;
+		}
+		else if ( e instanceof MissingTokenException ) {
+			MissingTokenException mte = (MissingTokenException)e;
+			String tokenName="<unknown>";
+			if ( mte.expecting== Token.EOF ) {
+				tokenName = "EOF";
+			}
+			else {
+				tokenName = tokenNames[mte.expecting];
+			}
+			msg = "missing "+tokenName+" at "+getTokenErrorDisplay(e.token);
+		}
+		else if ( e instanceof MismatchedTokenException ) {
+			MismatchedTokenException mte = (MismatchedTokenException)e;
+			String tokenName="<unknown>";
+			if ( mte.expecting== Token.EOF ) {
+				tokenName = "EOF";
+			}
+			else {
+				tokenName = tokenNames[mte.expecting];
+			}
+			msg = "mismatched input "+getTokenErrorDisplay(e.token)+
+				" expecting "+tokenName;
+		}
+		else if ( e instanceof MismatchedTreeNodeException ) {
+			MismatchedTreeNodeException mtne = (MismatchedTreeNodeException)e;
+			String tokenName="<unknown>";
+			if ( mtne.expecting==Token.EOF ) {
+				tokenName = "EOF";
+			}
+			else {
+				tokenName = tokenNames[mtne.expecting];
+			}
+			msg = "mismatched tree node: "+mtne.node+
+				" expecting "+tokenName;
+		}
+		else if ( e instanceof NoViableAltException ) {
+			//NoViableAltException nvae = (NoViableAltException)e;
+			// for development, can add "decision=<<"+nvae.grammarDecisionDescription+">>"
+			// and "(decision="+nvae.decisionNumber+") and
+			// "state "+nvae.stateNumber
+			msg = "no viable alternative at input "+getTokenErrorDisplay(e.token);
+		}
+		else if ( e instanceof EarlyExitException ) {
+			//EarlyExitException eee = (EarlyExitException)e;
+			// for development, can add "(decision="+eee.decisionNumber+")"
+			msg = "required (...)+ loop did not match anything at input "+
+				getTokenErrorDisplay(e.token);
+		}
+		else if ( e instanceof MismatchedSetException ) {
+			MismatchedSetException mse = (MismatchedSetException)e;
+			msg = "mismatched input "+getTokenErrorDisplay(e.token)+
+				" expecting set "+mse.expecting;
+		}
+		else if ( e instanceof MismatchedNotSetException ) {
+			MismatchedNotSetException mse = (MismatchedNotSetException)e;
+			msg = "mismatched input "+getTokenErrorDisplay(e.token)+
+				" expecting set "+mse.expecting;
+		}
+		else if ( e instanceof FailedPredicateException ) {
+			FailedPredicateException fpe = (FailedPredicateException)e;
+			msg = "rule "+fpe.ruleName+" failed predicate: {"+
+				fpe.predicateText+"}?";
+		}
+		return msg;
+	}
+
+	/** Get number of recognition errors (lexer, parser, tree parser).  Each
+	 *  recognizer tracks its own number.  So parser and lexer each have
+	 *  separate count.  Does not count the spurious errors found between
+	 *  an error and next valid token match
+	 *
+	 *  See also reportError()
+	 */
+	public int getNumberOfSyntaxErrors() {
+		return state.syntaxErrors;
+	}
+
+	/** What is the error header, normally line/character position information? */
+	public String getErrorHeader(RecognitionException e) {
+		if ( getSourceName()!=null )
+			return getSourceName()+" line "+e.line+":"+e.charPositionInLine;
+				
+		return "line "+e.line+":"+e.charPositionInLine;
+	}
+
+	/** How should a token be displayed in an error message? The default
+	 *  is to display just the text, but during development you might
+	 *  want to have a lot of information spit out.  Override in that case
+	 *  to use t.toString() (which, for CommonToken, dumps everything about
+	 *  the token). This is better than forcing you to override a method in
+	 *  your token objects because you don't have to go modify your lexer
+	 *  so that it creates a new Java type.
+	 */
+	public String getTokenErrorDisplay(Token t) {
+		String s = t.getText();
+		if ( s==null ) {
+			if ( t.getType()==Token.EOF ) {
+				s = "<EOF>";
+			}
+			else {
+				s = "<"+t.getType()+">";
+			}
+		}
+		s = s.replaceAll("\n","\\\\n");
+		s = s.replaceAll("\r","\\\\r");
+		s = s.replaceAll("\t","\\\\t");
+		return "'"+s+"'";
+	}
+
+	/** Override this method to change where error messages go */
+	public void emitErrorMessage(String msg) {
+		System.err.println(msg);
+	}
+
+	/** Recover from an error found on the input stream.  This is
+	 *  for NoViableAlt and mismatched symbol exceptions.  If you enable
+	 *  single token insertion and deletion, this will usually not
+	 *  handle mismatched symbol exceptions but there could be a mismatched
+	 *  token that the match() routine could not recover from.
+	 */
+	public void recover(IntStream input, RecognitionException re) {
+		if ( state.lastErrorIndex==input.index() ) {
+			// uh oh, another error at same token index; must be a case
+			// where LT(1) is in the recovery token set so nothing is
+			// consumed; consume a single token so at least to prevent
+			// an infinite loop; this is a failsafe.
+			input.consume();
+		}
+		state.lastErrorIndex = input.index();
+		BitSet followSet = computeErrorRecoverySet();
+		beginResync();
+		consumeUntil(input, followSet);
+		endResync();
+	}
+
+	/** A hook to listen in on the token consumption during error recovery.
+	 *  The DebugParser subclasses this to fire events to the listenter.
+	 */
+	public void beginResync() {
+	}
+
+	public void endResync() {
+	}
+
+	/*  Compute the error recovery set for the current rule.  During
+	 *  rule invocation, the parser pushes the set of tokens that can
+	 *  follow that rule reference on the stack; this amounts to
+	 *  computing FIRST of what follows the rule reference in the
+	 *  enclosing rule. This local follow set only includes tokens
+	 *  from within the rule; i.e., the FIRST computation done by
+	 *  ANTLR stops at the end of a rule.
+	 *
+	 *  EXAMPLE
+	 *
+	 *  When you find a "no viable alt exception", the input is not
+	 *  consistent with any of the alternatives for rule r.  The best
+	 *  thing to do is to consume tokens until you see something that
+	 *  can legally follow a call to r *or* any rule that called r.
+	 *  You don't want the exact set of viable next tokens because the
+	 *  input might just be missing a token--you might consume the
+	 *  rest of the input looking for one of the missing tokens.
+	 *
+	 *  Consider grammar:
+	 *
+	 *  a : '[' b ']'
+	 *    | '(' b ')'
+	 *    ;
+	 *  b : c '^' INT ;
+	 *  c : ID
+	 *    | INT
+	 *    ;
+	 *
+	 *  At each rule invocation, the set of tokens that could follow
+	 *  that rule is pushed on a stack.  Here are the various "local"
+	 *  follow sets:
+	 *
+	 *  FOLLOW(b1_in_a) = FIRST(']') = ']'
+	 *  FOLLOW(b2_in_a) = FIRST(')') = ')'
+	 *  FOLLOW(c_in_b) = FIRST('^') = '^'
+	 *
+	 *  Upon erroneous input "[]", the call chain is
+	 *
+	 *  a -> b -> c
+	 *
+	 *  and, hence, the follow context stack is:
+	 *
+	 *  depth  local follow set     after call to rule
+	 *    0         <EOF>                    a (from main())
+	 *    1          ']'                     b
+	 *    3          '^'                     c
+	 *
+	 *  Notice that ')' is not included, because b would have to have
+	 *  been called from a different context in rule a for ')' to be
+	 *  included.
+	 *
+	 *  For error recovery, we cannot consider FOLLOW(c)
+	 *  (context-sensitive or otherwise).  We need the combined set of
+	 *  all context-sensitive FOLLOW sets--the set of all tokens that
+	 *  could follow any reference in the call chain.  We need to
+	 *  resync to one of those tokens.  Note that FOLLOW(c)='^' and if
+	 *  we resync'd to that token, we'd consume until EOF.  We need to
+	 *  sync to context-sensitive FOLLOWs for a, b, and c: {']','^'}.
+	 *  In this case, for input "[]", LA(1) is in this set so we would
+	 *  not consume anything and after printing an error rule c would
+	 *  return normally.  It would not find the required '^' though.
+	 *  At this point, it gets a mismatched token error and throws an
+	 *  exception (since LA(1) is not in the viable following token
+	 *  set).  The rule exception handler tries to recover, but finds
+	 *  the same recovery set and doesn't consume anything.  Rule b
+	 *  exits normally returning to rule a.  Now it finds the ']' (and
+	 *  with the successful match exits errorRecovery mode).
+	 *
+	 *  So, you cna see that the parser walks up call chain looking
+	 *  for the token that was a member of the recovery set.
+	 *
+	 *  Errors are not generated in errorRecovery mode.
+	 *
+	 *  ANTLR's error recovery mechanism is based upon original ideas:
+	 *
+	 *  "Algorithms + Data Structures = Programs" by Niklaus Wirth
+	 *
+	 *  and
+	 *
+	 *  "A note on error recovery in recursive descent parsers":
+	 *  http://portal.acm.org/citation.cfm?id=947902.947905
+	 *
+	 *  Later, Josef Grosch had some good ideas:
+	 *
+	 *  "Efficient and Comfortable Error Recovery in Recursive Descent
+	 *  Parsers":
+	 *  ftp://www.cocolab.com/products/cocktail/doca4.ps/ell.ps.zip
+	 *
+	 *  Like Grosch I implemented local FOLLOW sets that are combined
+	 *  at run-time upon error to avoid overhead during parsing.
+	 */
+	protected BitSet computeErrorRecoverySet() {
+		return combineFollows(false);
+	}
+
+	/** Compute the context-sensitive FOLLOW set for current rule.
+	 *  This is set of token types that can follow a specific rule
+	 *  reference given a specific call chain.  You get the set of
+	 *  viable tokens that can possibly come next (lookahead depth 1)
+	 *  given the current call chain.  Contrast this with the
+	 *  definition of plain FOLLOW for rule r:
+	 *
+	 *   FOLLOW(r)={x | S=>*alpha r beta in G and x in FIRST(beta)}
+	 *
+	 *  where x in T* and alpha, beta in V*; T is set of terminals and
+	 *  V is the set of terminals and nonterminals.  In other words,
+	 *  FOLLOW(r) is the set of all tokens that can possibly follow
+	 *  references to r in *any* sentential form (context).  At
+	 *  runtime, however, we know precisely which context applies as
+	 *  we have the call chain.  We may compute the exact (rather
+	 *  than covering superset) set of following tokens.
+	 *
+	 *  For example, consider grammar:
+	 *
+	 *  stat : ID '=' expr ';'      // FOLLOW(stat)=={EOF}
+	 *       | "return" expr '.'
+	 *       ;
+	 *  expr : atom ('+' atom)* ;   // FOLLOW(expr)=={';','.',')'}
+	 *  atom : INT                  // FOLLOW(atom)=={'+',')',';','.'}
+	 *       | '(' expr ')'
+	 *       ;
+	 *
+	 *  The FOLLOW sets are all inclusive whereas context-sensitive
+	 *  FOLLOW sets are precisely what could follow a rule reference.
+	 *  For input input "i=(3);", here is the derivation:
+	 *
+	 *  stat => ID '=' expr ';'
+	 *       => ID '=' atom ('+' atom)* ';'
+	 *       => ID '=' '(' expr ')' ('+' atom)* ';'
+	 *       => ID '=' '(' atom ')' ('+' atom)* ';'
+	 *       => ID '=' '(' INT ')' ('+' atom)* ';'
+	 *       => ID '=' '(' INT ')' ';'
+	 *
+	 *  At the "3" token, you'd have a call chain of
+	 *
+	 *    stat -> expr -> atom -> expr -> atom
+	 *
+	 *  What can follow that specific nested ref to atom?  Exactly ')'
+	 *  as you can see by looking at the derivation of this specific
+	 *  input.  Contrast this with the FOLLOW(atom)={'+',')',';','.'}.
+	 *
+	 *  You want the exact viable token set when recovering from a
+	 *  token mismatch.  Upon token mismatch, if LA(1) is member of
+	 *  the viable next token set, then you know there is most likely
+	 *  a missing token in the input stream.  "Insert" one by just not
+	 *  throwing an exception.
+	 */
+	protected BitSet computeContextSensitiveRuleFOLLOW() {
+		return combineFollows(true);
+	}
+
+	// what is exact? it seems to only add sets from above on stack
+	// if EOR is in set i.  When it sees a set w/o EOR, it stops adding.
+	// Why would we ever want them all?  Maybe no viable alt instead of
+	// mismatched token?
+	protected BitSet combineFollows(boolean exact) {
+		int top = state._fsp;
+		BitSet followSet = new BitSet();
+		for (int i=top; i>=0; i--) {
+			BitSet localFollowSet = (BitSet)state.following[i];
+			/*
+			System.out.println("local follow depth "+i+"="+
+							   localFollowSet.toString(getTokenNames())+")");
+			 */
+			followSet.orInPlace(localFollowSet);
+			if ( exact ) {
+				// can we see end of rule?
+				if ( localFollowSet.member(Token.EOR_TOKEN_TYPE) ) {
+					// Only leave EOR in set if at top (start rule); this lets
+					// us know if have to include follow(start rule); i.e., EOF
+					if ( i>0 ) {
+						followSet.remove(Token.EOR_TOKEN_TYPE);
+					}
+				}
+				else { // can't see end of rule, quit
+					break;
+				}
+			}
+		}
+		return followSet;
+	}
+
+	/** Attempt to recover from a single missing or extra token.
+	 *
+	 *  EXTRA TOKEN
+	 *
+	 *  LA(1) is not what we are looking for.  If LA(2) has the right token,
+	 *  however, then assume LA(1) is some extra spurious token.  Delete it
+	 *  and LA(2) as if we were doing a normal match(), which advances the
+	 *  input.
+	 *
+	 *  MISSING TOKEN
+	 *
+	 *  If current token is consistent with what could come after
+	 *  ttype then it is ok to "insert" the missing token, else throw
+	 *  exception For example, Input "i=(3;" is clearly missing the
+	 *  ')'.  When the parser returns from the nested call to expr, it
+	 *  will have call chain:
+	 *
+	 *    stat -> expr -> atom
+	 *
+	 *  and it will be trying to match the ')' at this point in the
+	 *  derivation:
+	 *
+	 *       => ID '=' '(' INT ')' ('+' atom)* ';'
+	 *                          ^
+	 *  match() will see that ';' doesn't match ')' and report a
+	 *  mismatched token error.  To recover, it sees that LA(1)==';'
+	 *  is in the set of tokens that can follow the ')' token
+	 *  reference in rule atom.  It can assume that you forgot the ')'.
+	 */
+	protected Object recoverFromMismatchedToken(IntStream input, int ttype, BitSet follow)
+		throws RecognitionException
+	{
+		RecognitionException e = null;
+		// if next token is what we are looking for then "delete" this token
+		if ( mismatchIsUnwantedToken(input, ttype) ) {
+			e = new UnwantedTokenException(ttype, input);
+			/*
+			System.err.println("recoverFromMismatchedToken deleting "+
+							   ((TokenStream)input).LT(1)+
+							   " since "+((TokenStream)input).LT(2)+" is what we want");
+			 */
+			beginResync();
+			input.consume(); // simply delete extra token
+			endResync();
+			reportError(e);  // report after consuming so AW sees the token in the exception
+			// we want to return the token we're actually matching
+			Object matchedSymbol = getCurrentInputSymbol(input);
+			input.consume(); // move past ttype token as if all were ok
+			return matchedSymbol;
+		}
+		// can't recover with single token deletion, try insertion
+		if ( mismatchIsMissingToken(input, follow) ) {
+			Object inserted = getMissingSymbol(input, e, ttype, follow);
+			e = new MissingTokenException(ttype, input, inserted);
+			reportError(e);  // report after inserting so AW sees the token in the exception
+			return inserted;
+		}
+		// even that didn't work; must throw the exception
+		e = new MismatchedTokenException(ttype, input);
+		throw e;
+	}
+
+	/** Not currently used */
+	public Object recoverFromMismatchedSet(IntStream input,
+										   RecognitionException e,
+										   BitSet follow)
+		throws RecognitionException
+	{
+		if ( mismatchIsMissingToken(input, follow) ) {
+			// System.out.println("missing token");
+			reportError(e);
+			// we don't know how to conjure up a token for sets yet
+			return getMissingSymbol(input, e, Token.INVALID_TOKEN_TYPE, follow);
+		}
+		// TODO do single token deletion like above for Token mismatch
+		throw e;
+	}
+
+	/** Match needs to return the current input symbol, which gets put
+	 *  into the label for the associated token ref; e.g., x=ID.  Token
+	 *  and tree parsers need to return different objects. Rather than test
+	 *  for input stream type or change the IntStream interface, I use
+	 *  a simple method to ask the recognizer to tell me what the current
+	 *  input symbol is.
+	 * 
+	 *  This is ignored for lexers.
+	 */
+	protected Object getCurrentInputSymbol(IntStream input) { return null; }
+
+	/** Conjure up a missing token during error recovery.
+	 *
+	 *  The recognizer attempts to recover from single missing
+	 *  symbols. But, actions might refer to that missing symbol.
+	 *  For example, x=ID {f($x);}. The action clearly assumes
+	 *  that there has been an identifier matched previously and that
+	 *  $x points at that token. If that token is missing, but
+	 *  the next token in the stream is what we want we assume that
+	 *  this token is missing and we keep going. Because we
+	 *  have to return some token to replace the missing token,
+	 *  we have to conjure one up. This method gives the user control
+	 *  over the tokens returned for missing tokens. Mostly,
+	 *  you will want to create something special for identifier
+	 *  tokens. For literals such as '{' and ',', the default
+	 *  action in the parser or tree parser works. It simply creates
+	 *  a CommonToken of the appropriate type. The text will be the token.
+	 *  If you change what tokens must be created by the lexer,
+	 *  override this method to create the appropriate tokens.
+	 */
+	protected Object getMissingSymbol(IntStream input,
+									  RecognitionException e,
+									  int expectedTokenType,
+									  BitSet follow)
+	{
+		return null;
+	}
+
+	public void consumeUntil(IntStream input, int tokenType) {
+		//System.out.println("consumeUntil "+tokenType);
+		int ttype = input.LA(1);
+		while (ttype != Token.EOF && ttype != tokenType) {
+			input.consume();
+			ttype = input.LA(1);
+		}
+	}
+
+	/** Consume tokens until one matches the given token set */
+	public void consumeUntil(IntStream input, BitSet set) {
+		//System.out.println("consumeUntil("+set.toString(getTokenNames())+")");
+		int ttype = input.LA(1);
+		while (ttype != Token.EOF && !set.member(ttype) ) {
+			//System.out.println("consume during recover LA(1)="+getTokenNames()[input.LA(1)]);
+			input.consume();
+			ttype = input.LA(1);
+		}
+	}
+
+	/** Push a rule's follow set using our own hardcoded stack */
+	protected void pushFollow(BitSet fset) {
+		if ( (state._fsp +1)>=state.following.length ) {
+			BitSet[] f = new BitSet[state.following.length*2];
+			System.arraycopy(state.following, 0, f, 0, state.following.length);
+			state.following = f;
+		}
+		state.following[++state._fsp] = fset;
+	}
+
+	/** Return List<String> of the rules in your parser instance
+	 *  leading up to a call to this method.  You could override if
+	 *  you want more details such as the file/line info of where
+	 *  in the parser java code a rule is invoked.
+	 *
+	 *  This is very useful for error messages and for context-sensitive
+	 *  error recovery.
+	 */
+	public List getRuleInvocationStack() {
+		String parserClassName = getClass().getName();
+		return getRuleInvocationStack(new Throwable(), parserClassName);
+	}
+
+	/** A more general version of getRuleInvocationStack where you can
+	 *  pass in, for example, a RecognitionException to get it's rule
+	 *  stack trace.  This routine is shared with all recognizers, hence,
+	 *  static.
+	 *
+	 *  TODO: move to a utility class or something; weird having lexer call this
+	 */
+	public static List getRuleInvocationStack(Throwable e,
+											  String recognizerClassName)
+	{
+		List rules = new ArrayList();
+		StackTraceElement[] stack = e.getStackTrace();
+		int i = 0;
+		for (i=stack.length-1; i>=0; i--) {
+			StackTraceElement t = stack[i];
+			if ( t.getClassName().startsWith("org.antlr.runtime.") ) {
+				continue; // skip support code such as this method
+			}
+			if ( t.getMethodName().equals(NEXT_TOKEN_RULE_NAME) ) {
+				continue;
+			}
+			if ( !t.getClassName().equals(recognizerClassName) ) {
+				continue; // must not be part of this parser
+			}
+            rules.add(t.getMethodName());
+		}
+		return rules;
+	}
+
+    public int getBacktrackingLevel() { return state.backtracking; }
+
+    public void setBacktrackingLevel(int n) { state.backtracking = n; }
+
+    /** Return whether or not a backtracking attempt failed. */
+    public boolean failed() { return state.failed; }
+
+	/** Used to print out token names like ID during debugging and
+	 *  error reporting.  The generated parsers implement a method
+	 *  that overrides this to point to their String[] tokenNames.
+	 */
+	public String[] getTokenNames() {
+		return null;
+	}
+
+	/** For debugging and other purposes, might want the grammar name.
+	 *  Have ANTLR generate an implementation for this method.
+	 */
+	public String getGrammarFileName() {
+		return null;
+	}
+
+	public abstract String getSourceName();
+
+	/** A convenience method for use most often with template rewrites.
+	 *  Convert a List<Token> to List<String>
+	 */
+	public List toStrings(List tokens) {
+		if ( tokens==null ) return null;
+		List strings = new ArrayList(tokens.size());
+		for (int i=0; i<tokens.size(); i++) {
+			strings.add(((Token)tokens.get(i)).getText());
+		}
+		return strings;
+	}
+
+	/** Given a rule number and a start token index number, return
+	 *  MEMO_RULE_UNKNOWN if the rule has not parsed input starting from
+	 *  start index.  If this rule has parsed input starting from the
+	 *  start index before, then return where the rule stopped parsing.
+	 *  It returns the index of the last token matched by the rule.
+	 *
+	 *  For now we use a hashtable and just the slow Object-based one.
+	 *  Later, we can make a special one for ints and also one that
+	 *  tosses out data after we commit past input position i.
+	 */
+	public int getRuleMemoization(int ruleIndex, int ruleStartIndex) {
+		if ( state.ruleMemo[ruleIndex]==null ) {
+			state.ruleMemo[ruleIndex] = new HashMap();
+		}
+		Integer stopIndexI =
+			(Integer)state.ruleMemo[ruleIndex].get(new Integer(ruleStartIndex));
+		if ( stopIndexI==null ) {
+			return MEMO_RULE_UNKNOWN;
+		}
+		return stopIndexI.intValue();
+	}
+
+	/** Has this rule already parsed input at the current index in the
+	 *  input stream?  Return the stop token index or MEMO_RULE_UNKNOWN.
+	 *  If we attempted but failed to parse properly before, return
+	 *  MEMO_RULE_FAILED.
+	 *
+	 *  This method has a side-effect: if we have seen this input for
+	 *  this rule and successfully parsed before, then seek ahead to
+	 *  1 past the stop token matched for this rule last time.
+	 */
+	public boolean alreadyParsedRule(IntStream input, int ruleIndex) {
+		int stopIndex = getRuleMemoization(ruleIndex, input.index());
+		if ( stopIndex==MEMO_RULE_UNKNOWN ) {
+			return false;
+		}
+		if ( stopIndex==MEMO_RULE_FAILED ) {
+			//System.out.println("rule "+ruleIndex+" will never succeed");
+			state.failed=true;
+		}
+		else {
+			//System.out.println("seen rule "+ruleIndex+" before; skipping ahead to @"+(stopIndex+1)+" failed="+state.failed);
+			input.seek(stopIndex+1); // jump to one past stop token
+		}
+		return true;
+	}
+
+	/** Record whether or not this rule parsed the input at this position
+	 *  successfully.  Use a standard java hashtable for now.
+	 */
+	public void memoize(IntStream input,
+						int ruleIndex,
+						int ruleStartIndex)
+	{
+		int stopTokenIndex = state.failed?MEMO_RULE_FAILED:input.index()-1;
+		if ( state.ruleMemo==null ) {
+			System.err.println("!!!!!!!!! memo array is null for "+ getGrammarFileName());
+		}
+		if ( ruleIndex >= state.ruleMemo.length ) {
+			System.err.println("!!!!!!!!! memo size is "+state.ruleMemo.length+", but rule index is "+ruleIndex);
+		}
+		if ( state.ruleMemo[ruleIndex]!=null ) {
+			state.ruleMemo[ruleIndex].put(
+				new Integer(ruleStartIndex), new Integer(stopTokenIndex)
+			);
+		}
+	}
+
+	/** return how many rule/input-index pairs there are in total.
+	 *  TODO: this includes synpreds. :(
+	 */
+	public int getRuleMemoizationCacheSize() {
+		int n = 0;
+		for (int i = 0; state.ruleMemo!=null && i < state.ruleMemo.length; i++) {
+			Map ruleMap = state.ruleMemo[i];
+			if ( ruleMap!=null ) {
+				n += ruleMap.size(); // how many input indexes are recorded?
+			}
+		}
+		return n;
+	}
+
+	public void traceIn(String ruleName, int ruleIndex, Object inputSymbol)  {
+		System.out.print("enter "+ruleName+" "+inputSymbol);
+		if ( state.backtracking>0 ) {
+			System.out.print(" backtracking="+state.backtracking);
+		}
+		System.out.println();
+	}
+
+	public void traceOut(String ruleName,
+						 int ruleIndex,
+						 Object inputSymbol)
+	{
+		System.out.print("exit "+ruleName+" "+inputSymbol);
+		if ( state.backtracking>0 ) {
+            System.out.print(" backtracking="+state.backtracking);
+            if ( state.failed ) System.out.print(" failed");
+            else System.out.print(" succeeded");
+        }
+		System.out.println();
+	}
+
+}
diff --git a/src/org/antlr/runtime/BitSet.java b/src/org/antlr/runtime/BitSet.java
new file mode 100755
index 0000000..f013a26
--- /dev/null
+++ b/src/org/antlr/runtime/BitSet.java
@@ -0,0 +1,325 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime;
+
+import java.util.List;
+
+/**A stripped-down version of org.antlr.misc.BitSet that is just
+ * good enough to handle runtime requirements such as FOLLOW sets
+ * for automatic error recovery.
+ */
+public class BitSet implements Cloneable {
+    protected final static int BITS = 64;    // number of bits / long
+    protected final static int LOG_BITS = 6; // 2^6 == 64
+
+    /* We will often need to do a mod operator (i mod nbits).  Its
+     * turns out that, for powers of two, this mod operation is
+     * same as (i & (nbits-1)).  Since mod is slow, we use a
+     * precomputed mod mask to do the mod instead.
+     */
+    protected final static int MOD_MASK = BITS - 1;
+
+    /** The actual data bits */
+    protected long bits[];
+
+    /** Construct a bitset of size one word (64 bits) */
+    public BitSet() {
+        this(BITS);
+    }
+
+    /** Construction from a static array of longs */
+    public BitSet(long[] bits_) {
+        bits = bits_;
+    }
+
+	/** Construction from a list of integers */
+	public BitSet(List items) {
+		this();
+		for (int i = 0; i < items.size(); i++) {
+			Integer v = (Integer) items.get(i);
+			add(v.intValue());
+		}
+	}
+
+    /** Construct a bitset given the size
+     * @param nbits The size of the bitset in bits
+     */
+    public BitSet(int nbits) {
+        bits = new long[((nbits - 1) >> LOG_BITS) + 1];
+    }
+
+	public static BitSet of(int el) {
+		BitSet s = new BitSet(el + 1);
+		s.add(el);
+		return s;
+	}
+
+	public static BitSet of(int a, int b) {
+		BitSet s = new BitSet(Math.max(a,b)+1);
+		s.add(a);
+		s.add(b);
+		return s;
+	}
+
+	public static BitSet of(int a, int b, int c) {
+		BitSet s = new BitSet();
+		s.add(a);
+		s.add(b);
+		s.add(c);
+		return s;
+	}
+
+	public static BitSet of(int a, int b, int c, int d) {
+		BitSet s = new BitSet();
+		s.add(a);
+		s.add(b);
+		s.add(c);
+		s.add(d);
+		return s;
+	}
+
+	/** return this | a in a new set */
+	public BitSet or(BitSet a) {
+		if ( a==null ) {
+			return this;
+		}
+		BitSet s = (BitSet)this.clone();
+		s.orInPlace(a);
+		return s;
+	}
+
+	/** or this element into this set (grow as necessary to accommodate) */
+	public void add(int el) {
+		int n = wordNumber(el);
+		if (n >= bits.length) {
+			growToInclude(el);
+		}
+		bits[n] |= bitMask(el);
+	}
+
+	/**
+	 * Grows the set to a larger number of bits.
+	 * @param bit element that must fit in set
+	 */
+	public void growToInclude(int bit) {
+		int newSize = Math.max(bits.length << 1, numWordsToHold(bit));
+		long newbits[] = new long[newSize];
+		System.arraycopy(bits, 0, newbits, 0, bits.length);
+		bits = newbits;
+	}
+
+	public void orInPlace(BitSet a) {
+		if ( a==null ) {
+			return;
+		}
+		// If this is smaller than a, grow this first
+		if (a.bits.length > bits.length) {
+			setSize(a.bits.length);
+		}
+		int min = Math.min(bits.length, a.bits.length);
+		for (int i = min - 1; i >= 0; i--) {
+			bits[i] |= a.bits[i];
+		}
+	}
+
+	/**
+	 * Sets the size of a set.
+	 * @param nwords how many words the new set should be
+	 */
+	private void setSize(int nwords) {
+		long newbits[] = new long[nwords];
+		int n = Math.min(nwords, bits.length);
+		System.arraycopy(bits, 0, newbits, 0, n);
+		bits = newbits;
+	}
+
+    private final static long bitMask(int bitNumber) {
+        int bitPosition = bitNumber & MOD_MASK; // bitNumber mod BITS
+        return 1L << bitPosition;
+    }
+
+    public Object clone() {
+        BitSet s;
+        try {
+            s = (BitSet)super.clone();
+            s.bits = new long[bits.length];
+            System.arraycopy(bits, 0, s.bits, 0, bits.length);
+        }
+        catch (CloneNotSupportedException e) {
+            throw new InternalError();
+        }
+        return s;
+    }
+
+    public int size() {
+        int deg = 0;
+        for (int i = bits.length - 1; i >= 0; i--) {
+            long word = bits[i];
+            if (word != 0L) {
+                for (int bit = BITS - 1; bit >= 0; bit--) {
+                    if ((word & (1L << bit)) != 0) {
+                        deg++;
+                    }
+                }
+            }
+        }
+        return deg;
+    }
+
+    public boolean equals(Object other) {
+        if ( other == null || !(other instanceof BitSet) ) {
+            return false;
+        }
+
+        BitSet otherSet = (BitSet)other;
+
+        int n = Math.min(this.bits.length, otherSet.bits.length);
+
+        // for any bits in common, compare
+        for (int i=0; i<n; i++) {
+            if (this.bits[i] != otherSet.bits[i]) {
+                return false;
+            }
+        }
+
+        // make sure any extra bits are off
+
+        if (this.bits.length > n) {
+            for (int i = n+1; i<this.bits.length; i++) {
+                if (this.bits[i] != 0) {
+                    return false;
+                }
+            }
+        }
+        else if (otherSet.bits.length > n) {
+            for (int i = n+1; i<otherSet.bits.length; i++) {
+                if (otherSet.bits[i] != 0) {
+                    return false;
+                }
+            }
+        }
+
+        return true;
+    }
+
+    public boolean member(int el) {
+		if ( el<0 ) {
+			return false;
+		}
+        int n = wordNumber(el);
+        if (n >= bits.length) return false;
+        return (bits[n] & bitMask(el)) != 0;
+    }
+
+	// remove this element from this set
+	public void remove(int el) {
+		int n = wordNumber(el);
+		if (n < bits.length) {
+			bits[n] &= ~bitMask(el);
+		}
+	}
+
+    public boolean isNil() {
+        for (int i = bits.length - 1; i >= 0; i--) {
+            if (bits[i] != 0) return false;
+        }
+        return true;
+    }
+
+    private final int numWordsToHold(int el) {
+        return (el >> LOG_BITS) + 1;
+    }
+
+    public int numBits() {
+        return bits.length << LOG_BITS; // num words * bits per word
+    }
+
+    /** return how much space is being used by the bits array not
+     *  how many actually have member bits on.
+     */
+    public int lengthInLongWords() {
+        return bits.length;
+    }
+
+    /**Is this contained within a? */
+    /*
+	public boolean subset(BitSet a) {
+        if (a == null || !(a instanceof BitSet)) return false;
+        return this.and(a).equals(this);
+    }
+	*/
+
+    public int[] toArray() {
+        int[] elems = new int[size()];
+        int en = 0;
+        for (int i = 0; i < (bits.length << LOG_BITS); i++) {
+            if (member(i)) {
+                elems[en++] = i;
+            }
+        }
+        return elems;
+    }
+
+    public long[] toPackedArray() {
+        return bits;
+    }
+
+	private final static int wordNumber(int bit) {
+		return bit >> LOG_BITS; // bit / BITS
+	}
+
+	public String toString() {
+		return toString(null);
+	}
+
+	public String toString(String[] tokenNames) {
+		StringBuffer buf = new StringBuffer();
+		String separator = ",";
+		boolean havePrintedAnElement = false;
+		buf.append('{');
+
+		for (int i = 0; i < (bits.length << LOG_BITS); i++) {
+			if (member(i)) {
+				if (i > 0 && havePrintedAnElement ) {
+					buf.append(separator);
+				}
+				if ( tokenNames!=null ) {
+					buf.append(tokenNames[i]);
+				}
+				else {
+					buf.append(i);
+				}
+				havePrintedAnElement = true;
+			}
+		}
+		buf.append('}');
+		return buf.toString();
+	}
+
+
+}
diff --git a/src/org/antlr/runtime/BufferedTokenStream.java b/src/org/antlr/runtime/BufferedTokenStream.java
new file mode 100755
index 0000000..7742d4f
--- /dev/null
+++ b/src/org/antlr/runtime/BufferedTokenStream.java
@@ -0,0 +1,272 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.runtime;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.NoSuchElementException;
+
+/** Buffer all input tokens but do on-demand fetching of new tokens from
+ *  lexer. Useful when the parser or lexer has to set context/mode info before
+ *  proper lexing of future tokens. The ST template parser needs this,
+ *  for example, because it has to constantly flip back and forth between
+ *  inside/output templates. E.g., <names:{hi, <it>}> has to parse names
+ *  as part of an expression but "hi, <it>" as a nested template.
+ *
+ *  You can't use this stream if you pass whitespace or other off-channel
+ *  tokens to the parser. The stream can't ignore off-channel tokens.
+ *  (UnbufferedTokenStream is the same way.)
+ *
+ *  This is not a subclass of UnbufferedTokenStream because I don't want
+ *  to confuse small moving window of tokens it uses for the full buffer.
+ */
+public class BufferedTokenStream implements TokenStream {
+    protected TokenSource tokenSource;
+
+    /** Record every single token pulled from the source so we can reproduce
+     *  chunks of it later.  The buffer in LookaheadStream overlaps sometimes
+     *  as its moving window moves through the input.  This list captures
+     *  everything so we can access complete input text.
+     */
+    protected List<Token> tokens = new ArrayList<Token>(100);
+
+    /** Track the last mark() call result value for use in rewind(). */
+    protected int lastMarker;
+
+    /** The index into the tokens list of the current token (next token
+     *  to consume).  tokens[p] should be LT(1).  p=-1 indicates need
+     *  to initialize with first token.  The ctor doesn't get a token.
+     *  First call to LT(1) or whatever gets the first token and sets p=0;
+     */
+    protected int p = -1;
+
+	protected int range = -1; // how deep have we gone?
+
+    public BufferedTokenStream() {;}
+
+    public BufferedTokenStream(TokenSource tokenSource) {
+        this.tokenSource = tokenSource;
+    }
+
+    public TokenSource getTokenSource() { return tokenSource; }
+
+	public int index() { return p; }
+
+	public int range() { return range; }
+
+    public int mark() {
+        if ( p == -1 ) setup();
+		lastMarker = index();
+		return lastMarker;
+	}
+
+	public void release(int marker) {
+		// no resources to release
+	}
+
+    public void rewind(int marker) {
+        seek(marker);
+    }
+
+    public void rewind() {
+        seek(lastMarker);
+    }
+
+    public void reset() {
+        p = 0;
+        lastMarker = 0;
+    }
+
+    public void seek(int index) { p = index; }
+
+    public int size() { return tokens.size(); }
+
+    /** Move the input pointer to the next incoming token.  The stream
+     *  must become active with LT(1) available.  consume() simply
+     *  moves the input pointer so that LT(1) points at the next
+     *  input symbol. Consume at least one token.
+     *
+     *  Walk past any token not on the channel the parser is listening to.
+     */
+    public void consume() {
+        if ( p == -1 ) setup();
+        p++;
+        sync(p);
+    }
+
+    /** Make sure index i in tokens has a token. */
+    protected void sync(int i) {
+        int n = i - tokens.size() + 1; // how many more elements we need?
+        //System.out.println("sync("+i+") needs "+n);
+        if ( n > 0 ) fetch(n);
+    }
+
+    /** add n elements to buffer */
+    protected void fetch(int n) {
+        for (int i=1; i<=n; i++) {
+            Token t = tokenSource.nextToken();
+            t.setTokenIndex(tokens.size());
+            //System.out.println("adding "+t+" at index "+tokens.size());
+            tokens.add(t);
+            if ( t.getType()==Token.EOF ) break;
+        }
+    }
+
+    public Token get(int i) {
+        if ( i < 0 || i >= tokens.size() ) {
+            throw new NoSuchElementException("token index "+i+" out of range 0.."+(tokens.size()-1));
+        }
+        return tokens.get(i);
+    }
+
+	/** Get all tokens from start..stop inclusively */
+	public List get(int start, int stop) {
+		if ( start<0 || stop<0 ) return null;
+		if ( p == -1 ) setup();
+		List subset = new ArrayList();
+		if ( stop>=tokens.size() ) stop = tokens.size()-1;
+		for (int i = start; i <= stop; i++) {
+			Token t = tokens.get(i);
+			if ( t.getType()==Token.EOF ) break;
+			subset.add(t);
+		}
+		return subset;
+	}
+
+	public int LA(int i) { return LT(i).getType(); }
+
+    protected Token LB(int k) {
+        if ( (p-k)<0 ) return null;
+        return tokens.get(p-k);
+    }
+
+    public Token LT(int k) {
+        if ( p == -1 ) setup();
+        if ( k==0 ) return null;
+        if ( k < 0 ) return LB(-k);
+
+		int i = p + k - 1;
+		sync(i);
+        if ( i >= tokens.size() ) { // return EOF token
+            // EOF must be last token
+            return tokens.get(tokens.size()-1);
+        }
+		if ( i>range ) range = i; 		
+        return tokens.get(i);
+    }
+
+    protected void setup() { sync(0); p = 0; }
+
+    /** Reset this token stream by setting its token source. */
+    public void setTokenSource(TokenSource tokenSource) {
+        this.tokenSource = tokenSource;
+        tokens.clear();
+        p = -1;
+    }
+    
+    public List getTokens() { return tokens; }
+
+    public List getTokens(int start, int stop) {
+        return getTokens(start, stop, (BitSet)null);
+    }
+
+    /** Given a start and stop index, return a List of all tokens in
+     *  the token type BitSet.  Return null if no tokens were found.  This
+     *  method looks at both on and off channel tokens.
+     */
+    public List getTokens(int start, int stop, BitSet types) {
+        if ( p == -1 ) setup();
+        if ( stop>=tokens.size() ) stop=tokens.size()-1;
+        if ( start<0 ) start=0;
+        if ( start>stop ) return null;
+
+        // list = tokens[start:stop]:{Token t, t.getType() in types}
+        List<Token> filteredTokens = new ArrayList<Token>();
+        for (int i=start; i<=stop; i++) {
+            Token t = tokens.get(i);
+            if ( types==null || types.member(t.getType()) ) {
+                filteredTokens.add(t);
+            }
+        }
+        if ( filteredTokens.size()==0 ) {
+            filteredTokens = null;
+        }
+        return filteredTokens;
+    }
+
+    public List getTokens(int start, int stop, List types) {
+        return getTokens(start,stop,new BitSet(types));
+    }
+
+    public List getTokens(int start, int stop, int ttype) {
+        return getTokens(start,stop,BitSet.of(ttype));
+    }
+
+    public String getSourceName() {	return tokenSource.getSourceName();	}
+
+    /** Grab *all* tokens from stream and return string */
+    public String toString() {
+        if ( p == -1 ) setup();
+        fill();
+        return toString(0, tokens.size()-1);
+    }
+
+    public String toString(int start, int stop) {
+        if ( start<0 || stop<0 ) return null;
+        if ( p == -1 ) setup();
+        if ( stop>=tokens.size() ) stop = tokens.size()-1;
+        StringBuffer buf = new StringBuffer();
+        for (int i = start; i <= stop; i++) {
+            Token t = tokens.get(i);
+            if ( t.getType()==Token.EOF ) break;
+            buf.append(t.getText());
+        }
+        return buf.toString();
+    }
+
+    public String toString(Token start, Token stop) {
+        if ( start!=null && stop!=null ) {
+            return toString(start.getTokenIndex(), stop.getTokenIndex());
+        }
+        return null;
+    }
+
+    /** Get all tokens from lexer until EOF */
+    public void fill() {
+        if ( p == -1 ) setup();
+        if ( tokens.get(p).getType()==Token.EOF ) return;
+
+        int i = p+1;
+        sync(i);
+        while ( tokens.get(i).getType()!=Token.EOF ) {
+            i++;
+            sync(i);
+        }
+    }
+}
diff --git a/src/org/antlr/runtime/CharStream.java b/src/org/antlr/runtime/CharStream.java
new file mode 100755
index 0000000..db55755
--- /dev/null
+++ b/src/org/antlr/runtime/CharStream.java
@@ -0,0 +1,57 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime;
+
+/** A source of characters for an ANTLR lexer */
+public interface CharStream extends IntStream {
+    public static final int EOF = -1;
+
+	/** For infinite streams, you don't need this; primarily I'm providing
+	 *  a useful interface for action code.  Just make sure actions don't
+	 *  use this on streams that don't support it.
+	 */
+	public String substring(int start, int stop);
+
+	/** Get the ith character of lookahead.  This is the same usually as
+	 *  LA(i).  This will be used for labels in the generated
+	 *  lexer code.  I'd prefer to return a char here type-wise, but it's
+	 *  probably better to be 32-bit clean and be consistent with LA.
+	 */
+	public int LT(int i);
+
+	/** ANTLR tracks the line information automatically */
+	int getLine();
+
+	/** Because this stream can rewind, we need to be able to reset the line */
+	void setLine(int line);
+
+	void setCharPositionInLine(int pos);
+
+	/** The index of the character relative to the beginning of the line 0..n-1 */
+	int getCharPositionInLine();
+}
diff --git a/src/org/antlr/runtime/CharStreamState.java b/src/org/antlr/runtime/CharStreamState.java
new file mode 100755
index 0000000..04d969a
--- /dev/null
+++ b/src/org/antlr/runtime/CharStreamState.java
@@ -0,0 +1,45 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime;
+
+/** When walking ahead with cyclic DFA or for syntactic predicates,
+ *  we need to record the state of the input stream (char index,
+ *  line, etc...) so that we can rewind the state after scanning ahead.
+ *
+ *  This is the complete state of a stream.
+ */
+public class CharStreamState {
+	/** Index into the char stream of next lookahead char */
+	int p;
+
+	/** What line number is the scanner at before processing buffer[p]? */
+	int line;
+	
+	/** What char position 0..n-1 in line is scanner before processing buffer[p]? */
+	int charPositionInLine;
+}
diff --git a/src/org/antlr/runtime/ClassicToken.java b/src/org/antlr/runtime/ClassicToken.java
new file mode 100755
index 0000000..72c2bd9
--- /dev/null
+++ b/src/org/antlr/runtime/ClassicToken.java
@@ -0,0 +1,141 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime;
+
+/** A Token object like we'd use in ANTLR 2.x; has an actual string created
+ *  and associated with this object.  These objects are needed for imaginary
+ *  tree nodes that have payload objects.  We need to create a Token object
+ *  that has a string; the tree node will point at this token.  CommonToken
+ *  has indexes into a char stream and hence cannot be used to introduce
+ *  new strings.
+ */
+public class ClassicToken implements Token {
+	protected String text;
+	protected int type;
+	protected int line;
+	protected int charPositionInLine;
+	protected int channel=DEFAULT_CHANNEL;
+
+	/** What token number is this from 0..n-1 tokens */
+	protected int index;
+
+	public ClassicToken(int type) {
+		this.type = type;
+	}
+
+	public ClassicToken(Token oldToken) {
+		text = oldToken.getText();
+		type = oldToken.getType();
+		line = oldToken.getLine();
+		charPositionInLine = oldToken.getCharPositionInLine();
+		channel = oldToken.getChannel();
+	}
+
+	public ClassicToken(int type, String text) {
+		this.type = type;
+		this.text = text;
+	}
+
+	public ClassicToken(int type, String text, int channel) {
+		this.type = type;
+		this.text = text;
+		this.channel = channel;
+	}
+
+	public int getType() {
+		return type;
+	}
+
+	public void setLine(int line) {
+		this.line = line;
+	}
+
+	public String getText() {
+		return text;
+	}
+
+	public void setText(String text) {
+		this.text = text;
+	}
+
+	public int getLine() {
+		return line;
+	}
+
+	public int getCharPositionInLine() {
+		return charPositionInLine;
+	}
+
+	public void setCharPositionInLine(int charPositionInLine) {
+		this.charPositionInLine = charPositionInLine;
+	}
+
+	public int getChannel() {
+		return channel;
+	}
+
+	public void setChannel(int channel) {
+		this.channel = channel;
+	}
+
+	public void setType(int type) {
+		this.type = type;
+	}
+
+	public int getTokenIndex() {
+		return index;
+	}
+
+	public void setTokenIndex(int index) {
+		this.index = index;
+	}
+
+	public CharStream getInputStream() {
+		return null;
+	}
+
+	public void setInputStream(CharStream input) {
+	}
+	
+	public String toString() {
+		String channelStr = "";
+		if ( channel>0 ) {
+			channelStr=",channel="+channel;
+		}
+		String txt = getText();
+		if ( txt!=null ) {
+			txt = txt.replaceAll("\n","\\\\n");
+			txt = txt.replaceAll("\r","\\\\r");
+			txt = txt.replaceAll("\t","\\\\t");
+		}
+		else {
+			txt = "<no text>";
+		}
+		return "[@"+getTokenIndex()+",'"+txt+"',<"+type+">"+channelStr+","+line+":"+getCharPositionInLine()+"]";
+	}
+}
diff --git a/src/org/antlr/runtime/CommonToken.java b/src/org/antlr/runtime/CommonToken.java
new file mode 100755
index 0000000..f01e1f4
--- /dev/null
+++ b/src/org/antlr/runtime/CommonToken.java
@@ -0,0 +1,191 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime;
+
+import java.io.Serializable;
+
+public class CommonToken implements Token, Serializable {
+	protected int type;
+	protected int line;
+	protected int charPositionInLine = -1; // set to invalid position
+	protected int channel=DEFAULT_CHANNEL;
+	protected transient CharStream input;
+
+	/** We need to be able to change the text once in a while.  If
+	 *  this is non-null, then getText should return this.  Note that
+	 *  start/stop are not affected by changing this.
+	  */
+	protected String text;
+
+	/** What token number is this from 0..n-1 tokens; < 0 implies invalid index */
+	protected int index = -1;
+
+	/** The char position into the input buffer where this token starts */
+	protected int start;
+
+	/** The char position into the input buffer where this token stops */
+	protected int stop;
+
+	public CommonToken(int type) {
+		this.type = type;
+	}
+
+	public CommonToken(CharStream input, int type, int channel, int start, int stop) {
+		this.input = input;
+		this.type = type;
+		this.channel = channel;
+		this.start = start;
+		this.stop = stop;
+	}
+
+	public CommonToken(int type, String text) {
+		this.type = type;
+		this.channel = DEFAULT_CHANNEL;
+		this.text = text;
+	}
+
+	public CommonToken(Token oldToken) {
+		text = oldToken.getText();
+		type = oldToken.getType();
+		line = oldToken.getLine();
+		index = oldToken.getTokenIndex();
+		charPositionInLine = oldToken.getCharPositionInLine();
+		channel = oldToken.getChannel();
+        input = oldToken.getInputStream();
+		if ( oldToken instanceof CommonToken ) {
+			start = ((CommonToken)oldToken).start;
+			stop = ((CommonToken)oldToken).stop;
+		}
+	}
+
+	public int getType() {
+		return type;
+	}
+
+	public void setLine(int line) {
+		this.line = line;
+	}
+
+	public String getText() {
+		if ( text!=null ) {
+			return text;
+		}
+		if ( input==null ) {
+			return null;
+		}
+        if ( start<input.size() && stop<input.size() ) {
+		    text = input.substring(start,stop);
+        }
+        else {
+            text = "<EOF>";
+        }
+		return text;
+	}
+
+	/** Override the text for this token.  getText() will return this text
+	 *  rather than pulling from the buffer.  Note that this does not mean
+	 *  that start/stop indexes are not valid.  It means that that input
+	 *  was converted to a new string in the token object.
+	 */
+	public void setText(String text) {
+		this.text = text;
+	}
+
+	public int getLine() {
+		return line;
+	}
+
+	public int getCharPositionInLine() {
+		return charPositionInLine;
+	}
+
+	public void setCharPositionInLine(int charPositionInLine) {
+		this.charPositionInLine = charPositionInLine;
+	}
+
+	public int getChannel() {
+		return channel;
+	}
+
+	public void setChannel(int channel) {
+		this.channel = channel;
+	}
+
+	public void setType(int type) {
+		this.type = type;
+	}
+
+	public int getStartIndex() {
+		return start;
+	}
+
+	public void setStartIndex(int start) {
+		this.start = start;
+	}
+
+	public int getStopIndex() {
+		return stop;
+	}
+
+	public void setStopIndex(int stop) {
+		this.stop = stop;
+	}
+
+	public int getTokenIndex() {
+		return index;
+	}
+
+	public void setTokenIndex(int index) {
+		this.index = index;
+	}
+
+	public CharStream getInputStream() {
+		return input;
+	}
+
+	public void setInputStream(CharStream input) {
+		this.input = input;
+	}
+
+	public String toString() {
+		String channelStr = "";
+		if ( channel>0 ) {
+			channelStr=",channel="+channel;
+		}
+		String txt = getText();
+		if ( txt!=null ) {
+			txt = txt.replaceAll("\n","\\\\n");
+			txt = txt.replaceAll("\r","\\\\r");
+			txt = txt.replaceAll("\t","\\\\t");
+		}
+		else {
+			txt = "<no text>";
+		}
+		return "[@"+getTokenIndex()+","+start+":"+stop+"='"+txt+"',<"+type+">"+channelStr+","+line+":"+getCharPositionInLine()+"]";
+	}
+}
diff --git a/src/org/antlr/runtime/CommonTokenStream.java b/src/org/antlr/runtime/CommonTokenStream.java
new file mode 100755
index 0000000..28135a6
--- /dev/null
+++ b/src/org/antlr/runtime/CommonTokenStream.java
@@ -0,0 +1,153 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.runtime;
+
+/** The most common stream of tokens where every token is buffered up
+ *  and tokens are filtered for a certain channel (the parser will only
+ *  see these tokens).
+ *
+ *  Even though it buffers all of the tokens, this token stream pulls tokens
+ *  from the tokens source on demand. In other words, until you ask for a
+ *  token using consume(), LT(), etc. the stream does not pull from the lexer.
+ *
+ *  The only difference between this stream and BufferedTokenStream superclass
+ *  is that this stream knows how to ignore off channel tokens. There may be
+ *  a performance advantage to using the superclass if you don't pass
+ *  whitespace and comments etc. to the parser on a hidden channel (i.e.,
+ *  you set $channel instead of calling skip() in lexer rules.)
+ *
+ *  @see org.antlr.runtime.UnbufferedTokenStream
+ *  @see org.antlr.runtime.BufferedTokenStream
+ */
+public class CommonTokenStream extends BufferedTokenStream {
+    /** Skip tokens on any channel but this one; this is how we skip whitespace... */
+    protected int channel = Token.DEFAULT_CHANNEL;
+
+    public CommonTokenStream() { ; }
+
+    public CommonTokenStream(TokenSource tokenSource) {
+        super(tokenSource);
+    }
+
+    public CommonTokenStream(TokenSource tokenSource, int channel) {
+        this(tokenSource);
+        this.channel = channel;
+    }
+
+    /** Always leave p on an on-channel token. */
+    public void consume() {
+        if ( p == -1 ) setup();
+        p++;
+        sync(p);
+        while ( tokens.get(p).getChannel()!=channel ) {
+            p++;
+            sync(p);
+        }
+    }
+
+    protected Token LB(int k) {
+        if ( k==0 || (p-k)<0 ) return null;
+
+        int i = p;
+        int n = 1;
+        // find k good tokens looking backwards
+        while ( n<=k ) {
+            // skip off-channel tokens
+            i = skipOffTokenChannelsReverse(i-1);
+            n++;
+        }
+        if ( i<0 ) return null;
+        return tokens.get(i);
+    }
+
+    public Token LT(int k) {
+        //System.out.println("enter LT("+k+")");
+        if ( p == -1 ) setup();
+        if ( k == 0 ) return null;
+        if ( k < 0 ) return LB(-k);
+        int i = p;
+        int n = 1; // we know tokens[p] is a good one
+        // find k good tokens
+        while ( n<k ) {
+            // skip off-channel tokens
+            i = skipOffTokenChannels(i+1);
+            n++;
+        }
+		if ( i>range ) range = i;		
+        return tokens.get(i);
+    }
+
+    /** Given a starting index, return the index of the first on-channel
+     *  token.
+     */
+    protected int skipOffTokenChannels(int i) {
+        sync(i);
+        while ( tokens.get(i).getChannel()!=channel ) { // also stops at EOF (it's onchannel)
+            i++;
+            sync(i);
+        }
+        return i;
+    }
+
+    protected int skipOffTokenChannelsReverse(int i) {
+        while ( i>=0 && ((Token)tokens.get(i)).getChannel()!=channel ) {
+            i--;
+        }
+        return i;
+    }
+
+    protected void setup() {
+        p = 0;
+        sync(0);
+        int i = 0;
+        while ( tokens.get(i).getChannel()!=channel ) {
+            i++;
+            sync(i);
+        }
+        p = i;
+    }
+
+	/** Count EOF just once. */
+	public int getNumberOfOnChannelTokens() {
+		int n = 0;
+		fill();
+		for (int i = 0; i < tokens.size(); i++) {
+			Token t = tokens.get(i);
+			if ( t.getChannel()==channel ) n++;
+			if ( t.getType()==Token.EOF ) break;
+		}
+		return n;
+	}
+
+    /** Reset this token stream by setting its token source. */
+    public void setTokenSource(TokenSource tokenSource) {
+        super.setTokenSource(tokenSource);
+        channel = Token.DEFAULT_CHANNEL;
+    }
+}
diff --git a/src/org/antlr/runtime/DFA.java b/src/org/antlr/runtime/DFA.java
new file mode 100755
index 0000000..d1bebbc
--- /dev/null
+++ b/src/org/antlr/runtime/DFA.java
@@ -0,0 +1,229 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime;
+
+/** A DFA implemented as a set of transition tables.
+ *
+ *  Any state that has a semantic predicate edge is special; those states
+ *  are generated with if-then-else structures in a specialStateTransition()
+ *  which is generated by cyclicDFA template.
+ *
+ *  There are at most 32767 states (16-bit signed short).
+ *  Could get away with byte sometimes but would have to generate different
+ *  types and the simulation code too.  For a point of reference, the Java
+ *  lexer's Tokens rule DFA has 326 states roughly.
+ */
+public class DFA {
+	protected short[] eot;
+	protected short[] eof;
+	protected char[] min;
+    protected char[] max;
+    protected short[] accept;
+    protected short[] special;
+    protected short[][] transition;
+
+	protected int decisionNumber;
+
+	/** Which recognizer encloses this DFA?  Needed to check backtracking */
+	protected BaseRecognizer recognizer;
+
+	public static final boolean debug = false;
+
+	/** From the input stream, predict what alternative will succeed
+	 *  using this DFA (representing the covering regular approximation
+	 *  to the underlying CFL).  Return an alternative number 1..n.  Throw
+	 *  an exception upon error.
+	 */
+	public int predict(IntStream input)
+		throws RecognitionException
+	{
+		if ( debug ) {
+			System.err.println("Enter DFA.predict for decision "+decisionNumber);
+		}
+		int mark = input.mark(); // remember where decision started in input
+		int s = 0; // we always start at s0
+		try {
+			while ( true ) {
+				if ( debug ) System.err.println("DFA "+decisionNumber+" state "+s+" LA(1)="+(char)input.LA(1)+"("+input.LA(1)+
+												"), index="+input.index());
+				int specialState = special[s];
+				if ( specialState>=0 ) {
+					if ( debug ) {
+						System.err.println("DFA "+decisionNumber+
+							" state "+s+" is special state "+specialState);
+					}
+					s = specialStateTransition(specialState,input);
+					if ( debug ) {
+						System.err.println("DFA "+decisionNumber+
+							" returns from special state "+specialState+" to "+s);
+					}
+					if ( s==-1 ) {
+						noViableAlt(s,input);
+						return 0;
+					}
+					input.consume();
+					continue;
+				}
+				if ( accept[s] >= 1 ) {
+					if ( debug ) System.err.println("accept; predict "+accept[s]+" from state "+s);
+					return accept[s];
+				}
+				// look for a normal char transition
+				char c = (char)input.LA(1); // -1 == \uFFFF, all tokens fit in 65000 space
+				if (c>=min[s] && c<=max[s]) {
+					int snext = transition[s][c-min[s]]; // move to next state
+					if ( snext < 0 ) {
+						// was in range but not a normal transition
+						// must check EOT, which is like the else clause.
+						// eot[s]>=0 indicates that an EOT edge goes to another
+						// state.
+						if ( eot[s]>=0 ) {  // EOT Transition to accept state?
+							if ( debug ) System.err.println("EOT transition");
+							s = eot[s];
+							input.consume();
+							// TODO: I had this as return accept[eot[s]]
+							// which assumed here that the EOT edge always
+							// went to an accept...faster to do this, but
+							// what about predicated edges coming from EOT
+							// target?
+							continue;
+						}
+						noViableAlt(s,input);
+						return 0;
+					}
+					s = snext;
+					input.consume();
+					continue;
+				}
+				if ( eot[s]>=0 ) {  // EOT Transition?
+					if ( debug ) System.err.println("EOT transition");
+					s = eot[s];
+					input.consume();
+					continue;
+				}
+				if ( c==(char)Token.EOF && eof[s]>=0 ) {  // EOF Transition to accept state?
+					if ( debug ) System.err.println("accept via EOF; predict "+accept[eof[s]]+" from "+eof[s]);
+					return accept[eof[s]];
+				}
+				// not in range and not EOF/EOT, must be invalid symbol
+				if ( debug ) {
+					System.err.println("min["+s+"]="+min[s]);
+					System.err.println("max["+s+"]="+max[s]);
+					System.err.println("eot["+s+"]="+eot[s]);
+					System.err.println("eof["+s+"]="+eof[s]);
+					for (int p=0; p<transition[s].length; p++) {
+						System.err.print(transition[s][p]+" ");
+					}
+					System.err.println();
+				}
+				noViableAlt(s,input);
+				return 0;
+			}
+		}
+		finally {
+			input.rewind(mark);
+		}
+	}
+
+	protected void noViableAlt(int s, IntStream input) throws NoViableAltException {
+		if (recognizer.state.backtracking>0) {
+			recognizer.state.failed=true;
+			return;
+		}
+		NoViableAltException nvae =
+			new NoViableAltException(getDescription(),
+									 decisionNumber,
+									 s,
+									 input);
+		error(nvae);
+		throw nvae;
+	}
+
+	/** A hook for debugging interface */
+	protected void error(NoViableAltException nvae) { ; }
+
+	public int specialStateTransition(int s, IntStream input)
+		throws NoViableAltException
+	{
+		return -1;
+	}
+
+	public String getDescription() {
+		return "n/a";
+	}
+
+	/** Given a String that has a run-length-encoding of some unsigned shorts
+	 *  like "\1\2\3\9", convert to short[] {2,9,9,9}.  We do this to avoid
+	 *  static short[] which generates so much init code that the class won't
+	 *  compile. :(
+	 */
+	public static short[] unpackEncodedString(String encodedString) {
+		// walk first to find how big it is.
+		int size = 0;
+		for (int i=0; i<encodedString.length(); i+=2) {
+			size += encodedString.charAt(i);
+		}
+		short[] data = new short[size];
+		int di = 0;
+		for (int i=0; i<encodedString.length(); i+=2) {
+			char n = encodedString.charAt(i);
+			char v = encodedString.charAt(i+1);
+			// add v n times to data
+			for (int j=1; j<=n; j++) {
+				data[di++] = (short)v;
+			}
+		}
+		return data;
+	}
+
+	/** Hideous duplication of code, but I need different typed arrays out :( */
+	public static char[] unpackEncodedStringToUnsignedChars(String encodedString) {
+		// walk first to find how big it is.
+		int size = 0;
+		for (int i=0; i<encodedString.length(); i+=2) {
+			size += encodedString.charAt(i);
+		}
+		char[] data = new char[size];
+		int di = 0;
+		for (int i=0; i<encodedString.length(); i+=2) {
+			char n = encodedString.charAt(i);
+			char v = encodedString.charAt(i+1);
+			// add v n times to data
+			for (int j=1; j<=n; j++) {
+				data[di++] = v;
+			}
+		}
+		return data;
+	}
+
+	/*
+	public int specialTransition(int state, int symbol) {
+		return 0;
+	}
+	*/
+}
diff --git a/src/org/antlr/runtime/EarlyExitException.java b/src/org/antlr/runtime/EarlyExitException.java
new file mode 100755
index 0000000..1f9c1ec
--- /dev/null
+++ b/src/org/antlr/runtime/EarlyExitException.java
@@ -0,0 +1,41 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime;
+
+/**  The recognizer did not match anything for a (..)+ loop. */
+public class EarlyExitException extends RecognitionException {
+	public int decisionNumber;
+
+	/** Used for remote debugger deserialization */
+	public EarlyExitException() {;}
+	
+	public EarlyExitException(int decisionNumber, IntStream input) {
+		super(input);
+		this.decisionNumber = decisionNumber;
+	}
+}
diff --git a/src/org/antlr/runtime/FailedPredicateException.java b/src/org/antlr/runtime/FailedPredicateException.java
new file mode 100755
index 0000000..5bef1bd
--- /dev/null
+++ b/src/org/antlr/runtime/FailedPredicateException.java
@@ -0,0 +1,54 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime;
+
+/** A semantic predicate failed during validation.  Validation of predicates
+ *  occurs when normally parsing the alternative just like matching a token.
+ *  Disambiguating predicate evaluation occurs when we hoist a predicate into
+ *  a prediction decision.
+ */
+public class FailedPredicateException extends RecognitionException {
+	public String ruleName;
+	public String predicateText;
+
+	/** Used for remote debugger deserialization */
+	public FailedPredicateException() {;}
+
+	public FailedPredicateException(IntStream input,
+									String ruleName,
+									String predicateText)
+	{
+		super(input);
+		this.ruleName = ruleName;
+		this.predicateText = predicateText;
+	}
+
+	public String toString() {
+		return "FailedPredicateException("+ruleName+",{"+predicateText+"}?)";
+	}
+}
diff --git a/src/org/antlr/runtime/IntStream.java b/src/org/antlr/runtime/IntStream.java
new file mode 100755
index 0000000..01c7841
--- /dev/null
+++ b/src/org/antlr/runtime/IntStream.java
@@ -0,0 +1,122 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime;
+
+/** A simple stream of integers used when all I care about is the char
+ *  or token type sequence (such as interpretation).
+ */
+public interface IntStream {
+	void consume();
+
+	/** Get int at current input pointer + i ahead where i=1 is next int.
+	 *  Negative indexes are allowed.  LA(-1) is previous token (token
+	 *  just matched).  LA(-i) where i is before first token should
+	 *  yield -1, invalid char / EOF.
+	 */
+	int LA(int i);
+
+	/** Tell the stream to start buffering if it hasn't already.  Return
+     *  current input position, index(), or some other marker so that
+	 *  when passed to rewind() you get back to the same spot.
+	 *  rewind(mark()) should not affect the input cursor.  The Lexer
+	 *  track line/col info as well as input index so its markers are
+	 *  not pure input indexes.  Same for tree node streams.
+     */
+	int mark();
+
+	/** Return the current input symbol index 0..n where n indicates the
+     *  last symbol has been read.  The index is the symbol about to be
+	 *  read not the most recently read symbol.
+     */
+	int index();
+
+	/** Reset the stream so that next call to index would return marker.
+	 *  The marker will usually be index() but it doesn't have to be.  It's
+	 *  just a marker to indicate what state the stream was in.  This is
+	 *  essentially calling release() and seek().  If there are markers
+	 *  created after this marker argument, this routine must unroll them
+	 *  like a stack.  Assume the state the stream was in when this marker
+	 *  was created.
+	 */
+	void rewind(int marker);
+
+	/** Rewind to the input position of the last marker.
+	 *  Used currently only after a cyclic DFA and just
+	 *  before starting a sem/syn predicate to get the
+	 *  input position back to the start of the decision.
+	 *  Do not "pop" the marker off the state.  mark(i)
+	 *  and rewind(i) should balance still. It is
+	 *  like invoking rewind(last marker) but it should not "pop"
+	 *  the marker off.  It's like seek(last marker's input position).
+	 */
+	void rewind();
+
+	/** You may want to commit to a backtrack but don't want to force the
+	 *  stream to keep bookkeeping objects around for a marker that is
+	 *  no longer necessary.  This will have the same behavior as
+	 *  rewind() except it releases resources without the backward seek.
+	 *  This must throw away resources for all markers back to the marker
+	 *  argument.  So if you're nested 5 levels of mark(), and then release(2)
+	 *  you have to release resources for depths 2..5.
+	 */
+	void release(int marker);
+
+	/** Set the input cursor to the position indicated by index.  This is
+	 *  normally used to seek ahead in the input stream.  No buffering is
+	 *  required to do this unless you know your stream will use seek to
+	 *  move backwards such as when backtracking.
+	 *
+	 *  This is different from rewind in its multi-directional
+	 *  requirement and in that its argument is strictly an input cursor (index).
+	 *
+	 *  For char streams, seeking forward must update the stream state such
+	 *  as line number.  For seeking backwards, you will be presumably
+	 *  backtracking using the mark/rewind mechanism that restores state and
+	 *  so this method does not need to update state when seeking backwards.
+	 *
+	 *  Currently, this method is only used for efficient backtracking using
+	 *  memoization, but in the future it may be used for incremental parsing.
+	 *
+	 *  The index is 0..n-1.  A seek to position i means that LA(1) will
+	 *  return the ith symbol.  So, seeking to 0 means LA(1) will return the
+	 *  first element in the stream. 
+	 */
+	void seek(int index);
+
+	/** Only makes sense for streams that buffer everything up probably, but
+	 *  might be useful to display the entire stream or for testing.  This
+	 *  value includes a single EOF.
+	 */
+	int size();
+
+	/** Where are you getting symbols from?  Normally, implementations will
+	 *  pass the buck all the way to the lexer who can ask its input stream
+	 *  for the file name or whatever.
+	 */
+	public String getSourceName();
+}
diff --git a/src/org/antlr/runtime/LegacyCommonTokenStream.java b/src/org/antlr/runtime/LegacyCommonTokenStream.java
new file mode 100755
index 0000000..f9c5e39
--- /dev/null
+++ b/src/org/antlr/runtime/LegacyCommonTokenStream.java
@@ -0,0 +1,394 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime;
+
+import java.util.*;
+
+/** The most common stream of tokens is one where every token is buffered up
+ *  and tokens are prefiltered for a certain channel (the parser will only
+ *  see these tokens and cannot change the filter channel number during the
+ *  parse).
+ *
+ *  TODO: how to access the full token stream?  How to track all tokens matched per rule?
+ */
+public class LegacyCommonTokenStream implements TokenStream {
+    protected TokenSource tokenSource;
+
+	/** Record every single token pulled from the source so we can reproduce
+	 *  chunks of it later.
+	 */
+	protected List tokens;
+
+	/** Map<tokentype, channel> to override some Tokens' channel numbers */
+	protected Map channelOverrideMap;
+
+	/** Set<tokentype>; discard any tokens with this type */
+	protected Set discardSet;
+
+	/** Skip tokens on any channel but this one; this is how we skip whitespace... */
+	protected int channel = Token.DEFAULT_CHANNEL;
+
+	/** By default, track all incoming tokens */
+	protected boolean discardOffChannelTokens = false;
+
+	/** Track the last mark() call result value for use in rewind(). */
+	protected int lastMarker;
+
+	protected int range = -1; // how deep have we gone?	
+
+	/** The index into the tokens list of the current token (next token
+     *  to consume).  p==-1 indicates that the tokens list is empty
+     */
+    protected int p = -1;
+
+	public LegacyCommonTokenStream() {
+		tokens = new ArrayList(500);
+	}
+
+	public LegacyCommonTokenStream(TokenSource tokenSource) {
+	    this();
+		this.tokenSource = tokenSource;
+	}
+
+	public LegacyCommonTokenStream(TokenSource tokenSource, int channel) {
+		this(tokenSource);
+		this.channel = channel;
+	}
+
+	/** Reset this token stream by setting its token source. */
+	public void setTokenSource(TokenSource tokenSource) {
+		this.tokenSource = tokenSource;
+		tokens.clear();
+		p = -1;
+		channel = Token.DEFAULT_CHANNEL;
+	}
+
+	/** Load all tokens from the token source and put in tokens.
+	 *  This is done upon first LT request because you might want to
+	 *  set some token type / channel overrides before filling buffer.
+	 */
+	protected void fillBuffer() {
+		int index = 0;
+		Token t = tokenSource.nextToken();
+		while ( t!=null && t.getType()!=CharStream.EOF ) {
+			boolean discard = false;
+			// is there a channel override for token type?
+			if ( channelOverrideMap!=null ) {
+				Integer channelI = (Integer)
+					channelOverrideMap.get(new Integer(t.getType()));
+				if ( channelI!=null ) {
+					t.setChannel(channelI.intValue());
+				}
+			}
+			if ( discardSet!=null &&
+				 discardSet.contains(new Integer(t.getType())) )
+			{
+				discard = true;
+			}
+			else if ( discardOffChannelTokens && t.getChannel()!=this.channel ) {
+				discard = true;
+			}
+			if ( !discard )	{
+				t.setTokenIndex(index);
+				tokens.add(t);
+				index++;
+			}
+			t = tokenSource.nextToken();
+		}
+		// leave p pointing at first token on channel
+		p = 0;
+		p = skipOffTokenChannels(p);
+    }
+
+	/** Move the input pointer to the next incoming token.  The stream
+	 *  must become active with LT(1) available.  consume() simply
+	 *  moves the input pointer so that LT(1) points at the next
+	 *  input symbol. Consume at least one token.
+	 *
+	 *  Walk past any token not on the channel the parser is listening to.
+	 */
+	public void consume() {
+		if ( p<tokens.size() ) {
+            p++;
+			p = skipOffTokenChannels(p); // leave p on valid token
+        }
+    }
+
+	/** Given a starting index, return the index of the first on-channel
+	 *  token.
+	 */
+	protected int skipOffTokenChannels(int i) {
+		int n = tokens.size();
+		while ( i<n && ((Token)tokens.get(i)).getChannel()!=channel ) {
+			i++;
+		}
+		return i;
+	}
+
+	protected int skipOffTokenChannelsReverse(int i) {
+		while ( i>=0 && ((Token)tokens.get(i)).getChannel()!=channel ) {
+			i--;
+		}
+		return i;
+	}
+
+	/** A simple filter mechanism whereby you can tell this token stream
+	 *  to force all tokens of type ttype to be on channel.  For example,
+	 *  when interpreting, we cannot exec actions so we need to tell
+	 *  the stream to force all WS and NEWLINE to be a different, ignored
+	 *  channel.
+	 */
+	public void setTokenTypeChannel(int ttype, int channel) {
+		if ( channelOverrideMap==null ) {
+			channelOverrideMap = new HashMap();
+		}
+        channelOverrideMap.put(new Integer(ttype), new Integer(channel));
+	}
+
+	public void discardTokenType(int ttype) {
+		if ( discardSet==null ) {
+			discardSet = new HashSet();
+		}
+        discardSet.add(new Integer(ttype));
+	}
+
+	public void discardOffChannelTokens(boolean discardOffChannelTokens) {
+		this.discardOffChannelTokens = discardOffChannelTokens;
+	}
+
+	public List getTokens() {
+		if ( p == -1 ) {
+			fillBuffer();
+		}
+		return tokens;
+	}
+
+	public List getTokens(int start, int stop) {
+		return getTokens(start, stop, (BitSet)null);
+	}
+
+	/** Given a start and stop index, return a List of all tokens in
+	 *  the token type BitSet.  Return null if no tokens were found.  This
+	 *  method looks at both on and off channel tokens.
+	 */
+	public List getTokens(int start, int stop, BitSet types) {
+		if ( p == -1 ) {
+			fillBuffer();
+		}
+		if ( stop>=tokens.size() ) {
+			stop=tokens.size()-1;
+		}
+		if ( start<0 ) {
+			start=0;
+		}
+		if ( start>stop ) {
+			return null;
+		}
+
+		// list = tokens[start:stop]:{Token t, t.getType() in types}
+		List filteredTokens = new ArrayList();
+		for (int i=start; i<=stop; i++) {
+			Token t = (Token)tokens.get(i);
+			if ( types==null || types.member(t.getType()) ) {
+				filteredTokens.add(t);
+			}
+		}
+		if ( filteredTokens.size()==0 ) {
+			filteredTokens = null;
+		}
+		return filteredTokens;
+	}
+
+	public List getTokens(int start, int stop, List types) {
+		return getTokens(start,stop,new BitSet(types));
+	}
+
+	public List getTokens(int start, int stop, int ttype) {
+		return getTokens(start,stop,BitSet.of(ttype));
+	}
+
+	/** Get the ith token from the current position 1..n where k=1 is the
+	 *  first symbol of lookahead.
+	 */
+	public Token LT(int k) {
+		if ( p == -1 ) {
+			fillBuffer();
+		}
+		if ( k==0 ) {
+			return null;
+		}
+		if ( k<0 ) {
+			return LB(-k);
+		}
+		//System.out.print("LT(p="+p+","+k+")=");
+		if ( (p+k-1) >= tokens.size() ) {
+            return (Token)tokens.get(tokens.size()-1);
+		}
+		//System.out.println(tokens.get(p+k-1));
+		int i = p;
+		int n = 1;
+		// find k good tokens
+		while ( n<k ) {
+			// skip off-channel tokens
+			i = skipOffTokenChannels(i+1); // leave p on valid token
+			n++;
+		}
+		if ( i>=tokens.size() ) {
+            return (Token)tokens.get(tokens.size()-1); // must be EOF
+		}
+
+		if ( i>range ) range = i;
+        return (Token)tokens.get(i);
+    }
+
+	/** Look backwards k tokens on-channel tokens */
+	protected Token LB(int k) {
+		//System.out.print("LB(p="+p+","+k+") ");
+		if ( p == -1 ) {
+			fillBuffer();
+		}
+		if ( k==0 ) {
+			return null;
+		}
+		if ( (p-k)<0 ) {
+			return null;
+		}
+
+		int i = p;
+		int n = 1;
+		// find k good tokens looking backwards
+		while ( n<=k ) {
+			// skip off-channel tokens
+			i = skipOffTokenChannelsReverse(i-1); // leave p on valid token
+			n++;
+		}
+		if ( i<0 ) {
+			return null;
+		}
+		return (Token)tokens.get(i);
+	}
+
+	/** Return absolute token i; ignore which channel the tokens are on;
+	 *  that is, count all tokens not just on-channel tokens.
+	 */
+	public Token get(int i) {
+		return (Token)tokens.get(i);
+	}
+
+	/** Get all tokens from start..stop inclusively */
+	public List get(int start, int stop) {
+		if ( p == -1 ) fillBuffer();
+		if ( start<0 || stop<0 ) return null;
+		return tokens.subList(start, stop);
+	}
+
+	public int LA(int i) {
+        return LT(i).getType();
+    }
+
+    public int mark() {
+		if ( p == -1 ) {
+			fillBuffer();
+		}
+		lastMarker = index();
+		return lastMarker;
+	}
+
+	public void release(int marker) {
+		// no resources to release
+	}
+
+	public int size() {
+		return tokens.size();
+	}
+
+    public int index() {
+        return p;
+    }
+
+	public int range() {
+		return range;
+	}
+
+	public void rewind(int marker) {
+		seek(marker);
+	}
+
+	public void rewind() {
+		seek(lastMarker);
+	}
+
+	public void reset() {
+		p = 0;
+		lastMarker = 0;
+	}
+	
+	public void seek(int index) {
+		p = index;
+	}
+
+	public TokenSource getTokenSource() {
+		return tokenSource;
+	}
+
+	public String getSourceName() {
+		return getTokenSource().getSourceName();
+	}
+
+	public String toString() {
+		if ( p == -1 ) {
+			fillBuffer();
+		}
+		return toString(0, tokens.size()-1);
+	}
+
+	public String toString(int start, int stop) {
+		if ( start<0 || stop<0 ) {
+			return null;
+		}
+		if ( p == -1 ) {
+			fillBuffer();
+		}
+		if ( stop>=tokens.size() ) {
+			stop = tokens.size()-1;
+		}
+ 		StringBuffer buf = new StringBuffer();
+		for (int i = start; i <= stop; i++) {
+			Token t = (Token)tokens.get(i);
+			buf.append(t.getText());
+		}
+		return buf.toString();
+	}
+
+	public String toString(Token start, Token stop) {
+		if ( start!=null && stop!=null ) {
+			return toString(start.getTokenIndex(), stop.getTokenIndex());
+		}
+		return null;
+	}
+}
diff --git a/src/org/antlr/runtime/Lexer.java b/src/org/antlr/runtime/Lexer.java
new file mode 100755
index 0000000..6037bcf
--- /dev/null
+++ b/src/org/antlr/runtime/Lexer.java
@@ -0,0 +1,340 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime;
+
+/** A lexer is recognizer that draws input symbols from a character stream.
+ *  lexer grammars result in a subclass of this object. A Lexer object
+ *  uses simplified match() and error recovery mechanisms in the interest
+ *  of speed.
+ */
+public abstract class Lexer extends BaseRecognizer implements TokenSource {
+	/** Where is the lexer drawing characters from? */
+	protected CharStream input;
+
+	public Lexer() {
+	}
+
+	public Lexer(CharStream input) {
+		this.input = input;
+	}
+
+	public Lexer(CharStream input, RecognizerSharedState state) {
+		super(state);
+		this.input = input;
+	}
+
+	public void reset() {
+		super.reset(); // reset all recognizer state variables
+		// wack Lexer state variables
+		if ( input!=null ) {
+			input.seek(0); // rewind the input
+		}
+		if ( state==null ) {
+			return; // no shared state work to do
+		}
+		state.token = null;
+		state.type = Token.INVALID_TOKEN_TYPE;
+		state.channel = Token.DEFAULT_CHANNEL;
+		state.tokenStartCharIndex = -1;
+		state.tokenStartCharPositionInLine = -1;
+		state.tokenStartLine = -1;
+		state.text = null;
+	}
+
+	/** Return a token from this source; i.e., match a token on the char
+	 *  stream.
+	 */
+	public Token nextToken() {
+		while (true) {
+			state.token = null;
+			state.channel = Token.DEFAULT_CHANNEL;
+			state.tokenStartCharIndex = input.index();
+			state.tokenStartCharPositionInLine = input.getCharPositionInLine();
+			state.tokenStartLine = input.getLine();
+			state.text = null;
+			if ( input.LA(1)==CharStream.EOF ) {
+                Token eof = new CommonToken((CharStream)input,Token.EOF,
+                                            Token.DEFAULT_CHANNEL,
+                                            input.index(),input.index());
+                eof.setLine(getLine());
+                eof.setCharPositionInLine(getCharPositionInLine());
+                return eof;
+			}
+			try {
+				mTokens();
+				if ( state.token==null ) {
+					emit();
+				}
+				else if ( state.token==Token.SKIP_TOKEN ) {
+					continue;
+				}
+				return state.token;
+			}
+			catch (NoViableAltException nva) {
+				reportError(nva);
+				recover(nva); // throw out current char and try again
+			}
+			catch (RecognitionException re) {
+				reportError(re);
+				// match() routine has already called recover()
+			}
+		}
+	}
+
+	/** Instruct the lexer to skip creating a token for current lexer rule
+	 *  and look for another token.  nextToken() knows to keep looking when
+	 *  a lexer rule finishes with token set to SKIP_TOKEN.  Recall that
+	 *  if token==null at end of any token rule, it creates one for you
+	 *  and emits it.
+	 */
+	public void skip() {
+		state.token = Token.SKIP_TOKEN;
+	}
+
+	/** This is the lexer entry point that sets instance var 'token' */
+	public abstract void mTokens() throws RecognitionException;
+
+	/** Set the char stream and reset the lexer */
+	public void setCharStream(CharStream input) {
+		this.input = null;
+		reset();
+		this.input = input;
+	}
+
+	public CharStream getCharStream() {
+		return this.input;
+	}
+
+	public String getSourceName() {
+		return input.getSourceName();
+	}
+
+	/** Currently does not support multiple emits per nextToken invocation
+	 *  for efficiency reasons.  Subclass and override this method and
+	 *  nextToken (to push tokens into a list and pull from that list rather
+	 *  than a single variable as this implementation does).
+	 */
+	public void emit(Token token) {
+		state.token = token;
+	}
+
+	/** The standard method called to automatically emit a token at the
+	 *  outermost lexical rule.  The token object should point into the
+	 *  char buffer start..stop.  If there is a text override in 'text',
+	 *  use that to set the token's text.  Override this method to emit
+	 *  custom Token objects.
+	 *
+	 *  If you are building trees, then you should also override
+	 *  Parser or TreeParser.getMissingSymbol().
+	 */
+	public Token emit() {
+		Token t = new CommonToken(input, state.type, state.channel, state.tokenStartCharIndex, getCharIndex()-1);
+		t.setLine(state.tokenStartLine);
+		t.setText(state.text);
+		t.setCharPositionInLine(state.tokenStartCharPositionInLine);
+		emit(t);
+		return t;
+	}
+
+	public void match(String s) throws MismatchedTokenException {
+		int i = 0;
+		while ( i<s.length() ) {
+			if ( input.LA(1)!=s.charAt(i) ) {
+				if ( state.backtracking>0 ) {
+					state.failed = true;
+					return;
+				}
+				MismatchedTokenException mte =
+					new MismatchedTokenException(s.charAt(i), input);
+				recover(mte);
+				throw mte;
+			}
+			i++;
+			input.consume();
+			state.failed = false;
+		}
+	}
+
+	public void matchAny() {
+		input.consume();
+	}
+
+	public void match(int c) throws MismatchedTokenException {
+		if ( input.LA(1)!=c ) {
+			if ( state.backtracking>0 ) {
+				state.failed = true;
+				return;
+			}
+			MismatchedTokenException mte =
+				new MismatchedTokenException(c, input);
+			recover(mte);  // don't really recover; just consume in lexer
+			throw mte;
+		}
+		input.consume();
+		state.failed = false;
+	}
+
+	public void matchRange(int a, int b)
+		throws MismatchedRangeException
+	{
+		if ( input.LA(1)<a || input.LA(1)>b ) {
+			if ( state.backtracking>0 ) {
+				state.failed = true;
+				return;
+			}
+			MismatchedRangeException mre =
+				new MismatchedRangeException(a,b,input);
+			recover(mre);
+			throw mre;
+		}
+		input.consume();
+		state.failed = false;
+	}
+
+	public int getLine() {
+		return input.getLine();
+	}
+
+	public int getCharPositionInLine() {
+		return input.getCharPositionInLine();
+	}
+
+	/** What is the index of the current character of lookahead? */
+	public int getCharIndex() {
+		return input.index();
+	}
+
+	/** Return the text matched so far for the current token or any
+	 *  text override.
+	 */
+	public String getText() {
+		if ( state.text!=null ) {
+			return state.text;
+		}
+		return input.substring(state.tokenStartCharIndex,getCharIndex()-1);
+	}
+
+	/** Set the complete text of this token; it wipes any previous
+	 *  changes to the text.
+	 */
+	public void setText(String text) {
+		state.text = text;
+	}
+
+	public void reportError(RecognitionException e) {
+		/** TODO: not thought about recovery in lexer yet.
+		 *
+		// if we've already reported an error and have not matched a token
+		// yet successfully, don't report any errors.
+		if ( errorRecovery ) {
+			//System.err.print("[SPURIOUS] ");
+			return;
+		}
+		errorRecovery = true;
+		 */
+
+		displayRecognitionError(this.getTokenNames(), e);
+	}
+
+	public String getErrorMessage(RecognitionException e, String[] tokenNames) {
+		String msg = null;
+		if ( e instanceof MismatchedTokenException ) {
+			MismatchedTokenException mte = (MismatchedTokenException)e;
+			msg = "mismatched character "+getCharErrorDisplay(e.c)+" expecting "+getCharErrorDisplay(mte.expecting);
+		}
+		else if ( e instanceof NoViableAltException ) {
+			NoViableAltException nvae = (NoViableAltException)e;
+			// for development, can add "decision=<<"+nvae.grammarDecisionDescription+">>"
+			// and "(decision="+nvae.decisionNumber+") and
+			// "state "+nvae.stateNumber
+			msg = "no viable alternative at character "+getCharErrorDisplay(e.c);
+		}
+		else if ( e instanceof EarlyExitException ) {
+			EarlyExitException eee = (EarlyExitException)e;
+			// for development, can add "(decision="+eee.decisionNumber+")"
+			msg = "required (...)+ loop did not match anything at character "+getCharErrorDisplay(e.c);
+		}
+		else if ( e instanceof MismatchedNotSetException ) {
+			MismatchedNotSetException mse = (MismatchedNotSetException)e;
+			msg = "mismatched character "+getCharErrorDisplay(e.c)+" expecting set "+mse.expecting;
+		}
+		else if ( e instanceof MismatchedSetException ) {
+			MismatchedSetException mse = (MismatchedSetException)e;
+			msg = "mismatched character "+getCharErrorDisplay(e.c)+" expecting set "+mse.expecting;
+		}
+		else if ( e instanceof MismatchedRangeException ) {
+			MismatchedRangeException mre = (MismatchedRangeException)e;
+			msg = "mismatched character "+getCharErrorDisplay(e.c)+" expecting set "+
+				  getCharErrorDisplay(mre.a)+".."+getCharErrorDisplay(mre.b);
+		}
+		else {
+			msg = super.getErrorMessage(e, tokenNames);
+		}
+		return msg;
+	}
+
+	public String getCharErrorDisplay(int c) {
+		String s = String.valueOf((char)c);
+		switch ( c ) {
+			case Token.EOF :
+				s = "<EOF>";
+				break;
+			case '\n' :
+				s = "\\n";
+				break;
+			case '\t' :
+				s = "\\t";
+				break;
+			case '\r' :
+				s = "\\r";
+				break;
+		}
+		return "'"+s+"'";
+	}
+
+	/** Lexers can normally match any char in it's vocabulary after matching
+	 *  a token, so do the easy thing and just kill a character and hope
+	 *  it all works out.  You can instead use the rule invocation stack
+	 *  to do sophisticated error recovery if you are in a fragment rule.
+	 */
+	public void recover(RecognitionException re) {
+		//System.out.println("consuming char "+(char)input.LA(1)+" during recovery");
+		//re.printStackTrace();
+		input.consume();
+	}
+
+	public void traceIn(String ruleName, int ruleIndex)  {
+		String inputSymbol = ((char)input.LT(1))+" line="+getLine()+":"+getCharPositionInLine();
+		super.traceIn(ruleName, ruleIndex, inputSymbol);
+	}
+
+	public void traceOut(String ruleName, int ruleIndex)  {
+		String inputSymbol = ((char)input.LT(1))+" line="+getLine()+":"+getCharPositionInLine();
+		super.traceOut(ruleName, ruleIndex, inputSymbol);
+	}
+}
diff --git a/src/org/antlr/runtime/MismatchedNotSetException.java b/src/org/antlr/runtime/MismatchedNotSetException.java
new file mode 100755
index 0000000..49ceb27
--- /dev/null
+++ b/src/org/antlr/runtime/MismatchedNotSetException.java
@@ -0,0 +1,41 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime;
+
+public class MismatchedNotSetException extends MismatchedSetException {
+	/** Used for remote debugger deserialization */
+	public MismatchedNotSetException() {;}
+
+	public MismatchedNotSetException(BitSet expecting, IntStream input) {
+		super(expecting, input);
+	}
+
+	public String toString() {
+		return "MismatchedNotSetException("+getUnexpectedType()+"!="+expecting+")";
+	}
+}
diff --git a/src/org/antlr/runtime/MismatchedRangeException.java b/src/org/antlr/runtime/MismatchedRangeException.java
new file mode 100755
index 0000000..23b3d87
--- /dev/null
+++ b/src/org/antlr/runtime/MismatchedRangeException.java
@@ -0,0 +1,45 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime;
+
+public class MismatchedRangeException extends RecognitionException {
+	public int a,b;
+
+	/** Used for remote debugger deserialization */
+	public MismatchedRangeException() {;}
+
+	public MismatchedRangeException(int a, int b, IntStream input) {
+		super(input);
+		this.a = a;
+		this.b = b;
+	}
+
+	public String toString() {
+		return "MismatchedNotSetException("+getUnexpectedType()+" not in ["+a+","+b+"])";
+	}
+}
diff --git a/src/org/antlr/runtime/MismatchedSetException.java b/src/org/antlr/runtime/MismatchedSetException.java
new file mode 100755
index 0000000..9bfa530
--- /dev/null
+++ b/src/org/antlr/runtime/MismatchedSetException.java
@@ -0,0 +1,44 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime;
+
+public class MismatchedSetException extends RecognitionException {
+	public BitSet expecting;
+
+	/** Used for remote debugger deserialization */
+	public MismatchedSetException() {;}
+
+	public MismatchedSetException(BitSet expecting, IntStream input) {
+		super(input);
+		this.expecting = expecting;
+	}
+
+	public String toString() {
+		return "MismatchedSetException("+getUnexpectedType()+"!="+expecting+")";
+	}
+}
diff --git a/src/org/antlr/runtime/MismatchedTokenException.java b/src/org/antlr/runtime/MismatchedTokenException.java
new file mode 100755
index 0000000..07ae814
--- /dev/null
+++ b/src/org/antlr/runtime/MismatchedTokenException.java
@@ -0,0 +1,45 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime;
+
+/** A mismatched char or Token or tree node */
+public class MismatchedTokenException extends RecognitionException {
+	public int expecting = Token.INVALID_TOKEN_TYPE;
+
+	/** Used for remote debugger deserialization */
+	public MismatchedTokenException() {;}
+
+	public MismatchedTokenException(int expecting, IntStream input) {
+		super(input);
+		this.expecting = expecting;
+	}
+
+	public String toString() {
+		return "MismatchedTokenException("+getUnexpectedType()+"!="+expecting+")";
+	}
+}
diff --git a/src/org/antlr/runtime/MismatchedTreeNodeException.java b/src/org/antlr/runtime/MismatchedTreeNodeException.java
new file mode 100755
index 0000000..99c834d
--- /dev/null
+++ b/src/org/antlr/runtime/MismatchedTreeNodeException.java
@@ -0,0 +1,49 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime;
+
+import org.antlr.runtime.tree.TreeNodeStream;
+import org.antlr.runtime.tree.Tree;
+
+/**
+ */
+public class MismatchedTreeNodeException extends RecognitionException {
+	public int expecting;
+
+	public MismatchedTreeNodeException() {
+	}
+
+	public MismatchedTreeNodeException(int expecting, TreeNodeStream input) {
+		super(input);
+		this.expecting = expecting;
+	}
+
+	public String toString() {
+		return "MismatchedTreeNodeException("+getUnexpectedType()+"!="+expecting+")";
+	}
+}
diff --git a/src/org/antlr/runtime/MissingTokenException.java b/src/org/antlr/runtime/MissingTokenException.java
new file mode 100755
index 0000000..9eda1f2
--- /dev/null
+++ b/src/org/antlr/runtime/MissingTokenException.java
@@ -0,0 +1,56 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime;
+
+/** We were expecting a token but it's not found.  The current token
+ *  is actually what we wanted next.  Used for tree node errors too.
+ */
+public class MissingTokenException extends MismatchedTokenException {
+	public Object inserted;
+	/** Used for remote debugger deserialization */
+	public MissingTokenException() {;}
+
+	public MissingTokenException(int expecting, IntStream input, Object inserted) {
+		super(expecting, input);
+		this.inserted = inserted;
+	}
+
+	public int getMissingType() {
+		return expecting;
+	}
+
+	public String toString() {
+		if ( inserted!=null && token!=null ) {
+			return "MissingTokenException(inserted "+inserted+" at "+token.getText()+")";
+		}
+		if ( token!=null ) {
+			return "MissingTokenException(at "+token.getText()+")";
+		}
+		return "MissingTokenException";
+	}
+}
diff --git a/src/org/antlr/runtime/NoViableAltException.java b/src/org/antlr/runtime/NoViableAltException.java
new file mode 100755
index 0000000..889045f
--- /dev/null
+++ b/src/org/antlr/runtime/NoViableAltException.java
@@ -0,0 +1,57 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime;
+
+public class NoViableAltException extends RecognitionException {
+	public String grammarDecisionDescription;
+	public int decisionNumber;
+	public int stateNumber;
+
+	/** Used for remote debugger deserialization */
+	public NoViableAltException() {;}
+	
+	public NoViableAltException(String grammarDecisionDescription,
+								int decisionNumber,
+								int stateNumber,
+								IntStream input)
+	{
+		super(input);
+		this.grammarDecisionDescription = grammarDecisionDescription;
+		this.decisionNumber = decisionNumber;
+		this.stateNumber = stateNumber;
+	}
+
+	public String toString() {
+		if ( input instanceof CharStream ) {
+			return "NoViableAltException('"+(char)getUnexpectedType()+"'@["+grammarDecisionDescription+"])";
+		}
+		else {
+			return "NoViableAltException("+getUnexpectedType()+"@["+grammarDecisionDescription+"])";
+		}
+	}
+}
diff --git a/src/org/antlr/runtime/Parser.java b/src/org/antlr/runtime/Parser.java
new file mode 100755
index 0000000..9cf937a
--- /dev/null
+++ b/src/org/antlr/runtime/Parser.java
@@ -0,0 +1,98 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime;
+
+/** A parser for TokenStreams.  "parser grammars" result in a subclass
+ *  of this.
+ */
+public class Parser extends BaseRecognizer {
+	public TokenStream input;
+
+	public Parser(TokenStream input) {
+		super(); // highlight that we go to super to set state object
+		setTokenStream(input);
+    }
+
+	public Parser(TokenStream input, RecognizerSharedState state) {
+		super(state); // share the state object with another parser
+		this.input = input;
+    }
+
+	public void reset() {
+		super.reset(); // reset all recognizer state variables
+		if ( input!=null ) {
+			input.seek(0); // rewind the input
+		}
+	}
+
+	protected Object getCurrentInputSymbol(IntStream input) {
+		return ((TokenStream)input).LT(1);
+	}
+
+	protected Object getMissingSymbol(IntStream input,
+									  RecognitionException e,
+									  int expectedTokenType,
+									  BitSet follow)
+	{
+		String tokenText = null;
+		if ( expectedTokenType==Token.EOF ) tokenText = "<missing EOF>";
+		else tokenText = "<missing "+getTokenNames()[expectedTokenType]+">";
+		CommonToken t = new CommonToken(expectedTokenType, tokenText);
+		Token current = ((TokenStream)input).LT(1);
+		if ( current.getType() == Token.EOF ) {
+			current = ((TokenStream)input).LT(-1);
+		}
+		t.line = current.getLine();
+		t.charPositionInLine = current.getCharPositionInLine();
+		t.channel = DEFAULT_TOKEN_CHANNEL;
+		return t;
+	}
+
+	/** Set the token stream and reset the parser */
+	public void setTokenStream(TokenStream input) {
+		this.input = null;
+		reset();
+		this.input = input;
+	}
+
+    public TokenStream getTokenStream() {
+		return input;
+	}
+
+	public String getSourceName() {
+		return input.getSourceName();
+	}
+
+	public void traceIn(String ruleName, int ruleIndex)  {
+		super.traceIn(ruleName, ruleIndex, input.LT(1));
+	}
+
+	public void traceOut(String ruleName, int ruleIndex)  {
+		super.traceOut(ruleName, ruleIndex, input.LT(1));
+	}
+}
diff --git a/src/org/antlr/runtime/ParserRuleReturnScope.java b/src/org/antlr/runtime/ParserRuleReturnScope.java
new file mode 100755
index 0000000..9237e4e
--- /dev/null
+++ b/src/org/antlr/runtime/ParserRuleReturnScope.java
@@ -0,0 +1,52 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime;
+
+/** Rules that return more than a single value must return an object
+ *  containing all the values.  Besides the properties defined in
+ *  RuleLabelScope.predefinedRulePropertiesScope there may be user-defined
+ *  return values.  This class simply defines the minimum properties that
+ *  are always defined and methods to access the others that might be
+ *  available depending on output option such as template and tree.
+ *
+ *  Note text is not an actual property of the return value, it is computed
+ *  from start and stop using the input stream's toString() method.  I
+ *  could add a ctor to this so that we can pass in and store the input
+ *  stream, but I'm not sure we want to do that.  It would seem to be undefined
+ *  to get the .text property anyway if the rule matches tokens from multiple
+ *  input streams.
+ *
+ *  I do not use getters for fields of objects that are used simply to
+ *  group values such as this aggregate.  The getters/setters are there to
+ *  satisfy the superclass interface.
+ */
+public class ParserRuleReturnScope extends RuleReturnScope {
+	public Token start, stop;
+	public Object getStart() { return start; }
+	public Object getStop() { return stop; }
+}
diff --git a/src/org/antlr/runtime/RecognitionException.java b/src/org/antlr/runtime/RecognitionException.java
new file mode 100755
index 0000000..3e79f99
--- /dev/null
+++ b/src/org/antlr/runtime/RecognitionException.java
@@ -0,0 +1,180 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime;
+
+import org.antlr.runtime.tree.*;
+
+/** The root of the ANTLR exception hierarchy.
+ *
+ *  To avoid English-only error messages and to generally make things
+ *  as flexible as possible, these exceptions are not created with strings,
+ *  but rather the information necessary to generate an error.  Then
+ *  the various reporting methods in Parser and Lexer can be overridden
+ *  to generate a localized error message.  For example, MismatchedToken
+ *  exceptions are built with the expected token type.
+ *  So, don't expect getMessage() to return anything.
+ *
+ *  Note that as of Java 1.4, you can access the stack trace, which means
+ *  that you can compute the complete trace of rules from the start symbol.
+ *  This gives you considerable context information with which to generate
+ *  useful error messages.
+ *
+ *  ANTLR generates code that throws exceptions upon recognition error and
+ *  also generates code to catch these exceptions in each rule.  If you
+ *  want to quit upon first error, you can turn off the automatic error
+ *  handling mechanism using rulecatch action, but you still need to
+ *  override methods mismatch and recoverFromMismatchSet.
+ *
+ *  In general, the recognition exceptions can track where in a grammar a
+ *  problem occurred and/or what was the expected input.  While the parser
+ *  knows its state (such as current input symbol and line info) that
+ *  state can change before the exception is reported so current token index
+ *  is computed and stored at exception time.  From this info, you can
+ *  perhaps print an entire line of input not just a single token, for example.
+ *  Better to just say the recognizer had a problem and then let the parser
+ *  figure out a fancy report.
+ */
+public class RecognitionException extends Exception {
+	/** What input stream did the error occur in? */
+	public transient IntStream input;
+
+	/** What is index of token/char were we looking at when the error occurred? */
+	public int index;
+
+	/** The current Token when an error occurred.  Since not all streams
+	 *  can retrieve the ith Token, we have to track the Token object.
+	 *  For parsers.  Even when it's a tree parser, token might be set.
+	 */
+	public Token token;
+
+	/** If this is a tree parser exception, node is set to the node with
+	 *  the problem.
+	 */
+	public Object node;
+
+	/** The current char when an error occurred. For lexers. */
+	public int c;
+
+	/** Track the line at which the error occurred in case this is
+	 *  generated from a lexer.  We need to track this since the
+	 *  unexpected char doesn't carry the line info.
+	 */
+	public int line;
+
+	public int charPositionInLine;
+
+	/** If you are parsing a tree node stream, you will encounter som
+	 *  imaginary nodes w/o line/col info.  We now search backwards looking
+	 *  for most recent token with line/col info, but notify getErrorHeader()
+	 *  that info is approximate.
+	 */
+	public boolean approximateLineInfo;
+
+	/** Used for remote debugger deserialization */
+	public RecognitionException() {
+	}
+
+	public RecognitionException(IntStream input) {
+		this.input = input;
+		this.index = input.index();
+		if ( input instanceof TokenStream ) {
+			this.token = ((TokenStream)input).LT(1);
+			this.line = token.getLine();
+			this.charPositionInLine = token.getCharPositionInLine();
+		}
+		if ( input instanceof TreeNodeStream ) {
+			extractInformationFromTreeNodeStream(input);
+		}
+		else if ( input instanceof CharStream ) {
+			this.c = input.LA(1);
+			this.line = ((CharStream)input).getLine();
+			this.charPositionInLine = ((CharStream)input).getCharPositionInLine();
+		}
+		else {
+			this.c = input.LA(1);
+		}
+	}
+
+	protected void extractInformationFromTreeNodeStream(IntStream input) {
+		TreeNodeStream nodes = (TreeNodeStream)input;
+		this.node = nodes.LT(1);
+		TreeAdaptor adaptor = nodes.getTreeAdaptor();
+		Token payload = adaptor.getToken(node);
+		if ( payload!=null ) {
+			this.token = payload;
+			if ( payload.getLine()<= 0 ) {
+				// imaginary node; no line/pos info; scan backwards
+				int i = -1;
+				Object priorNode = nodes.LT(i);
+				while ( priorNode!=null ) {
+					Token priorPayload = adaptor.getToken(priorNode);
+					if ( priorPayload!=null && priorPayload.getLine()>0 ) {
+						// we found the most recent real line / pos info
+						this.line = priorPayload.getLine();
+						this.charPositionInLine = priorPayload.getCharPositionInLine();
+						this.approximateLineInfo = true;
+						break;
+					}
+					--i;
+					priorNode = nodes.LT(i);
+				}
+			}
+			else { // node created from real token
+				this.line = payload.getLine();
+				this.charPositionInLine = payload.getCharPositionInLine();
+			}
+		}
+		else if ( this.node instanceof Tree) {
+			this.line = ((Tree)this.node).getLine();
+			this.charPositionInLine = ((Tree)this.node).getCharPositionInLine();
+			if ( this.node instanceof CommonTree) {
+				this.token = ((CommonTree)this.node).token;
+			}
+		}
+		else {
+			int type = adaptor.getType(this.node);
+			String text = adaptor.getText(this.node);
+			this.token = new CommonToken(type, text);
+		}
+	}
+
+	/** Return the token type or char of the unexpected input element */
+	public int getUnexpectedType() {
+		if ( input instanceof TokenStream ) {
+			return token.getType();
+		}
+		else if ( input instanceof TreeNodeStream ) {
+			TreeNodeStream nodes = (TreeNodeStream)input;
+			TreeAdaptor adaptor = nodes.getTreeAdaptor();
+			return adaptor.getType(node);
+		}
+		else {
+			return c;
+		}
+	}
+}
diff --git a/src/org/antlr/runtime/RecognizerSharedState.java b/src/org/antlr/runtime/RecognizerSharedState.java
new file mode 100755
index 0000000..068ac3b
--- /dev/null
+++ b/src/org/antlr/runtime/RecognizerSharedState.java
@@ -0,0 +1,144 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */package org.antlr.runtime;
+
+import java.util.Map;
+
+/** The set of fields needed by an abstract recognizer to recognize input
+ *  and recover from errors etc...  As a separate state object, it can be
+ *  shared among multiple grammars; e.g., when one grammar imports another.
+ *
+ *  These fields are publically visible but the actual state pointer per
+ *  parser is protected.
+ */
+public class RecognizerSharedState {
+	/** Track the set of token types that can follow any rule invocation.
+	 *  Stack grows upwards.  When it hits the max, it grows 2x in size
+	 *  and keeps going.
+	 */
+	public BitSet[] following = new BitSet[BaseRecognizer.INITIAL_FOLLOW_STACK_SIZE];
+	public int _fsp = -1;
+
+	/** This is true when we see an error and before having successfully
+	 *  matched a token.  Prevents generation of more than one error message
+	 *  per error.
+	 */
+	public boolean errorRecovery = false;
+
+	/** The index into the input stream where the last error occurred.
+	 * 	This is used to prevent infinite loops where an error is found
+	 *  but no token is consumed during recovery...another error is found,
+	 *  ad naseum.  This is a failsafe mechanism to guarantee that at least
+	 *  one token/tree node is consumed for two errors.
+	 */
+	public int lastErrorIndex = -1;
+
+	/** In lieu of a return value, this indicates that a rule or token
+	 *  has failed to match.  Reset to false upon valid token match.
+	 */
+	public boolean failed = false;
+
+	/** Did the recognizer encounter a syntax error?  Track how many. */
+	public int syntaxErrors = 0;
+
+	/** If 0, no backtracking is going on.  Safe to exec actions etc...
+	 *  If >0 then it's the level of backtracking.
+	 */
+	public int backtracking = 0;
+
+	/** An array[size num rules] of Map<Integer,Integer> that tracks
+	 *  the stop token index for each rule.  ruleMemo[ruleIndex] is
+	 *  the memoization table for ruleIndex.  For key ruleStartIndex, you
+	 *  get back the stop token for associated rule or MEMO_RULE_FAILED.
+	 *
+	 *  This is only used if rule memoization is on (which it is by default).
+	 */
+	public Map[] ruleMemo;
+
+
+	// LEXER FIELDS (must be in same state object to avoid casting
+	//               constantly in generated code and Lexer object) :(
+
+
+	/** The goal of all lexer rules/methods is to create a token object.
+	 *  This is an instance variable as multiple rules may collaborate to
+	 *  create a single token.  nextToken will return this object after
+	 *  matching lexer rule(s).  If you subclass to allow multiple token
+	 *  emissions, then set this to the last token to be matched or
+	 *  something nonnull so that the auto token emit mechanism will not
+	 *  emit another token.
+	 */
+    public Token token;
+
+	/** What character index in the stream did the current token start at?
+	 *  Needed, for example, to get the text for current token.  Set at
+	 *  the start of nextToken.
+ 	 */
+	public int tokenStartCharIndex = -1;
+
+	/** The line on which the first character of the token resides */
+	public int tokenStartLine;
+
+	/** The character position of first character within the line */
+	public int tokenStartCharPositionInLine;
+
+	/** The channel number for the current token */
+	public int channel;
+
+	/** The token type for the current token */
+	public int type;
+
+	/** You can set the text for the current token to override what is in
+	 *  the input char buffer.  Use setText() or can set this instance var.
+ 	 */
+	public String text;
+
+    public RecognizerSharedState() {;}
+    
+    public RecognizerSharedState(RecognizerSharedState state) {
+        if ( this.following.length < state.following.length ) {
+            this.following = new BitSet[state.following.length];
+        }
+        System.arraycopy(state.following, 0, this.following, 0, state.following.length);
+        this._fsp = state._fsp;
+        this.errorRecovery = state.errorRecovery;
+        this.lastErrorIndex = state.lastErrorIndex;
+        this.failed = state.failed;
+        this.syntaxErrors = state.syntaxErrors;
+        this.backtracking = state.backtracking;
+        if ( state.ruleMemo!=null ) {
+            this.ruleMemo = new Map[state.ruleMemo.length];
+            System.arraycopy(state.ruleMemo, 0, this.ruleMemo, 0, state.ruleMemo.length);
+        }
+        this.token = state.token;
+        this.tokenStartCharIndex = state.tokenStartCharIndex;
+        this.tokenStartCharPositionInLine = state.tokenStartCharPositionInLine;
+        this.channel = state.channel;
+        this.type = state.type;
+        this.text = state.text;
+    }
+}
diff --git a/src/org/antlr/runtime/RuleReturnScope.java b/src/org/antlr/runtime/RuleReturnScope.java
new file mode 100755
index 0000000..85702ca
--- /dev/null
+++ b/src/org/antlr/runtime/RuleReturnScope.java
@@ -0,0 +1,42 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime;
+
+/** Rules can return start/stop info as well as possible trees and templates */
+public class RuleReturnScope {
+	/** Return the start token or tree */
+	public Object getStart() { return null; }
+	/** Return the stop token or tree */
+	public Object getStop() { return null; }
+	/** Has a value potentially if output=AST; */
+	public Object getTree() { return null; }
+	/** Has a value potentially if output=template; Don't use StringTemplate
+	 *  type as it then causes a dependency with ST lib.
+	 */
+	public Object getTemplate() { return null; }
+}
diff --git a/src/org/antlr/runtime/SerializedGrammar.java b/src/org/antlr/runtime/SerializedGrammar.java
new file mode 100755
index 0000000..a609053
--- /dev/null
+++ b/src/org/antlr/runtime/SerializedGrammar.java
@@ -0,0 +1,198 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.runtime;
+
+import java.io.IOException;
+import java.io.FileInputStream;
+import java.io.BufferedInputStream;
+import java.io.DataInputStream;
+import java.util.List;
+import java.util.ArrayList;
+
+public class SerializedGrammar {
+    public static final String COOKIE = "$ANTLR";
+    public static final int FORMAT_VERSION = 1;
+    //public static org.antlr.tool.Grammar gr; // TESTING ONLY; remove later
+
+    public String name;
+    public char type; // in {l, p, t, c}
+    public List rules;
+
+    class Rule {
+        String name;
+        Block block;
+        public Rule(String name, Block block) {
+            this.name = name;
+            this.block = block;
+        }
+        public String toString() {
+            return name+":"+block;
+        }
+    }
+
+    class Block {
+        List[] alts;
+        public Block(List[] alts) {
+            this.alts = alts;
+        }
+        public String toString() {
+            StringBuffer buf = new StringBuffer();
+            buf.append("(");
+            for (int i = 0; i < alts.length; i++) {
+                List alt = alts[i];
+                if ( i>0 ) buf.append("|");
+                buf.append(alt.toString());
+            }
+            buf.append(")");
+            return buf.toString();
+        }
+    }
+
+    class TokenRef {
+        int ttype;
+        public TokenRef(int ttype) { this.ttype = ttype; }
+        public String toString() { return String.valueOf(ttype); }
+    }
+
+    class RuleRef {
+        int ruleIndex;
+        public RuleRef(int ruleIndex) { this.ruleIndex = ruleIndex; }
+        public String toString() { return String.valueOf(ruleIndex); }
+    }
+
+    public SerializedGrammar(String filename) throws IOException {
+        System.out.println("loading "+filename);
+        FileInputStream fis = new FileInputStream(filename);
+        BufferedInputStream bos = new BufferedInputStream(fis);
+        DataInputStream in = new DataInputStream(bos);
+        readFile(in);
+        in.close();
+    }
+
+    protected void readFile(DataInputStream in) throws IOException {
+        String cookie = readString(in); // get $ANTLR
+        if ( !cookie.equals(COOKIE) ) throw new IOException("not a serialized grammar file");
+        int version = in.readByte();
+        char grammarType = (char)in.readByte();
+        this.type = grammarType;
+        String grammarName = readString(in);
+        this.name = grammarName;
+        System.out.println(grammarType+" grammar "+grammarName);
+        int numRules = in.readShort();
+        System.out.println("num rules = "+numRules);
+        rules = readRules(in, numRules);
+    }
+
+    protected List readRules(DataInputStream in, int numRules) throws IOException {
+        List rules = new ArrayList();
+        for (int i=0; i<numRules; i++) {
+            Rule r = readRule(in);
+            rules.add(r);
+        }
+        return rules;
+    }
+
+    protected Rule readRule(DataInputStream in) throws IOException {
+        byte R = in.readByte();
+        if ( R!='R' ) throw new IOException("missing R on start of rule");
+        String name = readString(in);
+        System.out.println("rule: "+name);
+        byte B = in.readByte();
+        Block b = readBlock(in);
+        byte period = in.readByte();
+        if ( period!='.' ) throw new IOException("missing . on end of rule");
+        return new Rule(name, b);
+    }
+
+    protected Block readBlock(DataInputStream in) throws IOException {
+        int nalts = in.readShort();
+        List[] alts = new List[nalts];
+        //System.out.println("enter block n="+nalts);
+        for (int i=0; i<nalts; i++) {
+            List alt = readAlt(in);
+            alts[i] = alt;
+        }
+        //System.out.println("exit block");
+        return new Block(alts);
+    }
+
+    protected List readAlt(DataInputStream in) throws IOException {
+        List alt = new ArrayList();
+        byte A = in.readByte();
+        if ( A!='A' ) throw new IOException("missing A on start of alt");
+        byte cmd = in.readByte();
+        while ( cmd!=';' ) {
+            switch (cmd) {
+                case 't' :
+                    int ttype = in.readShort();
+                    alt.add(new TokenRef(ttype));
+                    //System.out.println("read token "+gr.getTokenDisplayName(ttype));
+                    break;
+                case 'r' :
+                    int ruleIndex = in.readShort();
+                    alt.add(new RuleRef(ruleIndex));
+                    //System.out.println("read rule "+gr.getRuleName(ruleIndex));
+                    break;
+                case '.' : // wildcard
+                    break;
+                case '-' : // range
+                    int from = in.readChar();
+                    int to = in.readChar();
+                    break;
+                case '~' : // not
+                    int notThisTokenType = in.readShort();
+                    break;
+                case 'B' : // nested block
+                    Block b = readBlock(in);
+                    alt.add(b);
+                    break;
+            }
+            cmd = in.readByte();
+        }
+        //System.out.println("exit alt");
+        return alt;
+    }
+
+    protected String readString(DataInputStream in) throws IOException {
+        byte c = in.readByte();
+        StringBuffer buf = new StringBuffer();
+        while ( c!=';' ) {
+            buf.append((char)c);
+            c = in.readByte();
+        }
+        return buf.toString();
+    }
+
+    public String toString() {
+        StringBuffer buf = new StringBuffer();
+        buf.append(type+" grammar "+name);
+        buf.append(rules);
+        return buf.toString();
+    }
+}
diff --git a/src/org/antlr/runtime/Token.java b/src/org/antlr/runtime/Token.java
new file mode 100755
index 0000000..b8eb95e
--- /dev/null
+++ b/src/org/antlr/runtime/Token.java
@@ -0,0 +1,92 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime;
+
+public interface Token {
+	public static final int EOR_TOKEN_TYPE = 1;
+
+	/** imaginary tree navigation type; traverse "get child" link */
+	public static final int DOWN = 2;
+	/** imaginary tree navigation type; finish with a child list */
+	public static final int UP = 3;
+
+	public static final int MIN_TOKEN_TYPE = UP+1;
+
+    public static final int EOF = CharStream.EOF;
+    // TODO: remove once we go ANTLR v3.3
+    public static final Token EOF_TOKEN = new CommonToken(EOF);
+
+	public static final int INVALID_TOKEN_TYPE = 0;
+	public static final Token INVALID_TOKEN = new CommonToken(INVALID_TOKEN_TYPE);
+
+	/** In an action, a lexer rule can set token to this SKIP_TOKEN and ANTLR
+	 *  will avoid creating a token for this symbol and try to fetch another.
+	 */
+	public static final Token SKIP_TOKEN = new CommonToken(INVALID_TOKEN_TYPE);
+
+	/** All tokens go to the parser (unless skip() is called in that rule)
+	 *  on a particular "channel".  The parser tunes to a particular channel
+	 *  so that whitespace etc... can go to the parser on a "hidden" channel.
+	 */
+	public static final int DEFAULT_CHANNEL = 0;
+	
+	/** Anything on different channel than DEFAULT_CHANNEL is not parsed
+	 *  by parser.
+	 */
+	public static final int HIDDEN_CHANNEL = 99;
+
+	/** Get the text of the token */
+	public String getText();
+	public void setText(String text);
+
+	public int getType();
+	public void setType(int ttype);
+	/**  The line number on which this token was matched; line=1..n */
+	public int getLine();
+    public void setLine(int line);
+
+	/** The index of the first character relative to the beginning of the line 0..n-1 */
+	public int getCharPositionInLine();
+	public void setCharPositionInLine(int pos);
+
+	public int getChannel();
+	public void setChannel(int channel);
+
+	/** An index from 0..n-1 of the token object in the input stream.
+	 *  This must be valid in order to use the ANTLRWorks debugger.
+	 */
+	public int getTokenIndex();
+	public void setTokenIndex(int index);
+
+	/** From what character stream was this token created?  You don't have to
+	 *  implement but it's nice to know where a Token comes from if you have
+	 *  include files etc... on the input.
+	 */
+	public CharStream getInputStream();
+	public void setInputStream(CharStream input);
+}
diff --git a/src/org/antlr/runtime/TokenRewriteStream.java b/src/org/antlr/runtime/TokenRewriteStream.java
new file mode 100755
index 0000000..8437441
--- /dev/null
+++ b/src/org/antlr/runtime/TokenRewriteStream.java
@@ -0,0 +1,590 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime;
+
+import java.util.*;
+
+/** Useful for dumping out the input stream after doing some
+ *  augmentation or other manipulations.
+ *
+ *  You can insert stuff, replace, and delete chunks.  Note that the
+ *  operations are done lazily--only if you convert the buffer to a
+ *  String.  This is very efficient because you are not moving data around
+ *  all the time.  As the buffer of tokens is converted to strings, the
+ *  toString() method(s) check to see if there is an operation at the
+ *  current index.  If so, the operation is done and then normal String
+ *  rendering continues on the buffer.  This is like having multiple Turing
+ *  machine instruction streams (programs) operating on a single input tape. :)
+ *
+ *  Since the operations are done lazily at toString-time, operations do not
+ *  screw up the token index values.  That is, an insert operation at token
+ *  index i does not change the index values for tokens i+1..n-1.
+ *
+ *  Because operations never actually alter the buffer, you may always get
+ *  the original token stream back without undoing anything.  Since
+ *  the instructions are queued up, you can easily simulate transactions and
+ *  roll back any changes if there is an error just by removing instructions.
+ *  For example,
+ *
+ *   CharStream input = new ANTLRFileStream("input");
+ *   TLexer lex = new TLexer(input);
+ *   TokenRewriteStream tokens = new TokenRewriteStream(lex);
+ *   T parser = new T(tokens);
+ *   parser.startRule();
+ *
+ * 	 Then in the rules, you can execute
+ *      Token t,u;
+ *      ...
+ *      input.insertAfter(t, "text to put after t");}
+ * 		input.insertAfter(u, "text after u");}
+ * 		System.out.println(tokens.toString());
+ *
+ *  Actually, you have to cast the 'input' to a TokenRewriteStream. :(
+ *
+ *  You can also have multiple "instruction streams" and get multiple
+ *  rewrites from a single pass over the input.  Just name the instruction
+ *  streams and use that name again when printing the buffer.  This could be
+ *  useful for generating a C file and also its header file--all from the
+ *  same buffer:
+ *
+ *      tokens.insertAfter("pass1", t, "text to put after t");}
+ * 		tokens.insertAfter("pass2", u, "text after u");}
+ * 		System.out.println(tokens.toString("pass1"));
+ * 		System.out.println(tokens.toString("pass2"));
+ *
+ *  If you don't use named rewrite streams, a "default" stream is used as
+ *  the first example shows.
+ */
+public class TokenRewriteStream extends CommonTokenStream {
+	public static final String DEFAULT_PROGRAM_NAME = "default";
+    public static final int PROGRAM_INIT_SIZE = 100;
+	public static final int MIN_TOKEN_INDEX = 0;
+
+	// Define the rewrite operation hierarchy
+
+	class RewriteOperation {
+        /** What index into rewrites List are we? */
+        protected int instructionIndex;
+        /** Token buffer index. */
+        protected int index;
+		protected Object text;
+
+		protected RewriteOperation(int index) {
+			this.index = index;
+		}
+
+		protected RewriteOperation(int index, Object text) {
+			this.index = index;
+			this.text = text;
+		}
+		/** Execute the rewrite operation by possibly adding to the buffer.
+		 *  Return the index of the next token to operate on.
+		 */
+		public int execute(StringBuffer buf) {
+			return index;
+		}
+		public String toString() {
+			String opName = getClass().getName();
+			int $index = opName.indexOf('$');
+			opName = opName.substring($index+1, opName.length());
+			return "<"+opName+"@"+tokens.get(index)+
+				   ":\""+text+"\">";
+		}
+	}
+
+	class InsertBeforeOp extends RewriteOperation {
+		public InsertBeforeOp(int index, Object text) {
+			super(index,text);
+		}
+		public int execute(StringBuffer buf) {
+			buf.append(text);
+			if ( tokens.get(index).getType()!=Token.EOF ) {
+				buf.append(tokens.get(index).getText());
+			}
+			return index+1;
+		}
+	}
+
+	/** I'm going to try replacing range from x..y with (y-x)+1 ReplaceOp
+	 *  instructions.
+	 */
+	class ReplaceOp extends RewriteOperation {
+		protected int lastIndex;
+		public ReplaceOp(int from, int to, Object text) {
+			super(from,text);
+			lastIndex = to;
+		}
+		public int execute(StringBuffer buf) {
+			if ( text!=null ) {
+				buf.append(text);
+			}
+			return lastIndex+1;
+		}
+		public String toString() {
+			if ( text==null ) {
+				return "<DeleteOp@"+tokens.get(index)+
+					   ".."+tokens.get(lastIndex)+">";
+			}
+			return "<ReplaceOp@"+tokens.get(index)+
+				   ".."+tokens.get(lastIndex)+":\""+text+"\">";
+		}
+	}
+
+	/** You may have multiple, named streams of rewrite operations.
+	 *  I'm calling these things "programs."
+	 *  Maps String (name) -> rewrite (List)
+	 */
+	protected Map programs = null;
+
+	/** Map String (program name) -> Integer index */
+	protected Map lastRewriteTokenIndexes = null;
+
+	public TokenRewriteStream() {
+		init();
+	}
+
+	protected void init() {
+		programs = new HashMap();
+		programs.put(DEFAULT_PROGRAM_NAME, new ArrayList(PROGRAM_INIT_SIZE));
+		lastRewriteTokenIndexes = new HashMap();
+	}
+
+	public TokenRewriteStream(TokenSource tokenSource) {
+	    super(tokenSource);
+		init();
+	}
+
+	public TokenRewriteStream(TokenSource tokenSource, int channel) {
+		super(tokenSource, channel);
+		init();
+	}
+
+	public void rollback(int instructionIndex) {
+		rollback(DEFAULT_PROGRAM_NAME, instructionIndex);
+	}
+
+	/** Rollback the instruction stream for a program so that
+	 *  the indicated instruction (via instructionIndex) is no
+	 *  longer in the stream.  UNTESTED!
+	 */
+	public void rollback(String programName, int instructionIndex) {
+		List is = (List)programs.get(programName);
+		if ( is!=null ) {
+			programs.put(programName, is.subList(MIN_TOKEN_INDEX,instructionIndex));
+		}
+	}
+
+	public void deleteProgram() {
+		deleteProgram(DEFAULT_PROGRAM_NAME);
+	}
+
+	/** Reset the program so that no instructions exist */
+	public void deleteProgram(String programName) {
+		rollback(programName, MIN_TOKEN_INDEX);
+	}
+
+	public void insertAfter(Token t, Object text) {
+		insertAfter(DEFAULT_PROGRAM_NAME, t, text);
+	}
+
+	public void insertAfter(int index, Object text) {
+		insertAfter(DEFAULT_PROGRAM_NAME, index, text);
+	}
+
+	public void insertAfter(String programName, Token t, Object text) {
+		insertAfter(programName,t.getTokenIndex(), text);
+	}
+
+	public void insertAfter(String programName, int index, Object text) {
+		// to insert after, just insert before next index (even if past end)
+		insertBefore(programName,index+1, text);
+	}
+
+	public void insertBefore(Token t, Object text) {
+		insertBefore(DEFAULT_PROGRAM_NAME, t, text);
+	}
+
+	public void insertBefore(int index, Object text) {
+		insertBefore(DEFAULT_PROGRAM_NAME, index, text);
+	}
+
+	public void insertBefore(String programName, Token t, Object text) {
+		insertBefore(programName, t.getTokenIndex(), text);
+	}
+
+	public void insertBefore(String programName, int index, Object text) {
+		RewriteOperation op = new InsertBeforeOp(index,text);
+		List rewrites = getProgram(programName);
+        op.instructionIndex = rewrites.size();
+        rewrites.add(op);		
+	}
+
+	public void replace(int index, Object text) {
+		replace(DEFAULT_PROGRAM_NAME, index, index, text);
+	}
+
+	public void replace(int from, int to, Object text) {
+		replace(DEFAULT_PROGRAM_NAME, from, to, text);
+	}
+
+	public void replace(Token indexT, Object text) {
+		replace(DEFAULT_PROGRAM_NAME, indexT, indexT, text);
+	}
+
+	public void replace(Token from, Token to, Object text) {
+		replace(DEFAULT_PROGRAM_NAME, from, to, text);
+	}
+
+	public void replace(String programName, int from, int to, Object text) {
+		if ( from > to || from<0 || to<0 || to >= tokens.size() ) {
+			throw new IllegalArgumentException("replace: range invalid: "+from+".."+to+"(size="+tokens.size()+")");
+		}
+		RewriteOperation op = new ReplaceOp(from, to, text);
+		List rewrites = getProgram(programName);
+        op.instructionIndex = rewrites.size();
+        rewrites.add(op);
+	}
+
+	public void replace(String programName, Token from, Token to, Object text) {
+		replace(programName,
+				from.getTokenIndex(),
+				to.getTokenIndex(),
+				text);
+	}
+
+	public void delete(int index) {
+		delete(DEFAULT_PROGRAM_NAME, index, index);
+	}
+
+	public void delete(int from, int to) {
+		delete(DEFAULT_PROGRAM_NAME, from, to);
+	}
+
+	public void delete(Token indexT) {
+		delete(DEFAULT_PROGRAM_NAME, indexT, indexT);
+	}
+
+	public void delete(Token from, Token to) {
+		delete(DEFAULT_PROGRAM_NAME, from, to);
+	}
+
+	public void delete(String programName, int from, int to) {
+		replace(programName,from,to,null);
+	}
+
+	public void delete(String programName, Token from, Token to) {
+		replace(programName,from,to,null);
+	}
+
+	public int getLastRewriteTokenIndex() {
+		return getLastRewriteTokenIndex(DEFAULT_PROGRAM_NAME);
+	}
+
+	protected int getLastRewriteTokenIndex(String programName) {
+		Integer I = (Integer)lastRewriteTokenIndexes.get(programName);
+		if ( I==null ) {
+			return -1;
+		}
+		return I.intValue();
+	}
+
+	protected void setLastRewriteTokenIndex(String programName, int i) {
+		lastRewriteTokenIndexes.put(programName, new Integer(i));
+	}
+
+	protected List getProgram(String name) {
+		List is = (List)programs.get(name);
+		if ( is==null ) {
+			is = initializeProgram(name);
+		}
+		return is;
+	}
+
+	private List initializeProgram(String name) {
+		List is = new ArrayList(PROGRAM_INIT_SIZE);
+		programs.put(name, is);
+		return is;
+	}
+
+	public String toOriginalString() {
+        fill();
+		return toOriginalString(MIN_TOKEN_INDEX, size()-1);
+	}
+
+	public String toOriginalString(int start, int end) {
+		StringBuffer buf = new StringBuffer();
+		for (int i=start; i>=MIN_TOKEN_INDEX && i<=end && i<tokens.size(); i++) {
+			if ( get(i).getType()!=Token.EOF ) buf.append(get(i).getText());
+		}
+		return buf.toString();
+	}
+
+	public String toString() {
+        fill();
+		return toString(MIN_TOKEN_INDEX, size()-1);
+	}
+
+	public String toString(String programName) {
+        fill();
+		return toString(programName, MIN_TOKEN_INDEX, size()-1);
+	}
+
+	public String toString(int start, int end) {
+		return toString(DEFAULT_PROGRAM_NAME, start, end);
+	}
+
+	public String toString(String programName, int start, int end) {
+		List rewrites = (List)programs.get(programName);
+
+        // ensure start/end are in range
+        if ( end>tokens.size()-1 ) end = tokens.size()-1;
+        if ( start<0 ) start = 0;
+
+        if ( rewrites==null || rewrites.size()==0 ) {
+			return toOriginalString(start,end); // no instructions to execute
+		}
+		StringBuffer buf = new StringBuffer();
+
+		// First, optimize instruction stream
+		Map indexToOp = reduceToSingleOperationPerIndex(rewrites);
+
+        // Walk buffer, executing instructions and emitting tokens
+        int i = start;
+        while ( i <= end && i < tokens.size() ) {
+			RewriteOperation op = (RewriteOperation)indexToOp.get(new Integer(i));
+			indexToOp.remove(new Integer(i)); // remove so any left have index size-1
+			Token t = (Token) tokens.get(i);
+			if ( op==null ) {
+				// no operation at that index, just dump token
+				if ( t.getType()!=Token.EOF ) buf.append(t.getText());
+				i++; // move to next token
+			}
+			else {
+				i = op.execute(buf); // execute operation and skip
+			}
+		}
+
+        // include stuff after end if it's last index in buffer
+        // So, if they did an insertAfter(lastValidIndex, "foo"), include
+        // foo if end==lastValidIndex.
+        if ( end==tokens.size()-1 ) {
+            // Scan any remaining operations after last token
+            // should be included (they will be inserts).
+            Iterator it = indexToOp.values().iterator();
+            while (it.hasNext()) {
+                RewriteOperation op = (RewriteOperation)it.next();
+                if ( op.index >= tokens.size()-1 ) buf.append(op.text);
+            }
+        }
+        return buf.toString();
+	}
+
+	/** We need to combine operations and report invalid operations (like
+	 *  overlapping replaces that are not completed nested).  Inserts to
+	 *  same index need to be combined etc...   Here are the cases:
+	 *
+	 *  I.i.u I.j.v								leave alone, nonoverlapping
+	 *  I.i.u I.i.v								combine: Iivu
+	 *
+	 *  R.i-j.u R.x-y.v	| i-j in x-y			delete first R
+	 *  R.i-j.u R.i-j.v							delete first R
+	 *  R.i-j.u R.x-y.v	| x-y in i-j			ERROR
+	 *  R.i-j.u R.x-y.v	| boundaries overlap	ERROR
+	 *
+	 *  Delete special case of replace (text==null):
+	 *  D.i-j.u D.x-y.v	| boundaries overlap	combine to max(min)..max(right)
+	 *
+	 *  I.i.u R.x-y.v | i in (x+1)-y			delete I (since insert before
+	 *											we're not deleting i)
+	 *  I.i.u R.x-y.v | i not in (x+1)-y		leave alone, nonoverlapping
+	 *  R.x-y.v I.i.u | i in x-y				ERROR
+	 *  R.x-y.v I.x.u 							R.x-y.uv (combine, delete I)
+	 *  R.x-y.v I.i.u | i not in x-y			leave alone, nonoverlapping
+	 *
+	 *  I.i.u = insert u before op @ index i
+	 *  R.x-y.u = replace x-y indexed tokens with u
+	 *
+	 *  First we need to examine replaces.  For any replace op:
+	 *
+	 * 		1. wipe out any insertions before op within that range.
+	 *		2. Drop any replace op before that is contained completely within
+	 *         that range.
+	 *		3. Throw exception upon boundary overlap with any previous replace.
+	 *
+	 *  Then we can deal with inserts:
+	 *
+	 * 		1. for any inserts to same index, combine even if not adjacent.
+	 * 		2. for any prior replace with same left boundary, combine this
+	 *         insert with replace and delete this replace.
+	 * 		3. throw exception if index in same range as previous replace
+	 *
+	 *  Don't actually delete; make op null in list. Easier to walk list.
+	 *  Later we can throw as we add to index -> op map.
+	 *
+	 *  Note that I.2 R.2-2 will wipe out I.2 even though, technically, the
+	 *  inserted stuff would be before the replace range.  But, if you
+	 *  add tokens in front of a method body '{' and then delete the method
+	 *  body, I think the stuff before the '{' you added should disappear too.
+	 *
+	 *  Return a map from token index to operation.
+	 */
+	protected Map reduceToSingleOperationPerIndex(List rewrites) {
+//		System.out.println("rewrites="+rewrites);
+
+		// WALK REPLACES
+		for (int i = 0; i < rewrites.size(); i++) {
+			RewriteOperation op = (RewriteOperation)rewrites.get(i);
+			if ( op==null ) continue;
+			if ( !(op instanceof ReplaceOp) ) continue;
+			ReplaceOp rop = (ReplaceOp)rewrites.get(i);
+			// Wipe prior inserts within range
+			List inserts = getKindOfOps(rewrites, InsertBeforeOp.class, i);
+			for (int j = 0; j < inserts.size(); j++) {
+				InsertBeforeOp iop = (InsertBeforeOp) inserts.get(j);
+				if ( iop.index == rop.index ) {
+					// E.g., insert before 2, delete 2..2; update replace
+					// text to include insert before, kill insert
+					rewrites.set(iop.instructionIndex, null);
+					rop.text = iop.text.toString() + (rop.text!=null?rop.text.toString():"");
+				}
+				else if ( iop.index > rop.index && iop.index <= rop.lastIndex ) {
+                    // delete insert as it's a no-op.
+                    rewrites.set(iop.instructionIndex, null);
+				}
+			}
+			// Drop any prior replaces contained within
+			List prevReplaces = getKindOfOps(rewrites, ReplaceOp.class, i);
+			for (int j = 0; j < prevReplaces.size(); j++) {
+				ReplaceOp prevRop = (ReplaceOp) prevReplaces.get(j);
+				if ( prevRop.index>=rop.index && prevRop.lastIndex <= rop.lastIndex ) {
+                    // delete replace as it's a no-op.
+                    rewrites.set(prevRop.instructionIndex, null);
+					continue;
+				}
+				// throw exception unless disjoint or identical
+				boolean disjoint =
+					prevRop.lastIndex<rop.index || prevRop.index > rop.lastIndex;
+				boolean same =
+					prevRop.index==rop.index && prevRop.lastIndex==rop.lastIndex;
+				// Delete special case of replace (text==null):
+				// D.i-j.u D.x-y.v	| boundaries overlap	combine to max(min)..max(right)
+				if ( prevRop.text==null && rop.text==null && !disjoint ) {
+					//System.out.println("overlapping deletes: "+prevRop+", "+rop);
+					rewrites.set(prevRop.instructionIndex, null); // kill first delete
+					rop.index = Math.min(prevRop.index, rop.index);
+					rop.lastIndex = Math.max(prevRop.lastIndex, rop.lastIndex);
+					System.out.println("new rop "+rop);
+				}
+				else if ( !disjoint && !same ) {
+					throw new IllegalArgumentException("replace op boundaries of "+rop+
+													   " overlap with previous "+prevRop);
+				}
+			}
+		}
+
+		// WALK INSERTS
+		for (int i = 0; i < rewrites.size(); i++) {
+			RewriteOperation op = (RewriteOperation)rewrites.get(i);
+			if ( op==null ) continue;
+			if ( !(op instanceof InsertBeforeOp) ) continue;
+			InsertBeforeOp iop = (InsertBeforeOp)rewrites.get(i);
+			// combine current insert with prior if any at same index
+			List prevInserts = getKindOfOps(rewrites, InsertBeforeOp.class, i);
+			for (int j = 0; j < prevInserts.size(); j++) {
+				InsertBeforeOp prevIop = (InsertBeforeOp) prevInserts.get(j);
+				if ( prevIop.index == iop.index ) { // combine objects
+					// convert to strings...we're in process of toString'ing
+					// whole token buffer so no lazy eval issue with any templates
+					iop.text = catOpText(iop.text,prevIop.text);
+                    // delete redundant prior insert
+                    rewrites.set(prevIop.instructionIndex, null);
+				}
+			}
+			// look for replaces where iop.index is in range; error
+			List prevReplaces = getKindOfOps(rewrites, ReplaceOp.class, i);
+			for (int j = 0; j < prevReplaces.size(); j++) {
+				ReplaceOp rop = (ReplaceOp) prevReplaces.get(j);
+				if ( iop.index == rop.index ) {
+					rop.text = catOpText(iop.text,rop.text);
+					rewrites.set(i, null);  // delete current insert
+					continue;
+				}
+				if ( iop.index >= rop.index && iop.index <= rop.lastIndex ) {
+					throw new IllegalArgumentException("insert op "+iop+
+													   " within boundaries of previous "+rop);
+				}
+			}
+		}
+		// System.out.println("rewrites after="+rewrites);
+		Map m = new HashMap();
+		for (int i = 0; i < rewrites.size(); i++) {
+			RewriteOperation op = (RewriteOperation)rewrites.get(i);
+			if ( op==null ) continue; // ignore deleted ops
+			if ( m.get(new Integer(op.index))!=null ) {
+				throw new Error("should only be one op per index");
+			}
+			m.put(new Integer(op.index), op);
+		}
+		//System.out.println("index to op: "+m);
+		return m;
+	}
+
+	protected String catOpText(Object a, Object b) {
+		String x = "";
+		String y = "";
+		if ( a!=null ) x = a.toString();
+		if ( b!=null ) y = b.toString();
+		return x+y;
+	}
+	protected List getKindOfOps(List rewrites, Class kind) {
+		return getKindOfOps(rewrites, kind, rewrites.size());
+	}
+
+    /** Get all operations before an index of a particular kind */
+    protected List getKindOfOps(List rewrites, Class kind, int before) {
+		List ops = new ArrayList();
+		for (int i=0; i<before && i<rewrites.size(); i++) {
+			RewriteOperation op = (RewriteOperation)rewrites.get(i);
+			if ( op==null ) continue; // ignore deleted
+			if ( op.getClass() == kind ) ops.add(op);
+		}		
+		return ops;
+	}
+
+	public String toDebugString() {
+		return toDebugString(MIN_TOKEN_INDEX, size()-1);
+	}
+
+	public String toDebugString(int start, int end) {
+		StringBuffer buf = new StringBuffer();
+		for (int i=start; i>=MIN_TOKEN_INDEX && i<=end && i<tokens.size(); i++) {
+			buf.append(get(i));
+		}
+		return buf.toString();
+	}
+}
diff --git a/src/org/antlr/runtime/TokenSource.java b/src/org/antlr/runtime/TokenSource.java
new file mode 100755
index 0000000..1f4dc64
--- /dev/null
+++ b/src/org/antlr/runtime/TokenSource.java
@@ -0,0 +1,54 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime;
+
+/** A source of tokens must provide a sequence of tokens via nextToken()
+ *  and also must reveal it's source of characters; CommonToken's text is
+ *  computed from a CharStream; it only store indices into the char stream.
+ *
+ *  Errors from the lexer are never passed to the parser.  Either you want
+ *  to keep going or you do not upon token recognition error.  If you do not
+ *  want to continue lexing then you do not want to continue parsing.  Just
+ *  throw an exception not under RecognitionException and Java will naturally
+ *  toss you all the way out of the recognizers.  If you want to continue
+ *  lexing then you should not throw an exception to the parser--it has already
+ *  requested a token.  Keep lexing until you get a valid one.  Just report
+ *  errors and keep going, looking for a valid token.
+ */
+public interface TokenSource {
+	/** Return a Token object from your input stream (usually a CharStream).
+	 *  Do not fail/return upon lexing error; keep chewing on the characters
+	 *  until you get a good one; errors are not passed through to the parser.
+	 */
+	public Token nextToken();
+
+	/** Where are you getting tokens from? normally the implication will simply
+	 *  ask lexers input stream.
+	 */
+	public String getSourceName();
+}
diff --git a/src/org/antlr/runtime/TokenStream.java b/src/org/antlr/runtime/TokenStream.java
new file mode 100755
index 0000000..1b43c14
--- /dev/null
+++ b/src/org/antlr/runtime/TokenStream.java
@@ -0,0 +1,75 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime;
+
+import java.util.List;
+
+/** A stream of tokens accessing tokens from a TokenSource */
+public interface TokenStream extends IntStream {
+    /** Get Token at current input pointer + i ahead where i=1 is next Token.
+	 *  i<0 indicates tokens in the past.  So -1 is previous token and -2 is
+	 *  two tokens ago. LT(0) is undefined.  For i>=n, return Token.EOFToken.
+	 *  Return null for LT(0) and any index that results in an absolute address
+	 *  that is negative.
+	 */
+    public Token LT(int k);
+
+	/** How far ahead has the stream been asked to look?  The return
+	 *  value is a valid index from 0..n-1.
+	 */
+	int range();
+	
+	/** Get a token at an absolute index i; 0..n-1.  This is really only
+	 *  needed for profiling and debugging and token stream rewriting.
+	 *  If you don't want to buffer up tokens, then this method makes no
+	 *  sense for you.  Naturally you can't use the rewrite stream feature.
+	 *  I believe DebugTokenStream can easily be altered to not use
+	 *  this method, removing the dependency.
+	 */
+	public Token get(int i);
+
+	/** Where is this stream pulling tokens from?  This is not the name, but
+	 *  the object that provides Token objects.
+	 */
+	public TokenSource getTokenSource();
+
+	/** Return the text of all tokens from start to stop, inclusive.
+	 *  If the stream does not buffer all the tokens then it can just
+	 *  return "" or null;  Users should not access $ruleLabel.text in
+	 *  an action of course in that case.
+	 */
+	public String toString(int start, int stop);
+
+	/** Because the user is not required to use a token with an index stored
+	 *  in it, we must provide a means for two token objects themselves to
+	 *  indicate the start/end location.  Most often this will just delegate
+	 *  to the other toString(int,int).  This is also parallel with
+	 *  the TreeNodeStream.toString(Object,Object).
+	 */
+	public String toString(Token start, Token stop);
+}
diff --git a/src/org/antlr/runtime/UnbufferedTokenStream.java b/src/org/antlr/runtime/UnbufferedTokenStream.java
new file mode 100755
index 0000000..0b0e979
--- /dev/null
+++ b/src/org/antlr/runtime/UnbufferedTokenStream.java
@@ -0,0 +1,82 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime;
+
+import org.antlr.runtime.misc.LookaheadStream;
+
+import java.util.List;
+import java.util.NoSuchElementException;
+
+/** A token stream that pulls tokens from the code source on-demand and
+ *  without tracking a complete buffer of the tokens. This stream buffers
+ *  the minimum number of tokens possible.  It's the same as
+ *  OnDemandTokenStream except that OnDemandTokenStream buffers all tokens.
+ *
+ *  You can't use this stream if you pass whitespace or other off-channel
+ *  tokens to the parser. The stream can't ignore off-channel tokens.
+ * 
+ *  You can only look backwards 1 token: LT(-1).
+ *
+ *  Use this when you need to read from a socket or other infinite stream.
+ *
+ *  @see BufferedTokenStream
+ *  @see CommonTokenStream
+ */
+public class UnbufferedTokenStream extends LookaheadStream<Token> implements TokenStream {
+	protected TokenSource tokenSource;
+    protected int tokenIndex = 0; // simple counter to set token index in tokens
+
+    /** Skip tokens on any channel but this one; this is how we skip whitespace... */
+    protected int channel = Token.DEFAULT_CHANNEL;
+
+	public UnbufferedTokenStream(TokenSource tokenSource) {
+		this.tokenSource = tokenSource;
+	}
+
+	public Token nextElement() {
+		Token t = tokenSource.nextToken();
+        t.setTokenIndex(tokenIndex++);
+		return t;
+	}
+
+    public boolean isEOF(Token o) { return o.getType() == Token.EOF; }    
+
+	public TokenSource getTokenSource() { return tokenSource; }
+
+	public String toString(int start, int stop) { return "n/a"; }
+
+	public String toString(Token start, Token stop) { return "n/a"; }
+
+    public int LA(int i) { return LT(i).getType(); }
+
+    public Token get(int i) {
+        throw new UnsupportedOperationException("Absolute token indexes are meaningless in an unbuffered stream");
+    }
+
+	public String getSourceName() {	return tokenSource.getSourceName();	}
+}
diff --git a/src/org/antlr/runtime/UnwantedTokenException.java b/src/org/antlr/runtime/UnwantedTokenException.java
new file mode 100755
index 0000000..feb7445
--- /dev/null
+++ b/src/org/antlr/runtime/UnwantedTokenException.java
@@ -0,0 +1,53 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime;
+
+/** An extra token while parsing a TokenStream */
+public class UnwantedTokenException extends MismatchedTokenException {
+	/** Used for remote debugger deserialization */
+	public UnwantedTokenException() {;}
+
+	public UnwantedTokenException(int expecting, IntStream input) {
+		super(expecting, input);
+	}
+
+	public Token getUnexpectedToken() {
+		return token;
+	}
+
+	public String toString() {
+		String exp = ", expected "+expecting;
+		if ( expecting==Token.INVALID_TOKEN_TYPE ) {
+			exp = "";
+		}
+		if ( token==null ) {
+			return "UnwantedTokenException(found="+null+exp+")";
+		}
+		return "UnwantedTokenException(found="+token.getText()+exp+")";
+	}
+}
diff --git a/src/org/antlr/runtime/debug/BlankDebugEventListener.java b/src/org/antlr/runtime/debug/BlankDebugEventListener.java
new file mode 100755
index 0000000..d70aa26
--- /dev/null
+++ b/src/org/antlr/runtime/debug/BlankDebugEventListener.java
@@ -0,0 +1,77 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime.debug;
+
+import org.antlr.runtime.RecognitionException;
+import org.antlr.runtime.Token;
+
+/** A blank listener that does nothing; useful for real classes so
+ *  they don't have to have lots of blank methods and are less
+ *  sensitive to updates to debug interface.
+ */
+public class BlankDebugEventListener implements DebugEventListener {
+	public void enterRule(String grammarFileName, String ruleName) {}
+	public void exitRule(String grammarFileName, String ruleName) {}
+	public void enterAlt(int alt) {}
+	public void enterSubRule(int decisionNumber) {}
+	public void exitSubRule(int decisionNumber) {}
+	public void enterDecision(int decisionNumber, boolean couldBacktrack) {}
+	public void exitDecision(int decisionNumber) {}
+	public void location(int line, int pos) {}
+	public void consumeToken(Token token) {}
+	public void consumeHiddenToken(Token token) {}
+	public void LT(int i, Token t) {}
+	public void mark(int i) {}
+	public void rewind(int i) {}
+	public void rewind() {}
+	public void beginBacktrack(int level) {}
+	public void endBacktrack(int level, boolean successful) {}
+	public void recognitionException(RecognitionException e) {}
+	public void beginResync() {}
+	public void endResync() {}
+	public void semanticPredicate(boolean result, String predicate) {}
+	public void commence() {}
+	public void terminate() {}
+
+	// Tree parsing stuff
+
+	public void consumeNode(Object t) {}
+	public void LT(int i, Object t) {}
+
+	// AST Stuff
+
+	public void nilNode(Object t) {}
+	public void errorNode(Object t) {}
+	public void createNode(Object t) {}
+	public void createNode(Object node, Token token) {}
+	public void becomeRoot(Object newRoot, Object oldRoot) {}
+	public void addChild(Object root, Object child) {}
+	public void setTokenBoundaries(Object t, int tokenStartIndex, int tokenStopIndex) {}
+}
+
+
diff --git a/src/org/antlr/runtime/debug/DebugEventHub.java b/src/org/antlr/runtime/debug/DebugEventHub.java
new file mode 100755
index 0000000..7bfe6a8
--- /dev/null
+++ b/src/org/antlr/runtime/debug/DebugEventHub.java
@@ -0,0 +1,292 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime.debug;
+
+import org.antlr.runtime.Token;
+import org.antlr.runtime.RecognitionException;
+
+import java.util.List;
+import java.util.ArrayList;
+
+/** Broadcast debug events to multiple listeners.  Lets you debug and still
+ *  use the event mechanism to build parse trees etc...  Not thread-safe.
+ *  Don't add events in one thread while parser fires events in another.
+ * 
+ *  @see also DebugEventRepeater
+ */
+public class DebugEventHub implements DebugEventListener {
+	protected List listeners = new ArrayList();
+
+	public DebugEventHub(DebugEventListener listener) {
+		listeners.add(listener);
+	}
+
+	public DebugEventHub(DebugEventListener a, DebugEventListener b) {
+		listeners.add(a);
+		listeners.add(b);
+	}
+
+	/** Add another listener to broadcast events too.  Not thread-safe.
+	 *  Don't add events in one thread while parser fires events in another.
+	 */
+	public void addListener(DebugEventListener listener) {
+		listeners.add(listener);
+	}
+	
+	/* To avoid a mess like this:
+		public void enterRule(final String ruleName) {
+			broadcast(new Code(){
+				public void exec(DebugEventListener listener) {listener.enterRule(ruleName);}}
+				);
+		}
+		I am dup'ing the for-loop in each.  Where are Java closures!? blech!
+	 */
+
+	public void enterRule(String grammarFileName, String ruleName) {
+		for (int i = 0; i < listeners.size(); i++) {
+			DebugEventListener listener = (DebugEventListener)listeners.get(i);
+			listener.enterRule(grammarFileName,ruleName);
+		}
+	}
+
+	public void exitRule(String grammarFileName, String ruleName) {
+		for (int i = 0; i < listeners.size(); i++) {
+			DebugEventListener listener = (DebugEventListener)listeners.get(i);
+			listener.exitRule(grammarFileName, ruleName);
+		}
+	}
+
+	public void enterAlt(int alt) {
+		for (int i = 0; i < listeners.size(); i++) {
+			DebugEventListener listener = (DebugEventListener)listeners.get(i);
+			listener.enterAlt(alt);
+		}
+	}
+
+	public void enterSubRule(int decisionNumber) {
+		for (int i = 0; i < listeners.size(); i++) {
+			DebugEventListener listener = (DebugEventListener)listeners.get(i);
+			listener.enterSubRule(decisionNumber);
+		}
+	}
+
+	public void exitSubRule(int decisionNumber) {
+		for (int i = 0; i < listeners.size(); i++) {
+			DebugEventListener listener = (DebugEventListener)listeners.get(i);
+			listener.exitSubRule(decisionNumber);
+		}
+	}
+
+	public void enterDecision(int decisionNumber, boolean couldBacktrack) {
+		for (int i = 0; i < listeners.size(); i++) {
+			DebugEventListener listener = (DebugEventListener)listeners.get(i);
+			listener.enterDecision(decisionNumber, couldBacktrack);
+		}
+	}
+
+	public void exitDecision(int decisionNumber) {
+		for (int i = 0; i < listeners.size(); i++) {
+			DebugEventListener listener = (DebugEventListener)listeners.get(i);
+			listener.exitDecision(decisionNumber);
+		}
+	}
+
+	public void location(int line, int pos) {
+		for (int i = 0; i < listeners.size(); i++) {
+			DebugEventListener listener = (DebugEventListener)listeners.get(i);
+			listener.location(line, pos);
+		}
+	}
+
+	public void consumeToken(Token token) {
+		for (int i = 0; i < listeners.size(); i++) {
+			DebugEventListener listener = (DebugEventListener)listeners.get(i);
+			listener.consumeToken(token);
+		}
+	}
+
+	public void consumeHiddenToken(Token token) {
+		for (int i = 0; i < listeners.size(); i++) {
+			DebugEventListener listener = (DebugEventListener)listeners.get(i);
+			listener.consumeHiddenToken(token);
+		}
+	}
+
+	public void LT(int index, Token t) {
+		for (int i = 0; i < listeners.size(); i++) {
+			DebugEventListener listener = (DebugEventListener)listeners.get(i);
+			listener.LT(index, t);
+		}
+	}
+
+	public void mark(int index) {
+		for (int i = 0; i < listeners.size(); i++) {
+			DebugEventListener listener = (DebugEventListener)listeners.get(i);
+			listener.mark(index);
+		}
+	}
+
+	public void rewind(int index) {
+		for (int i = 0; i < listeners.size(); i++) {
+			DebugEventListener listener = (DebugEventListener)listeners.get(i);
+			listener.rewind(index);
+		}
+	}
+
+	public void rewind() {
+		for (int i = 0; i < listeners.size(); i++) {
+			DebugEventListener listener = (DebugEventListener)listeners.get(i);
+			listener.rewind();
+		}
+	}
+
+	public void beginBacktrack(int level) {
+		for (int i = 0; i < listeners.size(); i++) {
+			DebugEventListener listener = (DebugEventListener)listeners.get(i);
+			listener.beginBacktrack(level);
+		}
+	}
+
+	public void endBacktrack(int level, boolean successful) {
+		for (int i = 0; i < listeners.size(); i++) {
+			DebugEventListener listener = (DebugEventListener)listeners.get(i);
+			listener.endBacktrack(level, successful);
+		}
+	}
+
+	public void recognitionException(RecognitionException e) {
+		for (int i = 0; i < listeners.size(); i++) {
+			DebugEventListener listener = (DebugEventListener)listeners.get(i);
+			listener.recognitionException(e);
+		}
+	}
+
+	public void beginResync() {
+		for (int i = 0; i < listeners.size(); i++) {
+			DebugEventListener listener = (DebugEventListener)listeners.get(i);
+			listener.beginResync();
+		}
+	}
+
+	public void endResync() {
+		for (int i = 0; i < listeners.size(); i++) {
+			DebugEventListener listener = (DebugEventListener)listeners.get(i);
+			listener.endResync();
+		}
+	}
+
+	public void semanticPredicate(boolean result, String predicate) {
+		for (int i = 0; i < listeners.size(); i++) {
+			DebugEventListener listener = (DebugEventListener)listeners.get(i);
+			listener.semanticPredicate(result, predicate);
+		}
+	}
+
+	public void commence() {
+		for (int i = 0; i < listeners.size(); i++) {
+			DebugEventListener listener = (DebugEventListener)listeners.get(i);
+			listener.commence();
+		}
+	}
+
+	public void terminate() {
+		for (int i = 0; i < listeners.size(); i++) {
+			DebugEventListener listener = (DebugEventListener)listeners.get(i);
+			listener.terminate();
+		}
+	}
+
+
+	// Tree parsing stuff
+
+	public void consumeNode(Object t) {
+		for (int i = 0; i < listeners.size(); i++) {
+			DebugEventListener listener = (DebugEventListener)listeners.get(i);
+			listener.consumeNode(t);
+		}
+	}
+
+	public void LT(int index, Object t) {
+		for (int i = 0; i < listeners.size(); i++) {
+			DebugEventListener listener = (DebugEventListener)listeners.get(i);
+			listener.LT(index, t);
+		}
+	}
+
+
+	// AST Stuff
+
+	public void nilNode(Object t) {
+		for (int i = 0; i < listeners.size(); i++) {
+			DebugEventListener listener = (DebugEventListener)listeners.get(i);
+			listener.nilNode(t);
+		}
+	}
+
+	public void errorNode(Object t) {
+		for (int i = 0; i < listeners.size(); i++) {
+			DebugEventListener listener = (DebugEventListener)listeners.get(i);
+			listener.errorNode(t);
+		}
+	}
+
+	public void createNode(Object t) {
+		for (int i = 0; i < listeners.size(); i++) {
+			DebugEventListener listener = (DebugEventListener)listeners.get(i);
+			listener.createNode(t);
+		}
+	}
+
+	public void createNode(Object node, Token token) {
+		for (int i = 0; i < listeners.size(); i++) {
+			DebugEventListener listener = (DebugEventListener)listeners.get(i);
+			listener.createNode(node, token);
+		}
+	}
+
+	public void becomeRoot(Object newRoot, Object oldRoot) {
+		for (int i = 0; i < listeners.size(); i++) {
+			DebugEventListener listener = (DebugEventListener)listeners.get(i);
+			listener.becomeRoot(newRoot, oldRoot);
+		}
+	}
+
+	public void addChild(Object root, Object child) {
+		for (int i = 0; i < listeners.size(); i++) {
+			DebugEventListener listener = (DebugEventListener)listeners.get(i);
+			listener.addChild(root, child);
+		}
+	}
+
+	public void setTokenBoundaries(Object t, int tokenStartIndex, int tokenStopIndex) {
+		for (int i = 0; i < listeners.size(); i++) {
+			DebugEventListener listener = (DebugEventListener)listeners.get(i);
+			listener.setTokenBoundaries(t, tokenStartIndex, tokenStopIndex);
+		}
+	}
+}
diff --git a/src/org/antlr/runtime/debug/DebugEventListener.java b/src/org/antlr/runtime/debug/DebugEventListener.java
new file mode 100755
index 0000000..163b5cd
--- /dev/null
+++ b/src/org/antlr/runtime/debug/DebugEventListener.java
@@ -0,0 +1,323 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime.debug;
+
+import org.antlr.runtime.RecognitionException;
+import org.antlr.runtime.Token;
+
+/** All debugging events that a recognizer can trigger.
+ *
+ *  I did not create a separate AST debugging interface as it would create
+ *  lots of extra classes and DebugParser has a dbg var defined, which makes
+ *  it hard to change to ASTDebugEventListener.  I looked hard at this issue
+ *  and it is easier to understand as one monolithic event interface for all
+ *  possible events.  Hopefully, adding ST debugging stuff won't be bad.  Leave
+ *  for future. 4/26/2006.
+ */
+public interface DebugEventListener {
+	/** Moved to version 2 for v3.1: added grammar name to enter/exit Rule */
+	public static final String PROTOCOL_VERSION = "2";
+	
+	/** serialized version of true */
+	public static final int TRUE = 1;
+	public static final int FALSE = 0;
+
+	/** The parser has just entered a rule.  No decision has been made about
+	 *  which alt is predicted.  This is fired AFTER init actions have been
+	 *  executed.  Attributes are defined and available etc...
+	 *  The grammarFileName allows composite grammars to jump around among
+	 *  multiple grammar files.
+	 */
+	public void enterRule(String grammarFileName, String ruleName);
+
+	/** Because rules can have lots of alternatives, it is very useful to
+	 *  know which alt you are entering.  This is 1..n for n alts.
+	 */
+	public void enterAlt(int alt);
+
+	/** This is the last thing executed before leaving a rule.  It is
+	 *  executed even if an exception is thrown.  This is triggered after
+	 *  error reporting and recovery have occurred (unless the exception is
+	 *  not caught in this rule).  This implies an "exitAlt" event.
+	 *  The grammarFileName allows composite grammars to jump around among
+	 *  multiple grammar files.
+	 */
+	public void exitRule(String grammarFileName, String ruleName);
+
+	/** Track entry into any (...) subrule other EBNF construct */
+	public void enterSubRule(int decisionNumber);
+
+	public void exitSubRule(int decisionNumber);
+
+	/** Every decision, fixed k or arbitrary, has an enter/exit event
+	 *  so that a GUI can easily track what LT/consume events are
+	 *  associated with prediction.  You will see a single enter/exit
+	 *  subrule but multiple enter/exit decision events, one for each
+	 *  loop iteration.
+	 */
+	public void enterDecision(int decisionNumber, boolean couldBacktrack);
+
+	public void exitDecision(int decisionNumber);
+
+	/** An input token was consumed; matched by any kind of element.
+	 *  Trigger after the token was matched by things like match(), matchAny().
+	 */
+	public void consumeToken(Token t);
+
+	/** An off-channel input token was consumed.
+	 *  Trigger after the token was matched by things like match(), matchAny().
+	 *  (unless of course the hidden token is first stuff in the input stream).
+	 */
+	public void consumeHiddenToken(Token t);
+
+	/** Somebody (anybody) looked ahead.  Note that this actually gets
+	 *  triggered by both LA and LT calls.  The debugger will want to know
+	 *  which Token object was examined.  Like consumeToken, this indicates
+	 *  what token was seen at that depth.  A remote debugger cannot look
+	 *  ahead into a file it doesn't have so LT events must pass the token
+	 *  even if the info is redundant.
+	 */
+	public void LT(int i, Token t);
+
+	/** The parser is going to look arbitrarily ahead; mark this location,
+	 *  the token stream's marker is sent in case you need it.
+	 */
+	public void mark(int marker);
+
+	/** After an arbitrairly long lookahead as with a cyclic DFA (or with
+	 *  any backtrack), this informs the debugger that stream should be
+	 *  rewound to the position associated with marker.
+	 */
+	public void rewind(int marker);
+
+	/** Rewind to the input position of the last marker.
+	 *  Used currently only after a cyclic DFA and just
+	 *  before starting a sem/syn predicate to get the
+	 *  input position back to the start of the decision.
+	 *  Do not "pop" the marker off the state.  mark(i)
+	 *  and rewind(i) should balance still.
+	 */
+	public void rewind();
+
+	public void beginBacktrack(int level);
+
+	public void endBacktrack(int level, boolean successful);
+
+	/** To watch a parser move through the grammar, the parser needs to
+	 *  inform the debugger what line/charPos it is passing in the grammar.
+	 *  For now, this does not know how to switch from one grammar to the
+	 *  other and back for island grammars etc...
+	 *
+	 *  This should also allow breakpoints because the debugger can stop
+	 *  the parser whenever it hits this line/pos.
+	 */
+	public void location(int line, int pos);
+
+	/** A recognition exception occurred such as NoViableAltException.  I made
+	 *  this a generic event so that I can alter the exception hierachy later
+	 *  without having to alter all the debug objects.
+	 *
+	 *  Upon error, the stack of enter rule/subrule must be properly unwound.
+	 *  If no viable alt occurs it is within an enter/exit decision, which
+	 *  also must be rewound.  Even the rewind for each mark must be unwount.
+	 *  In the Java target this is pretty easy using try/finally, if a bit
+	 *  ugly in the generated code.  The rewind is generated in DFA.predict()
+	 *  actually so no code needs to be generated for that.  For languages
+	 *  w/o this "finally" feature (C++?), the target implementor will have
+	 *  to build an event stack or something.
+	 *
+	 *  Across a socket for remote debugging, only the RecognitionException
+	 *  data fields are transmitted.  The token object or whatever that
+	 *  caused the problem was the last object referenced by LT.  The
+	 *  immediately preceding LT event should hold the unexpected Token or
+	 *  char.
+	 *
+	 *  Here is a sample event trace for grammar:
+	 *
+	 *  b : C ({;}A|B) // {;} is there to prevent A|B becoming a set
+     *    | D
+     *    ;
+     *
+	 *  The sequence for this rule (with no viable alt in the subrule) for
+	 *  input 'c c' (there are 3 tokens) is:
+	 *
+	 *		commence
+	 *		LT(1)
+	 *		enterRule b
+	 *		location 7 1
+	 *		enter decision 3
+	 *		LT(1)
+	 *		exit decision 3
+	 *		enterAlt1
+	 *		location 7 5
+	 *		LT(1)
+	 *		consumeToken [c/<4>,1:0]
+	 *		location 7 7
+	 *		enterSubRule 2
+	 *		enter decision 2
+	 *		LT(1)
+	 *		LT(1)
+	 *		recognitionException NoViableAltException 2 1 2
+	 *		exit decision 2
+	 *		exitSubRule 2
+	 *		beginResync
+	 *		LT(1)
+	 *		consumeToken [c/<4>,1:1]
+	 *		LT(1)
+	 *		endResync
+	 *		LT(-1)
+	 *		exitRule b
+	 *		terminate
+	 */
+	public void recognitionException(RecognitionException e);
+
+	/** Indicates the recognizer is about to consume tokens to resynchronize
+	 *  the parser.  Any consume events from here until the recovered event
+	 *  are not part of the parse--they are dead tokens.
+	 */
+	public void beginResync();
+
+	/** Indicates that the recognizer has finished consuming tokens in order
+	 *  to resychronize.  There may be multiple beginResync/endResync pairs
+	 *  before the recognizer comes out of errorRecovery mode (in which
+	 *  multiple errors are suppressed).  This will be useful
+	 *  in a gui where you want to probably grey out tokens that are consumed
+	 *  but not matched to anything in grammar.  Anything between
+	 *  a beginResync/endResync pair was tossed out by the parser.
+	 */
+	public void endResync();
+
+	/** A semantic predicate was evaluate with this result and action text */
+	public void semanticPredicate(boolean result, String predicate);
+
+	/** Announce that parsing has begun.  Not technically useful except for
+	 *  sending events over a socket.  A GUI for example will launch a thread
+	 *  to connect and communicate with a remote parser.  The thread will want
+	 *  to notify the GUI when a connection is made.  ANTLR parsers
+	 *  trigger this upon entry to the first rule (the ruleLevel is used to
+	 *  figure this out).
+	 */
+	public void commence();
+
+	/** Parsing is over; successfully or not.  Mostly useful for telling
+	 *  remote debugging listeners that it's time to quit.  When the rule
+	 *  invocation level goes to zero at the end of a rule, we are done
+	 *  parsing.
+	 */
+	public void terminate();
+
+
+	// T r e e  P a r s i n g
+
+	/** Input for a tree parser is an AST, but we know nothing for sure
+	 *  about a node except its type and text (obtained from the adaptor).
+	 *  This is the analog of the consumeToken method.  Again, the ID is
+	 *  the hashCode usually of the node so it only works if hashCode is
+	 *  not implemented.  If the type is UP or DOWN, then
+	 *  the ID is not really meaningful as it's fixed--there is
+	 *  just one UP node and one DOWN navigation node.
+	 * @param t
+	 */
+	public void consumeNode(Object t);
+
+	/** The tree parser lookedahead.  If the type is UP or DOWN,
+	 *  then the ID is not really meaningful as it's fixed--there is
+	 *  just one UP node and one DOWN navigation node.
+	 */
+	public void LT(int i, Object t);
+
+
+	// A S T  E v e n t s
+
+	/** A nil was created (even nil nodes have a unique ID...
+	 *  they are not "null" per se).  As of 4/28/2006, this
+	 *  seems to be uniquely triggered when starting a new subtree
+	 *  such as when entering a subrule in automatic mode and when
+	 *  building a tree in rewrite mode.
+     *
+ 	 *  If you are receiving this event over a socket via
+	 *  RemoteDebugEventSocketListener then only t.ID is set.
+	 */
+	public void nilNode(Object t);
+
+	/** Upon syntax error, recognizers bracket the error with an error node
+	 *  if they are building ASTs.
+	 * @param t
+	 */
+	public void errorNode(Object t);
+
+	/** Announce a new node built from token elements such as type etc...
+	 * 
+	 *  If you are receiving this event over a socket via
+	 *  RemoteDebugEventSocketListener then only t.ID, type, text are
+	 *  set.
+	 */
+	public void createNode(Object t);
+
+	/** Announce a new node built from an existing token.
+	 *
+	 *  If you are receiving this event over a socket via
+	 *  RemoteDebugEventSocketListener then only node.ID and token.tokenIndex
+	 *  are set.
+	 */
+	public void createNode(Object node, Token token);
+
+	/** Make a node the new root of an existing root.  See
+	 *
+	 *  Note: the newRootID parameter is possibly different
+	 *  than the TreeAdaptor.becomeRoot() newRoot parameter.
+	 *  In our case, it will always be the result of calling
+	 *  TreeAdaptor.becomeRoot() and not root_n or whatever.
+	 *
+	 *  The listener should assume that this event occurs
+	 *  only when the current subrule (or rule) subtree is
+	 *  being reset to newRootID.
+	 * 
+	 *  If you are receiving this event over a socket via
+	 *  RemoteDebugEventSocketListener then only IDs are set.
+	 *
+	 *  @see org.antlr.runtime.tree.TreeAdaptor.becomeRoot()
+	 */
+	public void becomeRoot(Object newRoot, Object oldRoot);
+
+	/** Make childID a child of rootID.
+	 *
+	 *  If you are receiving this event over a socket via
+	 *  RemoteDebugEventSocketListener then only IDs are set.
+	 * 
+	 *  @see org.antlr.runtime.tree.TreeAdaptor.addChild()
+	 */
+	public void addChild(Object root, Object child);
+
+	/** Set the token start/stop token index for a subtree root or node.
+	 *
+	 *  If you are receiving this event over a socket via
+	 *  RemoteDebugEventSocketListener then only t.ID is set.
+	 */
+	public void setTokenBoundaries(Object t, int tokenStartIndex, int tokenStopIndex);
+}
diff --git a/src/org/antlr/runtime/debug/DebugEventRepeater.java b/src/org/antlr/runtime/debug/DebugEventRepeater.java
new file mode 100755
index 0000000..8fb6b66
--- /dev/null
+++ b/src/org/antlr/runtime/debug/DebugEventRepeater.java
@@ -0,0 +1,88 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime.debug;
+
+import org.antlr.runtime.Token;
+import org.antlr.runtime.RecognitionException;
+
+/** A simple event repeater (proxy) that delegates all functionality to the
+ *  listener sent into the ctor.  Useful if you want to listen in on a few
+ *  debug events w/o interrupting the debugger.  Just subclass the repeater
+ *  and override the methods you want to listen in on.  Remember to call
+ *  the method in this class so the event will continue on to the original
+ *  recipient.
+ *
+ *  @see DebugEventHub
+ */
+public class DebugEventRepeater implements DebugEventListener {
+	protected DebugEventListener listener;
+
+	public DebugEventRepeater(DebugEventListener listener) {
+		this.listener = listener;
+	}
+	
+	public void enterRule(String grammarFileName, String ruleName) { listener.enterRule(grammarFileName, ruleName); }
+	public void exitRule(String grammarFileName, String ruleName) { listener.exitRule(grammarFileName, ruleName); }
+	public void enterAlt(int alt) { listener.enterAlt(alt); }
+	public void enterSubRule(int decisionNumber) { listener.enterSubRule(decisionNumber); }
+	public void exitSubRule(int decisionNumber) { listener.exitSubRule(decisionNumber); }
+	public void enterDecision(int decisionNumber, boolean couldBacktrack) { listener.enterDecision(decisionNumber, couldBacktrack); }
+	public void exitDecision(int decisionNumber) { listener.exitDecision(decisionNumber); }
+	public void location(int line, int pos) { listener.location(line, pos); }
+	public void consumeToken(Token token) { listener.consumeToken(token); }
+	public void consumeHiddenToken(Token token) { listener.consumeHiddenToken(token); }
+	public void LT(int i, Token t) { listener.LT(i, t); }
+	public void mark(int i) { listener.mark(i); }
+	public void rewind(int i) { listener.rewind(i); }
+	public void rewind() { listener.rewind(); }
+	public void beginBacktrack(int level) { listener.beginBacktrack(level); }
+	public void endBacktrack(int level, boolean successful) { listener.endBacktrack(level, successful); }
+	public void recognitionException(RecognitionException e) { listener.recognitionException(e); }
+	public void beginResync() { listener.beginResync(); }
+	public void endResync() { listener.endResync(); }
+	public void semanticPredicate(boolean result, String predicate) { listener.semanticPredicate(result, predicate); }
+	public void commence() { listener.commence(); }
+	public void terminate() { listener.terminate(); }
+
+	// Tree parsing stuff
+
+	public void consumeNode(Object t) { listener.consumeNode(t); }
+	public void LT(int i, Object t) { listener.LT(i, t); }
+
+	// AST Stuff
+
+	public void nilNode(Object t) { listener.nilNode(t); }
+	public void errorNode(Object t) { listener.errorNode(t); }
+	public void createNode(Object t) { listener.createNode(t); }
+	public void createNode(Object node, Token token) { listener.createNode(node, token); }
+	public void becomeRoot(Object newRoot, Object oldRoot) { listener.becomeRoot(newRoot, oldRoot); }
+	public void addChild(Object root, Object child) { listener.addChild(root, child); }
+	public void setTokenBoundaries(Object t, int tokenStartIndex, int tokenStopIndex) {
+		listener.setTokenBoundaries(t, tokenStartIndex, tokenStopIndex);
+	}
+}
diff --git a/src/org/antlr/runtime/debug/DebugEventSocketProxy.java b/src/org/antlr/runtime/debug/DebugEventSocketProxy.java
new file mode 100755
index 0000000..3b480ad
--- /dev/null
+++ b/src/org/antlr/runtime/debug/DebugEventSocketProxy.java
@@ -0,0 +1,354 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime.debug;
+
+import org.antlr.runtime.RecognitionException;
+import org.antlr.runtime.Token;
+import org.antlr.runtime.BaseRecognizer;
+import org.antlr.runtime.tree.TreeAdaptor;
+
+import java.io.*;
+import java.net.ServerSocket;
+import java.net.Socket;
+
+/** A proxy debug event listener that forwards events over a socket to
+ *  a debugger (or any other listener) using a simple text-based protocol;
+ *  one event per line.  ANTLRWorks listens on server socket with a
+ *  RemoteDebugEventSocketListener instance.  These two objects must therefore
+ *  be kept in sync.  New events must be handled on both sides of socket.
+ */
+public class DebugEventSocketProxy extends BlankDebugEventListener {
+	public static final int DEFAULT_DEBUGGER_PORT = 49100; // was 49153
+	protected int port = DEFAULT_DEBUGGER_PORT;
+	protected ServerSocket serverSocket;
+	protected Socket socket;
+	protected String grammarFileName;
+	protected PrintWriter out;
+	protected BufferedReader in;
+
+	/** Who am i debugging? */
+	protected BaseRecognizer recognizer;
+
+	/** Almost certainly the recognizer will have adaptor set, but
+	 *  we don't know how to cast it (Parser or TreeParser) to get
+	 *  the adaptor field.  Must be set with a constructor. :(
+	 */
+	protected TreeAdaptor adaptor;
+
+	public DebugEventSocketProxy(BaseRecognizer recognizer, TreeAdaptor adaptor) {
+		this(recognizer, DEFAULT_DEBUGGER_PORT, adaptor);
+	}
+
+	public DebugEventSocketProxy(BaseRecognizer recognizer, int port, TreeAdaptor adaptor) {
+		this.grammarFileName = recognizer.getGrammarFileName();
+		this.adaptor = adaptor;
+		this.port = port;
+	}
+
+	public void handshake() throws IOException {
+		if ( serverSocket==null ) {
+			serverSocket = new ServerSocket(port);
+			socket = serverSocket.accept();
+			socket.setTcpNoDelay(true);
+			OutputStream os = socket.getOutputStream();
+			OutputStreamWriter osw = new OutputStreamWriter(os, "UTF8");
+			out = new PrintWriter(new BufferedWriter(osw));
+			InputStream is = socket.getInputStream();
+			InputStreamReader isr = new InputStreamReader(is, "UTF8");
+			in = new BufferedReader(isr);
+			out.println("ANTLR "+ DebugEventListener.PROTOCOL_VERSION);
+			out.println("grammar \""+ grammarFileName);
+			out.flush();
+			ack();
+		}
+	}
+
+	public void commence() {
+		// don't bother sending event; listener will trigger upon connection
+	}
+
+	public void terminate() {
+		transmit("terminate");
+		out.close();
+		try {
+			socket.close();
+		}
+		catch (IOException ioe) {
+			ioe.printStackTrace(System.err);
+		}
+	}
+
+	protected void ack() {
+		try {
+			in.readLine();
+		}
+		catch (IOException ioe) {
+			ioe.printStackTrace(System.err);
+		}
+	}
+
+	protected void transmit(String event) {
+		out.println(event);
+		out.flush();
+		ack();
+	}
+
+	public void enterRule(String grammarFileName, String ruleName) {
+		transmit("enterRule\t"+grammarFileName+"\t"+ruleName);
+	}
+
+	public void enterAlt(int alt) {
+		transmit("enterAlt\t"+alt);
+	}
+
+	public void exitRule(String grammarFileName, String ruleName) {
+		transmit("exitRule\t"+grammarFileName+"\t"+ruleName);
+	}
+
+	public void enterSubRule(int decisionNumber) {
+		transmit("enterSubRule\t"+decisionNumber);
+	}
+
+	public void exitSubRule(int decisionNumber) {
+		transmit("exitSubRule\t"+decisionNumber);
+	}
+
+	public void enterDecision(int decisionNumber, boolean couldBacktrack) {
+		transmit("enterDecision\t"+decisionNumber+"\t"+couldBacktrack);
+	}
+
+	public void exitDecision(int decisionNumber) {
+		transmit("exitDecision\t"+decisionNumber);
+	}
+
+	public void consumeToken(Token t) {
+		String buf = serializeToken(t);
+		transmit("consumeToken\t"+buf);
+	}
+
+	public void consumeHiddenToken(Token t) {
+		String buf = serializeToken(t);
+		transmit("consumeHiddenToken\t"+buf);
+	}
+
+	public void LT(int i, Token t) {
+        if(t != null)
+            transmit("LT\t"+i+"\t"+serializeToken(t));
+	}
+
+	public void mark(int i) {
+		transmit("mark\t"+i);
+	}
+
+	public void rewind(int i) {
+		transmit("rewind\t"+i);
+	}
+
+	public void rewind() {
+		transmit("rewind");
+	}
+
+	public void beginBacktrack(int level) {
+		transmit("beginBacktrack\t"+level);
+	}
+
+	public void endBacktrack(int level, boolean successful) {
+		transmit("endBacktrack\t"+level+"\t"+(successful?TRUE:FALSE));
+	}
+
+	public void location(int line, int pos) {
+		transmit("location\t"+line+"\t"+pos);
+	}
+
+	public void recognitionException(RecognitionException e) {
+		StringBuffer buf = new StringBuffer(50);
+		buf.append("exception\t");
+		buf.append(e.getClass().getName());
+		// dump only the data common to all exceptions for now
+		buf.append("\t");
+		buf.append(e.index);
+		buf.append("\t");
+		buf.append(e.line);
+		buf.append("\t");
+		buf.append(e.charPositionInLine);
+		transmit(buf.toString());
+	}
+
+	public void beginResync() {
+		transmit("beginResync");
+	}
+
+	public void endResync() {
+		transmit("endResync");
+	}
+
+	public void semanticPredicate(boolean result, String predicate) {
+		StringBuffer buf = new StringBuffer(50);
+		buf.append("semanticPredicate\t");
+		buf.append(result);
+		serializeText(buf, predicate);
+		transmit(buf.toString());
+	}
+
+	// A S T  P a r s i n g  E v e n t s
+
+	public void consumeNode(Object t) {
+		StringBuffer buf = new StringBuffer(50);
+		buf.append("consumeNode");
+		serializeNode(buf, t);
+		transmit(buf.toString());
+	}
+
+	public void LT(int i, Object t) {
+		int ID = adaptor.getUniqueID(t);
+		String text = adaptor.getText(t);
+		int type = adaptor.getType(t);
+		StringBuffer buf = new StringBuffer(50);
+		buf.append("LN\t"); // lookahead node; distinguish from LT in protocol
+		buf.append(i);
+		serializeNode(buf, t);
+		transmit(buf.toString());
+	}
+
+	protected void serializeNode(StringBuffer buf, Object t) {
+		int ID = adaptor.getUniqueID(t);
+		String text = adaptor.getText(t);
+		int type = adaptor.getType(t);
+		buf.append("\t");
+		buf.append(ID);
+		buf.append("\t");
+		buf.append(type);
+		Token token = adaptor.getToken(t);
+		int line = -1;
+		int pos = -1;
+		if ( token!=null ) {
+			line = token.getLine();
+			pos = token.getCharPositionInLine();
+		}
+		buf.append("\t");
+		buf.append(line);
+		buf.append("\t");
+		buf.append(pos);
+		int tokenIndex = adaptor.getTokenStartIndex(t);
+		buf.append("\t");
+		buf.append(tokenIndex);
+		serializeText(buf, text);
+	}
+
+
+	// A S T  E v e n t s
+
+	public void nilNode(Object t) {
+		int ID = adaptor.getUniqueID(t);
+		transmit("nilNode\t"+ID);
+	}
+
+	public void errorNode(Object t) {
+		int ID = adaptor.getUniqueID(t);
+		String text = t.toString();
+		StringBuffer buf = new StringBuffer(50);
+		buf.append("errorNode\t");
+		buf.append(ID);
+		buf.append("\t");
+		buf.append(Token.INVALID_TOKEN_TYPE);
+		serializeText(buf, text);
+		transmit(buf.toString());
+	}
+
+	public void createNode(Object t) {
+		int ID = adaptor.getUniqueID(t);
+		String text = adaptor.getText(t);
+		int type = adaptor.getType(t);
+		StringBuffer buf = new StringBuffer(50);
+		buf.append("createNodeFromTokenElements\t");
+		buf.append(ID);
+		buf.append("\t");
+		buf.append(type);
+		serializeText(buf, text);
+		transmit(buf.toString());
+	}
+
+	public void createNode(Object node, Token token) {
+		int ID = adaptor.getUniqueID(node);
+		int tokenIndex = token.getTokenIndex();
+		transmit("createNode\t"+ID+"\t"+tokenIndex);
+	}
+
+	public void becomeRoot(Object newRoot, Object oldRoot) {
+		int newRootID = adaptor.getUniqueID(newRoot);
+		int oldRootID = adaptor.getUniqueID(oldRoot);
+		transmit("becomeRoot\t"+newRootID+"\t"+oldRootID);
+	}
+
+	public void addChild(Object root, Object child) {
+		int rootID = adaptor.getUniqueID(root);
+		int childID = adaptor.getUniqueID(child);
+		transmit("addChild\t"+rootID+"\t"+childID);
+	}
+
+	public void setTokenBoundaries(Object t, int tokenStartIndex, int tokenStopIndex) {
+		int ID = adaptor.getUniqueID(t);
+		transmit("setTokenBoundaries\t"+ID+"\t"+tokenStartIndex+"\t"+tokenStopIndex);
+	}
+
+
+    // support
+
+    public void setTreeAdaptor(TreeAdaptor adaptor) { this.adaptor = adaptor; }
+    public TreeAdaptor getTreeAdaptor() { return adaptor; }
+
+    protected String serializeToken(Token t) {
+        StringBuffer buf = new StringBuffer(50);
+        buf.append(t.getTokenIndex()); buf.append('\t');
+        buf.append(t.getType()); buf.append('\t');
+        buf.append(t.getChannel()); buf.append('\t');
+        buf.append(t.getLine()); buf.append('\t');
+		buf.append(t.getCharPositionInLine());
+		serializeText(buf, t.getText());
+		return buf.toString();
+	}
+
+	protected void serializeText(StringBuffer buf, String text) {
+		buf.append("\t\"");
+		if ( text==null ) {
+			text = "";
+		}
+		// escape \n and \r all text for token appears to exist on one line
+		// this escape is slow but easy to understand
+		text = escapeNewlines(text);
+		buf.append(text);
+	}
+
+	protected String escapeNewlines(String txt) {
+		txt = txt.replaceAll("%","%25");   // escape all escape char ;)
+		txt = txt.replaceAll("\n","%0A");  // escape \n
+		txt = txt.replaceAll("\r","%0D");  // escape \r
+		return txt;
+	}
+}
+
diff --git a/src/org/antlr/runtime/debug/DebugParser.java b/src/org/antlr/runtime/debug/DebugParser.java
new file mode 100755
index 0000000..49d78e7
--- /dev/null
+++ b/src/org/antlr/runtime/debug/DebugParser.java
@@ -0,0 +1,98 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime.debug;
+
+import org.antlr.runtime.*;
+
+import java.io.IOException;
+
+public class DebugParser extends Parser {
+	/** Who to notify when events in the parser occur. */
+	protected DebugEventListener dbg = null;
+
+	/** Used to differentiate between fixed lookahead and cyclic DFA decisions
+	 *  while profiling.
+ 	 */
+	public boolean isCyclicDecision = false;
+
+	/** Create a normal parser except wrap the token stream in a debug
+	 *  proxy that fires consume events.
+	 */
+	public DebugParser(TokenStream input, DebugEventListener dbg, RecognizerSharedState state) {
+		super(input instanceof DebugTokenStream?input:new DebugTokenStream(input,dbg), state);
+		setDebugListener(dbg);
+	}
+
+	public DebugParser(TokenStream input, RecognizerSharedState state) {
+		super(input instanceof DebugTokenStream?input:new DebugTokenStream(input,null), state);
+	}
+
+	public DebugParser(TokenStream input, DebugEventListener dbg) {
+		this(input instanceof DebugTokenStream?input:new DebugTokenStream(input,dbg), dbg, null);
+	}
+
+	/** Provide a new debug event listener for this parser.  Notify the
+	 *  input stream too that it should send events to this listener.
+	 */
+	public void setDebugListener(DebugEventListener dbg) {
+		if ( input instanceof DebugTokenStream ) {
+			((DebugTokenStream)input).setDebugListener(dbg);
+		}
+		this.dbg = dbg;
+	}
+
+	public DebugEventListener getDebugListener() {
+		return dbg;
+	}
+
+	public void reportError(IOException e) {
+		System.err.println(e);
+		e.printStackTrace(System.err);
+	}
+
+	public void beginResync() {
+		dbg.beginResync();
+	}
+
+	public void endResync() {
+		dbg.endResync();
+	}
+
+	public void beginBacktrack(int level) {
+		dbg.beginBacktrack(level);
+	}
+
+	public void endBacktrack(int level, boolean successful) {
+		dbg.endBacktrack(level,successful);		
+	}
+
+	public void reportError(RecognitionException e) {
+		super.reportError(e);
+		dbg.recognitionException(e);
+	}
+}
diff --git a/src/org/antlr/runtime/debug/DebugTokenStream.java b/src/org/antlr/runtime/debug/DebugTokenStream.java
new file mode 100755
index 0000000..9a7a75f
--- /dev/null
+++ b/src/org/antlr/runtime/debug/DebugTokenStream.java
@@ -0,0 +1,156 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime.debug;
+
+import org.antlr.runtime.*;
+
+import java.util.List;
+
+public class DebugTokenStream implements TokenStream {
+	protected DebugEventListener dbg;
+	public TokenStream input;
+	protected boolean initialStreamState = true;
+
+	/** Track the last mark() call result value for use in rewind(). */
+	protected int lastMarker;
+
+	public DebugTokenStream(TokenStream input, DebugEventListener dbg) {
+		this.input = input;
+		setDebugListener(dbg);
+		// force TokenStream to get at least first valid token
+		// so we know if there are any hidden tokens first in the stream
+		input.LT(1);
+	}
+
+	public void setDebugListener(DebugEventListener dbg) {
+		this.dbg = dbg;
+	}
+
+	public void consume() {
+		if ( initialStreamState ) {
+			consumeInitialHiddenTokens();
+		}
+		int a = input.index();
+		Token t = input.LT(1);
+		input.consume();
+		int b = input.index();
+		dbg.consumeToken(t);
+		if ( b>a+1 ) {
+			// then we consumed more than one token; must be off channel tokens
+			for (int i=a+1; i<b; i++) {
+				dbg.consumeHiddenToken(input.get(i));
+			}
+		}
+	}
+
+	/* consume all initial off-channel tokens */
+	protected void consumeInitialHiddenTokens() {
+		int firstOnChannelTokenIndex = input.index();
+		for (int i=0; i<firstOnChannelTokenIndex; i++) {
+			dbg.consumeHiddenToken(input.get(i));
+		}
+		initialStreamState = false;
+	}
+
+	public Token LT(int i) {
+		if ( initialStreamState ) {
+			consumeInitialHiddenTokens();
+		}
+		dbg.LT(i, input.LT(i));
+		return input.LT(i);
+	}
+
+	public int LA(int i) {
+		if ( initialStreamState ) {
+			consumeInitialHiddenTokens();
+		}
+		dbg.LT(i, input.LT(i));
+		return input.LA(i);
+	}
+
+	public Token get(int i) {
+		return input.get(i);
+	}
+
+	public int mark() {
+		lastMarker = input.mark();
+		dbg.mark(lastMarker);
+		return lastMarker;
+	}
+
+	public int index() {
+		return input.index();
+	}
+
+	public int range() {
+		return input.range();
+	}
+
+	public void rewind(int marker) {
+		dbg.rewind(marker);
+		input.rewind(marker);
+	}
+
+	public void rewind() {
+		dbg.rewind();
+		input.rewind(lastMarker);
+	}
+
+	public void release(int marker) {
+	}
+
+	public void seek(int index) {
+		// TODO: implement seek in dbg interface
+		// db.seek(index);
+		input.seek(index);
+	}
+
+	public int size() {
+		return input.size();
+	}
+
+	public TokenSource getTokenSource() {
+		return input.getTokenSource();
+	}
+
+	public String getSourceName() {
+		return getTokenSource().getSourceName();
+	}
+
+	public String toString() {
+		return input.toString();
+	}
+
+	public String toString(int start, int stop) {
+		return input.toString(start,stop);
+	}
+
+	public String toString(Token start, Token stop) {
+		return input.toString(start,stop);
+	}
+}
diff --git a/src/org/antlr/runtime/debug/DebugTreeAdaptor.java b/src/org/antlr/runtime/debug/DebugTreeAdaptor.java
new file mode 100755
index 0000000..c72a2b6
--- /dev/null
+++ b/src/org/antlr/runtime/debug/DebugTreeAdaptor.java
@@ -0,0 +1,250 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime.debug;
+
+import org.antlr.runtime.Token;
+import org.antlr.runtime.TokenStream;
+import org.antlr.runtime.RecognitionException;
+import org.antlr.runtime.tree.TreeAdaptor;
+
+/** A TreeAdaptor proxy that fires debugging events to a DebugEventListener
+ *  delegate and uses the TreeAdaptor delegate to do the actual work.  All
+ *  AST events are triggered by this adaptor; no code gen changes are needed
+ *  in generated rules.  Debugging events are triggered *after* invoking
+ *  tree adaptor routines.
+ *
+ *  Trees created with actions in rewrite actions like "-> ^(ADD {foo} {bar})"
+ *  cannot be tracked as they might not use the adaptor to create foo, bar.
+ *  The debug listener has to deal with tree node IDs for which it did
+ *  not see a createNode event.  A single <unknown> node is sufficient even
+ *  if it represents a whole tree.
+ */
+public class DebugTreeAdaptor implements TreeAdaptor {
+	protected DebugEventListener dbg;
+	protected TreeAdaptor adaptor;
+
+	public DebugTreeAdaptor(DebugEventListener dbg, TreeAdaptor adaptor) {
+		this.dbg = dbg;
+		this.adaptor = adaptor;
+	}
+
+	public Object create(Token payload) {
+		if ( payload.getTokenIndex() < 0 ) {
+			// could be token conjured up during error recovery
+			return create(payload.getType(), payload.getText());
+		}
+		Object node = adaptor.create(payload);
+		dbg.createNode(node, payload);
+		return node;
+	}
+
+	public Object errorNode(TokenStream input, Token start, Token stop,
+							RecognitionException e)
+	{
+		Object node = adaptor.errorNode(input, start, stop, e);
+		if ( node!=null ) {
+			dbg.errorNode(node);
+		}
+		return node;
+	}
+
+	public Object dupTree(Object tree) {
+		Object t = adaptor.dupTree(tree);
+		// walk the tree and emit create and add child events
+		// to simulate what dupTree has done. dupTree does not call this debug
+		// adapter so I must simulate.
+		simulateTreeConstruction(t);
+		return t;
+	}
+
+	/** ^(A B C): emit create A, create B, add child, ...*/
+	protected void simulateTreeConstruction(Object t) {
+		dbg.createNode(t);
+		int n = adaptor.getChildCount(t);
+		for (int i=0; i<n; i++) {
+			Object child = adaptor.getChild(t, i);
+			simulateTreeConstruction(child);
+			dbg.addChild(t, child);
+		}
+	}
+
+	public Object dupNode(Object treeNode) {
+		Object d = adaptor.dupNode(treeNode);
+		dbg.createNode(d);
+		return d;
+	}
+
+	public Object nil() {
+		Object node = adaptor.nil();
+		dbg.nilNode(node);
+		return node;
+	}
+
+	public boolean isNil(Object tree) {
+		return adaptor.isNil(tree);
+	}
+
+	public void addChild(Object t, Object child) {
+		if ( t==null || child==null ) {
+			return;
+		}
+		adaptor.addChild(t,child);
+		dbg.addChild(t, child);
+	}
+
+	public Object becomeRoot(Object newRoot, Object oldRoot) {
+		Object n = adaptor.becomeRoot(newRoot, oldRoot);
+		dbg.becomeRoot(newRoot, oldRoot);
+		return n;
+	}
+
+	public Object rulePostProcessing(Object root) {
+		return adaptor.rulePostProcessing(root);
+	}
+
+	public void addChild(Object t, Token child) {
+		Object n = this.create(child);
+		this.addChild(t, n);
+	}
+
+	public Object becomeRoot(Token newRoot, Object oldRoot) {
+		Object n = this.create(newRoot);
+		adaptor.becomeRoot(n, oldRoot);
+		dbg.becomeRoot(newRoot, oldRoot);
+		return n;
+	}
+
+	public Object create(int tokenType, Token fromToken) {
+		Object node = adaptor.create(tokenType, fromToken);
+		dbg.createNode(node);
+		return node;
+	}
+
+	public Object create(int tokenType, Token fromToken, String text) {
+		Object node = adaptor.create(tokenType, fromToken, text);
+		dbg.createNode(node);
+		return node;
+	}
+
+	public Object create(int tokenType, String text) {
+		Object node = adaptor.create(tokenType, text);
+		dbg.createNode(node);
+		return node;
+	}
+
+	public int getType(Object t) {
+		return adaptor.getType(t);
+	}
+
+	public void setType(Object t, int type) {
+		adaptor.setType(t, type);
+	}
+
+	public String getText(Object t) {
+		return adaptor.getText(t);
+	}
+
+	public void setText(Object t, String text) {
+		adaptor.setText(t, text);
+	}
+
+	public Token getToken(Object t) {
+		return adaptor.getToken(t);
+	}
+
+	public void setTokenBoundaries(Object t, Token startToken, Token stopToken) {
+		adaptor.setTokenBoundaries(t, startToken, stopToken);
+		if ( t!=null && startToken!=null && stopToken!=null ) {
+			dbg.setTokenBoundaries(
+				t, startToken.getTokenIndex(),
+				stopToken.getTokenIndex());
+		}
+	}
+
+	public int getTokenStartIndex(Object t) {
+		return adaptor.getTokenStartIndex(t);
+	}
+
+	public int getTokenStopIndex(Object t) {
+		return adaptor.getTokenStopIndex(t);
+	}
+
+	public Object getChild(Object t, int i) {
+		return adaptor.getChild(t, i);
+	}
+
+	public void setChild(Object t, int i, Object child) {
+		adaptor.setChild(t, i, child);
+	}
+
+	public Object deleteChild(Object t, int i) {
+		return deleteChild(t, i);
+	}
+
+	public int getChildCount(Object t) {
+		return adaptor.getChildCount(t);
+	}
+
+	public int getUniqueID(Object node) {
+		return adaptor.getUniqueID(node);
+	}
+
+	public Object getParent(Object t) {
+		return adaptor.getParent(t);
+	}
+
+	public int getChildIndex(Object t) {
+		return adaptor.getChildIndex(t);
+	}
+
+	public void setParent(Object t, Object parent) {
+		adaptor.setParent(t, parent);
+	}
+
+	public void setChildIndex(Object t, int index) {
+		adaptor.setChildIndex(t, index);
+	}
+
+	public void replaceChildren(Object parent, int startChildIndex, int stopChildIndex, Object t) {
+		adaptor.replaceChildren(parent, startChildIndex, stopChildIndex, t);
+	}
+
+	// support
+
+	public DebugEventListener getDebugListener() {
+		return dbg;
+	}
+
+	public void setDebugListener(DebugEventListener dbg) {
+		this.dbg = dbg;
+	}
+
+	public TreeAdaptor getTreeAdaptor() {
+		return adaptor;
+	}
+}
diff --git a/src/org/antlr/runtime/debug/DebugTreeNodeStream.java b/src/org/antlr/runtime/debug/DebugTreeNodeStream.java
new file mode 100755
index 0000000..92ff009
--- /dev/null
+++ b/src/org/antlr/runtime/debug/DebugTreeNodeStream.java
@@ -0,0 +1,155 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime.debug;
+
+import org.antlr.runtime.tree.TreeAdaptor;
+import org.antlr.runtime.tree.TreeNodeStream;
+import org.antlr.runtime.TokenStream;
+
+/** Debug any tree node stream.  The constructor accepts the stream
+ *  and a debug listener.  As node stream calls come in, debug events
+ *  are triggered.
+ */
+public class DebugTreeNodeStream implements TreeNodeStream {
+	protected DebugEventListener dbg;
+	protected TreeAdaptor adaptor;
+	protected TreeNodeStream input;
+	protected boolean initialStreamState = true;
+
+	/** Track the last mark() call result value for use in rewind(). */
+	protected int lastMarker;
+
+	public DebugTreeNodeStream(TreeNodeStream input,
+							   DebugEventListener dbg)
+	{
+		this.input = input;
+		this.adaptor = input.getTreeAdaptor();
+		this.input.setUniqueNavigationNodes(true);
+		setDebugListener(dbg);
+	}
+
+	public void setDebugListener(DebugEventListener dbg) {
+		this.dbg = dbg;
+	}
+
+	public TreeAdaptor getTreeAdaptor() {
+		return adaptor;
+	}
+
+	public void consume() {
+		Object node = input.LT(1);
+		input.consume();
+		dbg.consumeNode(node);
+	}
+
+	public Object get(int i) {
+		return input.get(i);
+	}
+
+	public Object LT(int i) {
+		Object node = input.LT(i);
+		int ID = adaptor.getUniqueID(node);
+		String text = adaptor.getText(node);
+		int type = adaptor.getType(node);
+		dbg.LT(i, node);
+		return node;
+	}
+
+	public int LA(int i) {
+		Object node = input.LT(i);
+		int ID = adaptor.getUniqueID(node);
+		String text = adaptor.getText(node);
+		int type = adaptor.getType(node);
+		dbg.LT(i, node);
+		return type;
+	}
+
+	public int mark() {
+		lastMarker = input.mark();
+		dbg.mark(lastMarker);
+		return lastMarker;
+	}
+
+	public int index() {
+		return input.index();
+	}
+
+	public void rewind(int marker) {
+		dbg.rewind(marker);
+		input.rewind(marker);
+	}
+
+	public void rewind() {
+		dbg.rewind();
+		input.rewind(lastMarker);
+	}
+
+	public void release(int marker) {
+	}
+
+	public void seek(int index) {
+		// TODO: implement seek in dbg interface
+		// db.seek(index);
+		input.seek(index);
+	}
+
+	public int size() {
+		return input.size();
+	}
+
+    public void reset() { ; }
+
+    public Object getTreeSource() {
+		return input;
+	}
+
+	public String getSourceName() {
+		return getTokenStream().getSourceName();
+	}
+
+	public TokenStream getTokenStream() {
+		return input.getTokenStream();
+	}
+
+	/** It is normally this object that instructs the node stream to
+	 *  create unique nav nodes, but to satisfy interface, we have to
+	 *  define it.  It might be better to ignore the parameter but
+	 *  there might be a use for it later, so I'll leave.
+	 */
+	public void setUniqueNavigationNodes(boolean uniqueNavigationNodes) {
+		input.setUniqueNavigationNodes(uniqueNavigationNodes);
+	}
+
+	public void replaceChildren(Object parent, int startChildIndex, int stopChildIndex, Object t) {
+		input.replaceChildren(parent, startChildIndex, stopChildIndex, t);
+	}
+
+	public String toString(Object start, Object stop) {
+		return input.toString(start,stop);
+	}
+}
diff --git a/src/org/antlr/runtime/debug/DebugTreeParser.java b/src/org/antlr/runtime/debug/DebugTreeParser.java
new file mode 100755
index 0000000..6e1ece8
--- /dev/null
+++ b/src/org/antlr/runtime/debug/DebugTreeParser.java
@@ -0,0 +1,109 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime.debug;
+
+import org.antlr.runtime.*;
+import org.antlr.runtime.tree.TreeNodeStream;
+import org.antlr.runtime.tree.TreeParser;
+
+import java.io.IOException;
+
+public class DebugTreeParser extends TreeParser {
+	/** Who to notify when events in the parser occur. */
+	protected DebugEventListener dbg = null;
+
+	/** Used to differentiate between fixed lookahead and cyclic DFA decisions
+	 *  while profiling.
+ 	 */
+	public boolean isCyclicDecision = false;
+
+	/** Create a normal parser except wrap the token stream in a debug
+	 *  proxy that fires consume events.
+	 */
+	public DebugTreeParser(TreeNodeStream input, DebugEventListener dbg, RecognizerSharedState state) {
+		super(input instanceof DebugTreeNodeStream?input:new DebugTreeNodeStream(input,dbg), state);
+		setDebugListener(dbg);
+	}
+
+	public DebugTreeParser(TreeNodeStream input, RecognizerSharedState state) {
+		super(input instanceof DebugTreeNodeStream?input:new DebugTreeNodeStream(input,null), state);
+	}
+
+	public DebugTreeParser(TreeNodeStream input, DebugEventListener dbg) {
+		this(input instanceof DebugTreeNodeStream?input:new DebugTreeNodeStream(input,dbg), dbg, null);
+	}
+
+	/** Provide a new debug event listener for this parser.  Notify the
+	 *  input stream too that it should send events to this listener.
+	 */
+	public void setDebugListener(DebugEventListener dbg) {
+		if ( input instanceof DebugTreeNodeStream ) {
+			((DebugTreeNodeStream)input).setDebugListener(dbg);
+		}
+		this.dbg = dbg;
+	}
+
+	public DebugEventListener getDebugListener() {
+		return dbg;
+	}
+
+	public void reportError(IOException e) {
+		System.err.println(e);
+		e.printStackTrace(System.err);
+	}
+
+	public void reportError(RecognitionException e) {
+		dbg.recognitionException(e);
+	}
+
+	protected Object getMissingSymbol(IntStream input,
+									  RecognitionException e,
+									  int expectedTokenType,
+									  BitSet follow)
+	{
+		Object o = super.getMissingSymbol(input, e, expectedTokenType, follow);
+		dbg.consumeNode(o);
+		return o;
+	}
+
+	public void beginResync() {
+		dbg.beginResync();
+	}
+
+	public void endResync() {
+		dbg.endResync();
+	}
+
+	public void beginBacktrack(int level) {
+		dbg.beginBacktrack(level);
+	}
+
+	public void endBacktrack(int level, boolean successful) {
+		dbg.endBacktrack(level,successful);		
+	}
+}
diff --git a/src/org/antlr/runtime/debug/ParseTreeBuilder.java b/src/org/antlr/runtime/debug/ParseTreeBuilder.java
new file mode 100755
index 0000000..13c6ed0
--- /dev/null
+++ b/src/org/antlr/runtime/debug/ParseTreeBuilder.java
@@ -0,0 +1,109 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime.debug;
+
+import org.antlr.runtime.RecognitionException;
+import org.antlr.runtime.Token;
+import org.antlr.runtime.tree.ParseTree;
+
+import java.util.Stack;
+import java.util.ArrayList;
+import java.util.List;
+
+/** This parser listener tracks rule entry/exit and token matches
+ *  to build a simple parse tree using ParseTree nodes.
+ */
+public class ParseTreeBuilder extends BlankDebugEventListener {
+	public static final String EPSILON_PAYLOAD = "<epsilon>";
+	
+	Stack callStack = new Stack();
+	List hiddenTokens = new ArrayList();
+	int backtracking = 0;
+
+	public ParseTreeBuilder(String grammarName) {
+		ParseTree root = create("<grammar "+grammarName+">");
+		callStack.push(root);
+	}
+
+	public ParseTree getTree() {
+		return (ParseTree)callStack.elementAt(0);
+	}
+
+	/**  What kind of node to create.  You might want to override
+	 *   so I factored out creation here.
+	 */
+	public ParseTree create(Object payload) {
+		return new ParseTree(payload);
+	}
+
+	public ParseTree epsilonNode() {
+		return create(EPSILON_PAYLOAD);
+	}
+
+	/** Backtracking or cyclic DFA, don't want to add nodes to tree */
+	public void enterDecision(int d, boolean couldBacktrack) { backtracking++; }
+	public void exitDecision(int i) { backtracking--; }
+
+	public void enterRule(String filename, String ruleName) {
+		if ( backtracking>0 ) return;
+		ParseTree parentRuleNode = (ParseTree)callStack.peek();
+		ParseTree ruleNode = create(ruleName);
+		parentRuleNode.addChild(ruleNode);
+		callStack.push(ruleNode);
+	}
+
+	public void exitRule(String filename, String ruleName) {
+		if ( backtracking>0 ) return;
+		ParseTree ruleNode = (ParseTree)callStack.peek();
+		if ( ruleNode.getChildCount()==0 ) {
+			ruleNode.addChild(epsilonNode());
+		}
+		callStack.pop();		
+	}
+
+	public void consumeToken(Token token) {
+		if ( backtracking>0 ) return;
+		ParseTree ruleNode = (ParseTree)callStack.peek();
+		ParseTree elementNode = create(token);
+		elementNode.hiddenTokens = this.hiddenTokens;
+		this.hiddenTokens = new ArrayList();
+		ruleNode.addChild(elementNode);
+	}
+
+	public void consumeHiddenToken(Token token) {
+		if ( backtracking>0 ) return;
+		hiddenTokens.add(token);
+	}
+
+	public void recognitionException(RecognitionException e) {
+		if ( backtracking>0 ) return;
+		ParseTree ruleNode = (ParseTree)callStack.peek();
+		ParseTree errorNode = create(e);
+		ruleNode.addChild(errorNode);
+	}
+}
diff --git a/src/org/antlr/runtime/debug/Profiler.java b/src/org/antlr/runtime/debug/Profiler.java
new file mode 100755
index 0000000..aea9a17
--- /dev/null
+++ b/src/org/antlr/runtime/debug/Profiler.java
@@ -0,0 +1,734 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime.debug;
+
+import org.antlr.runtime.*;
+import org.antlr.runtime.misc.DoubleKeyMap;
+
+import java.util.*;
+
+/** Using the debug event interface, track what is happening in the parser
+ *  and record statistics about the runtime.
+ */
+public class Profiler extends BlankDebugEventListener {
+	public static final String DATA_SEP = "\t";
+	public static final String newline = System.getProperty("line.separator");
+
+	static boolean dump = false;
+
+	public static class ProfileStats {
+		public String Version;
+		public String name;
+		public int numRuleInvocations;
+		public int numUniqueRulesInvoked;
+		public int numDecisionEvents;
+		public int numDecisionsCovered;
+		public int numDecisionsThatPotentiallyBacktrack;
+		public int numDecisionsThatDoBacktrack;
+		public int maxRuleInvocationDepth;
+		public float avgkPerDecisionEvent;
+		public float avgkPerBacktrackingDecisionEvent;
+		public float averageDecisionPercentBacktracks;
+		public int numBacktrackOccurrences; // doesn't count gated DFA edges
+
+		public int numFixedDecisions;
+		public int minDecisionMaxFixedLookaheads;
+		public int maxDecisionMaxFixedLookaheads;
+		public int avgDecisionMaxFixedLookaheads;
+		public int stddevDecisionMaxFixedLookaheads;
+		public int numCyclicDecisions;
+		public int minDecisionMaxCyclicLookaheads;
+		public int maxDecisionMaxCyclicLookaheads;
+		public int avgDecisionMaxCyclicLookaheads;
+		public int stddevDecisionMaxCyclicLookaheads;
+//		int Stats.min(toArray(decisionMaxSynPredLookaheads);
+//		int Stats.max(toArray(decisionMaxSynPredLookaheads);
+//		int Stats.avg(toArray(decisionMaxSynPredLookaheads);
+//		int Stats.stddev(toArray(decisionMaxSynPredLookaheads);
+		public int numSemanticPredicates;
+		public int numTokens;
+		public int numHiddenTokens;
+		public int numCharsMatched;
+		public int numHiddenCharsMatched;
+		public int numReportedErrors;
+		public int numMemoizationCacheHits;
+		public int numMemoizationCacheMisses;
+		public int numGuessingRuleInvocations;
+		public int numMemoizationCacheEntries;
+	}
+
+	public static class DecisionDescriptor {
+		public int decision;
+		public String fileName;
+		public String ruleName;
+		public int line;
+		public int pos;
+		public boolean couldBacktrack;
+
+		public int n;
+		public float avgk; // avg across all decision events
+		public int maxk;
+		public int numBacktrackOccurrences;
+		public int numSemPredEvals;
+	}
+
+	// all about a specific exec of a single decision
+	public static class DecisionEvent {
+		public DecisionDescriptor decision;
+		public int startIndex;
+		public int k;
+		public boolean backtracks; // doesn't count gated DFA edges
+		public boolean evalSemPred;
+		public long startTime;
+		public long stopTime;
+		public int numMemoizationCacheHits;
+		public int numMemoizationCacheMisses;
+	}
+
+	/** Because I may change the stats, I need to track that for later
+	 *  computations to be consistent.
+	 */
+	public static final String Version = "3";
+	public static final String RUNTIME_STATS_FILENAME = "runtime.stats";
+
+	/** Ack, should not store parser; can't do remote stuff.  Well, we pass
+	 *  input stream around too so I guess it's ok.
+	 */
+	public DebugParser parser = null;
+
+	// working variables
+
+	protected int ruleLevel = 0;
+	//protected int decisionLevel = 0;
+	protected Token lastRealTokenTouchedInDecision;
+	protected Set<String> uniqueRules = new HashSet<String>();
+	protected Stack<String> currentGrammarFileName = new Stack();
+	protected Stack<String> currentRuleName = new Stack();
+	protected Stack<Integer> currentLine = new Stack();
+	protected Stack<Integer> currentPos = new Stack();
+
+	// Vector<DecisionStats>
+	//protected Vector decisions = new Vector(200); // need setSize
+	protected DoubleKeyMap<String,Integer, DecisionDescriptor> decisions =
+		new DoubleKeyMap<String,Integer, DecisionDescriptor>();
+
+	// Record a DecisionData for each decision we hit while parsing
+	protected List<DecisionEvent> decisionEvents = new ArrayList<DecisionEvent>();
+	protected Stack<DecisionEvent> decisionStack = new Stack<DecisionEvent>();
+
+	protected int backtrackDepth;
+	
+	ProfileStats stats = new ProfileStats();
+
+	public Profiler() {
+	}
+
+	public Profiler(DebugParser parser) {
+		this.parser = parser;
+	}
+
+	public void enterRule(String grammarFileName, String ruleName) {
+//		System.out.println("enterRule "+grammarFileName+":"+ruleName);
+		ruleLevel++;
+		stats.numRuleInvocations++;
+		uniqueRules.add(grammarFileName+":"+ruleName);
+		stats.maxRuleInvocationDepth = Math.max(stats.maxRuleInvocationDepth, ruleLevel);
+		currentGrammarFileName.push( grammarFileName );
+		currentRuleName.push( ruleName );
+	}
+
+	public void exitRule(String grammarFileName, String ruleName) {
+		ruleLevel--;
+		currentGrammarFileName.pop();
+		currentRuleName.pop();
+	}
+
+	/** Track memoization; this is not part of standard debug interface
+	 *  but is triggered by profiling.  Code gen inserts an override
+	 *  for this method in the recognizer, which triggers this method.
+	 *  Called from alreadyParsedRule().
+	 */
+	public void examineRuleMemoization(IntStream input,
+									   int ruleIndex,
+									   int stopIndex, // index or MEMO_RULE_UNKNOWN...
+									   String ruleName)
+	{
+		if (dump) System.out.println("examine memo "+ruleName+" at "+input.index()+": "+stopIndex);
+		if ( stopIndex==BaseRecognizer.MEMO_RULE_UNKNOWN ) {
+			//System.out.println("rule "+ruleIndex+" missed @ "+input.index());
+			stats.numMemoizationCacheMisses++;
+			stats.numGuessingRuleInvocations++; // we'll have to enter
+			currentDecision().numMemoizationCacheMisses++;
+		}
+		else {
+			// regardless of rule success/failure, if in cache, we have a cache hit
+			//System.out.println("rule "+ruleIndex+" hit @ "+input.index());
+			stats.numMemoizationCacheHits++;
+			currentDecision().numMemoizationCacheHits++;
+		}
+	}
+
+	/** Warning: doesn't track success/failure, just unique recording event */
+	public void memoize(IntStream input,
+						int ruleIndex,
+						int ruleStartIndex,
+						String ruleName)
+	{
+		// count how many entries go into table
+		if (dump) System.out.println("memoize "+ruleName);
+		stats.numMemoizationCacheEntries++;
+	}
+
+	@Override
+	public void location(int line, int pos) {
+		currentLine.push(line);
+		currentPos.push(pos);
+	}
+
+	public void enterDecision(int decisionNumber, boolean couldBacktrack) {
+		lastRealTokenTouchedInDecision = null;
+		stats.numDecisionEvents++;
+		int startingLookaheadIndex = parser.getTokenStream().index();
+		TokenStream input = parser.getTokenStream();
+		if ( dump ) System.out.println("enterDecision canBacktrack="+couldBacktrack+" "+ decisionNumber +
+						   " backtrack depth " + backtrackDepth +
+						   " @ " + input.get(input.index()) +
+						   " rule " +locationDescription());
+		String g = (String) currentGrammarFileName.peek();
+		DecisionDescriptor descriptor = decisions.get(g, decisionNumber);
+		if ( descriptor == null ) {
+			descriptor = new DecisionDescriptor();
+			decisions.put(g, decisionNumber, descriptor);
+			descriptor.decision = decisionNumber;
+			descriptor.fileName = (String)currentGrammarFileName.peek();
+			descriptor.ruleName = (String)currentRuleName.peek();
+			descriptor.line = (Integer)currentLine.peek();
+			descriptor.pos = (Integer)currentPos.peek();
+			descriptor.couldBacktrack = couldBacktrack;
+		}
+		descriptor.n++;
+
+		DecisionEvent d = new DecisionEvent();
+		decisionStack.push(d);
+		d.decision = descriptor;
+		d.startTime = System.currentTimeMillis();
+		d.startIndex = startingLookaheadIndex;
+	}
+
+	public void exitDecision(int decisionNumber) {
+		DecisionEvent d = decisionStack.pop();
+		d.stopTime = System.currentTimeMillis();
+
+		int lastTokenIndex = lastRealTokenTouchedInDecision.getTokenIndex();
+		int numHidden = getNumberOfHiddenTokens(d.startIndex, lastTokenIndex);
+		int depth = lastTokenIndex - d.startIndex - numHidden + 1; // +1 counts consuming start token as 1
+		d.k = depth;
+		d.decision.maxk = Math.max(d.decision.maxk, depth);
+
+		if (dump) System.out.println("exitDecision "+decisionNumber+" in "+d.decision.ruleName+
+						   " lookahead "+d.k +" max token "+lastRealTokenTouchedInDecision);
+		decisionEvents.add(d); // done with decision; track all
+	}
+
+	public void consumeToken(Token token) {
+		if (dump) System.out.println("consume token "+token);
+		if ( !inDecision() ) {
+			stats.numTokens++;
+			return;
+		}
+		if ( lastRealTokenTouchedInDecision==null ||
+			 lastRealTokenTouchedInDecision.getTokenIndex() < token.getTokenIndex() )
+		{
+			lastRealTokenTouchedInDecision = token;
+		}
+		DecisionEvent d = currentDecision();
+		// compute lookahead depth
+		int thisRefIndex = token.getTokenIndex();
+		int numHidden = getNumberOfHiddenTokens(d.startIndex, thisRefIndex);
+		int depth = thisRefIndex - d.startIndex - numHidden + 1; // +1 counts consuming start token as 1
+		//d.maxk = Math.max(d.maxk, depth);
+		if (dump) System.out.println("consume "+thisRefIndex+" "+depth+" tokens ahead in "+
+						   d.decision.ruleName+"-"+d.decision.decision+" start index "+d.startIndex);		
+	}
+
+	/** The parser is in a decision if the decision depth > 0.  This
+	 *  works for backtracking also, which can have nested decisions.
+	 */
+	public boolean inDecision() {
+		return decisionStack.size()>0;
+	}
+
+	public void consumeHiddenToken(Token token) {
+		//System.out.println("consume hidden token "+token);
+		if ( !inDecision() ) stats.numHiddenTokens++;
+	}
+
+	/** Track refs to lookahead if in a fixed/nonfixed decision.
+	 */
+	public void LT(int i, Token t) {
+		if ( inDecision() && i>0 ) {
+			DecisionEvent d = currentDecision();
+			if (dump) System.out.println("LT("+i+")="+t+" index "+t.getTokenIndex()+" relative to "+d.decision.ruleName+"-"+
+							   d.decision.decision+" start index "+d.startIndex);
+			if ( lastRealTokenTouchedInDecision==null ||
+				 lastRealTokenTouchedInDecision.getTokenIndex() < t.getTokenIndex() )
+			{
+				lastRealTokenTouchedInDecision = t;
+				if (dump) System.out.println("set last token "+lastRealTokenTouchedInDecision);
+			}
+			// get starting index off stack
+//			int stackTop = lookaheadStack.size()-1;
+//			Integer startingIndex = (Integer)lookaheadStack.get(stackTop);
+//			// compute lookahead depth
+//			int thisRefIndex = parser.getTokenStream().index();
+//			int numHidden =
+//				getNumberOfHiddenTokens(startingIndex.intValue(), thisRefIndex);
+//			int depth = i + thisRefIndex - startingIndex.intValue() - numHidden;
+//			/*
+//			System.out.println("LT("+i+") @ index "+thisRefIndex+" is depth "+depth+
+//				" max is "+maxLookaheadInCurrentDecision);
+//			*/
+//			if ( depth>maxLookaheadInCurrentDecision ) {
+//				maxLookaheadInCurrentDecision = depth;
+//			}
+//			d.maxk = currentDecision()/
+		}
+	}
+
+	/** Track backtracking decisions.  You'll see a fixed or cyclic decision
+	 *  and then a backtrack.
+	 *
+	 * 		enter rule
+	 * 		...
+	 * 		enter decision
+	 * 		LA and possibly consumes (for cyclic DFAs)
+	 * 		begin backtrack level
+	 * 		mark m
+	 * 		rewind m
+	 * 		end backtrack level, success
+	 * 		exit decision
+	 * 		...
+	 * 		exit rule
+	 */
+	public void beginBacktrack(int level) {
+		if (dump) System.out.println("enter backtrack "+level);
+		backtrackDepth++;
+		DecisionEvent e = currentDecision();
+		if ( e.decision.couldBacktrack ) {
+			stats.numBacktrackOccurrences++;
+			e.decision.numBacktrackOccurrences++;
+			e.backtracks = true;
+		}
+	}
+
+	/** Successful or not, track how much lookahead synpreds use */
+	public void endBacktrack(int level, boolean successful) {
+		if (dump) System.out.println("exit backtrack "+level+": "+successful);
+		backtrackDepth--;		
+	}
+
+	@Override
+	public void mark(int i) {
+		if (dump) System.out.println("mark "+i);
+	}
+
+	@Override
+	public void rewind(int i) {
+		if (dump) System.out.println("rewind "+i);
+	}
+
+	@Override
+	public void rewind() {
+		if (dump) System.out.println("rewind");
+	}
+
+
+
+	protected DecisionEvent currentDecision() {
+		return decisionStack.peek();
+	}
+
+	public void recognitionException(RecognitionException e) {
+		stats.numReportedErrors++;
+	}
+
+	public void semanticPredicate(boolean result, String predicate) {
+		stats.numSemanticPredicates++;
+		if ( inDecision() ) {
+			DecisionEvent d = currentDecision();
+			d.evalSemPred = true;
+			d.decision.numSemPredEvals++;
+			if (dump) System.out.println("eval "+predicate+" in "+d.decision.ruleName+"-"+
+							   d.decision.decision);
+		}
+	}
+
+	public void terminate() {
+		for (DecisionEvent e : decisionEvents) {
+			//System.out.println("decision "+e.decision.decision+": k="+e.k);
+			e.decision.avgk += e.k;
+			stats.avgkPerDecisionEvent += e.k;
+			if ( e.backtracks ) { // doesn't count gated syn preds on DFA edges
+				stats.avgkPerBacktrackingDecisionEvent += e.k;
+			}
+		}
+		stats.averageDecisionPercentBacktracks = 0.0f;
+		for (DecisionDescriptor d : decisions.values()) {
+			stats.numDecisionsCovered++;
+			d.avgk /= (double)d.n;
+			if ( d.couldBacktrack ) {
+				stats.numDecisionsThatPotentiallyBacktrack++;
+				float percentBacktracks = d.numBacktrackOccurrences / (float)d.n;
+				//System.out.println("dec "+d.decision+" backtracks "+percentBacktracks*100+"%");
+				stats.averageDecisionPercentBacktracks += percentBacktracks;
+			}
+			// ignore rules that backtrack along gated DFA edges
+			if ( d.numBacktrackOccurrences > 0 ) {
+				stats.numDecisionsThatDoBacktrack++;
+			}
+		}
+		stats.averageDecisionPercentBacktracks /= stats.numDecisionsThatPotentiallyBacktrack;
+		stats.averageDecisionPercentBacktracks *= 100; // it's a percentage
+		stats.avgkPerDecisionEvent /= stats.numDecisionEvents;
+		stats.avgkPerBacktrackingDecisionEvent /= (double)stats.numBacktrackOccurrences;
+
+		System.err.println(toString());
+		System.err.println(getDecisionStatsDump());
+
+//		String stats = toNotifyString();
+//		try {
+//			Stats.writeReport(RUNTIME_STATS_FILENAME,stats);
+//		}
+//		catch (IOException ioe) {
+//			System.err.println(ioe);
+//			ioe.printStackTrace(System.err);
+//		}
+	}
+
+	public void setParser(DebugParser parser) {
+		this.parser = parser;
+	}
+
+	// R E P O R T I N G
+
+	public String toNotifyString() {
+		StringBuffer buf = new StringBuffer();
+		buf.append(Version);
+		buf.append('\t');
+		buf.append(parser.getClass().getName());
+//		buf.append('\t');
+//		buf.append(numRuleInvocations);
+//		buf.append('\t');
+//		buf.append(maxRuleInvocationDepth);
+//		buf.append('\t');
+//		buf.append(numFixedDecisions);
+//		buf.append('\t');
+//		buf.append(Stats.min(decisionMaxFixedLookaheads));
+//		buf.append('\t');
+//		buf.append(Stats.max(decisionMaxFixedLookaheads));
+//		buf.append('\t');
+//		buf.append(Stats.avg(decisionMaxFixedLookaheads));
+//		buf.append('\t');
+//		buf.append(Stats.stddev(decisionMaxFixedLookaheads));
+//		buf.append('\t');
+//		buf.append(numCyclicDecisions);
+//		buf.append('\t');
+//		buf.append(Stats.min(decisionMaxCyclicLookaheads));
+//		buf.append('\t');
+//		buf.append(Stats.max(decisionMaxCyclicLookaheads));
+//		buf.append('\t');
+//		buf.append(Stats.avg(decisionMaxCyclicLookaheads));
+//		buf.append('\t');
+//		buf.append(Stats.stddev(decisionMaxCyclicLookaheads));
+//		buf.append('\t');
+//		buf.append(numBacktrackDecisions);
+//		buf.append('\t');
+//		buf.append(Stats.min(toArray(decisionMaxSynPredLookaheads)));
+//		buf.append('\t');
+//		buf.append(Stats.max(toArray(decisionMaxSynPredLookaheads)));
+//		buf.append('\t');
+//		buf.append(Stats.avg(toArray(decisionMaxSynPredLookaheads)));
+//		buf.append('\t');
+//		buf.append(Stats.stddev(toArray(decisionMaxSynPredLookaheads)));
+//		buf.append('\t');
+//		buf.append(numSemanticPredicates);
+//		buf.append('\t');
+//		buf.append(parser.getTokenStream().size());
+//		buf.append('\t');
+//		buf.append(numHiddenTokens);
+//		buf.append('\t');
+//		buf.append(numCharsMatched);
+//		buf.append('\t');
+//		buf.append(numHiddenCharsMatched);
+//		buf.append('\t');
+//		buf.append(numberReportedErrors);
+//		buf.append('\t');
+//		buf.append(numMemoizationCacheHits);
+//		buf.append('\t');
+//		buf.append(numMemoizationCacheMisses);
+//		buf.append('\t');
+//		buf.append(numGuessingRuleInvocations);
+//		buf.append('\t');
+//		buf.append(numMemoizationCacheEntries);
+		return buf.toString();
+	}
+
+	public String toString() {
+		return toString(getReport());
+	}
+
+	public ProfileStats getReport() {
+//		TokenStream input = parser.getTokenStream();
+//		for (int i=0; i<input.size()&& lastRealTokenTouchedInDecision !=null&&i<= lastRealTokenTouchedInDecision.getTokenIndex(); i++) {
+//			Token t = input.get(i);
+//			if ( t.getChannel()!=Token.DEFAULT_CHANNEL ) {
+//				stats.numHiddenTokens++;
+//				stats.numHiddenCharsMatched += t.getText().length();
+//			}
+//		}
+		stats.Version = Version;
+		stats.name = parser.getClass().getName();
+		stats.numUniqueRulesInvoked = uniqueRules.size();
+		//stats.numCharsMatched = lastTokenConsumed.getStopIndex() + 1;
+		return stats;
+	}
+
+	public DoubleKeyMap getDecisionStats() {
+		return decisions;
+	}
+
+	public List getDecisionEvents() {
+		return decisionEvents;
+	}
+
+	public static String toString(ProfileStats stats) {
+		StringBuffer buf = new StringBuffer();
+		buf.append("ANTLR Runtime Report; Profile Version ");
+		buf.append(stats.Version);
+		buf.append(newline);
+		buf.append("parser name ");
+		buf.append(stats.name);
+		buf.append(newline);
+		buf.append("Number of rule invocations ");
+		buf.append(stats.numRuleInvocations);
+		buf.append(newline);
+		buf.append("Number of unique rules visited ");
+		buf.append(stats.numUniqueRulesInvoked);
+		buf.append(newline);
+		buf.append("Number of decision events ");
+		buf.append(stats.numDecisionEvents);
+		buf.append(newline);
+		buf.append("Overall average k per decision event ");
+		buf.append(stats.avgkPerDecisionEvent);
+		buf.append(newline);
+		buf.append("Number of backtracking occurrences (can be multiple per decision) ");
+		buf.append(stats.numBacktrackOccurrences);
+		buf.append(newline);
+		buf.append("Overall average k per decision event that backtracks ");
+		buf.append(stats.avgkPerBacktrackingDecisionEvent);
+		buf.append(newline);
+		buf.append("Number of rule invocations while backtracking ");
+		buf.append(stats.numGuessingRuleInvocations);
+		buf.append(newline);
+		buf.append("num decisions that potentially backtrack ");
+		buf.append(stats.numDecisionsThatPotentiallyBacktrack);
+		buf.append(newline);
+		buf.append("num decisions that do backtrack ");
+		buf.append(stats.numDecisionsThatDoBacktrack);
+		buf.append(newline);
+		buf.append("num decisions that potentially backtrack but don't ");
+		buf.append(stats.numDecisionsThatPotentiallyBacktrack - stats.numDecisionsThatDoBacktrack);
+		buf.append(newline);
+		buf.append("average % of time a potentially backtracking decision backtracks ");
+		buf.append(stats.averageDecisionPercentBacktracks);
+		buf.append(newline);
+		buf.append("num unique decisions covered ");
+		buf.append(stats.numDecisionsCovered);
+		buf.append(newline);
+		buf.append("max rule invocation nesting depth ");
+		buf.append(stats.maxRuleInvocationDepth);
+		buf.append(newline);
+
+//		buf.append("number of fixed lookahead decisions ");
+//		buf.append();
+//		buf.append('\n');
+//		buf.append("min lookahead used in a fixed lookahead decision ");
+//		buf.append();
+//		buf.append('\n');
+//		buf.append("max lookahead used in a fixed lookahead decision ");
+//		buf.append();
+//		buf.append('\n');
+//		buf.append("average lookahead depth used in fixed lookahead decisions ");
+//		buf.append();
+//		buf.append('\n');
+//		buf.append("standard deviation of depth used in fixed lookahead decisions ");
+//		buf.append();
+//		buf.append('\n');
+//		buf.append("number of arbitrary lookahead decisions ");
+//		buf.append();
+//		buf.append('\n');
+//		buf.append("min lookahead used in an arbitrary lookahead decision ");
+//		buf.append();
+//		buf.append('\n');
+//		buf.append("max lookahead used in an arbitrary lookahead decision ");
+//		buf.append();
+//		buf.append('\n');
+//		buf.append("average lookahead depth used in arbitrary lookahead decisions ");
+//		buf.append();
+//		buf.append('\n');
+//		buf.append("standard deviation of depth used in arbitrary lookahead decisions ");
+//		buf.append();
+//		buf.append('\n');
+//		buf.append("number of evaluated syntactic predicates ");
+//		buf.append();
+//		buf.append('\n');
+//		buf.append("min lookahead used in a syntactic predicate ");
+//		buf.append();
+//		buf.append('\n');
+//		buf.append("max lookahead used in a syntactic predicate ");
+//		buf.append();
+//		buf.append('\n');
+//		buf.append("average lookahead depth used in syntactic predicates ");
+//		buf.append();
+//		buf.append('\n');
+//		buf.append("standard deviation of depth used in syntactic predicates ");
+//		buf.append();
+//		buf.append('\n');
+		buf.append("rule memoization cache size ");
+		buf.append(stats.numMemoizationCacheEntries);
+		buf.append(newline);
+		buf.append("number of rule memoization cache hits ");
+		buf.append(stats.numMemoizationCacheHits);
+		buf.append(newline);
+		buf.append("number of rule memoization cache misses ");
+		buf.append(stats.numMemoizationCacheMisses);
+		buf.append(newline);
+//		buf.append("number of evaluated semantic predicates ");
+//		buf.append();
+//		buf.append(newline);
+		buf.append("number of tokens ");
+		buf.append(stats.numTokens);
+		buf.append(newline);
+		buf.append("number of hidden tokens ");
+		buf.append(stats.numHiddenTokens);
+		buf.append(newline);
+		buf.append("number of char ");
+		buf.append(stats.numCharsMatched);
+		buf.append(newline);
+		buf.append("number of hidden char ");
+		buf.append(stats.numHiddenCharsMatched);
+		buf.append(newline);
+		buf.append("number of syntax errors ");
+		buf.append(stats.numReportedErrors);
+		buf.append(newline);
+		return buf.toString();
+	}
+
+	public String getDecisionStatsDump() {
+		StringBuffer buf = new StringBuffer();
+		buf.append("location");
+		buf.append(DATA_SEP);
+		buf.append("n");
+		buf.append(DATA_SEP);
+		buf.append("avgk");
+		buf.append(DATA_SEP);
+		buf.append("maxk");
+		buf.append(DATA_SEP);
+		buf.append("synpred");
+		buf.append(DATA_SEP);
+		buf.append("sempred");
+		buf.append(DATA_SEP);
+		buf.append("canbacktrack");
+		buf.append("\n");
+		for (String fileName : decisions.keySet()) {
+			for (int d : decisions.keySet(fileName)) {
+				DecisionDescriptor s = decisions.get(fileName, d);
+				buf.append(s.decision);
+				buf.append("@");
+				buf.append(locationDescription(s.fileName,s.ruleName,s.line,s.pos)); // decision number
+				buf.append(DATA_SEP);
+				buf.append(s.n);
+				buf.append(DATA_SEP);
+				buf.append(String.format("%.2f",s.avgk));
+				buf.append(DATA_SEP);
+				buf.append(s.maxk);
+				buf.append(DATA_SEP);
+				buf.append(s.numBacktrackOccurrences);
+				buf.append(DATA_SEP);
+				buf.append(s.numSemPredEvals);
+				buf.append(DATA_SEP);
+				buf.append(s.couldBacktrack ?"1":"0");
+				buf.append(newline);
+			}
+		}
+		return buf.toString();
+	}
+
+	protected int[] trim(int[] X, int n) {
+		if ( n<X.length ) {
+			int[] trimmed = new int[n];
+			System.arraycopy(X,0,trimmed,0,n);
+			X = trimmed;
+		}
+		return X;
+	}
+
+	protected int[] toArray(List a) {
+		int[] x = new int[a.size()];
+		for (int i = 0; i < a.size(); i++) {
+			Integer I = (Integer) a.get(i);
+			x[i] = I.intValue();
+		}
+		return x;
+	}
+
+	/** Get num hidden tokens between i..j inclusive */
+	public int getNumberOfHiddenTokens(int i, int j) {
+		int n = 0;
+		TokenStream input = parser.getTokenStream();
+		for (int ti = i; ti<input.size() && ti <= j; ti++) {
+			Token t = input.get(ti);
+			if ( t.getChannel()!=Token.DEFAULT_CHANNEL ) {
+				n++;
+			}
+		}
+		return n;
+	}
+
+	protected String locationDescription() {
+		return locationDescription(
+			currentGrammarFileName.peek(),
+			currentRuleName.peek(),
+			currentLine.peek(),
+			currentPos.peek());
+	}
+
+	protected String locationDescription(String file, String rule, int line, int pos) {
+		return file+":"+line+":"+pos+"(" + rule + ")";
+	}
+}
diff --git a/src/org/antlr/runtime/debug/RemoteDebugEventSocketListener.java b/src/org/antlr/runtime/debug/RemoteDebugEventSocketListener.java
new file mode 100755
index 0000000..933fdae
--- /dev/null
+++ b/src/org/antlr/runtime/debug/RemoteDebugEventSocketListener.java
@@ -0,0 +1,527 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime.debug;
+
+import org.antlr.runtime.RecognitionException;
+import org.antlr.runtime.Token;
+import org.antlr.runtime.CharStream;
+import org.antlr.runtime.tree.BaseTree;
+import org.antlr.runtime.tree.Tree;
+
+import java.io.*;
+import java.net.ConnectException;
+import java.net.Socket;
+import java.util.StringTokenizer;
+
+public class RemoteDebugEventSocketListener implements Runnable {
+	static final int MAX_EVENT_ELEMENTS = 8;
+	DebugEventListener listener;
+	String machine;
+	int port;
+	Socket channel = null;
+	PrintWriter out;
+	BufferedReader in;
+	String event;
+	/** Version of ANTLR (dictates events) */
+	public String version;
+	public String grammarFileName;
+	/** Track the last token index we saw during a consume.  If same, then
+	 *  set a flag that we have a problem.
+	 */
+	int previousTokenIndex = -1;
+	boolean tokenIndexesInvalid = false;
+
+	public static class ProxyToken implements Token {
+		int index;
+		int type;
+		int channel;
+		int line;
+		int charPos;
+		String text;
+		public ProxyToken(int index) { this.index = index; }		
+		public ProxyToken(int index, int type, int channel,
+						  int line, int charPos, String text)
+		{
+			this.index = index;
+			this.type = type;
+			this.channel = channel;
+			this.line = line;
+			this.charPos = charPos;
+			this.text = text;
+		}
+		public String getText() {
+			return text;
+		}
+		public void setText(String text) {
+			this.text = text;
+		}
+		public int getType() {
+			return type;
+		}
+		public void setType(int ttype) {
+			this.type = ttype;
+		}
+		public int getLine() {
+			return line;
+		}
+		public void setLine(int line) {
+			this.line = line;
+		}
+		public int getCharPositionInLine() {
+			return charPos;
+		}
+		public void setCharPositionInLine(int pos) {
+			this.charPos = pos;
+		}
+		public int getChannel() {
+			return channel;
+		}
+		public void setChannel(int channel) {
+			this.channel = channel;
+		}
+		public int getTokenIndex() {
+			return index;
+		}
+		public void setTokenIndex(int index) {
+			this.index = index;
+		}
+		public CharStream getInputStream() {
+			return null;
+		}
+		public void setInputStream(CharStream input) {
+		}
+		public String toString() {
+			String channelStr = "";
+			if ( channel!=Token.DEFAULT_CHANNEL ) {
+				channelStr=",channel="+channel;
+			}
+			return "["+getText()+"/<"+type+">"+channelStr+","+line+":"+getCharPositionInLine()+",@"+index+"]";
+		}
+	}
+
+	public static class ProxyTree extends BaseTree {
+		public int ID;
+		public int type;
+		public int line = 0;
+		public int charPos = -1;
+		public int tokenIndex = -1;
+		public String text;
+		
+		public ProxyTree(int ID, int type, int line, int charPos, int tokenIndex, String text) {
+			this.ID = ID;
+			this.type = type;
+			this.line = line;
+			this.charPos = charPos;
+			this.tokenIndex = tokenIndex;
+			this.text = text;
+		}
+
+		public ProxyTree(int ID) { this.ID = ID; }
+
+		public int getTokenStartIndex() { return tokenIndex; }
+		public void setTokenStartIndex(int index) {	}
+		public int getTokenStopIndex() { return 0; }
+		public void setTokenStopIndex(int index) { }
+		public Tree dupNode() {	return null; }
+		public int getType() { return type; }
+		public String getText() { return text; }
+		public String toString() {
+			return "fix this";
+		}
+	}
+
+	public RemoteDebugEventSocketListener(DebugEventListener listener,
+										  String machine,
+										  int port) throws IOException
+	{
+		this.listener = listener;
+		this.machine = machine;
+		this.port = port;
+
+        if( !openConnection() ) {
+            throw new ConnectException();
+        }
+	}
+
+	protected void eventHandler() {
+		try {
+			handshake();
+			event = in.readLine();
+			while ( event!=null ) {
+				dispatch(event);
+				ack();
+				event = in.readLine();
+			}
+		}
+		catch (Exception e) {
+			System.err.println(e);
+			e.printStackTrace(System.err);
+		}
+		finally {
+            closeConnection();
+		}
+	}
+
+    protected boolean openConnection() {
+        boolean success = false;
+        try {
+            channel = new Socket(machine, port);
+            channel.setTcpNoDelay(true);
+			OutputStream os = channel.getOutputStream();
+			OutputStreamWriter osw = new OutputStreamWriter(os, "UTF8");
+			out = new PrintWriter(new BufferedWriter(osw));
+			InputStream is = channel.getInputStream();
+			InputStreamReader isr = new InputStreamReader(is, "UTF8");
+			in = new BufferedReader(isr);
+            success = true;
+        } catch(Exception e) {
+            System.err.println(e);
+        }
+        return success;
+    }
+
+    protected void closeConnection() {
+        try {
+            in.close(); in = null;
+            out.close(); out = null;
+            channel.close(); channel=null;
+        }
+        catch (Exception e) {
+            System.err.println(e);
+            e.printStackTrace(System.err);
+        }
+        finally {
+            if ( in!=null ) {
+                try {in.close();} catch (IOException ioe) {
+                    System.err.println(ioe);
+                }
+            }
+            if ( out!=null ) {
+                out.close();
+            }
+            if ( channel!=null ) {
+                try {channel.close();} catch (IOException ioe) {
+                    System.err.println(ioe);
+                }
+            }
+        }
+
+    }
+
+	protected void handshake() throws IOException {
+		String antlrLine = in.readLine();
+		String[] antlrElements = getEventElements(antlrLine);
+		version = antlrElements[1];
+		String grammarLine = in.readLine();
+		String[] grammarElements = getEventElements(grammarLine);
+		grammarFileName = grammarElements[1];
+		ack();
+		listener.commence(); // inform listener after handshake
+	}
+
+	protected void ack() {
+        out.println("ack");
+		out.flush();
+	}
+
+	protected void dispatch(String line) {
+        //System.out.println("event: "+line);
+        String[] elements = getEventElements(line);
+		if ( elements==null || elements[0]==null ) {
+			System.err.println("unknown debug event: "+line);
+			return;
+		}
+		if ( elements[0].equals("enterRule") ) {
+			listener.enterRule(elements[1], elements[2]);
+		}
+		else if ( elements[0].equals("exitRule") ) {
+			listener.exitRule(elements[1], elements[2]);
+		}
+		else if ( elements[0].equals("enterAlt") ) {
+			listener.enterAlt(Integer.parseInt(elements[1]));
+		}
+		else if ( elements[0].equals("enterSubRule") ) {
+			listener.enterSubRule(Integer.parseInt(elements[1]));
+		}
+		else if ( elements[0].equals("exitSubRule") ) {
+			listener.exitSubRule(Integer.parseInt(elements[1]));
+		}
+		else if ( elements[0].equals("enterDecision") ) {
+			listener.enterDecision(Integer.parseInt(elements[1]), elements[2].equals("true"));
+		}
+		else if ( elements[0].equals("exitDecision") ) {
+			listener.exitDecision(Integer.parseInt(elements[1]));
+		}
+		else if ( elements[0].equals("location") ) {
+			listener.location(Integer.parseInt(elements[1]),
+							  Integer.parseInt(elements[2]));
+		}
+		else if ( elements[0].equals("consumeToken") ) {
+			ProxyToken t = deserializeToken(elements, 1);
+			if ( t.getTokenIndex() == previousTokenIndex ) {
+				tokenIndexesInvalid = true;
+			}
+			previousTokenIndex = t.getTokenIndex();
+			listener.consumeToken(t);
+		}
+		else if ( elements[0].equals("consumeHiddenToken") ) {
+			ProxyToken t = deserializeToken(elements, 1);
+			if ( t.getTokenIndex() == previousTokenIndex ) {
+				tokenIndexesInvalid = true;
+			}
+			previousTokenIndex = t.getTokenIndex();
+			listener.consumeHiddenToken(t);
+		}
+		else if ( elements[0].equals("LT") ) {
+			Token t = deserializeToken(elements, 2);
+			listener.LT(Integer.parseInt(elements[1]), t);
+		}
+		else if ( elements[0].equals("mark") ) {
+			listener.mark(Integer.parseInt(elements[1]));
+		}
+		else if ( elements[0].equals("rewind") ) {
+			if ( elements[1]!=null ) {
+				listener.rewind(Integer.parseInt(elements[1]));
+			}
+			else {
+				listener.rewind();
+			}
+		}
+		else if ( elements[0].equals("beginBacktrack") ) {
+			listener.beginBacktrack(Integer.parseInt(elements[1]));
+		}
+		else if ( elements[0].equals("endBacktrack") ) {
+			int level = Integer.parseInt(elements[1]);
+			int successI = Integer.parseInt(elements[2]);
+			listener.endBacktrack(level, successI==DebugEventListener.TRUE);
+		}
+		else if ( elements[0].equals("exception") ) {
+			String excName = elements[1];
+			String indexS = elements[2];
+			String lineS = elements[3];
+			String posS = elements[4];
+			Class excClass = null;
+			try {
+				excClass = Class.forName(excName);
+				RecognitionException e =
+					(RecognitionException)excClass.newInstance();
+				e.index = Integer.parseInt(indexS);
+				e.line = Integer.parseInt(lineS);
+				e.charPositionInLine = Integer.parseInt(posS);
+				listener.recognitionException(e);
+			}
+			catch (ClassNotFoundException cnfe) {
+				System.err.println("can't find class "+cnfe);
+				cnfe.printStackTrace(System.err);
+			}
+			catch (InstantiationException ie) {
+				System.err.println("can't instantiate class "+ie);
+				ie.printStackTrace(System.err);
+			}
+			catch (IllegalAccessException iae) {
+				System.err.println("can't access class "+iae);
+				iae.printStackTrace(System.err);
+			}
+		}
+		else if ( elements[0].equals("beginResync") ) {
+			listener.beginResync();
+		}
+		else if ( elements[0].equals("endResync") ) {
+			listener.endResync();
+		}
+		else if ( elements[0].equals("terminate") ) {
+			listener.terminate();
+		}
+		else if ( elements[0].equals("semanticPredicate") ) {
+			Boolean result = Boolean.valueOf(elements[1]);
+			String predicateText = elements[2];
+			predicateText = unEscapeNewlines(predicateText);
+			listener.semanticPredicate(result.booleanValue(),
+									   predicateText);
+		}
+		else if ( elements[0].equals("consumeNode") ) {
+			ProxyTree node = deserializeNode(elements, 1);
+			listener.consumeNode(node);
+		}
+		else if ( elements[0].equals("LN") ) {
+			int i = Integer.parseInt(elements[1]);
+			ProxyTree node = deserializeNode(elements, 2);
+			listener.LT(i, node);
+		}
+		else if ( elements[0].equals("createNodeFromTokenElements") ) {
+			int ID = Integer.parseInt(elements[1]);
+			int type = Integer.parseInt(elements[2]);
+			String text = elements[3];
+			text = unEscapeNewlines(text);
+			ProxyTree node = new ProxyTree(ID, type, -1, -1, -1, text);
+			listener.createNode(node);
+		}
+		else if ( elements[0].equals("createNode") ) {
+			int ID = Integer.parseInt(elements[1]);
+			int tokenIndex = Integer.parseInt(elements[2]);
+			// create dummy node/token filled with ID, tokenIndex
+			ProxyTree node = new ProxyTree(ID);
+			ProxyToken token = new ProxyToken(tokenIndex);
+			listener.createNode(node, token);
+		}
+		else if ( elements[0].equals("nilNode") ) {
+			int ID = Integer.parseInt(elements[1]);
+			ProxyTree node = new ProxyTree(ID);
+			listener.nilNode(node);
+		}
+		else if ( elements[0].equals("errorNode") ) {
+			// TODO: do we need a special tree here?
+			int ID = Integer.parseInt(elements[1]);
+			int type = Integer.parseInt(elements[2]);
+			String text = elements[3];
+			text = unEscapeNewlines(text);
+			ProxyTree node = new ProxyTree(ID, type, -1, -1, -1, text);
+			listener.errorNode(node);
+		}
+		else if ( elements[0].equals("becomeRoot") ) {
+			int newRootID = Integer.parseInt(elements[1]);
+			int oldRootID = Integer.parseInt(elements[2]);
+			ProxyTree newRoot = new ProxyTree(newRootID);
+			ProxyTree oldRoot = new ProxyTree(oldRootID);
+			listener.becomeRoot(newRoot, oldRoot);
+		}
+		else if ( elements[0].equals("addChild") ) {
+			int rootID = Integer.parseInt(elements[1]);
+			int childID = Integer.parseInt(elements[2]);
+			ProxyTree root = new ProxyTree(rootID);
+			ProxyTree child = new ProxyTree(childID);
+			listener.addChild(root, child);
+		}
+		else if ( elements[0].equals("setTokenBoundaries") ) {
+			int ID = Integer.parseInt(elements[1]);
+			ProxyTree node = new ProxyTree(ID);
+			listener.setTokenBoundaries(
+				node,
+				Integer.parseInt(elements[2]),
+				Integer.parseInt(elements[3]));
+		}
+		else {
+			System.err.println("unknown debug event: "+line);
+		}
+	}
+
+	protected ProxyTree deserializeNode(String[] elements, int offset) {
+		int ID = Integer.parseInt(elements[offset+0]);
+		int type = Integer.parseInt(elements[offset+1]);
+		int tokenLine = Integer.parseInt(elements[offset+2]);
+		int charPositionInLine = Integer.parseInt(elements[offset+3]);
+		int tokenIndex = Integer.parseInt(elements[offset+4]);
+		String text = elements[offset+5];
+		text = unEscapeNewlines(text);
+		return new ProxyTree(ID, type, tokenLine, charPositionInLine, tokenIndex, text);
+	}
+
+	protected ProxyToken deserializeToken(String[] elements,
+										  int offset)
+	{
+		String indexS = elements[offset+0];
+		String typeS = elements[offset+1];
+		String channelS = elements[offset+2];
+		String lineS = elements[offset+3];
+		String posS = elements[offset+4];
+		String text = elements[offset+5];
+		text = unEscapeNewlines(text);
+		int index = Integer.parseInt(indexS);
+		ProxyToken t =
+			new ProxyToken(index,
+						   Integer.parseInt(typeS),
+						   Integer.parseInt(channelS),
+						   Integer.parseInt(lineS),
+						   Integer.parseInt(posS),
+						   text);
+		return t;
+	}
+
+	/** Create a thread to listen to the remote running recognizer */
+	public void start() {
+		Thread t = new Thread(this);
+		t.start();
+	}
+
+	public void run() {
+		eventHandler();
+	}
+
+	// M i s c
+
+	public String[] getEventElements(String event) {
+		if ( event==null ) {
+			return null;
+		}
+		String[] elements = new String[MAX_EVENT_ELEMENTS];
+		String str = null; // a string element if present (must be last)
+		try {
+			int firstQuoteIndex = event.indexOf('"');
+			if ( firstQuoteIndex>=0 ) {
+				// treat specially; has a string argument like "a comment\n
+				// Note that the string is terminated by \n not end quote.
+				// Easier to parse that way.
+				String eventWithoutString = event.substring(0,firstQuoteIndex);
+				str = event.substring(firstQuoteIndex+1,event.length());
+				event = eventWithoutString;
+			}
+			StringTokenizer st = new StringTokenizer(event, "\t", false);
+			int i = 0;
+			while ( st.hasMoreTokens() ) {
+				if ( i>=MAX_EVENT_ELEMENTS ) {
+					// ErrorManager.internalError("event has more than "+MAX_EVENT_ELEMENTS+" args: "+event);
+					return elements;
+				}
+				elements[i] = st.nextToken();
+				i++;
+			}
+			if ( str!=null ) {
+				elements[i] = str;
+			}
+		}
+		catch (Exception e) {
+			e.printStackTrace(System.err);
+		}
+		return elements;
+	}
+
+	protected String unEscapeNewlines(String txt) {
+		// this unescape is slow but easy to understand
+		txt = txt.replaceAll("%0A","\n");  // unescape \n
+		txt = txt.replaceAll("%0D","\r");  // unescape \r
+		txt = txt.replaceAll("%25","%");   // undo escaped escape chars
+		return txt;
+	}
+
+	public boolean tokenIndexesAreInvalid() {
+		return false;
+		//return tokenIndexesInvalid;
+	}
+
+}
+
diff --git a/src/org/antlr/runtime/debug/TraceDebugEventListener.java b/src/org/antlr/runtime/debug/TraceDebugEventListener.java
new file mode 100755
index 0000000..de9366d
--- /dev/null
+++ b/src/org/antlr/runtime/debug/TraceDebugEventListener.java
@@ -0,0 +1,96 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime.debug;
+
+import org.antlr.runtime.Token;
+import org.antlr.runtime.tree.TreeAdaptor;
+
+/** Print out (most of) the events... Useful for debugging, testing... */
+public class TraceDebugEventListener extends BlankDebugEventListener {
+	TreeAdaptor adaptor;
+
+	public TraceDebugEventListener(TreeAdaptor adaptor) {
+		this.adaptor = adaptor;
+	}
+
+	public void enterRule(String ruleName) { System.out.println("enterRule "+ruleName); }
+	public void exitRule(String ruleName) { System.out.println("exitRule "+ruleName); }
+	public void enterSubRule(int decisionNumber) { System.out.println("enterSubRule"); }
+	public void exitSubRule(int decisionNumber) { System.out.println("exitSubRule"); }
+	public void location(int line, int pos) {System.out.println("location "+line+":"+pos);}
+
+	// Tree parsing stuff
+
+	public void consumeNode(Object t) {
+		int ID = adaptor.getUniqueID(t);
+		String text = adaptor.getText(t);
+		int type = adaptor.getType(t);
+		System.out.println("consumeNode "+ID+" "+text+" "+type);
+	}
+
+	public void LT(int i, Object t) {
+		int ID = adaptor.getUniqueID(t);
+		String text = adaptor.getText(t);
+		int type = adaptor.getType(t);
+		System.out.println("LT "+i+" "+ID+" "+text+" "+type);
+	}
+
+
+	// AST stuff
+	public void nilNode(Object t) {System.out.println("nilNode "+adaptor.getUniqueID(t));}
+
+	public void createNode(Object t) {
+		int ID = adaptor.getUniqueID(t);
+		String text = adaptor.getText(t);
+		int type = adaptor.getType(t);
+		System.out.println("create "+ID+": "+text+", "+type);
+	}
+
+	public void createNode(Object node, Token token) {
+		int ID = adaptor.getUniqueID(node);
+		String text = adaptor.getText(node);
+		int tokenIndex = token.getTokenIndex();
+		System.out.println("create "+ID+": "+tokenIndex);
+	}
+
+	public void becomeRoot(Object newRoot, Object oldRoot) {
+		System.out.println("becomeRoot "+adaptor.getUniqueID(newRoot)+", "+
+						   adaptor.getUniqueID(oldRoot));
+	}
+
+	public void addChild(Object root, Object child) {
+		System.out.println("addChild "+adaptor.getUniqueID(root)+", "+
+						   adaptor.getUniqueID(child));
+	}
+
+	public void setTokenBoundaries(Object t, int tokenStartIndex, int tokenStopIndex) {
+		System.out.println("setTokenBoundaries "+adaptor.getUniqueID(t)+", "+
+						   tokenStartIndex+", "+tokenStopIndex);
+	}
+}
+
diff --git a/src/org/antlr/runtime/debug/Tracer.java b/src/org/antlr/runtime/debug/Tracer.java
new file mode 100755
index 0000000..c2c73da
--- /dev/null
+++ b/src/org/antlr/runtime/debug/Tracer.java
@@ -0,0 +1,65 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime.debug;
+
+import org.antlr.runtime.IntStream;
+import org.antlr.runtime.TokenStream;
+
+/** The default tracer mimics the traceParser behavior of ANTLR 2.x.
+ *  This listens for debugging events from the parser and implies
+ *  that you cannot debug and trace at the same time.
+ */
+public class Tracer extends BlankDebugEventListener {
+	public IntStream input;
+	protected int level = 0;
+
+	public Tracer(IntStream input) {
+		this.input = input;
+	}
+
+	public void enterRule(String ruleName) {
+		for (int i=1; i<=level; i++) {System.out.print(" ");}
+		System.out.println("> "+ruleName+" lookahead(1)="+getInputSymbol(1));
+		level++;
+	}
+
+	public void exitRule(String ruleName) {
+		level--;
+		for (int i=1; i<=level; i++) {System.out.print(" ");}
+		System.out.println("< "+ruleName+" lookahead(1)="+getInputSymbol(1));
+	}
+
+	public Object getInputSymbol(int k) {
+		if ( input instanceof TokenStream ) {
+			return ((TokenStream)input).LT(k);
+		}
+		return new Character((char)input.LA(k));
+	}
+}
+
+
diff --git a/src/org/antlr/runtime/misc/DoubleKeyMap.java b/src/org/antlr/runtime/misc/DoubleKeyMap.java
new file mode 100755
index 0000000..b69ae32
--- /dev/null
+++ b/src/org/antlr/runtime/misc/DoubleKeyMap.java
@@ -0,0 +1,62 @@
+package org.antlr.runtime.misc;
+
+import java.util.*;
+
+/** Sometimes we need to map a key to a value but key is two pieces of data.
+ *  This nested hash table saves creating a single key each time we access
+ *  map; avoids mem creation.
+ */
+public class DoubleKeyMap<Key1, Key2, Value> {
+	Map<Key1, Map<Key2, Value>> data = new LinkedHashMap<Key1, Map<Key2, Value>>();
+
+	public Value put(Key1 k1, Key2 k2, Value v) {
+		Map<Key2, Value> data2 = data.get(k1);
+		Value prev = null;
+		if ( data2==null ) {
+			data2 = new LinkedHashMap<Key2, Value>();
+			data.put(k1, data2);
+		}
+		else {
+			prev = data2.get(k2);
+		}
+		data2.put(k2, v);
+		return prev;
+	}
+
+	public Value get(Key1 k1, Key2 k2) {
+		Map<Key2, Value> data2 = data.get(k1);
+		if ( data2==null ) return null;
+		return data2.get(k2);
+	}
+
+	public Map<Key2, Value> get(Key1 k1) { return data.get(k1); }
+
+	/** Get all values associated with primary key */
+	public Collection<Value> values(Key1 k1) {
+		Map<Key2, Value> data2 = data.get(k1);
+		if ( data2==null ) return null;
+		return data2.values();
+	}
+
+	/** get all primary keys */
+	public Set<Key1> keySet() {
+		return data.keySet();
+	}
+
+	/** get all secondary keys associated with a primary key */
+	public Set<Key2> keySet(Key1 k1) {
+		Map<Key2, Value> data2 = data.get(k1);
+		if ( data2==null ) return null;
+		return data2.keySet();
+	}
+
+	public Collection<Value> values() {
+		Set<Value> s = new HashSet<Value>();
+		for (Map<Key2, Value> k2 : data.values()) {
+			for (Value v : k2.values()) {
+				s.add(v);
+			}
+		}
+		return s;
+	}
+}
diff --git a/src/org/antlr/runtime/misc/FastQueue.java b/src/org/antlr/runtime/misc/FastQueue.java
new file mode 100755
index 0000000..08843dd
--- /dev/null
+++ b/src/org/antlr/runtime/misc/FastQueue.java
@@ -0,0 +1,100 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime.misc;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.NoSuchElementException;
+
+/** A queue that can dequeue and get(i) in O(1) and grow arbitrarily large.
+ *  A linked list is fast at dequeue but slow at get(i).  An array is
+ *  the reverse.  This is O(1) for both operations.
+ *
+ *  List grows until you dequeue last element at end of buffer. Then
+ *  it resets to start filling at 0 again.  If adds/removes are balanced, the
+ *  buffer will not grow too large.
+ *
+ *  No iterator stuff as that's not how we'll use it.
+ */
+public class FastQueue<T> {
+    /** dynamically-sized buffer of elements */
+    protected List<T> data = new ArrayList<T>();
+    /** index of next element to fill */
+    protected int p = 0;
+	protected int range = -1; // how deep have we gone?	
+
+    public void reset() { clear(); }
+    public void clear() { p = 0; data.clear(); }
+
+    /** Get and remove first element in queue */
+    public T remove() {
+        T o = elementAt(0);
+        p++;
+        // have we hit end of buffer?
+        if ( p == data.size() ) {
+            // if so, it's an opportunity to start filling at index 0 again
+            clear(); // size goes to 0, but retains memory
+        }
+        return o;
+    }
+
+    public void add(T o) { data.add(o); }
+
+    public int size() { return data.size() - p; }
+
+	public int range() { return range; }
+
+    public T head() { return elementAt(0); }
+
+    /** Return element i elements ahead of current element.  i==0 gets
+     *  current element.  This is not an absolute index into the data list
+     *  since p defines the start of the real list.
+     */
+    public T elementAt(int i) {
+		int absIndex = p + i;
+		if ( absIndex >= data.size() ) {
+            throw new NoSuchElementException("queue index "+ absIndex +" > last index "+(data.size()-1));
+        }
+        if ( absIndex < 0 ) {
+            throw new NoSuchElementException("queue index "+ absIndex +" < 0");
+        }
+		if ( absIndex>range ) range = absIndex;
+        return data.get(absIndex);
+    }
+
+    /** Return string of current buffer contents; non-destructive */
+    public String toString() {
+        StringBuffer buf = new StringBuffer();
+        int n = size();
+        for (int i=0; i<n; i++) {
+            buf.append(elementAt(i));
+            if ( (i+1)<n ) buf.append(" ");
+        }
+        return buf.toString();
+    }
+}
\ No newline at end of file
diff --git a/src/org/antlr/runtime/misc/IntArray.java b/src/org/antlr/runtime/misc/IntArray.java
new file mode 100755
index 0000000..bc484aa
--- /dev/null
+++ b/src/org/antlr/runtime/misc/IntArray.java
@@ -0,0 +1,87 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime.misc;
+
+/** A dynamic array that uses int not Integer objects. In principle this
+ *  is more efficient in time, but certainly in space.
+ *
+ *  This is simple enough that you can access the data array directly,
+ *  but make sure that you append elements only with add() so that you
+ *  get dynamic sizing.  Make sure to call ensureCapacity() when you are
+ *  manually adding new elements.
+ *
+ *  Doesn't impl List because it doesn't return objects and I mean this
+ *  really as just an array not a List per se.  Manipulate the elements
+ *  at will.  This has stack methods too.
+ *
+ *  When runtime can be 1.5, I'll make this generic.
+ */
+public class IntArray {
+	public static final int INITIAL_SIZE = 10;
+	public int[] data;
+	protected int p = -1;
+
+	public void add(int v) {
+		ensureCapacity(p+1);
+		data[++p] = v;
+	}
+
+	public void push(int v) {
+		add(v);
+	}
+
+	public int pop() {
+		int v = data[p];
+		p--;
+		return v;
+	}
+
+	/** This only tracks elements added via push/add. */
+	public int size() {
+		return p;
+	}
+
+    public void clear() {
+        p = -1;
+    }
+
+    public void ensureCapacity(int index) {
+		if ( data==null ) {
+			data = new int[INITIAL_SIZE];
+		}
+		else if ( (index+1)>=data.length ) {
+			int newSize = data.length*2;
+			if ( index>newSize ) {
+				newSize = index+1;
+			}
+			int[] newData = new int[newSize];
+			System.arraycopy(data, 0, newData, 0, data.length);
+			data = newData;
+		}
+	}
+}
diff --git a/src/org/antlr/runtime/misc/LookaheadStream.java b/src/org/antlr/runtime/misc/LookaheadStream.java
new file mode 100755
index 0000000..6f19c44
--- /dev/null
+++ b/src/org/antlr/runtime/misc/LookaheadStream.java
@@ -0,0 +1,161 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime.misc;
+
+import org.antlr.runtime.Token;
+
+import java.util.NoSuchElementException;
+
+/** A lookahead queue that knows how to mark/release locations
+ *  in the buffer for backtracking purposes. Any markers force the FastQueue
+ *  superclass to keep all tokens until no more markers; then can reset
+ *  to avoid growing a huge buffer.
+ */
+public abstract class LookaheadStream<T> extends FastQueue<T> {
+    public static final int UNINITIALIZED_EOF_ELEMENT_INDEX = Integer.MAX_VALUE;
+
+    /** Absolute token index. It's the index of the symbol about to be
+	 *  read via LT(1). Goes from 0 to numtokens.
+     */
+    protected int currentElementIndex = 0;
+
+    protected T prevElement;
+
+    /** Track object returned by nextElement upon end of stream;
+     *  Return it later when they ask for LT passed end of input.
+     */
+    public T eof = null;
+
+    /** Track the last mark() call result value for use in rewind(). */
+    protected int lastMarker;
+
+    /** tracks how deep mark() calls are nested */
+    protected int markDepth = 0;
+
+    public void reset() {
+        super.reset();
+        currentElementIndex = 0;
+        p = 0;
+        prevElement=null;        
+    }
+    
+    /** Implement nextElement to supply a stream of elements to this
+     *  lookahead buffer.  Return eof upon end of the stream we're pulling from.
+     */
+    public abstract T nextElement();
+
+    public abstract boolean isEOF(T o);
+
+    /** Get and remove first element in queue; override FastQueue.remove();
+     *  it's the same, just checks for backtracking.
+     */
+    public T remove() {
+        T o = elementAt(0);
+        p++;
+        // have we hit end of buffer and not backtracking?
+        if ( p == data.size() && markDepth==0 ) {
+            // if so, it's an opportunity to start filling at index 0 again
+            clear(); // size goes to 0, but retains memory
+        }
+        return o;
+    }
+
+    /** Make sure we have at least one element to remove, even if EOF */
+    public void consume() {
+        syncAhead(1);
+        prevElement = remove();
+        currentElementIndex++;
+    }
+
+    /** Make sure we have 'need' elements from current position p. Last valid
+     *  p index is data.size()-1.  p+need-1 is the data index 'need' elements
+     *  ahead.  If we need 1 element, (p+1-1)==p must be < data.size().
+     */
+    protected void syncAhead(int need) {
+        int n = (p+need-1) - data.size() + 1; // how many more elements we need?
+        if ( n > 0 ) fill(n);                 // out of elements?
+    }
+
+    /** add n elements to buffer */
+    public void fill(int n) {
+        for (int i=1; i<=n; i++) {
+            T o = nextElement();
+            if ( isEOF(o) ) eof = o;
+            data.add(o);
+        }
+    }
+
+    /** Size of entire stream is unknown; we only know buffer size from FastQueue */
+    public int size() { throw new UnsupportedOperationException("streams are of unknown size"); }
+
+    public T LT(int k) {
+		if ( k==0 ) {
+			return null;
+		}
+		if ( k<0 ) return LB(-k);
+		//System.out.print("LT(p="+p+","+k+")=");
+        syncAhead(k);
+        if ( (p+k-1) > data.size() ) return eof;
+        return elementAt(k-1);
+	}
+
+    public int index() { return currentElementIndex; }
+
+	public int mark() {
+        markDepth++;
+        lastMarker = p; // track where we are in buffer not absolute token index
+        return lastMarker;
+	}
+
+	public void release(int marker) {
+		// no resources to release
+	}
+
+	public void rewind(int marker) {
+        markDepth--;
+        seek(marker); // assume marker is top
+        // release(marker); // waste of call; it does nothing in this class
+    }
+
+	public void rewind() {
+        seek(lastMarker); // rewind but do not release marker
+    }
+
+    /** Seek to a 0-indexed position within data buffer.  Can't handle
+     *  case where you seek beyond end of existing buffer.  Normally used
+     *  to seek backwards in the buffer. Does not force loading of nodes.
+     *  Doesn't see to absolute position in input stream since this stream
+     *  is unbuffered. Seeks only into our moving window of elements.
+     */
+    public void seek(int index) { p = index; }
+
+    protected T LB(int k) {
+        if ( k==1 ) return prevElement;
+        throw new NoSuchElementException("can't look backwards more than one token in this stream");
+    }
+}
\ No newline at end of file
diff --git a/src/org/antlr/runtime/misc/Stats.java b/src/org/antlr/runtime/misc/Stats.java
new file mode 100755
index 0000000..9fdd21e
--- /dev/null
+++ b/src/org/antlr/runtime/misc/Stats.java
@@ -0,0 +1,189 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime.misc;
+
+import java.io.*;
+import java.util.List;
+
+/** Stats routines needed by profiler etc...
+
+ // note that these routines return 0.0 if no values exist in the X[]
+ // which is not "correct", but it is useful so I don't generate NaN
+ // in my output
+
+ */
+public class Stats {
+	public static final String ANTLRWORKS_DIR = "antlrworks";
+
+	/** Compute the sample (unbiased estimator) standard deviation following:
+	 *
+	 *  Computing Deviations: Standard Accuracy
+	 *  Tony F. Chan and John Gregg Lewis
+	 *  Stanford University
+	 *  Communications of ACM September 1979 of Volume 22 the ACM Number 9
+	 *
+	 *  The "two-pass" method from the paper; supposed to have better
+	 *  numerical properties than the textbook summation/sqrt.  To me
+	 *  this looks like the textbook method, but I ain't no numerical
+	 *  methods guy.
+	 */
+	public static double stddev(int[] X) {
+		int m = X.length;
+		if ( m<=1 ) {
+			return 0;
+		}
+		double xbar = avg(X);
+		double s2 = 0.0;
+		for (int i=0; i<m; i++){
+			s2 += (X[i] - xbar)*(X[i] - xbar);
+		}
+		s2 = s2/(m-1);
+		return Math.sqrt(s2);
+	}
+
+	/** Compute the sample mean */
+	public static double avg(int[] X) {
+		double xbar = 0.0;
+		int m = X.length;
+		if ( m==0 ) {
+			return 0;
+		}
+		for (int i=0; i<m; i++){
+			xbar += X[i];
+		}
+		if ( xbar>=0.0 ) {
+			return xbar / m;
+		}
+		return 0.0;
+	}
+
+	public static int min(int[] X) {
+		int min = Integer.MAX_VALUE;
+		int m = X.length;
+		if ( m==0 ) {
+			return 0;
+		}
+		for (int i=0; i<m; i++){
+			if ( X[i] < min ) {
+				min = X[i];
+			}
+		}
+		return min;
+	}
+
+	public static int max(int[] X) {
+		int max = Integer.MIN_VALUE;
+		int m = X.length;
+		if ( m==0 ) {
+			return 0;
+		}
+		for (int i=0; i<m; i++){
+			if ( X[i] > max ) {
+				max = X[i];
+			}
+		}
+		return max;
+	}
+
+	/** Compute the sample mean */
+	public static double avg(List<Integer> X) {
+		double xbar = 0.0;
+		int m = X.size();
+		if ( m==0 ) {
+			return 0;
+		}
+		for (int i=0; i<m; i++){
+			xbar += X.get(i);
+		}
+		if ( xbar>=0.0 ) {
+			return xbar / m;
+		}
+		return 0.0;
+	}
+
+	public static int min(List<Integer> X) {
+		int min = Integer.MAX_VALUE;
+		int m = X.size();
+		if ( m==0 ) {
+			return 0;
+		}
+		for (int i=0; i<m; i++){
+			if ( X.get(i) < min ) {
+				min = X.get(i);
+			}
+		}
+		return min;
+	}
+
+	public static int max(List<Integer> X) {
+		int max = Integer.MIN_VALUE;
+		int m = X.size();
+		if ( m==0 ) {
+			return 0;
+		}
+		for (int i=0; i<m; i++){
+			if ( X.get(i) > max ) {
+				max = X.get(i);
+			}
+		}
+		return max;
+	}
+
+	public static int sum(int[] X) {
+		int s = 0;
+		int m = X.length;
+		if ( m==0 ) {
+			return 0;
+		}
+		for (int i=0; i<m; i++){
+			s += X[i];
+		}
+		return s;
+	}
+
+	public static void writeReport(String filename, String data) throws IOException {
+		String absoluteFilename = getAbsoluteFileName(filename);
+		File f = new File(absoluteFilename);
+		File parent = f.getParentFile();
+		parent.mkdirs(); // ensure parent dir exists
+		// write file
+		FileOutputStream fos = new FileOutputStream(f, true); // append
+		BufferedOutputStream bos = new BufferedOutputStream(fos);
+		PrintStream ps = new PrintStream(bos);
+		ps.println(data);
+		ps.close();
+		bos.close();
+		fos.close();
+	}
+
+	public static String getAbsoluteFileName(String filename) {
+		return System.getProperty("user.home")+File.separator+
+					ANTLRWORKS_DIR +File.separator+
+					filename;
+	}
+}
diff --git a/src/org/antlr/runtime/tree/.DS_Store b/src/org/antlr/runtime/tree/.DS_Store
new file mode 100644
index 0000000..5008ddf
--- /dev/null
+++ b/src/org/antlr/runtime/tree/.DS_Store
Binary files differ
diff --git a/src/org/antlr/runtime/tree/BaseTree.java b/src/org/antlr/runtime/tree/BaseTree.java
new file mode 100755
index 0000000..ebffdb3
--- /dev/null
+++ b/src/org/antlr/runtime/tree/BaseTree.java
@@ -0,0 +1,349 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime.tree;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/** A generic tree implementation with no payload.  You must subclass to
+ *  actually have any user data.  ANTLR v3 uses a list of children approach
+ *  instead of the child-sibling approach in v2.  A flat tree (a list) is
+ *  an empty node whose children represent the list.  An empty, but
+ *  non-null node is called "nil".
+ */
+public abstract class BaseTree implements Tree {
+	protected List children;
+
+	public BaseTree() {
+	}
+
+	/** Create a new node from an existing node does nothing for BaseTree
+	 *  as there are no fields other than the children list, which cannot
+	 *  be copied as the children are not considered part of this node. 
+	 */
+	public BaseTree(Tree node) {
+	}
+
+	public Tree getChild(int i) {
+		if ( children==null || i>=children.size() ) {
+			return null;
+		}
+		return (Tree)children.get(i);
+	}
+
+	/** Get the children internal List; note that if you directly mess with
+	 *  the list, do so at your own risk.
+	 */
+	public List getChildren() {
+		return children;
+	}
+
+	public Tree getFirstChildWithType(int type) {
+		for (int i = 0; children!=null && i < children.size(); i++) {
+			Tree t = (Tree) children.get(i);
+			if ( t.getType()==type ) {
+				return t;
+			}
+		}	
+		return null;
+	}
+
+	public int getChildCount() {
+		if ( children==null ) {
+			return 0;
+		}
+		return children.size();
+	}
+
+	/** Add t as child of this node.
+	 *
+	 *  Warning: if t has no children, but child does
+	 *  and child isNil then this routine moves children to t via
+	 *  t.children = child.children; i.e., without copying the array.
+	 */
+	public void addChild(Tree t) {
+		//System.out.println("add child "+t.toStringTree()+" "+this.toStringTree());
+		//System.out.println("existing children: "+children);
+		if ( t==null ) {
+			return; // do nothing upon addChild(null)
+		}
+		BaseTree childTree = (BaseTree)t;
+		if ( childTree.isNil() ) { // t is an empty node possibly with children
+			if ( this.children!=null && this.children == childTree.children ) {
+				throw new RuntimeException("attempt to add child list to itself");
+			}
+			// just add all of childTree's children to this
+			if ( childTree.children!=null ) {
+				if ( this.children!=null ) { // must copy, this has children already
+					int n = childTree.children.size();
+					for (int i = 0; i < n; i++) {
+						Tree c = (Tree)childTree.children.get(i);
+						this.children.add(c);
+						// handle double-link stuff for each child of nil root
+						c.setParent(this);
+						c.setChildIndex(children.size()-1);
+					}
+				}
+				else {
+					// no children for this but t has children; just set pointer
+					// call general freshener routine
+					this.children = childTree.children;
+					this.freshenParentAndChildIndexes();
+				}
+			}
+		}
+		else { // child is not nil (don't care about children)
+			if ( children==null ) {
+				children = createChildrenList(); // create children list on demand
+			}
+			children.add(t);
+			childTree.setParent(this);
+			childTree.setChildIndex(children.size()-1);
+		}
+		// System.out.println("now children are: "+children);
+	}
+
+	/** Add all elements of kids list as children of this node */
+	public void addChildren(List kids) {
+		for (int i = 0; i < kids.size(); i++) {
+			Tree t = (Tree) kids.get(i);
+			addChild(t);
+		}
+	}
+
+	public void setChild(int i, Tree t) {
+		if ( t==null ) {
+			return;
+		}
+		if ( t.isNil() ) {
+			throw new IllegalArgumentException("Can't set single child to a list");
+		}
+		if ( children==null ) {
+			children = createChildrenList();
+		}
+		children.set(i, t);
+		t.setParent(this);
+		t.setChildIndex(i);
+	}
+	
+	public Object deleteChild(int i) {
+		if ( children==null ) {
+			return null;
+		}
+		Tree killed = (Tree)children.remove(i);
+		// walk rest and decrement their child indexes
+		this.freshenParentAndChildIndexes(i);
+		return killed;
+	}
+
+	/** Delete children from start to stop and replace with t even if t is
+	 *  a list (nil-root tree).  num of children can increase or decrease.
+	 *  For huge child lists, inserting children can force walking rest of
+	 *  children to set their childindex; could be slow.
+	 */
+	public void replaceChildren(int startChildIndex, int stopChildIndex, Object t) {
+		/*
+		System.out.println("replaceChildren "+startChildIndex+", "+stopChildIndex+
+						   " with "+((BaseTree)t).toStringTree());
+		System.out.println("in="+toStringTree());
+		*/
+		if ( children==null ) {
+			throw new IllegalArgumentException("indexes invalid; no children in list");
+		}
+		int replacingHowMany = stopChildIndex - startChildIndex + 1;
+		int replacingWithHowMany;
+		BaseTree newTree = (BaseTree)t;
+		List newChildren = null;
+		// normalize to a list of children to add: newChildren
+		if ( newTree.isNil() ) {
+			newChildren = newTree.children;
+		}
+		else {
+			newChildren = new ArrayList(1);
+			newChildren.add(newTree);
+		}
+		replacingWithHowMany = newChildren.size();
+		int numNewChildren = newChildren.size();
+		int delta = replacingHowMany - replacingWithHowMany;
+		// if same number of nodes, do direct replace
+		if ( delta == 0 ) {
+			int j = 0; // index into new children
+			for (int i=startChildIndex; i<=stopChildIndex; i++) {
+				BaseTree child = (BaseTree)newChildren.get(j);
+				children.set(i, child);
+				child.setParent(this);
+				child.setChildIndex(i);
+                j++;
+            }
+		}
+		else if ( delta > 0 ) { // fewer new nodes than there were
+			// set children and then delete extra
+			for (int j=0; j<numNewChildren; j++) {
+				children.set(startChildIndex+j, newChildren.get(j));
+			}
+			int indexToDelete = startChildIndex+numNewChildren;
+			for (int c=indexToDelete; c<=stopChildIndex; c++) {
+				// delete same index, shifting everybody down each time
+				children.remove(indexToDelete);
+			}
+			freshenParentAndChildIndexes(startChildIndex);
+		}
+		else { // more new nodes than were there before
+			// fill in as many children as we can (replacingHowMany) w/o moving data
+			for (int j=0; j<replacingHowMany; j++) {
+				children.set(startChildIndex+j, newChildren.get(j));
+			}
+			int numToInsert = replacingWithHowMany-replacingHowMany;
+			for (int j=replacingHowMany; j<replacingWithHowMany; j++) {
+				children.add(startChildIndex+j, newChildren.get(j));
+			}
+			freshenParentAndChildIndexes(startChildIndex);
+		}
+		//System.out.println("out="+toStringTree());
+	}
+
+	/** Override in a subclass to change the impl of children list */
+	protected List createChildrenList() {
+		return new ArrayList();
+	}
+
+	public boolean isNil() {
+		return false;
+	}
+
+	/** Set the parent and child index values for all child of t */
+	public void freshenParentAndChildIndexes() {
+		freshenParentAndChildIndexes(0);
+	}
+
+	public void freshenParentAndChildIndexes(int offset) {
+		int n = getChildCount();
+		for (int c = offset; c < n; c++) {
+			Tree child = (Tree)getChild(c);
+			child.setChildIndex(c);
+			child.setParent(this);
+		}
+	}
+
+	public void sanityCheckParentAndChildIndexes() {
+		sanityCheckParentAndChildIndexes(null, -1);
+	}
+
+	public void sanityCheckParentAndChildIndexes(Tree parent, int i) {
+		if ( parent!=this.getParent() ) {
+			throw new IllegalStateException("parents don't match; expected "+parent+" found "+this.getParent());
+		}
+		if ( i!=this.getChildIndex() ) {
+			throw new IllegalStateException("child indexes don't match; expected "+i+" found "+this.getChildIndex());
+		}
+		int n = this.getChildCount();
+		for (int c = 0; c < n; c++) {
+			CommonTree child = (CommonTree)this.getChild(c);
+			child.sanityCheckParentAndChildIndexes(this, c);
+		}
+	}
+
+	/** BaseTree doesn't track child indexes. */
+	public int getChildIndex() {
+		return 0;
+	}
+	public void setChildIndex(int index) {
+	}
+
+	/** BaseTree doesn't track parent pointers. */
+	public Tree getParent() {
+		return null;
+	}
+
+    public void setParent(Tree t) {
+	}
+
+    /** Walk upwards looking for ancestor with this token type. */
+    public boolean hasAncestor(int ttype) { return getAncestor(ttype)!=null; }
+
+    /** Walk upwards and get first ancestor with this token type. */
+    public Tree getAncestor(int ttype) {
+        Tree t = this;
+        t = t.getParent();
+        while ( t!=null ) {
+            if ( t.getType()==ttype ) return t;
+            t = t.getParent();
+        }
+        return null;
+    }
+
+    /** Return a list of all ancestors of this node.  The first node of
+     *  list is the root and the last is the parent of this node.
+     */
+    public List getAncestors() {
+        if ( getParent()==null ) return null;
+        List ancestors = new ArrayList();
+        Tree t = this;
+        t = t.getParent();
+        while ( t!=null ) {
+            ancestors.add(0, t); // insert at start
+            t = t.getParent();
+        }
+        return ancestors;
+    }
+
+    /** Print out a whole tree not just a node */
+    public String toStringTree() {
+		if ( children==null || children.size()==0 ) {
+			return this.toString();
+		}
+		StringBuffer buf = new StringBuffer();
+		if ( !isNil() ) {
+			buf.append("(");
+			buf.append(this.toString());
+			buf.append(' ');
+		}
+		for (int i = 0; children!=null && i < children.size(); i++) {
+			Tree t = (Tree)children.get(i);
+			if ( i>0 ) {
+				buf.append(' ');
+			}
+			buf.append(t.toStringTree());
+		}
+		if ( !isNil() ) {
+			buf.append(")");
+		}
+		return buf.toString();
+	}
+
+    public int getLine() {
+		return 0;
+	}
+
+	public int getCharPositionInLine() {
+		return 0;
+	}
+
+	/** Override to say how a node (not a tree) should look as text */
+	public abstract String toString();
+}
diff --git a/src/org/antlr/runtime/tree/BaseTreeAdaptor.java b/src/org/antlr/runtime/tree/BaseTreeAdaptor.java
new file mode 100755
index 0000000..33140b1
--- /dev/null
+++ b/src/org/antlr/runtime/tree/BaseTreeAdaptor.java
@@ -0,0 +1,279 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime.tree;
+
+import org.antlr.runtime.Token;
+import org.antlr.runtime.TokenStream;
+import org.antlr.runtime.RecognitionException;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/** A TreeAdaptor that works with any Tree implementation. */
+public abstract class BaseTreeAdaptor implements TreeAdaptor {
+	/** System.identityHashCode() is not always unique; we have to
+	 *  track ourselves.  That's ok, it's only for debugging, though it's
+	 *  expensive: we have to create a hashtable with all tree nodes in it.
+	 */
+	protected Map treeToUniqueIDMap;
+	protected int uniqueNodeID = 1;
+
+	public Object nil() {
+		return create(null);
+	}
+
+	/** create tree node that holds the start and stop tokens associated
+	 *  with an error.
+	 *
+	 *  If you specify your own kind of tree nodes, you will likely have to
+	 *  override this method. CommonTree returns Token.INVALID_TOKEN_TYPE
+	 *  if no token payload but you might have to set token type for diff
+	 *  node type.
+     *
+     *  You don't have to subclass CommonErrorNode; you will likely need to
+     *  subclass your own tree node class to avoid class cast exception.
+	 */
+	public Object errorNode(TokenStream input, Token start, Token stop,
+							RecognitionException e)
+	{
+		CommonErrorNode t = new CommonErrorNode(input, start, stop, e);
+		//System.out.println("returning error node '"+t+"' @index="+input.index());
+		return t;
+	}
+
+	public boolean isNil(Object tree) {
+		return ((Tree)tree).isNil();
+	}
+
+	public Object dupTree(Object tree) {
+		return dupTree(tree, null);
+	}
+
+	/** This is generic in the sense that it will work with any kind of
+	 *  tree (not just Tree interface).  It invokes the adaptor routines
+	 *  not the tree node routines to do the construction.  
+	 */
+	public Object dupTree(Object t, Object parent) {
+		if ( t==null ) {
+			return null;
+		}
+		Object newTree = dupNode(t);
+		// ensure new subtree root has parent/child index set
+		setChildIndex(newTree, getChildIndex(t)); // same index in new tree
+		setParent(newTree, parent);
+		int n = getChildCount(t);
+		for (int i = 0; i < n; i++) {
+			Object child = getChild(t, i);
+			Object newSubTree = dupTree(child, t);
+			addChild(newTree, newSubTree);
+		}
+		return newTree;
+	}
+
+	/** Add a child to the tree t.  If child is a flat tree (a list), make all
+	 *  in list children of t.  Warning: if t has no children, but child does
+	 *  and child isNil then you can decide it is ok to move children to t via
+	 *  t.children = child.children; i.e., without copying the array.  Just
+	 *  make sure that this is consistent with have the user will build
+	 *  ASTs.
+	 */
+	public void addChild(Object t, Object child) {
+		if ( t!=null && child!=null ) {
+			((Tree)t).addChild((Tree)child);
+		}
+	}
+
+	/** If oldRoot is a nil root, just copy or move the children to newRoot.
+	 *  If not a nil root, make oldRoot a child of newRoot.
+	 *
+	 *    old=^(nil a b c), new=r yields ^(r a b c)
+	 *    old=^(a b c), new=r yields ^(r ^(a b c))
+	 *
+	 *  If newRoot is a nil-rooted single child tree, use the single
+	 *  child as the new root node.
+	 *
+	 *    old=^(nil a b c), new=^(nil r) yields ^(r a b c)
+	 *    old=^(a b c), new=^(nil r) yields ^(r ^(a b c))
+	 *
+	 *  If oldRoot was null, it's ok, just return newRoot (even if isNil).
+	 *
+	 *    old=null, new=r yields r
+	 *    old=null, new=^(nil r) yields ^(nil r)
+	 *
+	 *  Return newRoot.  Throw an exception if newRoot is not a
+	 *  simple node or nil root with a single child node--it must be a root
+	 *  node.  If newRoot is ^(nil x) return x as newRoot.
+	 *
+	 *  Be advised that it's ok for newRoot to point at oldRoot's
+	 *  children; i.e., you don't have to copy the list.  We are
+	 *  constructing these nodes so we should have this control for
+	 *  efficiency.
+	 */
+	public Object becomeRoot(Object newRoot, Object oldRoot) {
+        //System.out.println("becomeroot new "+newRoot.toString()+" old "+oldRoot);
+        Tree newRootTree = (Tree)newRoot;
+		Tree oldRootTree = (Tree)oldRoot;
+		if ( oldRoot==null ) {
+			return newRoot;
+		}
+		// handle ^(nil real-node)
+		if ( newRootTree.isNil() ) {
+            int nc = newRootTree.getChildCount();
+            if ( nc==1 ) newRootTree = (Tree)newRootTree.getChild(0);
+            else if ( nc >1 ) {
+				// TODO: make tree run time exceptions hierarchy
+				throw new RuntimeException("more than one node as root (TODO: make exception hierarchy)");
+			}
+        }
+		// add oldRoot to newRoot; addChild takes care of case where oldRoot
+		// is a flat list (i.e., nil-rooted tree).  All children of oldRoot
+		// are added to newRoot.
+		newRootTree.addChild(oldRootTree);
+		return newRootTree;
+	}
+
+	/** Transform ^(nil x) to x and nil to null */
+	public Object rulePostProcessing(Object root) {
+		//System.out.println("rulePostProcessing: "+((Tree)root).toStringTree());
+		Tree r = (Tree)root;
+		if ( r!=null && r.isNil() ) {
+			if ( r.getChildCount()==0 ) {
+				r = null;
+			}
+			else if ( r.getChildCount()==1 ) {
+				r = (Tree)r.getChild(0);
+				// whoever invokes rule will set parent and child index
+				r.setParent(null);
+				r.setChildIndex(-1);
+			}
+		}
+		return r;
+	}
+
+	public Object becomeRoot(Token newRoot, Object oldRoot) {
+		return becomeRoot(create(newRoot), oldRoot);
+	}
+
+	public Object create(int tokenType, Token fromToken) {
+		fromToken = createToken(fromToken);
+		//((ClassicToken)fromToken).setType(tokenType);
+		fromToken.setType(tokenType);
+		Tree t = (Tree)create(fromToken);
+		return t;
+	}
+
+	public Object create(int tokenType, Token fromToken, String text) {
+        if (fromToken == null) return create(tokenType, text);
+		fromToken = createToken(fromToken);
+		fromToken.setType(tokenType);
+		fromToken.setText(text);
+		Tree t = (Tree)create(fromToken);
+		return t;
+	}
+
+	public Object create(int tokenType, String text) {
+		Token fromToken = createToken(tokenType, text);
+		Tree t = (Tree)create(fromToken);
+		return t;
+	}
+
+	public int getType(Object t) {
+		return ((Tree)t).getType();
+	}
+
+	public void setType(Object t, int type) {
+		throw new NoSuchMethodError("don't know enough about Tree node");
+	}
+
+	public String getText(Object t) {
+		return ((Tree)t).getText();
+	}
+
+	public void setText(Object t, String text) {
+		throw new NoSuchMethodError("don't know enough about Tree node");
+	}
+
+	public Object getChild(Object t, int i) {
+		return ((Tree)t).getChild(i);
+	}
+
+	public void setChild(Object t, int i, Object child) {
+		((Tree)t).setChild(i, (Tree)child);
+	}
+
+	public Object deleteChild(Object t, int i) {
+		return ((Tree)t).deleteChild(i);
+	}
+
+	public int getChildCount(Object t) {
+		return ((Tree)t).getChildCount();
+	}
+
+	public int getUniqueID(Object node) {
+		if ( treeToUniqueIDMap==null ) {
+			 treeToUniqueIDMap = new HashMap();
+		}
+		Integer prevID = (Integer)treeToUniqueIDMap.get(node);
+		if ( prevID!=null ) {
+			return prevID.intValue();
+		}
+		int ID = uniqueNodeID;
+		treeToUniqueIDMap.put(node, new Integer(ID));
+		uniqueNodeID++;
+		return ID;
+		// GC makes these nonunique:
+		// return System.identityHashCode(node);
+	}
+
+	/** Tell me how to create a token for use with imaginary token nodes.
+	 *  For example, there is probably no input symbol associated with imaginary
+	 *  token DECL, but you need to create it as a payload or whatever for
+	 *  the DECL node as in ^(DECL type ID).
+	 *
+	 *  If you care what the token payload objects' type is, you should
+	 *  override this method and any other createToken variant.
+	 */
+	public abstract Token createToken(int tokenType, String text);
+
+	/** Tell me how to create a token for use with imaginary token nodes.
+	 *  For example, there is probably no input symbol associated with imaginary
+	 *  token DECL, but you need to create it as a payload or whatever for
+	 *  the DECL node as in ^(DECL type ID).
+	 *
+	 *  This is a variant of createToken where the new token is derived from
+	 *  an actual real input token.  Typically this is for converting '{'
+	 *  tokens to BLOCK etc...  You'll see
+	 *
+	 *    r : lc='{' ID+ '}' -> ^(BLOCK[$lc] ID+) ;
+	 *
+	 *  If you care what the token payload objects' type is, you should
+	 *  override this method and any other createToken variant.
+	 */
+	public abstract Token createToken(Token fromToken);
+}
+
diff --git a/src/org/antlr/runtime/tree/BufferedTreeNodeStream.java b/src/org/antlr/runtime/tree/BufferedTreeNodeStream.java
new file mode 100755
index 0000000..d9a2a7e
--- /dev/null
+++ b/src/org/antlr/runtime/tree/BufferedTreeNodeStream.java
@@ -0,0 +1,478 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime.tree;
+
+import org.antlr.runtime.Token;
+import org.antlr.runtime.TokenStream;
+import org.antlr.runtime.misc.IntArray;
+import java.util.*;
+
+/** A buffered stream of tree nodes.  Nodes can be from a tree of ANY kind.
+ *
+ *  This node stream sucks all nodes out of the tree specified in
+ *  the constructor during construction and makes pointers into
+ *  the tree using an array of Object pointers. The stream necessarily
+ *  includes pointers to DOWN and UP and EOF nodes.
+ *
+ *  This stream knows how to mark/release for backtracking.
+ *
+ *  This stream is most suitable for tree interpreters that need to
+ *  jump around a lot or for tree parsers requiring speed (at cost of memory).
+ *  There is some duplicated functionality here with UnBufferedTreeNodeStream
+ *  but just in bookkeeping, not tree walking etc...
+ *
+ *  TARGET DEVELOPERS:
+ *
+ *  This is the old CommonTreeNodeStream that buffered up entire node stream.
+ *  No need to implement really as new CommonTreeNodeStream is much better
+ *  and covers what we need.
+ *
+ *  @see CommonTreeNodeStream
+ */
+public class BufferedTreeNodeStream implements TreeNodeStream {
+	public static final int DEFAULT_INITIAL_BUFFER_SIZE = 100;
+	public static final int INITIAL_CALL_STACK_SIZE = 10;
+
+    protected class StreamIterator implements Iterator {
+		int i = 0;
+		public boolean hasNext() {
+			return i<nodes.size();
+		}
+
+		public Object next() {
+			int current = i;
+			i++;
+			if ( current < nodes.size() ) {
+				return nodes.get(current);
+			}
+			return eof;
+		}
+
+		public void remove() {
+			throw new RuntimeException("cannot remove nodes from stream");
+		}
+	}
+
+	// all these navigation nodes are shared and hence they
+	// cannot contain any line/column info
+
+	protected Object down;
+	protected Object up;
+	protected Object eof;
+
+	/** The complete mapping from stream index to tree node.
+	 *  This buffer includes pointers to DOWN, UP, and EOF nodes.
+	 *  It is built upon ctor invocation.  The elements are type
+	 *  Object as we don't what the trees look like.
+	 *
+	 *  Load upon first need of the buffer so we can set token types
+	 *  of interest for reverseIndexing.  Slows us down a wee bit to
+	 *  do all of the if p==-1 testing everywhere though.
+	 */
+	protected List nodes;
+
+	/** Pull nodes from which tree? */
+	protected Object root;
+
+	/** IF this tree (root) was created from a token stream, track it. */
+	protected TokenStream tokens;
+
+	/** What tree adaptor was used to build these trees */
+	TreeAdaptor adaptor;
+
+	/** Reuse same DOWN, UP navigation nodes unless this is true */
+	protected boolean uniqueNavigationNodes = false;
+
+	/** The index into the nodes list of the current node (next node
+	 *  to consume).  If -1, nodes array not filled yet.
+	 */
+	protected int p = -1;
+
+	/** Track the last mark() call result value for use in rewind(). */
+	protected int lastMarker;
+
+	/** Stack of indexes used for push/pop calls */
+	protected IntArray calls;
+
+	public BufferedTreeNodeStream(Object tree) {
+		this(new CommonTreeAdaptor(), tree);
+	}
+
+	public BufferedTreeNodeStream(TreeAdaptor adaptor, Object tree) {
+		this(adaptor, tree, DEFAULT_INITIAL_BUFFER_SIZE);
+	}
+
+	public BufferedTreeNodeStream(TreeAdaptor adaptor, Object tree, int initialBufferSize) {
+		this.root = tree;
+		this.adaptor = adaptor;
+		nodes = new ArrayList(initialBufferSize);
+		down = adaptor.create(Token.DOWN, "DOWN");
+		up = adaptor.create(Token.UP, "UP");
+		eof = adaptor.create(Token.EOF, "EOF");
+	}
+
+	/** Walk tree with depth-first-search and fill nodes buffer.
+	 *  Don't do DOWN, UP nodes if its a list (t is isNil).
+	 */
+	protected void fillBuffer() {
+		fillBuffer(root);
+		//System.out.println("revIndex="+tokenTypeToStreamIndexesMap);
+		p = 0; // buffer of nodes intialized now
+	}
+
+	public void fillBuffer(Object t) {
+		boolean nil = adaptor.isNil(t);
+		if ( !nil ) {
+			nodes.add(t); // add this node
+		}
+		// add DOWN node if t has children
+		int n = adaptor.getChildCount(t);
+		if ( !nil && n>0 ) {
+			addNavigationNode(Token.DOWN);
+		}
+		// and now add all its children
+		for (int c=0; c<n; c++) {
+			Object child = adaptor.getChild(t,c);
+			fillBuffer(child);
+		}
+		// add UP node if t has children
+		if ( !nil && n>0 ) {
+			addNavigationNode(Token.UP);
+		}
+	}
+
+	/** What is the stream index for node? 0..n-1
+	 *  Return -1 if node not found.
+	 */
+	protected int getNodeIndex(Object node) {
+		if ( p==-1 ) {
+			fillBuffer();
+		}
+		for (int i = 0; i < nodes.size(); i++) {
+			Object t = (Object) nodes.get(i);
+			if ( t==node ) {
+				return i;
+			}
+		}
+		return -1;
+	}
+
+	/** As we flatten the tree, we use UP, DOWN nodes to represent
+	 *  the tree structure.  When debugging we need unique nodes
+	 *  so instantiate new ones when uniqueNavigationNodes is true.
+	 */
+	protected void addNavigationNode(final int ttype) {
+		Object navNode = null;
+		if ( ttype==Token.DOWN ) {
+			if ( hasUniqueNavigationNodes() ) {
+				navNode = adaptor.create(Token.DOWN, "DOWN");
+			}
+			else {
+				navNode = down;
+			}
+		}
+		else {
+			if ( hasUniqueNavigationNodes() ) {
+				navNode = adaptor.create(Token.UP, "UP");
+			}
+			else {
+				navNode = up;
+			}
+		}
+		nodes.add(navNode);
+	}
+
+	public Object get(int i) {
+		if ( p==-1 ) {
+			fillBuffer();
+		}
+		return nodes.get(i);
+	}
+
+	public Object LT(int k) {
+		if ( p==-1 ) {
+			fillBuffer();
+		}
+		if ( k==0 ) {
+			return null;
+		}
+		if ( k<0 ) {
+			return LB(-k);
+		}
+		//System.out.print("LT(p="+p+","+k+")=");
+		if ( (p+k-1) >= nodes.size() ) {
+			return eof;
+		}
+		return nodes.get(p+k-1);
+	}
+
+	public Object getCurrentSymbol() { return LT(1); }
+
+/*
+	public Object getLastTreeNode() {
+		int i = index();
+		if ( i>=size() ) {
+			i--; // if at EOF, have to start one back
+		}
+		System.out.println("start last node: "+i+" size=="+nodes.size());
+		while ( i>=0 &&
+			(adaptor.getType(get(i))==Token.EOF ||
+			 adaptor.getType(get(i))==Token.UP ||
+			 adaptor.getType(get(i))==Token.DOWN) )
+		{
+			i--;
+		}
+		System.out.println("stop at node: "+i+" "+nodes.get(i));
+		return nodes.get(i);
+	}
+*/
+	
+	/** Look backwards k nodes */
+	protected Object LB(int k) {
+		if ( k==0 ) {
+			return null;
+		}
+		if ( (p-k)<0 ) {
+			return null;
+		}
+		return nodes.get(p-k);
+	}
+
+	public Object getTreeSource() {
+		return root;
+	}
+
+	public String getSourceName() {
+		return getTokenStream().getSourceName();
+	}
+
+	public TokenStream getTokenStream() {
+		return tokens;
+	}
+
+	public void setTokenStream(TokenStream tokens) {
+		this.tokens = tokens;
+	}
+
+	public TreeAdaptor getTreeAdaptor() {
+		return adaptor;
+	}
+
+	public void setTreeAdaptor(TreeAdaptor adaptor) {
+		this.adaptor = adaptor;
+	}
+
+	public boolean hasUniqueNavigationNodes() {
+		return uniqueNavigationNodes;
+	}
+
+	public void setUniqueNavigationNodes(boolean uniqueNavigationNodes) {
+		this.uniqueNavigationNodes = uniqueNavigationNodes;
+	}
+
+	public void consume() {
+		if ( p==-1 ) {
+			fillBuffer();
+		}
+		p++;
+	}
+
+	public int LA(int i) {
+		return adaptor.getType(LT(i));
+	}
+
+	public int mark() {
+		if ( p==-1 ) {
+			fillBuffer();
+		}
+		lastMarker = index();
+		return lastMarker;
+	}
+
+	public void release(int marker) {
+		// no resources to release
+	}
+
+	public int index() {
+		return p;
+	}
+
+	public void rewind(int marker) {
+		seek(marker);
+	}
+
+	public void rewind() {
+		seek(lastMarker);
+	}
+
+	public void seek(int index) {
+		if ( p==-1 ) {
+			fillBuffer();
+		}
+		p = index;
+	}
+
+	/** Make stream jump to a new location, saving old location.
+	 *  Switch back with pop().
+	 */
+	public void push(int index) {
+		if ( calls==null ) {
+			calls = new IntArray();
+		}
+		calls.push(p); // save current index
+		seek(index);
+	}
+
+	/** Seek back to previous index saved during last push() call.
+	 *  Return top of stack (return index).
+	 */
+	public int pop() {
+		int ret = calls.pop();
+		seek(ret);
+		return ret;
+	}
+
+	public void reset() {
+		p = 0;
+		lastMarker = 0;
+        if (calls != null) {
+            calls.clear();
+        }
+    }
+
+	public int size() {
+		if ( p==-1 ) {
+			fillBuffer();
+		}
+		return nodes.size();
+	}
+
+	public Iterator iterator() {
+		if ( p==-1 ) {
+			fillBuffer();
+		}
+		return new StreamIterator();
+	}
+
+	// TREE REWRITE INTERFACE
+
+	public void replaceChildren(Object parent, int startChildIndex, int stopChildIndex, Object t) {
+		if ( parent!=null ) {
+			adaptor.replaceChildren(parent, startChildIndex, stopChildIndex, t);
+		}
+	}
+
+	/** Used for testing, just return the token type stream */
+	public String toTokenTypeString() {
+		if ( p==-1 ) {
+			fillBuffer();
+		}
+		StringBuffer buf = new StringBuffer();
+		for (int i = 0; i < nodes.size(); i++) {
+			Object t = (Object) nodes.get(i);
+			buf.append(" ");
+			buf.append(adaptor.getType(t));
+		}
+		return buf.toString();
+	}
+
+	/** Debugging */
+	public String toTokenString(int start, int stop) {
+		if ( p==-1 ) {
+			fillBuffer();
+		}
+		StringBuffer buf = new StringBuffer();
+		for (int i = start; i < nodes.size() && i <= stop; i++) {
+			Object t = (Object) nodes.get(i);
+			buf.append(" ");
+			buf.append(adaptor.getToken(t));
+		}
+		return buf.toString();
+	}
+
+	public String toString(Object start, Object stop) {
+		System.out.println("toString");
+		if ( start==null || stop==null ) {
+			return null;
+		}
+		if ( p==-1 ) {
+			fillBuffer();
+		}
+		//System.out.println("stop: "+stop);
+		if ( start instanceof CommonTree )
+			System.out.print("toString: "+((CommonTree)start).getToken()+", ");
+		else
+			System.out.println(start);
+		if ( stop instanceof CommonTree )
+			System.out.println(((CommonTree)stop).getToken());
+		else
+			System.out.println(stop);
+		// if we have the token stream, use that to dump text in order
+		if ( tokens!=null ) {
+			int beginTokenIndex = adaptor.getTokenStartIndex(start);
+			int endTokenIndex = adaptor.getTokenStopIndex(stop);
+			// if it's a tree, use start/stop index from start node
+			// else use token range from start/stop nodes
+			if ( adaptor.getType(stop)==Token.UP ) {
+				endTokenIndex = adaptor.getTokenStopIndex(start);
+			}
+			else if ( adaptor.getType(stop)==Token.EOF ) {
+				endTokenIndex = size()-2; // don't use EOF
+			}
+			return tokens.toString(beginTokenIndex, endTokenIndex);
+		}
+		// walk nodes looking for start
+		Object t = null;
+		int i = 0;
+		for (; i < nodes.size(); i++) {
+			t = nodes.get(i);
+			if ( t==start ) {
+				break;
+			}
+		}
+		// now walk until we see stop, filling string buffer with text
+		 StringBuffer buf = new StringBuffer();
+		t = nodes.get(i);
+		while ( t!=stop ) {
+			String text = adaptor.getText(t);
+			if ( text==null ) {
+				text = " "+String.valueOf(adaptor.getType(t));
+			}
+			buf.append(text);
+			i++;
+			t = nodes.get(i);
+		}
+		// include stop node too
+		String text = adaptor.getText(stop);
+		if ( text==null ) {
+			text = " "+String.valueOf(adaptor.getType(stop));
+		}
+		buf.append(text);
+		return buf.toString();
+	}
+}
diff --git a/src/org/antlr/runtime/tree/CommonErrorNode.java b/src/org/antlr/runtime/tree/CommonErrorNode.java
new file mode 100755
index 0000000..26b9933
--- /dev/null
+++ b/src/org/antlr/runtime/tree/CommonErrorNode.java
@@ -0,0 +1,108 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime.tree;
+
+import org.antlr.runtime.*;
+
+/** A node representing erroneous token range in token stream */
+public class CommonErrorNode extends CommonTree {
+	public IntStream input;
+	public Token start;
+	public Token stop;
+	public RecognitionException trappedException;
+
+	public CommonErrorNode(TokenStream input, Token start, Token stop,
+						   RecognitionException e)
+	{
+		//System.out.println("start: "+start+", stop: "+stop);
+		if ( stop==null ||
+			 (stop.getTokenIndex() < start.getTokenIndex() &&
+			  stop.getType()!=Token.EOF) )
+		{
+			// sometimes resync does not consume a token (when LT(1) is
+			// in follow set.  So, stop will be 1 to left to start. adjust.
+			// Also handle case where start is the first token and no token
+			// is consumed during recovery; LT(-1) will return null.
+			stop = start;
+		}
+		this.input = input;
+		this.start = start;
+		this.stop = stop;
+		this.trappedException = e;
+	}
+
+	public boolean isNil() {
+		return false;
+	}
+
+	public int getType() {
+		return Token.INVALID_TOKEN_TYPE;
+	}
+
+	public String getText() {
+		String badText = null;
+		if ( start instanceof Token ) {
+			int i = ((Token)start).getTokenIndex();
+			int j = ((Token)stop).getTokenIndex();
+			if ( ((Token)stop).getType() == Token.EOF ) {
+				j = ((TokenStream)input).size();
+			}
+			badText = ((TokenStream)input).toString(i, j);
+		}
+		else if ( start instanceof Tree ) {
+			badText = ((TreeNodeStream)input).toString(start, stop);
+		}
+		else {
+			// people should subclass if they alter the tree type so this
+			// next one is for sure correct.
+			badText = "<unknown>";
+		}
+		return badText;
+	}
+
+	public String toString() {
+		if ( trappedException instanceof MissingTokenException ) {
+			return "<missing type: "+
+				   ((MissingTokenException)trappedException).getMissingType()+
+				   ">";
+		}
+		else if ( trappedException instanceof UnwantedTokenException ) {
+			return "<extraneous: "+
+				   ((UnwantedTokenException)trappedException).getUnexpectedToken()+
+				   ", resync="+getText()+">";
+		}
+		else if ( trappedException instanceof MismatchedTokenException ) {
+			return "<mismatched token: "+trappedException.token+", resync="+getText()+">";
+		}
+		else if ( trappedException instanceof NoViableAltException ) {
+			return "<unexpected: "+trappedException.token+
+				   ", resync="+getText()+">";
+		}
+		return "<error: "+getText()+">";
+	}
+}
diff --git a/src/org/antlr/runtime/tree/CommonTree.java b/src/org/antlr/runtime/tree/CommonTree.java
new file mode 100755
index 0000000..91c59de
--- /dev/null
+++ b/src/org/antlr/runtime/tree/CommonTree.java
@@ -0,0 +1,185 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime.tree;
+
+import org.antlr.runtime.Token;
+
+/** A tree node that is wrapper for a Token object.  After 3.0 release
+ *  while building tree rewrite stuff, it became clear that computing
+ *  parent and child index is very difficult and cumbersome.  Better to
+ *  spend the space in every tree node.  If you don't want these extra
+ *  fields, it's easy to cut them out in your own BaseTree subclass.
+ */
+public class CommonTree extends BaseTree {
+	/** A single token is the payload */
+	public Token token;
+
+	/** What token indexes bracket all tokens associated with this node
+	 *  and below?
+	 */
+	protected int startIndex=-1, stopIndex=-1;
+
+	/** Who is the parent node of this node; if null, implies node is root */
+	public CommonTree parent;
+
+	/** What index is this node in the child list? Range: 0..n-1 */
+	public int childIndex = -1;
+
+	public CommonTree() { }
+	
+	public CommonTree(CommonTree node) {
+		super(node);
+		this.token = node.token;
+		this.startIndex = node.startIndex;
+		this.stopIndex = node.stopIndex;
+	}
+
+	public CommonTree(Token t) {
+		this.token = t;
+	}
+
+	public Token getToken() {
+		return token;
+	}
+
+	public Tree dupNode() {
+		return new CommonTree(this);
+	}
+
+	public boolean isNil() {
+		return token==null;
+	}
+
+	public int getType() {
+		if ( token==null ) {
+			return Token.INVALID_TOKEN_TYPE;
+		}
+		return token.getType();
+	}
+
+	public String getText() {
+		if ( token==null ) {
+			return null;
+		}
+		return token.getText();
+	}
+
+	public int getLine() {
+		if ( token==null || token.getLine()==0 ) {
+			if ( getChildCount()>0 ) {
+				return getChild(0).getLine();
+			}
+			return 0;
+		}
+		return token.getLine();
+	}
+
+	public int getCharPositionInLine() {
+		if ( token==null || token.getCharPositionInLine()==-1 ) {
+			if ( getChildCount()>0 ) {
+				return getChild(0).getCharPositionInLine();
+			}
+			return 0;
+		}
+		return token.getCharPositionInLine();
+	}
+
+	public int getTokenStartIndex() {
+		if ( startIndex==-1 && token!=null ) {
+			return token.getTokenIndex();
+		}
+		return startIndex;
+	}
+
+	public void setTokenStartIndex(int index) {
+		startIndex = index;
+	}
+
+	public int getTokenStopIndex() {
+		if ( stopIndex==-1 && token!=null ) {
+			return token.getTokenIndex();
+		}
+		return stopIndex;
+	}
+
+	public void setTokenStopIndex(int index) {
+		stopIndex = index;
+	}
+
+    /** For every node in this subtree, make sure it's start/stop token's
+     *  are set.  Walk depth first, visit bottom up.  Only updates nodes
+     *  with at least one token index < 0.
+     */
+    public void setUnknownTokenBoundaries() {
+        if ( children==null ) {
+            if ( startIndex<0 || stopIndex<0 ) {
+                startIndex = stopIndex = token.getTokenIndex();
+            }
+            return;
+        }
+        for (int i=0; i<children.size(); i++) {
+            ((CommonTree)children.get(i)).setUnknownTokenBoundaries();
+        }
+        if ( startIndex>=0 && stopIndex>=0 ) return; // already set
+        if ( children.size() > 0 ) {
+            CommonTree firstChild = (CommonTree)children.get(0);
+            CommonTree lastChild = (CommonTree)children.get(children.size()-1);
+            startIndex = firstChild.getTokenStartIndex();
+            stopIndex = lastChild.getTokenStopIndex();
+        }
+    }
+
+	public int getChildIndex() {
+		return childIndex;
+	}
+
+	public Tree getParent() {
+		return parent;
+	}
+
+	public void setParent(Tree t) {
+		this.parent = (CommonTree)t;
+	}
+
+	public void setChildIndex(int index) {
+		this.childIndex = index;
+	}
+
+	public String toString() {
+		if ( isNil() ) {
+			return "nil";
+		}
+		if ( getType()==Token.INVALID_TOKEN_TYPE ) {
+			return "<errornode>";
+		}
+		if ( token==null ) {
+			return null;
+		}
+		return token.getText();
+	}
+}
diff --git a/src/org/antlr/runtime/tree/CommonTreeAdaptor.java b/src/org/antlr/runtime/tree/CommonTreeAdaptor.java
new file mode 100755
index 0000000..ebf560b
--- /dev/null
+++ b/src/org/antlr/runtime/tree/CommonTreeAdaptor.java
@@ -0,0 +1,168 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime.tree;
+
+import org.antlr.runtime.CommonToken;
+import org.antlr.runtime.Token;
+
+/** A TreeAdaptor that works with any Tree implementation.  It provides
+ *  really just factory methods; all the work is done by BaseTreeAdaptor.
+ *  If you would like to have different tokens created than ClassicToken
+ *  objects, you need to override this and then set the parser tree adaptor to
+ *  use your subclass.
+ *
+ *  To get your parser to build nodes of a different type, override
+ *  create(Token), errorNode(), and to be safe, YourTreeClass.dupNode().
+ *  dupNode is called to duplicate nodes during rewrite operations.
+ */
+public class CommonTreeAdaptor extends BaseTreeAdaptor {
+	/** Duplicate a node.  This is part of the factory;
+	 *	override if you want another kind of node to be built.
+	 *
+	 *  I could use reflection to prevent having to override this
+	 *  but reflection is slow.
+	 */
+	public Object dupNode(Object t) {
+		if ( t==null ) return null;
+		return ((Tree)t).dupNode();
+	}
+
+	public Object create(Token payload) {
+		return new CommonTree(payload);
+	}
+
+	/** Tell me how to create a token for use with imaginary token nodes.
+	 *  For example, there is probably no input symbol associated with imaginary
+	 *  token DECL, but you need to create it as a payload or whatever for
+	 *  the DECL node as in ^(DECL type ID).
+	 *
+	 *  If you care what the token payload objects' type is, you should
+	 *  override this method and any other createToken variant.
+	 */
+	public Token createToken(int tokenType, String text) {
+		return new CommonToken(tokenType, text);
+	}
+
+	/** Tell me how to create a token for use with imaginary token nodes.
+	 *  For example, there is probably no input symbol associated with imaginary
+	 *  token DECL, but you need to create it as a payload or whatever for
+	 *  the DECL node as in ^(DECL type ID).
+	 *
+	 *  This is a variant of createToken where the new token is derived from
+	 *  an actual real input token.  Typically this is for converting '{'
+	 *  tokens to BLOCK etc...  You'll see
+	 *
+	 *    r : lc='{' ID+ '}' -> ^(BLOCK[$lc] ID+) ;
+	 *
+	 *  If you care what the token payload objects' type is, you should
+	 *  override this method and any other createToken variant.
+	 */
+	public Token createToken(Token fromToken) {
+		return new CommonToken(fromToken);
+	}
+
+	/** Track start/stop token for subtree root created for a rule.
+	 *  Only works with Tree nodes.  For rules that match nothing,
+	 *  seems like this will yield start=i and stop=i-1 in a nil node.
+	 *  Might be useful info so I'll not force to be i..i.
+	 */
+	public void setTokenBoundaries(Object t, Token startToken, Token stopToken) {
+		if ( t==null ) return;
+		int start = 0;
+		int stop = 0;
+		if ( startToken!=null ) start = startToken.getTokenIndex();
+		if ( stopToken!=null ) stop = stopToken.getTokenIndex();
+		((Tree)t).setTokenStartIndex(start);
+		((Tree)t).setTokenStopIndex(stop);
+	}
+
+	public int getTokenStartIndex(Object t) {
+		if ( t==null ) return -1;
+		return ((Tree)t).getTokenStartIndex();
+	}
+
+	public int getTokenStopIndex(Object t) {
+		if ( t==null ) return -1;
+		return ((Tree)t).getTokenStopIndex();
+	}
+
+	public String getText(Object t) {
+		if ( t==null ) return null;
+		return ((Tree)t).getText();
+	}
+
+    public int getType(Object t) {
+		if ( t==null ) return Token.INVALID_TOKEN_TYPE;
+		return ((Tree)t).getType();
+	}
+
+	/** What is the Token associated with this node?  If
+	 *  you are not using CommonTree, then you must
+	 *  override this in your own adaptor.
+	 */
+	public Token getToken(Object t) {
+		if ( t instanceof CommonTree ) {
+			return ((CommonTree)t).getToken();
+		}
+		return null; // no idea what to do
+	}
+
+	public Object getChild(Object t, int i) {
+		if ( t==null ) return null;
+        return ((Tree)t).getChild(i);
+    }
+
+    public int getChildCount(Object t) {
+		if ( t==null ) return 0;
+        return ((Tree)t).getChildCount();
+    }
+
+	public Object getParent(Object t) {
+		if ( t==null ) return null;
+        return ((Tree)t).getParent();
+	}
+
+	public void setParent(Object t, Object parent) {
+        if ( t!=null ) ((Tree)t).setParent((Tree)parent);
+	}
+
+	public int getChildIndex(Object t) {
+        if ( t==null ) return 0;
+		return ((Tree)t).getChildIndex();
+	}
+
+	public void setChildIndex(Object t, int index) {
+        if ( t!=null ) ((Tree)t).setChildIndex(index);
+	}
+
+	public void replaceChildren(Object parent, int startChildIndex, int stopChildIndex, Object t) {
+		if ( parent!=null ) {
+			((Tree)parent).replaceChildren(startChildIndex, stopChildIndex, t);
+		}
+	}
+}
diff --git a/src/org/antlr/runtime/tree/CommonTreeNodeStream.java b/src/org/antlr/runtime/tree/CommonTreeNodeStream.java
new file mode 100755
index 0000000..05dbbdd
--- /dev/null
+++ b/src/org/antlr/runtime/tree/CommonTreeNodeStream.java
@@ -0,0 +1,171 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime.tree;
+
+import org.antlr.runtime.Token;
+import org.antlr.runtime.TokenStream;
+import org.antlr.runtime.misc.LookaheadStream;
+import org.antlr.runtime.misc.IntArray;
+
+import java.util.*;
+
+public class CommonTreeNodeStream extends LookaheadStream<Object> implements TreeNodeStream {
+	public static final int DEFAULT_INITIAL_BUFFER_SIZE = 100;
+	public static final int INITIAL_CALL_STACK_SIZE = 10;
+
+	/** Pull nodes from which tree? */
+	protected Object root;
+
+	/** If this tree (root) was created from a token stream, track it. */
+	protected TokenStream tokens;
+
+	/** What tree adaptor was used to build these trees */
+	TreeAdaptor adaptor;
+
+    /** The tree iterator we using */
+    protected TreeIterator it;
+
+    /** Stack of indexes used for push/pop calls */
+    protected IntArray calls;    
+
+    /** Tree (nil A B C) trees like flat A B C streams */
+    protected boolean hasNilRoot = false;
+
+    /** Tracks tree depth.  Level=0 means we're at root node level. */
+    protected int level = 0;
+
+	public CommonTreeNodeStream(Object tree) {
+		this(new CommonTreeAdaptor(), tree);
+	}
+
+	public CommonTreeNodeStream(TreeAdaptor adaptor, Object tree) {
+		this.root = tree;
+		this.adaptor = adaptor;
+        it = new TreeIterator(adaptor,root);
+	}
+
+    public void reset() {
+        super.reset();
+        it.reset();
+        hasNilRoot = false;
+        level = 0;
+        if ( calls != null ) calls.clear();
+    }
+    
+    /** Pull elements from tree iterator.  Track tree level 0..max_level.
+     *  If nil rooted tree, don't give initial nil and DOWN nor final UP.
+     */
+    public Object nextElement() {
+        Object t = it.next();
+        //System.out.println("pulled "+adaptor.getType(t));
+        if ( t == it.up ) {
+            level--;
+            if ( level==0 && hasNilRoot ) return it.next(); // don't give last UP; get EOF
+        }
+        else if ( t == it.down ) level++;
+        if ( level==0 && adaptor.isNil(t) ) { // if nil root, scarf nil, DOWN
+            hasNilRoot = true;
+            t = it.next(); // t is now DOWN, so get first real node next
+            level++;
+            t = it.next();
+        }
+        return t;
+    }
+
+    public boolean isEOF(Object o) { return adaptor.getType(o) == Token.EOF; }
+
+    public void setUniqueNavigationNodes(boolean uniqueNavigationNodes) { }
+
+	public Object getTreeSource() {	return root; }
+
+	public String getSourceName() { return getTokenStream().getSourceName(); }
+
+	public TokenStream getTokenStream() { return tokens; }
+
+	public void setTokenStream(TokenStream tokens) { this.tokens = tokens; }
+
+	public TreeAdaptor getTreeAdaptor() { return adaptor; }
+
+	public void setTreeAdaptor(TreeAdaptor adaptor) { this.adaptor = adaptor; }
+
+    public Object get(int i) {
+        throw new UnsupportedOperationException("Absolute node indexes are meaningless in an unbuffered stream");
+    }
+
+    public int LA(int i) { return adaptor.getType(LT(i)); }
+
+    /** Make stream jump to a new location, saving old location.
+     *  Switch back with pop().
+     */
+    public void push(int index) {
+        if ( calls==null ) {
+            calls = new IntArray();
+        }
+        calls.push(p); // save current index
+        seek(index);
+    }
+
+    /** Seek back to previous index saved during last push() call.
+     *  Return top of stack (return index).
+     */
+    public int pop() {
+        int ret = calls.pop();
+        seek(ret);
+        return ret;
+    }    
+
+	// TREE REWRITE INTERFACE
+
+	public void replaceChildren(Object parent, int startChildIndex, int stopChildIndex, Object t) {
+		if ( parent!=null ) {
+			adaptor.replaceChildren(parent, startChildIndex, stopChildIndex, t);
+		}
+	}
+
+	public String toString(Object start, Object stop) {
+        // we'll have to walk from start to stop in tree; we're not keeping
+        // a complete node stream buffer
+        return "n/a";
+	}
+
+    /** For debugging; destructive: moves tree iterator to end. */
+    public String toTokenTypeString() {
+        reset();
+		StringBuffer buf = new StringBuffer();
+        Object o = LT(1);
+        int type = adaptor.getType(o);
+        while ( type!=Token.EOF ) {
+            buf.append(" ");
+            buf.append(type);
+            consume();
+            o = LT(1);
+            type = adaptor.getType(o);
+		}
+		return buf.toString();
+    }
+}
diff --git a/src/org/antlr/runtime/tree/ParseTree.java b/src/org/antlr/runtime/tree/ParseTree.java
new file mode 100755
index 0000000..5811c55
--- /dev/null
+++ b/src/org/antlr/runtime/tree/ParseTree.java
@@ -0,0 +1,119 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime.tree;
+
+import org.antlr.runtime.Token;
+
+import java.util.List;
+
+/** A record of the rules used to match a token sequence.  The tokens
+ *  end up as the leaves of this tree and rule nodes are the interior nodes.
+ *  This really adds no functionality, it is just an alias for CommonTree
+ *  that is more meaningful (specific) and holds a String to display for a node.
+ */
+public class ParseTree extends BaseTree {
+	public Object payload;
+	public List hiddenTokens;
+
+	public ParseTree(Object label) {
+		this.payload = label;
+	}
+
+	public Tree dupNode() {
+		return null;
+	}
+
+	public int getType() {
+		return 0;
+	}
+
+	public String getText() {
+		return toString();
+	}
+
+	public int getTokenStartIndex() {
+		return 0;
+	}
+
+	public void setTokenStartIndex(int index) {
+	}
+
+	public int getTokenStopIndex() {
+		return 0;
+	}
+
+	public void setTokenStopIndex(int index) {
+	}
+
+	public String toString() {
+		if ( payload instanceof Token ) {
+			Token t = (Token)payload;
+			if ( t.getType() == Token.EOF ) {
+				return "<EOF>";
+			}
+			return t.getText();
+		}
+		return payload.toString();
+	}
+
+	/** Emit a token and all hidden nodes before.  EOF node holds all
+	 *  hidden tokens after last real token.
+	 */
+	public String toStringWithHiddenTokens() {
+		StringBuffer buf = new StringBuffer();
+		if ( hiddenTokens!=null ) {
+			for (int i = 0; i < hiddenTokens.size(); i++) {
+				Token hidden = (Token) hiddenTokens.get(i);
+				buf.append(hidden.getText());
+			}
+		}
+		String nodeText = this.toString();
+		if ( !nodeText.equals("<EOF>") ) buf.append(nodeText);
+		return buf.toString();
+	}
+
+	/** Print out the leaves of this tree, which means printing original
+	 *  input back out.
+	 */
+	public String toInputString() {
+		StringBuffer buf = new StringBuffer();
+		_toStringLeaves(buf);
+		return buf.toString();
+	}
+
+	public void _toStringLeaves(StringBuffer buf) {
+		if ( payload instanceof Token ) { // leaf node token?
+			buf.append(this.toStringWithHiddenTokens());
+			return;
+		}
+		for (int i = 0; children!=null && i < children.size(); i++) {
+			ParseTree t = (ParseTree)children.get(i);
+			t._toStringLeaves(buf);
+		}
+	}
+}
diff --git a/src/org/antlr/runtime/tree/RewriteCardinalityException.java b/src/org/antlr/runtime/tree/RewriteCardinalityException.java
new file mode 100755
index 0000000..7f909cd
--- /dev/null
+++ b/src/org/antlr/runtime/tree/RewriteCardinalityException.java
@@ -0,0 +1,47 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime.tree;
+
+/** Base class for all exceptions thrown during AST rewrite construction.
+ *  This signifies a case where the cardinality of two or more elements
+ *  in a subrule are different: (ID INT)+ where |ID|!=|INT|
+ */
+public class RewriteCardinalityException extends RuntimeException {
+	public String elementDescription;
+
+	public RewriteCardinalityException(String elementDescription) {
+		this.elementDescription = elementDescription;
+	}
+
+	public String getMessage() {
+		if ( elementDescription!=null ) {
+			return elementDescription;
+		}
+		return null;
+	}
+}
diff --git a/src/org/antlr/runtime/tree/RewriteEarlyExitException.java b/src/org/antlr/runtime/tree/RewriteEarlyExitException.java
new file mode 100755
index 0000000..9dbcc76
--- /dev/null
+++ b/src/org/antlr/runtime/tree/RewriteEarlyExitException.java
@@ -0,0 +1,39 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime.tree;
+
+/** No elements within a (...)+ in a rewrite rule */
+public class RewriteEarlyExitException extends RewriteCardinalityException {
+	public RewriteEarlyExitException() {
+		super(null);
+	}
+	public RewriteEarlyExitException(String elementDescription) {
+		super(elementDescription);
+	}
+
+}
diff --git a/src/org/antlr/runtime/tree/RewriteEmptyStreamException.java b/src/org/antlr/runtime/tree/RewriteEmptyStreamException.java
new file mode 100755
index 0000000..8f3a3fc
--- /dev/null
+++ b/src/org/antlr/runtime/tree/RewriteEmptyStreamException.java
@@ -0,0 +1,35 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime.tree;
+
+/** Ref to ID or expr but no tokens in ID stream or subtrees in expr stream */
+public class RewriteEmptyStreamException extends RewriteCardinalityException {
+	public RewriteEmptyStreamException(String elementDescription) {
+		super(elementDescription);
+	}
+}
diff --git a/src/org/antlr/runtime/tree/RewriteRuleElementStream.java b/src/org/antlr/runtime/tree/RewriteRuleElementStream.java
new file mode 100755
index 0000000..61f1860
--- /dev/null
+++ b/src/org/antlr/runtime/tree/RewriteRuleElementStream.java
@@ -0,0 +1,210 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime.tree;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/** A generic list of elements tracked in an alternative to be used in
+ *  a -> rewrite rule.  We need to subclass to fill in the next() method,
+ *  which returns either an AST node wrapped around a token payload or
+ *  an existing subtree.
+ *
+ *  Once you start next()ing, do not try to add more elements.  It will
+ *  break the cursor tracking I believe.
+ *
+ *  @see org.antlr.runtime.tree.RewriteRuleSubtreeStream
+ *  @see org.antlr.runtime.tree.RewriteRuleTokenStream
+ *
+ *  TODO: add mechanism to detect/puke on modification after reading from stream
+ */
+public abstract class RewriteRuleElementStream {
+	/** Cursor 0..n-1.  If singleElement!=null, cursor is 0 until you next(),
+	 *  which bumps it to 1 meaning no more elements.
+	 */
+	protected int cursor = 0;
+
+	/** Track single elements w/o creating a list.  Upon 2nd add, alloc list */
+	protected Object singleElement;
+
+	/** The list of tokens or subtrees we are tracking */
+	protected List elements;
+
+	/** Once a node / subtree has been used in a stream, it must be dup'd
+	 *  from then on.  Streams are reset after subrules so that the streams
+	 *  can be reused in future subrules.  So, reset must set a dirty bit.
+	 *  If dirty, then next() always returns a dup.
+	 *
+	 *  I wanted to use "naughty bit" here, but couldn't think of a way
+	 *  to use "naughty".
+	 *
+	 *  TODO: unused?
+	 */
+	protected boolean dirty = false;
+
+	/** The element or stream description; usually has name of the token or
+	 *  rule reference that this list tracks.  Can include rulename too, but
+	 *  the exception would track that info.
+	 */
+	protected String elementDescription;
+	protected TreeAdaptor adaptor;
+
+	public RewriteRuleElementStream(TreeAdaptor adaptor, String elementDescription) {
+		this.elementDescription = elementDescription;
+		this.adaptor = adaptor;
+	}
+
+	/** Create a stream with one element */
+	public RewriteRuleElementStream(TreeAdaptor adaptor,
+									String elementDescription,
+									Object oneElement)
+	{
+		this(adaptor, elementDescription);
+		add(oneElement);
+	}
+
+	/** Create a stream, but feed off an existing list */
+	public RewriteRuleElementStream(TreeAdaptor adaptor,
+									String elementDescription,
+									List elements)
+	{
+		this(adaptor, elementDescription);
+		this.singleElement = null;
+		this.elements = elements;
+	}
+
+	/** Reset the condition of this stream so that it appears we have
+	 *  not consumed any of its elements.  Elements themselves are untouched.
+	 *  Once we reset the stream, any future use will need duplicates.  Set
+	 *  the dirty bit.
+	 */
+	public void reset() {
+		cursor = 0;
+		dirty = true;
+	}
+
+	public void add(Object el) {
+		//System.out.println("add '"+elementDescription+"' is "+el);
+		if ( el==null ) {
+			return;
+		}
+		if ( elements!=null ) { // if in list, just add
+			elements.add(el);
+			return;
+		}
+		if ( singleElement == null ) { // no elements yet, track w/o list
+			singleElement = el;
+			return;
+		}
+		// adding 2nd element, move to list
+		elements = new ArrayList(5);
+		elements.add(singleElement);
+		singleElement = null;
+		elements.add(el);
+	}
+
+	/** Return the next element in the stream.  If out of elements, throw
+	 *  an exception unless size()==1.  If size is 1, then return elements[0].
+	 *  Return a duplicate node/subtree if stream is out of elements and
+	 *  size==1.  If we've already used the element, dup (dirty bit set).
+	 */
+	public Object nextTree() {
+		int n = size();
+		if ( dirty || (cursor>=n && n==1) ) {
+			// if out of elements and size is 1, dup
+			Object el = _next();
+			return dup(el);
+		}
+		// test size above then fetch
+		Object el = _next();
+		return el;
+	}
+
+	/** do the work of getting the next element, making sure that it's
+	 *  a tree node or subtree.  Deal with the optimization of single-
+	 *  element list versus list of size > 1.  Throw an exception
+	 *  if the stream is empty or we're out of elements and size>1.
+	 *  protected so you can override in a subclass if necessary.
+	 */
+	protected Object _next() {
+		int n = size();
+		if ( n ==0 ) {
+			throw new RewriteEmptyStreamException(elementDescription);
+		}
+		if ( cursor>= n) { // out of elements?
+			if ( n ==1 ) {  // if size is 1, it's ok; return and we'll dup
+				return toTree(singleElement);
+			}
+			// out of elements and size was not 1, so we can't dup
+			throw new RewriteCardinalityException(elementDescription);
+		}
+		// we have elements
+		if ( singleElement!=null ) {
+			cursor++; // move cursor even for single element list
+			return toTree(singleElement);
+		}
+		// must have more than one in list, pull from elements
+		Object o = toTree(elements.get(cursor));
+		cursor++;
+		return o;
+	}
+
+	/** When constructing trees, sometimes we need to dup a token or AST
+	 * 	subtree.  Dup'ing a token means just creating another AST node
+	 *  around it.  For trees, you must call the adaptor.dupTree() unless
+	 *  the element is for a tree root; then it must be a node dup.
+	 */
+	protected abstract Object dup(Object el);
+
+	/** Ensure stream emits trees; tokens must be converted to AST nodes.
+	 *  AST nodes can be passed through unmolested.
+	 */
+	protected Object toTree(Object el) {
+		return el;
+	}
+
+	public boolean hasNext() {
+		 return (singleElement != null && cursor < 1) ||
+			   (elements!=null && cursor < elements.size());
+	}
+
+	public int size() {
+		int n = 0;
+		if ( singleElement != null ) {
+			n = 1;
+		}
+		if ( elements!=null ) {
+			return elements.size();
+		}
+		return n;
+	}
+
+	public String getDescription() {
+		return elementDescription;
+	}
+}
diff --git a/src/org/antlr/runtime/tree/RewriteRuleNodeStream.java b/src/org/antlr/runtime/tree/RewriteRuleNodeStream.java
new file mode 100755
index 0000000..713e9ff
--- /dev/null
+++ b/src/org/antlr/runtime/tree/RewriteRuleNodeStream.java
@@ -0,0 +1,70 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime.tree;
+
+import java.util.List;
+
+/** Queues up nodes matched on left side of -> in a tree parser. This is
+ *  the analog of RewriteRuleTokenStream for normal parsers. 
+ */
+public class RewriteRuleNodeStream extends RewriteRuleElementStream {
+
+	public RewriteRuleNodeStream(TreeAdaptor adaptor, String elementDescription) {
+		super(adaptor, elementDescription);
+	}
+
+	/** Create a stream with one element */
+	public RewriteRuleNodeStream(TreeAdaptor adaptor,
+								 String elementDescription,
+								 Object oneElement)
+	{
+		super(adaptor, elementDescription, oneElement);
+	}
+
+	/** Create a stream, but feed off an existing list */
+	public RewriteRuleNodeStream(TreeAdaptor adaptor,
+								 String elementDescription,
+								 List elements)
+	{
+		super(adaptor, elementDescription, elements);
+	}
+
+	public Object nextNode() {
+		return _next();
+	}
+
+	protected Object toTree(Object el) {
+		return adaptor.dupNode(el);
+	}
+
+	protected Object dup(Object el) {
+		// we dup every node, so don't have to worry about calling dup; short-
+		// circuited next() so it doesn't call.
+		throw new UnsupportedOperationException("dup can't be called for a node stream.");
+	}
+}
diff --git a/src/org/antlr/runtime/tree/RewriteRuleSubtreeStream.java b/src/org/antlr/runtime/tree/RewriteRuleSubtreeStream.java
new file mode 100755
index 0000000..5189f21
--- /dev/null
+++ b/src/org/antlr/runtime/tree/RewriteRuleSubtreeStream.java
@@ -0,0 +1,88 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime.tree;
+
+import java.util.List;
+
+public class RewriteRuleSubtreeStream extends RewriteRuleElementStream {
+
+	public RewriteRuleSubtreeStream(TreeAdaptor adaptor, String elementDescription) {
+		super(adaptor, elementDescription);
+	}
+
+	/** Create a stream with one element */
+	public RewriteRuleSubtreeStream(TreeAdaptor adaptor,
+									String elementDescription,
+									Object oneElement)
+	{
+		super(adaptor, elementDescription, oneElement);
+	}
+
+	/** Create a stream, but feed off an existing list */
+	public RewriteRuleSubtreeStream(TreeAdaptor adaptor,
+									String elementDescription,
+									List elements)
+	{
+		super(adaptor, elementDescription, elements);
+	}
+
+	/** Treat next element as a single node even if it's a subtree.
+	 *  This is used instead of next() when the result has to be a
+	 *  tree root node.  Also prevents us from duplicating recently-added
+	 *  children; e.g., ^(type ID)+ adds ID to type and then 2nd iteration
+	 *  must dup the type node, but ID has been added.
+	 *
+	 *  Referencing a rule result twice is ok; dup entire tree as
+	 *  we can't be adding trees as root; e.g., expr expr.
+	 *
+	 *  Hideous code duplication here with super.next().  Can't think of
+	 *  a proper way to refactor.  This needs to always call dup node
+	 *  and super.next() doesn't know which to call: dup node or dup tree.
+	 */
+	public Object nextNode() {
+		//System.out.println("nextNode: elements="+elements+", singleElement="+((Tree)singleElement).toStringTree());
+		int n = size();
+		if ( dirty || (cursor>=n && n==1) ) {
+			// if out of elements and size is 1, dup (at most a single node
+			// since this is for making root nodes).
+			Object el = _next();
+			return adaptor.dupNode(el);
+		}
+		// test size above then fetch
+		Object tree = _next();
+		while (adaptor.isNil(tree) && adaptor.getChildCount(tree) == 1)
+			tree = adaptor.getChild(tree, 0);
+		//System.out.println("_next="+((Tree)tree).toStringTree());
+		Object el = adaptor.dupNode(tree); // dup just the root (want node here)
+		return el;
+	}
+
+	protected Object dup(Object el) {
+		return adaptor.dupTree(el);
+	}
+}
\ No newline at end of file
diff --git a/src/org/antlr/runtime/tree/RewriteRuleTokenStream.java b/src/org/antlr/runtime/tree/RewriteRuleTokenStream.java
new file mode 100755
index 0000000..4cd7b08
--- /dev/null
+++ b/src/org/antlr/runtime/tree/RewriteRuleTokenStream.java
@@ -0,0 +1,76 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime.tree;
+
+import org.antlr.runtime.Token;
+
+import java.util.List;
+
+public class RewriteRuleTokenStream extends RewriteRuleElementStream {
+
+	public RewriteRuleTokenStream(TreeAdaptor adaptor, String elementDescription) {
+		super(adaptor, elementDescription);
+	}
+
+	/** Create a stream with one element */
+	public RewriteRuleTokenStream(TreeAdaptor adaptor,
+								  String elementDescription,
+								  Object oneElement)
+	{
+		super(adaptor, elementDescription, oneElement);
+	}
+
+	/** Create a stream, but feed off an existing list */
+	public RewriteRuleTokenStream(TreeAdaptor adaptor,
+								  String elementDescription,
+								  List elements)
+	{
+		super(adaptor, elementDescription, elements);
+	}
+
+	/** Get next token from stream and make a node for it */
+	public Object nextNode() {
+		Token t = (Token)_next();
+		return adaptor.create(t);
+	}
+
+	public Token nextToken() {
+		return (Token)_next();
+	}
+
+	/** Don't convert to a tree unless they explicitly call nextTree.
+	 *  This way we can do hetero tree nodes in rewrite.
+	 */
+	protected Object toTree(Object el) {
+		return el;
+	}
+
+	protected Object dup(Object el) {
+		throw new UnsupportedOperationException("dup can't be called for a token stream.");
+	}
+}
diff --git a/src/org/antlr/runtime/tree/Tree.java b/src/org/antlr/runtime/tree/Tree.java
new file mode 100755
index 0000000..7875be3
--- /dev/null
+++ b/src/org/antlr/runtime/tree/Tree.java
@@ -0,0 +1,127 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime.tree;
+
+import org.antlr.runtime.Token;
+
+import java.util.List;
+
+/** What does a tree look like?  ANTLR has a number of support classes
+ *  such as CommonTreeNodeStream that work on these kinds of trees.  You
+ *  don't have to make your trees implement this interface, but if you do,
+ *  you'll be able to use more support code.
+ *
+ *  NOTE: When constructing trees, ANTLR can build any kind of tree; it can
+ *  even use Token objects as trees if you add a child list to your tokens.
+ *
+ *  This is a tree node without any payload; just navigation and factory stuff.
+ */
+public interface Tree {
+	public static final Tree INVALID_NODE = new CommonTree(Token.INVALID_TOKEN);
+
+	Tree getChild(int i);
+
+	int getChildCount();
+
+	// Tree tracks parent and child index now > 3.0
+
+	public Tree getParent();
+
+	public void setParent(Tree t);
+
+    /** Is there is a node above with token type ttype? */
+    public boolean hasAncestor(int ttype);
+
+    /** Walk upwards and get first ancestor with this token type. */
+    public Tree getAncestor(int ttype);
+
+    /** Return a list of all ancestors of this node.  The first node of
+     *  list is the root and the last is the parent of this node.
+     */
+    public List getAncestors();
+
+    /** This node is what child index? 0..n-1 */
+	public int getChildIndex();
+
+	public void setChildIndex(int index);
+
+	/** Set the parent and child index values for all children */
+	public void freshenParentAndChildIndexes();
+
+	/** Add t as a child to this node.  If t is null, do nothing.  If t
+	 *  is nil, add all children of t to this' children.
+	 */
+	void addChild(Tree t);
+
+	/** Set ith child (0..n-1) to t; t must be non-null and non-nil node */
+	public void setChild(int i, Tree t);
+
+	public Object deleteChild(int i);
+
+	/** Delete children from start to stop and replace with t even if t is
+	 *  a list (nil-root tree).  num of children can increase or decrease.
+	 *  For huge child lists, inserting children can force walking rest of
+	 *  children to set their childindex; could be slow.
+	 */
+	public void replaceChildren(int startChildIndex, int stopChildIndex, Object t);	
+
+	/** Indicates the node is a nil node but may still have children, meaning
+	 *  the tree is a flat list.
+	 */
+	boolean isNil();
+
+	/**  What is the smallest token index (indexing from 0) for this node
+	 *   and its children?
+	 */
+	int getTokenStartIndex();
+
+	void setTokenStartIndex(int index);
+
+	/**  What is the largest token index (indexing from 0) for this node
+	 *   and its children?
+	 */
+	int getTokenStopIndex();
+
+	void setTokenStopIndex(int index);
+
+	Tree dupNode();
+
+	/** Return a token type; needed for tree parsing */
+	int getType();
+
+	String getText();
+
+	/** In case we don't have a token payload, what is the line for errors? */
+	int getLine();
+
+	int getCharPositionInLine();
+
+	String toStringTree();
+
+	String toString();
+}
diff --git a/src/org/antlr/runtime/tree/TreeAdaptor.java b/src/org/antlr/runtime/tree/TreeAdaptor.java
new file mode 100755
index 0000000..8e889f8
--- /dev/null
+++ b/src/org/antlr/runtime/tree/TreeAdaptor.java
@@ -0,0 +1,263 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime.tree;
+
+import org.antlr.runtime.Token;
+import org.antlr.runtime.TokenStream;
+import org.antlr.runtime.RecognitionException;
+
+/** How to create and navigate trees.  Rather than have a separate factory
+ *  and adaptor, I've merged them.  Makes sense to encapsulate.
+ *
+ *  This takes the place of the tree construction code generated in the
+ *  generated code in 2.x and the ASTFactory.
+ *
+ *  I do not need to know the type of a tree at all so they are all
+ *  generic Objects.  This may increase the amount of typecasting needed. :(
+ */
+public interface TreeAdaptor {
+	// C o n s t r u c t i o n
+
+	/** Create a tree node from Token object; for CommonTree type trees,
+	 *  then the token just becomes the payload.  This is the most
+	 *  common create call.
+	 *
+	 *  Override if you want another kind of node to be built.
+	 */
+	public Object create(Token payload);
+
+	/** Duplicate a single tree node.
+	 *  Override if you want another kind of node to be built.
+	 */
+	public Object dupNode(Object treeNode);
+
+	/** Duplicate tree recursively, using dupNode() for each node */
+	public Object dupTree(Object tree);
+
+	/** Return a nil node (an empty but non-null node) that can hold
+	 *  a list of element as the children.  If you want a flat tree (a list)
+	 *  use "t=adaptor.nil(); t.addChild(x); t.addChild(y);"
+	 */
+	public Object nil();
+
+	/** Return a tree node representing an error.  This node records the
+	 *  tokens consumed during error recovery.  The start token indicates the
+	 *  input symbol at which the error was detected.  The stop token indicates
+	 *  the last symbol consumed during recovery.
+	 *
+	 *  You must specify the input stream so that the erroneous text can
+	 *  be packaged up in the error node.  The exception could be useful
+	 *  to some applications; default implementation stores ptr to it in
+	 *  the CommonErrorNode.
+	 *
+	 *  This only makes sense during token parsing, not tree parsing.
+	 *  Tree parsing should happen only when parsing and tree construction
+	 *  succeed.
+	 */
+	public Object errorNode(TokenStream input, Token start, Token stop, RecognitionException e);
+
+	/** Is tree considered a nil node used to make lists of child nodes? */
+	public boolean isNil(Object tree);
+
+	/** Add a child to the tree t.  If child is a flat tree (a list), make all
+	 *  in list children of t.  Warning: if t has no children, but child does
+	 *  and child isNil then you can decide it is ok to move children to t via
+	 *  t.children = child.children; i.e., without copying the array.  Just
+	 *  make sure that this is consistent with have the user will build
+	 *  ASTs.  Do nothing if t or child is null.
+	 */
+	public void addChild(Object t, Object child);
+
+	/** If oldRoot is a nil root, just copy or move the children to newRoot.
+	 *  If not a nil root, make oldRoot a child of newRoot.
+	 *
+	 *    old=^(nil a b c), new=r yields ^(r a b c)
+	 *    old=^(a b c), new=r yields ^(r ^(a b c))
+	 *
+	 *  If newRoot is a nil-rooted single child tree, use the single
+	 *  child as the new root node.
+	 *
+	 *    old=^(nil a b c), new=^(nil r) yields ^(r a b c)
+	 *    old=^(a b c), new=^(nil r) yields ^(r ^(a b c))
+	 *
+	 *  If oldRoot was null, it's ok, just return newRoot (even if isNil).
+	 *
+	 *    old=null, new=r yields r
+	 *    old=null, new=^(nil r) yields ^(nil r)
+	 *
+	 *  Return newRoot.  Throw an exception if newRoot is not a
+	 *  simple node or nil root with a single child node--it must be a root
+	 *  node.  If newRoot is ^(nil x) return x as newRoot.
+	 *
+	 *  Be advised that it's ok for newRoot to point at oldRoot's
+	 *  children; i.e., you don't have to copy the list.  We are
+	 *  constructing these nodes so we should have this control for
+	 *  efficiency.
+	 */
+	public Object becomeRoot(Object newRoot, Object oldRoot);
+
+	/** Given the root of the subtree created for this rule, post process
+	 *  it to do any simplifications or whatever you want.  A required
+	 *  behavior is to convert ^(nil singleSubtree) to singleSubtree
+	 *  as the setting of start/stop indexes relies on a single non-nil root
+	 *  for non-flat trees.
+	 *
+	 *  Flat trees such as for lists like "idlist : ID+ ;" are left alone
+	 *  unless there is only one ID.  For a list, the start/stop indexes
+	 *  are set in the nil node.
+	 *
+	 *  This method is executed after all rule tree construction and right
+	 *  before setTokenBoundaries().
+	 */
+	public Object rulePostProcessing(Object root);
+
+	/** For identifying trees.
+	 *
+	 *  How to identify nodes so we can say "add node to a prior node"?
+	 *  Even becomeRoot is an issue.  Use System.identityHashCode(node)
+	 *  usually.
+	 */
+	public int getUniqueID(Object node);
+
+
+	// R e w r i t e  R u l e s
+
+	/** Create a node for newRoot make it the root of oldRoot.
+	 *  If oldRoot is a nil root, just copy or move the children to newRoot.
+	 *  If not a nil root, make oldRoot a child of newRoot.
+	 *
+	 *  Return node created for newRoot.
+	 *
+	 *  Be advised: when debugging ASTs, the DebugTreeAdaptor manually
+	 *  calls create(Token child) and then plain becomeRoot(node, node)
+	 *  because it needs to trap calls to create, but it can't since it delegates
+	 *  to not inherits from the TreeAdaptor.
+	 */
+	public Object becomeRoot(Token newRoot, Object oldRoot);
+
+	/** Create a new node derived from a token, with a new token type.
+	 *  This is invoked from an imaginary node ref on right side of a
+	 *  rewrite rule as IMAG[$tokenLabel].
+	 *
+	 *  This should invoke createToken(Token).
+	 */
+	public Object create(int tokenType, Token fromToken);
+
+	/** Same as create(tokenType,fromToken) except set the text too.
+	 *  This is invoked from an imaginary node ref on right side of a
+	 *  rewrite rule as IMAG[$tokenLabel, "IMAG"].
+	 *
+	 *  This should invoke createToken(Token).
+	 */
+	public Object create(int tokenType, Token fromToken, String text);
+
+	/** Create a new node derived from a token, with a new token type.
+	 *  This is invoked from an imaginary node ref on right side of a
+	 *  rewrite rule as IMAG["IMAG"].
+	 *
+	 *  This should invoke createToken(int,String).
+	 */
+	public Object create(int tokenType, String text);
+
+
+	// C o n t e n t
+
+	/** For tree parsing, I need to know the token type of a node */
+	public int getType(Object t);
+
+	/** Node constructors can set the type of a node */
+	public void setType(Object t, int type);
+
+	public String getText(Object t);
+
+	/** Node constructors can set the text of a node */
+	public void setText(Object t, String text);
+
+	/** Return the token object from which this node was created.
+	 *  Currently used only for printing an error message.
+	 *  The error display routine in BaseRecognizer needs to
+	 *  display where the input the error occurred. If your
+	 *  tree of limitation does not store information that can
+	 *  lead you to the token, you can create a token filled with
+	 *  the appropriate information and pass that back.  See
+	 *  BaseRecognizer.getErrorMessage().
+	 */
+	public Token getToken(Object t);
+
+	/** Where are the bounds in the input token stream for this node and
+	 *  all children?  Each rule that creates AST nodes will call this
+	 *  method right before returning.  Flat trees (i.e., lists) will
+	 *  still usually have a nil root node just to hold the children list.
+	 *  That node would contain the start/stop indexes then.
+	 */
+	public void setTokenBoundaries(Object t, Token startToken, Token stopToken);
+
+	/** Get the token start index for this subtree; return -1 if no such index */
+	public int getTokenStartIndex(Object t);
+
+	/** Get the token stop index for this subtree; return -1 if no such index */
+	public int getTokenStopIndex(Object t);
+
+
+	// N a v i g a t i o n  /  T r e e  P a r s i n g
+
+	/** Get a child 0..n-1 node */
+	public Object getChild(Object t, int i);
+
+	/** Set ith child (0..n-1) to t; t must be non-null and non-nil node */
+	public void setChild(Object t, int i, Object child);
+
+	/** Remove ith child and shift children down from right. */
+	public Object deleteChild(Object t, int i);
+
+	/** How many children?  If 0, then this is a leaf node */
+	public int getChildCount(Object t);
+
+	/** Who is the parent node of this node; if null, implies node is root.
+	 *  If your node type doesn't handle this, it's ok but the tree rewrites
+	 *  in tree parsers need this functionality.
+	 */
+	public Object getParent(Object t);
+	public void setParent(Object t, Object parent);
+
+	/** What index is this node in the child list? Range: 0..n-1
+	 *  If your node type doesn't handle this, it's ok but the tree rewrites
+	 *  in tree parsers need this functionality.
+	 */
+	public int getChildIndex(Object t);
+	public void setChildIndex(Object t, int index);
+
+	/** Replace from start to stop child index of parent with t, which might
+	 *  be a list.  Number of children may be different
+	 *  after this call.
+	 *
+	 *  If parent is null, don't do anything; must be at root of overall tree.
+	 *  Can't replace whatever points to the parent externally.  Do nothing.
+	 */
+	public void replaceChildren(Object parent, int startChildIndex, int stopChildIndex, Object t);
+}
diff --git a/src/org/antlr/runtime/tree/TreeFilter.java b/src/org/antlr/runtime/tree/TreeFilter.java
new file mode 100755
index 0000000..b6a7e05
--- /dev/null
+++ b/src/org/antlr/runtime/tree/TreeFilter.java
@@ -0,0 +1,135 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime.tree;
+
+import org.antlr.runtime.RecognizerSharedState;
+import org.antlr.runtime.RecognitionException;
+import org.antlr.runtime.TokenStream;
+
+/**
+ Cut-n-paste from material I'm not using in the book anymore (edit later
+ to make sense):
+
+ Now, how are we going to test these tree patterns against every
+subtree in our original tree?  In what order should we visit nodes?
+For this application, it turns out we need a simple ``apply once''
+rule application strategy and a ``down then up'' tree traversal
+strategy.  Let's look at rule application first.
+
+As we visit each node, we need to see if any of our patterns match. If
+a pattern matches, we execute the associated tree rewrite and move on
+to the next node. In other words, we only look for a single rule
+application opportunity (we'll see below that we sometimes need to
+repeatedly apply rules). The following method applies a rule in a @cl
+TreeParser (derived from a tree grammar) to a tree:
+
+here is where weReferenced code/walking/patterns/TreePatternMatcher.java
+
+It uses reflection to lookup the appropriate rule within the generated
+tree parser class (@cl Simplify in this case). Most of the time, the
+rule will not match the tree.  To avoid issuing syntax errors and
+attempting error recovery, it bumps up the backtracking level.  Upon
+failure, the invoked rule immediately returns. If you don't plan on
+using this technique in your own ANTLR-based application, don't sweat
+the details. This method boils down to ``call a rule to match a tree,
+executing any embedded actions and rewrite rules.''
+
+At this point, we know how to define tree grammar rules and how to
+apply them to a particular subtree. The final piece of the tree
+pattern matcher is the actual tree traversal. We have to get the
+correct node visitation order.  In particular, we need to perform the
+scalar-vector multiply transformation on the way down (preorder) and
+we need to reduce multiply-by-zero subtrees on the way up (postorder).
+
+To implement a top-down visitor, we do a depth first walk of the tree,
+executing an action in the preorder position. To get a bottom-up
+visitor, we execute an action in the postorder position.  ANTLR
+provides a standard @cl TreeVisitor class with a depth first search @v
+visit method. That method executes either a @m pre or @m post method
+or both. In our case, we need to call @m applyOnce in both. On the way
+down, we'll look for @r vmult patterns. On the way up,
+we'll look for @r mult0 patterns.
+ */
+public class TreeFilter extends TreeParser {
+    public interface fptr {
+        public void rule() throws RecognitionException;
+    }
+
+    protected TokenStream originalTokenStream;
+    protected TreeAdaptor originalAdaptor;
+
+    public TreeFilter(TreeNodeStream input) {
+        this(input, new RecognizerSharedState());
+    }
+    public TreeFilter(TreeNodeStream input, RecognizerSharedState state) {
+        super(input, state);
+        originalAdaptor = input.getTreeAdaptor();
+        originalTokenStream = input.getTokenStream();
+    }
+
+    public void applyOnce(Object t, fptr whichRule) {
+        if ( t==null ) return;
+        try {
+            // share TreeParser object but not parsing-related state
+            state = new RecognizerSharedState();
+            input = new CommonTreeNodeStream(originalAdaptor, t);
+            ((CommonTreeNodeStream)input).setTokenStream(originalTokenStream);
+            setBacktrackingLevel(1);
+            whichRule.rule();
+            setBacktrackingLevel(0);
+        }
+        catch (RecognitionException e) { ; }
+    }
+
+    public void downup(Object t) {
+        TreeVisitor v = new TreeVisitor(new CommonTreeAdaptor());
+        TreeVisitorAction actions = new TreeVisitorAction() {
+            public Object pre(Object t)  { applyOnce(t, topdown_fptr); return t; }
+            public Object post(Object t) { applyOnce(t, bottomup_fptr); return t; }
+        };
+        v.visit(t, actions);
+    }
+        
+    fptr topdown_fptr = new fptr() {
+        public void rule() throws RecognitionException {
+            topdown();
+        }
+    };
+
+    fptr bottomup_fptr = new fptr() {
+        public void rule() throws RecognitionException {
+            bottomup();
+        }
+    };
+
+    // methods the downup strategy uses to do the up and down rules.
+    // to override, just define tree grammar rule topdown and turn on
+    // filter=true.
+    public void topdown() throws RecognitionException {;}
+    public void bottomup() throws RecognitionException {;}
+}
diff --git a/src/org/antlr/runtime/tree/TreeIterator.java b/src/org/antlr/runtime/tree/TreeIterator.java
new file mode 100755
index 0000000..43ead6d
--- /dev/null
+++ b/src/org/antlr/runtime/tree/TreeIterator.java
@@ -0,0 +1,132 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime.tree;
+
+import org.antlr.runtime.Token;
+import org.antlr.runtime.CommonToken;
+import org.antlr.runtime.misc.FastQueue;
+
+import java.util.Iterator;
+
+/** Return a node stream from a doubly-linked tree whose nodes
+ *  know what child index they are.  No remove() is supported.
+ *
+ *  Emit navigation nodes (DOWN, UP, and EOF) to let show tree structure.
+ */
+public class TreeIterator implements Iterator {
+    protected TreeAdaptor adaptor;
+    protected Object root;
+    protected Object tree;
+    protected boolean firstTime = true;
+
+    // navigation nodes to return during walk and at end
+    public Object up;
+    public Object down;
+    public Object eof;
+
+    /** If we emit UP/DOWN nodes, we need to spit out multiple nodes per
+     *  next() call.
+     */
+    protected FastQueue nodes;
+
+    public TreeIterator(Object tree) {
+        this(new CommonTreeAdaptor(),tree);
+    }
+
+    public TreeIterator(TreeAdaptor adaptor, Object tree) {
+        this.adaptor = adaptor;
+        this.tree = tree;
+        this.root = tree;
+        nodes = new FastQueue();
+        down = adaptor.create(Token.DOWN, "DOWN");
+        up = adaptor.create(Token.UP, "UP");
+        eof = adaptor.create(Token.EOF, "EOF");
+    }
+
+    public void reset() {
+        firstTime = true;
+        tree = root;
+        nodes.clear();
+    }
+
+    public boolean hasNext() {
+        if ( firstTime ) return root!=null;
+        if ( nodes!=null && nodes.size()>0 ) return true;
+        if ( tree==null ) return false;
+        if ( adaptor.getChildCount(tree)>0 ) return true;
+        return adaptor.getParent(tree)!=null; // back at root?
+    }
+
+    public Object next() {
+        if ( firstTime ) { // initial condition
+            firstTime = false;
+            if ( adaptor.getChildCount(tree)==0 ) { // single node tree (special)
+                nodes.add(eof);
+                return tree;
+            }
+            return tree;
+        }
+        // if any queued up, use those first
+        if ( nodes!=null && nodes.size()>0 ) return nodes.remove();
+
+        // no nodes left?
+        if ( tree==null ) return eof;
+
+        // next node will be child 0 if any children
+        if ( adaptor.getChildCount(tree)>0 ) {
+            tree = adaptor.getChild(tree, 0);
+            nodes.add(tree); // real node is next after DOWN
+            return down;
+        }
+        // if no children, look for next sibling of tree or ancestor
+        Object parent = adaptor.getParent(tree);
+        // while we're out of siblings, keep popping back up towards root
+        while ( parent!=null &&
+                adaptor.getChildIndex(tree)+1 >= adaptor.getChildCount(parent) )
+        {
+            nodes.add(up); // we're moving back up
+            tree = parent;
+            parent = adaptor.getParent(tree);
+        }
+        // no nodes left?
+        if ( parent==null ) {
+            tree = null; // back at root? nothing left then
+            nodes.add(eof); // add to queue, might have UP nodes in there
+            return nodes.remove();
+        }
+
+        // must have found a node with an unvisited sibling
+        // move to it and return it
+        int nextSiblingIndex = adaptor.getChildIndex(tree) + 1;
+        tree = adaptor.getChild(parent, nextSiblingIndex);
+        nodes.add(tree); // add to queue, might have UP nodes in there
+        return nodes.remove();
+    }
+
+    public void remove() { throw new UnsupportedOperationException(); }
+}
diff --git a/src/org/antlr/runtime/tree/TreeNodeStream.java b/src/org/antlr/runtime/tree/TreeNodeStream.java
new file mode 100755
index 0000000..df0ad34
--- /dev/null
+++ b/src/org/antlr/runtime/tree/TreeNodeStream.java
@@ -0,0 +1,106 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime.tree;
+
+import org.antlr.runtime.IntStream;
+import org.antlr.runtime.TokenStream;
+
+/** A stream of tree nodes, accessing nodes from a tree of some kind */
+public interface TreeNodeStream extends IntStream {
+	/** Get a tree node at an absolute index i; 0..n-1.
+	 *  If you don't want to buffer up nodes, then this method makes no
+	 *  sense for you.
+	 */
+	public Object get(int i);
+
+	/** Get tree node at current input pointer + i ahead where i=1 is next node.
+	 *  i<0 indicates nodes in the past.  So LT(-1) is previous node, but
+	 *  implementations are not required to provide results for k < -1.
+	 *  LT(0) is undefined.  For i>=n, return null.
+	 *  Return null for LT(0) and any index that results in an absolute address
+	 *  that is negative.
+	 *
+	 *  This is analogus to the LT() method of the TokenStream, but this
+	 *  returns a tree node instead of a token.  Makes code gen identical
+	 *  for both parser and tree grammars. :)
+	 */
+	public Object LT(int k);
+
+	/** Where is this stream pulling nodes from?  This is not the name, but
+	 *  the object that provides node objects.
+	 */
+	public Object getTreeSource();
+
+	/** If the tree associated with this stream was created from a TokenStream,
+	 *  you can specify it here.  Used to do rule $text attribute in tree
+	 *  parser.  Optional unless you use tree parser rule text attribute
+	 *  or output=template and rewrite=true options.
+	 */
+	public TokenStream getTokenStream();
+
+	/** What adaptor can tell me how to interpret/navigate nodes and
+	 *  trees.  E.g., get text of a node.
+	 */
+	public TreeAdaptor getTreeAdaptor();
+
+	/** As we flatten the tree, we use UP, DOWN nodes to represent
+	 *  the tree structure.  When debugging we need unique nodes
+	 *  so we have to instantiate new ones.  When doing normal tree
+	 *  parsing, it's slow and a waste of memory to create unique
+	 *  navigation nodes.  Default should be false;
+	 */
+	public void setUniqueNavigationNodes(boolean uniqueNavigationNodes);
+
+    /** Reset the tree node stream in such a way that it acts like
+     *  a freshly constructed stream.
+     */
+    public void reset();
+
+	/** Return the text of all nodes from start to stop, inclusive.
+	 *  If the stream does not buffer all the nodes then it can still
+	 *  walk recursively from start until stop.  You can always return
+	 *  null or "" too, but users should not access $ruleLabel.text in
+	 *  an action of course in that case.
+	 */
+	public String toString(Object start, Object stop);
+
+
+	// REWRITING TREES (used by tree parser)
+
+	/** Replace from start to stop child index of parent with t, which might
+	 *  be a list.  Number of children may be different
+	 *  after this call.  The stream is notified because it is walking the
+	 *  tree and might need to know you are monkeying with the underlying
+	 *  tree.  Also, it might be able to modify the node stream to avoid
+	 *  restreaming for future phases.
+	 *
+	 *  If parent is null, don't do anything; must be at root of overall tree.
+	 *  Can't replace whatever points to the parent externally.  Do nothing.
+	 */
+	public void replaceChildren(Object parent, int startChildIndex, int stopChildIndex, Object t);
+}
diff --git a/src/org/antlr/runtime/tree/TreeParser.java b/src/org/antlr/runtime/tree/TreeParser.java
new file mode 100755
index 0000000..e568bc9
--- /dev/null
+++ b/src/org/antlr/runtime/tree/TreeParser.java
@@ -0,0 +1,169 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime.tree;
+
+import org.antlr.runtime.*;
+
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+
+/** A parser for a stream of tree nodes.  "tree grammars" result in a subclass
+ *  of this.  All the error reporting and recovery is shared with Parser via
+ *  the BaseRecognizer superclass.
+*/
+public class TreeParser extends BaseRecognizer {
+	public static final int DOWN = Token.DOWN;
+	public static final int UP = Token.UP;
+
+    // precompiled regex used by inContext
+    static String dotdot = ".*[^.]\\.\\.[^.].*";
+    static String doubleEtc = ".*\\.\\.\\.\\s+\\.\\.\\..*";
+    static Pattern dotdotPattern = Pattern.compile(dotdot);
+    static Pattern doubleEtcPattern = Pattern.compile(doubleEtc);
+
+	protected TreeNodeStream input;
+
+	public TreeParser(TreeNodeStream input) {
+		super(); // highlight that we go to super to set state object
+		setTreeNodeStream(input);
+	}
+
+	public TreeParser(TreeNodeStream input, RecognizerSharedState state) {
+		super(state); // share the state object with another parser
+		setTreeNodeStream(input);
+    }
+
+	public void reset() {
+		super.reset(); // reset all recognizer state variables
+		if ( input!=null ) {
+			input.seek(0); // rewind the input
+		}
+	}
+
+	/** Set the input stream */
+	public void setTreeNodeStream(TreeNodeStream input) {
+		this.input = input;
+	}
+
+	public TreeNodeStream getTreeNodeStream() {
+		return input;
+	}
+
+	public String getSourceName() {
+		return input.getSourceName();
+	}
+
+	protected Object getCurrentInputSymbol(IntStream input) {
+		return ((TreeNodeStream)input).LT(1);
+	}
+
+	protected Object getMissingSymbol(IntStream input,
+									  RecognitionException e,
+									  int expectedTokenType,
+									  BitSet follow)
+	{
+		String tokenText =
+			"<missing "+getTokenNames()[expectedTokenType]+">";
+        TreeAdaptor adaptor = ((TreeNodeStream)e.input).getTreeAdaptor();
+        return adaptor.create(new CommonToken(expectedTokenType, tokenText));
+	}
+
+    /** Match '.' in tree parser has special meaning.  Skip node or
+	 *  entire tree if node has children.  If children, scan until
+	 *  corresponding UP node.
+	 */
+	public void matchAny(IntStream ignore) { // ignore stream, copy of input
+		state.errorRecovery = false;
+		state.failed = false;
+		Object look = input.LT(1);
+		if ( input.getTreeAdaptor().getChildCount(look)==0 ) {
+			input.consume(); // not subtree, consume 1 node and return
+			return;
+		}
+		// current node is a subtree, skip to corresponding UP.
+		// must count nesting level to get right UP
+		int level=0;
+		int tokenType = input.getTreeAdaptor().getType(look);
+		while ( tokenType!=Token.EOF && !(tokenType==UP && level==0) ) {
+			input.consume();
+			look = input.LT(1);
+			tokenType = input.getTreeAdaptor().getType(look);
+			if ( tokenType == DOWN ) {
+				level++;
+			}
+			else if ( tokenType == UP ) {
+				level--;
+			}
+		}
+		input.consume(); // consume UP
+	}
+
+    /** We have DOWN/UP nodes in the stream that have no line info; override.
+	 *  plus we want to alter the exception type.  Don't try to recover
+	 *  from tree parser errors inline...
+     */
+    protected Object recoverFromMismatchedToken(IntStream input,
+                                                int ttype,
+                                                BitSet follow)
+        throws RecognitionException
+    {
+        throw new MismatchedTreeNodeException(ttype, (TreeNodeStream)input);
+    }
+
+    /** Prefix error message with the grammar name because message is
+	 *  always intended for the programmer because the parser built
+	 *  the input tree not the user.
+	 */
+	public String getErrorHeader(RecognitionException e) {
+		return getGrammarFileName()+": node from "+
+			   (e.approximateLineInfo?"after ":"")+"line "+e.line+":"+e.charPositionInLine;
+	}
+
+	/** Tree parsers parse nodes they usually have a token object as
+	 *  payload. Set the exception token and do the default behavior.
+	 */
+	public String getErrorMessage(RecognitionException e, String[] tokenNames) {
+		if ( this instanceof TreeParser ) {
+			TreeAdaptor adaptor = ((TreeNodeStream)e.input).getTreeAdaptor();
+			e.token = adaptor.getToken(e.node);
+			if ( e.token==null ) { // could be an UP/DOWN node
+				e.token = new CommonToken(adaptor.getType(e.node),
+										  adaptor.getText(e.node));
+			}
+		}
+		return super.getErrorMessage(e, tokenNames);
+	}
+
+	public void traceIn(String ruleName, int ruleIndex)  {
+		super.traceIn(ruleName, ruleIndex, input.LT(1));
+	}
+
+	public void traceOut(String ruleName, int ruleIndex)  {
+		super.traceOut(ruleName, ruleIndex, input.LT(1));
+	}
+}
diff --git a/src/org/antlr/runtime/tree/TreePatternLexer.java b/src/org/antlr/runtime/tree/TreePatternLexer.java
new file mode 100755
index 0000000..2677c4e
--- /dev/null
+++ b/src/org/antlr/runtime/tree/TreePatternLexer.java
@@ -0,0 +1,135 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime.tree;
+
+public class TreePatternLexer {
+	public static final int EOF = -1;
+	public static final int BEGIN = 1;
+	public static final int END = 2;
+	public static final int ID = 3;
+	public static final int ARG = 4;
+	public static final int PERCENT = 5;
+	public static final int COLON = 6;
+	public static final int DOT = 7;
+
+	/** The tree pattern to lex like "(A B C)" */
+	protected String pattern;
+
+	/** Index into input string */
+	protected int p = -1;
+
+	/** Current char */
+	protected int c;
+
+	/** How long is the pattern in char? */
+	protected int n;
+
+	/** Set when token type is ID or ARG (name mimics Java's StreamTokenizer) */
+	public StringBuffer sval = new StringBuffer();
+
+	public boolean error = false;
+
+	public TreePatternLexer(String pattern) {
+		this.pattern = pattern;
+		this.n = pattern.length();
+		consume();
+	}
+
+	public int nextToken() {
+		sval.setLength(0); // reset, but reuse buffer
+		while ( c != EOF ) {
+			if ( c==' ' || c=='\n' || c=='\r' || c=='\t' ) {
+				consume();
+				continue;
+			}
+			if ( (c>='a' && c<='z') || (c>='A' && c<='Z') || c=='_' ) {
+				sval.append((char)c);
+				consume();
+				while ( (c>='a' && c<='z') || (c>='A' && c<='Z') ||
+						(c>='0' && c<='9') || c=='_' )
+				{
+					sval.append((char)c);
+					consume();
+				}
+				return ID;
+			}
+			if ( c=='(' ) {
+				consume();
+				return BEGIN;
+			}
+			if ( c==')' ) {
+				consume();
+				return END;
+			}
+			if ( c=='%' ) {
+				consume();
+				return PERCENT;
+			}
+			if ( c==':' ) {
+				consume();
+				return COLON;
+			}
+			if ( c=='.' ) {
+				consume();
+				return DOT;
+			}
+			if ( c=='[' ) { // grab [x] as a string, returning x
+				consume();
+				while ( c!=']' ) {
+					if ( c=='\\' ) {
+						consume();
+						if ( c!=']' ) {
+							sval.append('\\');
+						}
+						sval.append((char)c);
+					}
+					else {
+						sval.append((char)c);
+					}
+					consume();
+				}
+				consume();
+				return ARG;
+			}
+			consume();
+			error = true;
+			return EOF;
+		}
+		return EOF;
+	}
+
+	protected void consume() {
+		p++;
+		if ( p>=n ) {
+			c = EOF;
+		}
+		else {
+			c = pattern.charAt(p);
+		}
+	}
+}
\ No newline at end of file
diff --git a/src/org/antlr/runtime/tree/TreePatternParser.java b/src/org/antlr/runtime/tree/TreePatternParser.java
new file mode 100755
index 0000000..14983ab
--- /dev/null
+++ b/src/org/antlr/runtime/tree/TreePatternParser.java
@@ -0,0 +1,154 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime.tree;
+
+import org.antlr.runtime.Token;
+import org.antlr.runtime.CommonToken;
+
+public class TreePatternParser {
+	protected TreePatternLexer tokenizer;
+	protected int ttype;
+	protected TreeWizard wizard;
+	protected TreeAdaptor adaptor;
+
+	public TreePatternParser(TreePatternLexer tokenizer, TreeWizard wizard, TreeAdaptor adaptor) {
+		this.tokenizer = tokenizer;
+		this.wizard = wizard;
+		this.adaptor = adaptor;
+		ttype = tokenizer.nextToken(); // kickstart
+	}
+
+	public Object pattern() {
+		if ( ttype==TreePatternLexer.BEGIN ) {
+			return parseTree();
+		}
+		else if ( ttype==TreePatternLexer.ID ) {
+			Object node = parseNode();
+			if ( ttype==TreePatternLexer.EOF ) {
+				return node;
+			}
+			return null; // extra junk on end
+		}
+		return null;
+	}
+
+	public Object parseTree() {
+		if ( ttype != TreePatternLexer.BEGIN ) {
+			throw new RuntimeException("no BEGIN");
+		}
+		ttype = tokenizer.nextToken();
+		Object root = parseNode();
+		if ( root==null ) {
+			return null;
+		}
+		while ( ttype==TreePatternLexer.BEGIN ||
+				ttype==TreePatternLexer.ID ||
+				ttype==TreePatternLexer.PERCENT ||
+				ttype==TreePatternLexer.DOT )
+		{
+			if ( ttype==TreePatternLexer.BEGIN ) {
+				Object subtree = parseTree();
+				adaptor.addChild(root, subtree);
+			}
+			else {
+				Object child = parseNode();
+				if ( child==null ) {
+					return null;
+				}
+				adaptor.addChild(root, child);
+			}
+		}
+		if ( ttype != TreePatternLexer.END ) {
+			throw new RuntimeException("no END");
+		}
+		ttype = tokenizer.nextToken();
+		return root;
+	}
+
+	public Object parseNode() {
+		// "%label:" prefix
+		String label = null;
+		if ( ttype == TreePatternLexer.PERCENT ) {
+			ttype = tokenizer.nextToken();
+			if ( ttype != TreePatternLexer.ID ) {
+				return null;
+			}
+			label = tokenizer.sval.toString();
+			ttype = tokenizer.nextToken();
+			if ( ttype != TreePatternLexer.COLON ) {
+				return null;
+			}
+			ttype = tokenizer.nextToken(); // move to ID following colon
+		}
+
+		// Wildcard?
+		if ( ttype == TreePatternLexer.DOT ) {
+			ttype = tokenizer.nextToken();
+			Token wildcardPayload = new CommonToken(0, ".");
+			TreeWizard.TreePattern node =
+				new TreeWizard.WildcardTreePattern(wildcardPayload);
+			if ( label!=null ) {
+				node.label = label;
+			}
+			return node;
+		}
+
+		// "ID" or "ID[arg]"
+		if ( ttype != TreePatternLexer.ID ) {
+			return null;
+		}
+		String tokenName = tokenizer.sval.toString();
+		ttype = tokenizer.nextToken();
+		if ( tokenName.equals("nil") ) {
+			return adaptor.nil();
+		}
+		String text = tokenName;
+		// check for arg
+		String arg = null;
+		if ( ttype == TreePatternLexer.ARG ) {
+			arg = tokenizer.sval.toString();
+			text = arg;
+			ttype = tokenizer.nextToken();
+		}
+		
+		// create node
+		int treeNodeType = wizard.getTokenType(tokenName);
+		if ( treeNodeType==Token.INVALID_TOKEN_TYPE ) {
+			return null;
+		}
+		Object node;
+		node = adaptor.create(treeNodeType, text);
+		if ( label!=null && node.getClass()==TreeWizard.TreePattern.class ) {
+			((TreeWizard.TreePattern)node).label = label;
+		}
+		if ( arg!=null && node.getClass()==TreeWizard.TreePattern.class ) {
+			((TreeWizard.TreePattern)node).hasTextArg = true;
+		}
+		return node;
+	}
+}
diff --git a/src/org/antlr/runtime/tree/TreeRewriter.java b/src/org/antlr/runtime/tree/TreeRewriter.java
new file mode 100755
index 0000000..91aee93
--- /dev/null
+++ b/src/org/antlr/runtime/tree/TreeRewriter.java
@@ -0,0 +1,120 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime.tree;
+
+import org.antlr.runtime.RecognizerSharedState;
+import org.antlr.runtime.RecognitionException;
+import org.antlr.runtime.TokenStream;
+
+public class TreeRewriter extends TreeParser {
+    public interface fptr {
+        public Object rule() throws RecognitionException;
+    }
+
+    protected boolean showTransformations = false;
+
+    protected TokenStream originalTokenStream;
+    protected TreeAdaptor originalAdaptor;
+    
+    public TreeRewriter(TreeNodeStream input) {
+        this(input, new RecognizerSharedState());
+    }
+    public TreeRewriter(TreeNodeStream input, RecognizerSharedState state) {
+        super(input, state);
+        originalAdaptor = input.getTreeAdaptor();
+        originalTokenStream = input.getTokenStream();        
+    }
+
+    public Object applyOnce(Object t, fptr whichRule) {
+        if ( t==null ) return null;
+        try {
+            // share TreeParser object but not parsing-related state
+            state = new RecognizerSharedState();
+            input = new CommonTreeNodeStream(originalAdaptor, t);
+            ((CommonTreeNodeStream)input).setTokenStream(originalTokenStream);
+            setBacktrackingLevel(1);
+            TreeRuleReturnScope r = (TreeRuleReturnScope)whichRule.rule();
+            setBacktrackingLevel(0);
+            if ( failed() ) return t;
+            if ( showTransformations &&
+                 r!=null && !t.equals(r.getTree()) && r.getTree()!=null )
+            {
+                reportTransformation(t, r.getTree());
+            }
+            if ( r!=null && r.getTree()!=null ) return r.getTree();
+            else return t;
+        }
+        catch (RecognitionException e) { ; }
+        return t;
+    }
+
+    public Object applyRepeatedly(Object t, fptr whichRule) {
+        boolean treeChanged = true;
+        while ( treeChanged ) {
+            Object u = applyOnce(t, whichRule);
+            treeChanged = !t.equals(u);
+            t = u;
+        }
+        return t;
+    }
+
+    public Object downup(Object t) { return downup(t, false); }
+
+    public Object downup(Object t, boolean showTransformations) {
+        this.showTransformations = showTransformations;
+        TreeVisitor v = new TreeVisitor(new CommonTreeAdaptor());
+        TreeVisitorAction actions = new TreeVisitorAction() {
+            public Object pre(Object t)  { return applyOnce(t, topdown_fptr); }
+            public Object post(Object t) { return applyRepeatedly(t, bottomup_ftpr); }
+        };
+        t = v.visit(t, actions);
+        return t;
+    }
+
+    /** Override this if you need transformation tracing to go somewhere
+     *  other than stdout or if you're not using Tree-derived trees.
+     */
+    public void reportTransformation(Object oldTree, Object newTree) {
+        System.out.println(((Tree)oldTree).toStringTree()+" -> "+
+                           ((Tree)newTree).toStringTree());
+    }
+
+    fptr topdown_fptr = new fptr() {
+        public Object rule() throws RecognitionException { return topdown(); }
+    };
+    
+    fptr bottomup_ftpr = new fptr() {
+        public Object rule() throws RecognitionException { return bottomup(); }
+    };
+
+    // methods the downup strategy uses to do the up and down rules.
+    // to override, just define tree grammar rule topdown and turn on
+    // filter=true.
+    public Object topdown() throws RecognitionException { return null; }
+    public Object bottomup() throws RecognitionException { return null; }
+}
diff --git a/src/org/antlr/runtime/tree/TreeRuleReturnScope.java b/src/org/antlr/runtime/tree/TreeRuleReturnScope.java
new file mode 100755
index 0000000..4ea65c0
--- /dev/null
+++ b/src/org/antlr/runtime/tree/TreeRuleReturnScope.java
@@ -0,0 +1,41 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime.tree;
+
+import org.antlr.runtime.RuleReturnScope;
+
+/** This is identical to the ParserRuleReturnScope except that
+ *  the start property is a tree nodes not Token object
+ *  when you are parsing trees.  To be generic the tree node types
+ *  have to be Object.
+ */
+public class TreeRuleReturnScope extends RuleReturnScope {
+	/** First node or root node of tree matched for this rule. */
+	public Object start;
+	public Object getStart() { return start; }	
+}
diff --git a/src/org/antlr/runtime/tree/TreeVisitor.java b/src/org/antlr/runtime/tree/TreeVisitor.java
new file mode 100755
index 0000000..8c5a717
--- /dev/null
+++ b/src/org/antlr/runtime/tree/TreeVisitor.java
@@ -0,0 +1,69 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.runtime.tree;
+
+/** Do a depth first walk of a tree, applying pre() and post() actions
+ *  as we discover and finish nodes.
+ */
+public class TreeVisitor {
+    protected TreeAdaptor adaptor;
+    
+    public TreeVisitor(TreeAdaptor adaptor) {
+        this.adaptor = adaptor;
+    }
+    public TreeVisitor() { this(new CommonTreeAdaptor()); }
+    
+    /** Visit every node in tree t and trigger an action for each node
+     *  before/after having visited all of its children.
+     *  Execute both actions even if t has no children.
+     *  If a child visit yields a new child, it can update its
+     *  parent's child list or just return the new child.  The
+     *  child update code works even if the child visit alters its parent
+     *  and returns the new tree.
+     *
+     *  Return result of applying post action to this node.
+     */
+    public Object visit(Object t, TreeVisitorAction action) {
+        // System.out.println("visit "+((Tree)t).toStringTree());
+        boolean isNil = adaptor.isNil(t);
+        if ( action!=null && !isNil ) {
+            t = action.pre(t); // if rewritten, walk children of new t
+        }
+        for (int i=0; i<adaptor.getChildCount(t); i++) {
+            Object child = adaptor.getChild(t, i);
+            Object visitResult = visit(child, action);
+            Object childAfterVisit = adaptor.getChild(t, i);
+            if ( visitResult !=  childAfterVisit ) { // result & child differ?
+                adaptor.setChild(t, i, visitResult);
+            }
+        }
+        if ( action!=null && !isNil ) t = action.post(t);
+        return t;
+    }
+}
diff --git a/src/org/antlr/runtime/tree/TreeVisitorAction.java b/src/org/antlr/runtime/tree/TreeVisitorAction.java
new file mode 100755
index 0000000..ef0f93c
--- /dev/null
+++ b/src/org/antlr/runtime/tree/TreeVisitorAction.java
@@ -0,0 +1,47 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.runtime.tree;
+
+/** How to execute code for node t when a visitor visits node t.  Execute
+ *  pre() before visiting children and execute post() after visiting children.
+ */
+public interface TreeVisitorAction {
+    /** Execute an action before visiting children of t.  Return t or
+     *  a rewritten t.  It is up to the visitor to decide what to do
+     *  with the return value.  Children of returned value will be
+     *  visited if using TreeVisitor.visit().
+     */
+    public Object pre(Object t);
+
+    /** Execute an action after visiting children of t.  Return t or
+     *  a rewritten t.  It is up to the visitor to decide what to do
+     *  with the return value.
+     */
+    public Object post(Object t);
+}
diff --git a/src/org/antlr/runtime/tree/TreeWizard.java b/src/org/antlr/runtime/tree/TreeWizard.java
new file mode 100755
index 0000000..666cfd6
--- /dev/null
+++ b/src/org/antlr/runtime/tree/TreeWizard.java
@@ -0,0 +1,531 @@
+/*
+ [The "BSD license"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.runtime.tree;
+
+import org.antlr.runtime.Token;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/** Build and navigate trees with this object.  Must know about the names
+ *  of tokens so you have to pass in a map or array of token names (from which
+ *  this class can build the map).  I.e., Token DECL means nothing unless the
+ *  class can translate it to a token type.
+ *
+ *  In order to create nodes and navigate, this class needs a TreeAdaptor.
+ *
+ *  This class can build a token type -> node index for repeated use or for
+ *  iterating over the various nodes with a particular type.
+ *
+ *  This class works in conjunction with the TreeAdaptor rather than moving
+ *  all this functionality into the adaptor.  An adaptor helps build and
+ *  navigate trees using methods.  This class helps you do it with string
+ *  patterns like "(A B C)".  You can create a tree from that pattern or
+ *  match subtrees against it.
+ */
+public class TreeWizard {
+	protected TreeAdaptor adaptor;
+	protected Map tokenNameToTypeMap;
+
+	public interface ContextVisitor {
+		// TODO: should this be called visit or something else?
+		public void visit(Object t, Object parent, int childIndex, Map labels);
+	}
+
+	public static abstract class Visitor implements ContextVisitor {
+		public void visit(Object t, Object parent, int childIndex, Map labels) {
+			visit(t);
+		}
+		public abstract void visit(Object t);
+	}
+
+	/** When using %label:TOKENNAME in a tree for parse(), we must
+	 *  track the label.
+	 */
+	public static class TreePattern extends CommonTree {
+		public String label;
+		public boolean hasTextArg;
+		public TreePattern(Token payload) {
+			super(payload);
+		}
+		public String toString() {
+			if ( label!=null ) {
+				return "%"+label+":"+super.toString();
+			}
+			else {
+				return super.toString();				
+			}
+		}
+	}
+
+	public static class WildcardTreePattern extends TreePattern {
+		public WildcardTreePattern(Token payload) {
+			super(payload);
+		}
+	}
+
+	/** This adaptor creates TreePattern objects for use during scan() */
+	public static class TreePatternTreeAdaptor extends CommonTreeAdaptor {
+		public Object create(Token payload) {
+			return new TreePattern(payload);
+		}
+	}
+
+	// TODO: build indexes for the wizard
+
+	/** During fillBuffer(), we can make a reverse index from a set
+	 *  of token types of interest to the list of indexes into the
+	 *  node stream.  This lets us convert a node pointer to a
+	 *  stream index semi-efficiently for a list of interesting
+	 *  nodes such as function definition nodes (you'll want to seek
+	 *  to their bodies for an interpreter).  Also useful for doing
+	 *  dynamic searches; i.e., go find me all PLUS nodes.
+	protected Map tokenTypeToStreamIndexesMap;
+
+	/** If tokenTypesToReverseIndex set to INDEX_ALL then indexing
+	 *  occurs for all token types.
+	public static final Set INDEX_ALL = new HashSet();
+
+	/** A set of token types user would like to index for faster lookup.
+	 *  If this is INDEX_ALL, then all token types are tracked.  If null,
+	 *  then none are indexed.
+	protected Set tokenTypesToReverseIndex = null;
+	*/
+
+	public TreeWizard(TreeAdaptor adaptor) {
+		this.adaptor = adaptor;
+	}
+
+	public TreeWizard(TreeAdaptor adaptor, Map tokenNameToTypeMap) {
+		this.adaptor = adaptor;
+		this.tokenNameToTypeMap = tokenNameToTypeMap;
+	}
+
+	public TreeWizard(TreeAdaptor adaptor, String[] tokenNames) {
+		this.adaptor = adaptor;
+		this.tokenNameToTypeMap = computeTokenTypes(tokenNames);
+	}
+
+	public TreeWizard(String[] tokenNames) {
+		this(new CommonTreeAdaptor(), tokenNames);
+	}
+
+	/** Compute a Map<String, Integer> that is an inverted index of
+	 *  tokenNames (which maps int token types to names).
+	 */
+	public Map computeTokenTypes(String[] tokenNames) {
+		Map m = new HashMap();
+		if ( tokenNames==null ) {
+			return m;
+		}
+		for (int ttype = Token.MIN_TOKEN_TYPE; ttype < tokenNames.length; ttype++) {
+			String name = tokenNames[ttype];
+			m.put(name, new Integer(ttype));
+		}
+		return m;
+	}
+
+	/** Using the map of token names to token types, return the type. */
+	public int getTokenType(String tokenName) {
+	 	if ( tokenNameToTypeMap==null ) {
+			 return Token.INVALID_TOKEN_TYPE;
+		 }
+		Integer ttypeI = (Integer)tokenNameToTypeMap.get(tokenName);
+		if ( ttypeI!=null ) {
+			return ttypeI.intValue();
+		}
+		return Token.INVALID_TOKEN_TYPE;
+	}
+
+	/** Walk the entire tree and make a node name to nodes mapping.
+	 *  For now, use recursion but later nonrecursive version may be
+	 *  more efficient.  Returns Map<Integer, List> where the List is
+	 *  of your AST node type.  The Integer is the token type of the node.
+	 *
+	 *  TODO: save this index so that find and visit are faster
+	 */
+	public Map index(Object t) {
+		Map m = new HashMap();
+		_index(t, m);
+		return m;
+	}
+
+	/** Do the work for index */
+	protected void _index(Object t, Map m) {
+		if ( t==null ) {
+			return;
+		}
+		int ttype = adaptor.getType(t);
+		List elements = (List)m.get(new Integer(ttype));
+		if ( elements==null ) {
+			elements = new ArrayList();
+			m.put(new Integer(ttype), elements);
+		}
+		elements.add(t);
+		int n = adaptor.getChildCount(t);
+		for (int i=0; i<n; i++) {
+			Object child = adaptor.getChild(t, i);
+			_index(child, m);
+		}
+	}
+
+	/** Return a List of tree nodes with token type ttype */
+	public List find(Object t, int ttype) {
+		final List nodes = new ArrayList();
+		visit(t, ttype, new TreeWizard.Visitor() {
+			public void visit(Object t) {
+				nodes.add(t);
+			}
+		});
+		return nodes;
+	}
+
+	/** Return a List of subtrees matching pattern. */
+	public List find(Object t, String pattern) {
+		final List subtrees = new ArrayList();
+		// Create a TreePattern from the pattern
+		TreePatternLexer tokenizer = new TreePatternLexer(pattern);
+		TreePatternParser parser =
+			new TreePatternParser(tokenizer, this, new TreePatternTreeAdaptor());
+		final TreePattern tpattern = (TreePattern)parser.pattern();
+		// don't allow invalid patterns
+		if ( tpattern==null ||
+			 tpattern.isNil() ||
+			 tpattern.getClass()==WildcardTreePattern.class )
+		{
+			return null;
+		}
+		int rootTokenType = tpattern.getType();
+		visit(t, rootTokenType, new TreeWizard.ContextVisitor() {
+			public void visit(Object t, Object parent, int childIndex, Map labels) {
+				if ( _parse(t, tpattern, null) ) {
+					subtrees.add(t);
+				}
+			}
+		});
+		return subtrees;
+	}
+
+	public Object findFirst(Object t, int ttype) {
+		return null;
+	}
+
+	public Object findFirst(Object t, String pattern) {
+		return null;
+	}
+
+	/** Visit every ttype node in t, invoking the visitor.  This is a quicker
+	 *  version of the general visit(t, pattern) method.  The labels arg
+	 *  of the visitor action method is never set (it's null) since using
+	 *  a token type rather than a pattern doesn't let us set a label.
+	 */
+	public void visit(Object t, int ttype, ContextVisitor visitor) {
+		_visit(t, null, 0, ttype, visitor);
+	}
+
+	/** Do the recursive work for visit */
+	protected void _visit(Object t, Object parent, int childIndex, int ttype, ContextVisitor visitor) {
+		if ( t==null ) {
+			return;
+		}
+		if ( adaptor.getType(t)==ttype ) {
+			visitor.visit(t, parent, childIndex, null);
+		}
+		int n = adaptor.getChildCount(t);
+		for (int i=0; i<n; i++) {
+			Object child = adaptor.getChild(t, i);
+			_visit(child, t, i, ttype, visitor);
+		}
+	}
+
+	/** For all subtrees that match the pattern, execute the visit action.
+	 *  The implementation uses the root node of the pattern in combination
+	 *  with visit(t, ttype, visitor) so nil-rooted patterns are not allowed.
+	 *  Patterns with wildcard roots are also not allowed.
+	 */
+	public void visit(Object t, final String pattern, final ContextVisitor visitor) {
+		// Create a TreePattern from the pattern
+		TreePatternLexer tokenizer = new TreePatternLexer(pattern);
+		TreePatternParser parser =
+			new TreePatternParser(tokenizer, this, new TreePatternTreeAdaptor());
+		final TreePattern tpattern = (TreePattern)parser.pattern();
+		// don't allow invalid patterns
+		if ( tpattern==null ||
+			 tpattern.isNil() ||
+			 tpattern.getClass()==WildcardTreePattern.class )
+		{
+			return;
+		}
+		final Map labels = new HashMap(); // reused for each _parse
+		int rootTokenType = tpattern.getType();
+		visit(t, rootTokenType, new TreeWizard.ContextVisitor() {
+			public void visit(Object t, Object parent, int childIndex, Map unusedlabels) {
+				// the unusedlabels arg is null as visit on token type doesn't set.
+				labels.clear();
+				if ( _parse(t, tpattern, labels) ) {
+					visitor.visit(t, parent, childIndex, labels);
+				}
+			}
+		});
+	}
+
+	/** Given a pattern like (ASSIGN %lhs:ID %rhs:.) with optional labels
+	 *  on the various nodes and '.' (dot) as the node/subtree wildcard,
+	 *  return true if the pattern matches and fill the labels Map with
+	 *  the labels pointing at the appropriate nodes.  Return false if
+	 *  the pattern is malformed or the tree does not match.
+	 *
+	 *  If a node specifies a text arg in pattern, then that must match
+	 *  for that node in t.
+	 *
+	 *  TODO: what's a better way to indicate bad pattern? Exceptions are a hassle 
+	 */
+	public boolean parse(Object t, String pattern, Map labels) {
+		TreePatternLexer tokenizer = new TreePatternLexer(pattern);
+		TreePatternParser parser =
+			new TreePatternParser(tokenizer, this, new TreePatternTreeAdaptor());
+		TreePattern tpattern = (TreePattern)parser.pattern();
+		/*
+		System.out.println("t="+((Tree)t).toStringTree());
+		System.out.println("scant="+tpattern.toStringTree());
+		*/
+		boolean matched = _parse(t, tpattern, labels);
+		return matched;
+	}
+
+	public boolean parse(Object t, String pattern) {
+		return parse(t, pattern, null);
+	}
+
+	/** Do the work for parse. Check to see if the t2 pattern fits the
+	 *  structure and token types in t1.  Check text if the pattern has
+	 *  text arguments on nodes.  Fill labels map with pointers to nodes
+	 *  in tree matched against nodes in pattern with labels.
+	 */
+	protected boolean _parse(Object t1, TreePattern tpattern, Map labels) {
+		// make sure both are non-null
+		if ( t1==null || tpattern==null ) {
+			return false;
+		}
+		// check roots (wildcard matches anything)
+		if ( tpattern.getClass() != WildcardTreePattern.class ) {
+			if ( adaptor.getType(t1) != tpattern.getType() ) return false;
+            // if pattern has text, check node text
+			if ( tpattern.hasTextArg && !adaptor.getText(t1).equals(tpattern.getText()) ) {
+				return false;
+			}
+		}
+		if ( tpattern.label!=null && labels!=null ) {
+			// map label in pattern to node in t1
+			labels.put(tpattern.label, t1);
+		}
+		// check children
+		int n1 = adaptor.getChildCount(t1);
+		int n2 = tpattern.getChildCount();
+		if ( n1 != n2 ) {
+			return false;
+		}
+		for (int i=0; i<n1; i++) {
+			Object child1 = adaptor.getChild(t1, i);
+			TreePattern child2 = (TreePattern)tpattern.getChild(i);
+			if ( !_parse(child1, child2, labels) ) {
+				return false;
+			}
+		}
+		return true;
+	}
+
+	/** Create a tree or node from the indicated tree pattern that closely
+	 *  follows ANTLR tree grammar tree element syntax:
+	 *
+	 * 		(root child1 ... child2).
+	 *
+	 *  You can also just pass in a node: ID
+	 * 
+	 *  Any node can have a text argument: ID[foo]
+	 *  (notice there are no quotes around foo--it's clear it's a string).
+	 *
+	 *  nil is a special name meaning "give me a nil node".  Useful for
+	 *  making lists: (nil A B C) is a list of A B C.
+ 	 */
+	public Object create(String pattern) {
+		TreePatternLexer tokenizer = new TreePatternLexer(pattern);
+		TreePatternParser parser = new TreePatternParser(tokenizer, this, adaptor);
+		Object t = parser.pattern();
+		return t;
+	}
+
+	/** Compare t1 and t2; return true if token types/text, structure match exactly.
+	 *  The trees are examined in their entirety so that (A B) does not match
+	 *  (A B C) nor (A (B C)). 
+	 // TODO: allow them to pass in a comparator
+	 *  TODO: have a version that is nonstatic so it can use instance adaptor
+	 *
+	 *  I cannot rely on the tree node's equals() implementation as I make
+	 *  no constraints at all on the node types nor interface etc... 
+	 */
+	public static boolean equals(Object t1, Object t2, TreeAdaptor adaptor) {
+		return _equals(t1, t2, adaptor);
+	}
+
+	/** Compare type, structure, and text of two trees, assuming adaptor in
+	 *  this instance of a TreeWizard.
+	 */
+	public boolean equals(Object t1, Object t2) {
+		return _equals(t1, t2, adaptor);
+	}
+
+	protected static boolean _equals(Object t1, Object t2, TreeAdaptor adaptor) {
+		// make sure both are non-null
+		if ( t1==null || t2==null ) {
+			return false;
+		}
+		// check roots
+		if ( adaptor.getType(t1) != adaptor.getType(t2) ) {
+			return false;
+		}
+		if ( !adaptor.getText(t1).equals(adaptor.getText(t2)) ) {
+			return false;
+		}
+		// check children
+		int n1 = adaptor.getChildCount(t1);
+		int n2 = adaptor.getChildCount(t2);
+		if ( n1 != n2 ) {
+			return false;
+		}
+		for (int i=0; i<n1; i++) {
+			Object child1 = adaptor.getChild(t1, i);
+			Object child2 = adaptor.getChild(t2, i);
+			if ( !_equals(child1, child2, adaptor) ) {
+				return false;
+			}
+		}
+		return true;
+	}
+
+	// TODO: next stuff taken from CommonTreeNodeStream
+	
+		/** Given a node, add this to the reverse index tokenTypeToStreamIndexesMap.
+	 *  You can override this method to alter how indexing occurs.  The
+	 *  default is to create a
+	 *
+	 *    Map<Integer token type,ArrayList<Integer stream index>>
+	 *
+	 *  This data structure allows you to find all nodes with type INT in order.
+	 *
+	 *  If you really need to find a node of type, say, FUNC quickly then perhaps
+	 *
+	 *    Map<Integertoken type,Map<Object tree node,Integer stream index>>
+	 *
+	 *  would be better for you.  The interior maps map a tree node to
+	 *  the index so you don't have to search linearly for a specific node.
+	 *
+	 *  If you change this method, you will likely need to change
+	 *  getNodeIndex(), which extracts information.
+	protected void fillReverseIndex(Object node, int streamIndex) {
+		//System.out.println("revIndex "+node+"@"+streamIndex);
+		if ( tokenTypesToReverseIndex==null ) {
+			return; // no indexing if this is empty (nothing of interest)
+		}
+		if ( tokenTypeToStreamIndexesMap==null ) {
+			tokenTypeToStreamIndexesMap = new HashMap(); // first indexing op
+		}
+		int tokenType = adaptor.getType(node);
+		Integer tokenTypeI = new Integer(tokenType);
+		if ( !(tokenTypesToReverseIndex==INDEX_ALL ||
+			   tokenTypesToReverseIndex.contains(tokenTypeI)) )
+		{
+			return; // tokenType not of interest
+		}
+		Integer streamIndexI = new Integer(streamIndex);
+		ArrayList indexes = (ArrayList)tokenTypeToStreamIndexesMap.get(tokenTypeI);
+		if ( indexes==null ) {
+			indexes = new ArrayList(); // no list yet for this token type
+			indexes.add(streamIndexI); // not there yet, add
+			tokenTypeToStreamIndexesMap.put(tokenTypeI, indexes);
+		}
+		else {
+			if ( !indexes.contains(streamIndexI) ) {
+				indexes.add(streamIndexI); // not there yet, add
+			}
+		}
+	}
+
+	/** Track the indicated token type in the reverse index.  Call this
+	 *  repeatedly for each type or use variant with Set argument to
+	 *  set all at once.
+	 * @param tokenType
+	public void reverseIndex(int tokenType) {
+		if ( tokenTypesToReverseIndex==null ) {
+			tokenTypesToReverseIndex = new HashSet();
+		}
+		else if ( tokenTypesToReverseIndex==INDEX_ALL ) {
+			return;
+		}
+		tokenTypesToReverseIndex.add(new Integer(tokenType));
+	}
+
+	/** Track the indicated token types in the reverse index. Set
+	 *  to INDEX_ALL to track all token types.
+	public void reverseIndex(Set tokenTypes) {
+		tokenTypesToReverseIndex = tokenTypes;
+	}
+
+	/** Given a node pointer, return its index into the node stream.
+	 *  This is not its Token stream index.  If there is no reverse map
+	 *  from node to stream index or the map does not contain entries
+	 *  for node's token type, a linear search of entire stream is used.
+	 *
+	 *  Return -1 if exact node pointer not in stream.
+	public int getNodeIndex(Object node) {
+		//System.out.println("get "+node);
+		if ( tokenTypeToStreamIndexesMap==null ) {
+			return getNodeIndexLinearly(node);
+		}
+		int tokenType = adaptor.getType(node);
+		Integer tokenTypeI = new Integer(tokenType);
+		ArrayList indexes = (ArrayList)tokenTypeToStreamIndexesMap.get(tokenTypeI);
+		if ( indexes==null ) {
+			//System.out.println("found linearly; stream index = "+getNodeIndexLinearly(node));
+			return getNodeIndexLinearly(node);
+		}
+		for (int i = 0; i < indexes.size(); i++) {
+			Integer streamIndexI = (Integer)indexes.get(i);
+			Object n = get(streamIndexI.intValue());
+			if ( n==node ) {
+				//System.out.println("found in index; stream index = "+streamIndexI);
+				return streamIndexI.intValue(); // found it!
+			}
+		}
+		return -1;
+	}
+
+	*/
+}