add initial antlr4 files (mainly runtime)

[git-p4: depot-paths = "//depot/code/antlr4/main/": change = 8636]
This commit is contained in:
parrt 2011-06-14 16:22:05 -08:00
parent 36fb229434
commit 55f384237b
91 changed files with 9844 additions and 0 deletions

0
CHANGES.txt Normal file
View File

26
LICENSE.txt Normal file
View File

@ -0,0 +1,26 @@
[The "BSD license"]
Copyright (c) 2011 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.

5
build.xml Normal file
View File

@ -0,0 +1,5 @@
<project name="ANTLRv4">
<property file="build.properties"/>
</project>

View File

@ -0,0 +1,81 @@
/*
[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.v4.runtime;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
/** 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;
}
}

View File

@ -0,0 +1,6 @@
package org.antlr.v4.runtime;
/** */
public interface ANTLRParserListener {
public void error(RecognitionException msg);
}

View File

@ -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.v4.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); }
}

View File

@ -0,0 +1,630 @@
/*
[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.v4.runtime;
import org.antlr.v4.analysis.ATNConfig;
import org.antlr.v4.misc.*;
import org.antlr.v4.runtime.atn.ParserInterpreter;
import java.util.*;
/** A generic recognizer that can handle recognizers generated from
* parser and tree grammars. This is all the parsing
* support code essentially; most of it is error recovery stuff and
* backtracking.
*
* TODO: rename since lexer not under. or reorg parser/treeparser; treeparser under parser?
*/
public abstract class BaseRecognizer extends Recognizer<ParserSharedState, ParserInterpreter> {
public static final int MEMO_RULE_FAILED = -2;
public static final int MEMO_RULE_UNKNOWN = -1;
public static final String NEXT_TOKEN_RULE_NAME = "nextToken";
public BaseRecognizer(TokenStream input) {
this(input, new ParserSharedState());
}
public BaseRecognizer(TokenStream input, ParserSharedState state) {
if ( state==null ) {
state = new ParserSharedState();
}
this.state = state;
state.input = input;
}
/** reset the parser's state; subclasses must rewinds the input stream */
public void reset() {
state = new ParserSharedState();
}
/** 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(int ttype) throws RecognitionException {
// System.out.println("match "+((TokenStream)state.input).LT(1)+" vs expected "+ttype);
Object matchedSymbol = getCurrentInputSymbol();
if ( state.input.LA(1)==ttype ) {
state.input.consume();
state.errorRecovery = false;
state.failed = false;
return matchedSymbol;
}
System.out.println("MATCH failure at state "+state.ctx.s+
", ctx="+state.ctx.toString(this));
IntervalSet expecting = _interp.atn.nextTokens(state.ctx);
System.out.println("could match "+expecting);
matchedSymbol = recoverFromMismatchedToken(ttype, expecting);
System.out.println("rsync'd to "+matchedSymbol);
return matchedSymbol;
}
// like matchSet but w/o consume; error checking routine.
public void sync(IntervalSet expecting) {
if ( expecting.member(state.input.LA(1)) ) return;
System.out.println("failed sync to "+expecting);
IntervalSet followSet = computeErrorRecoverySet();
followSet.addAll(expecting);
NoViableAltException e = new NoViableAltException(this, state.ctx);
recoverFromMismatchedSet(e, followSet);
}
/** Match the wildcard: in a symbol */
public void matchAny() {
state.errorRecovery = false;
state.failed = false;
state.input.consume();
}
public boolean mismatchIsUnwantedToken(int ttype) {
return state.input.LA(2)==ttype;
}
public boolean mismatchIsMissingToken(IntervalSet follow) {
return false;
/*
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) ) {
IntervalSet viableTokensFollowingThisRule = computeNextViableTokenSet();
follow = follow.or(viableTokensFollowingThisRule);
if ( state.ctx.sp>=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)state.input).LT(1));
// IntervalSet 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(state.input.LA(1)) || follow.member(Token.EOR_TOKEN_TYPE) ) {
//System.out.println("LT(1)=="+((TokenStream)state.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
*/
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;
notifyListeners(e);
}
/** 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;
}
/** 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() {
state.input.consume();
/*
if ( state.lastErrorIndex==state.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.
state.input.consume();
}
state.lastErrorIndex = state.input.index();
IntervalSet followSet = computeErrorRecoverySet();
beginResync();
consumeUntil(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. See LinearApproximator.FIRST().
* 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
* context-sensitive 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 follow set start of rule execution
* 0 <EOF> a (from main())
* 1 ']' b
* 2 '^' 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 ']' and in the set, so we would
* not consume anything. After printing an error, rule c would
* return normally. Rule b 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 can see that the parser walks up the 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 implement context-sensitive FOLLOW sets that are combined
* at run-time upon error to avoid overhead during parsing.
*/
protected IntervalSet computeErrorRecoverySet() {
return null;
// int top = state.ctx.sp;
// IntervalSet followSet = new IntervalSet();
// for (int i=top; i>=0; i--) { // i==0 is EOF context for start rule invocation
// IntervalSet f = (IntervalSet)state.ctx.get(i).follow;
// followSet.orInPlace(f);
// }
// return followSet;
}
/** 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.
*/
public IntervalSet computeNextViableTokenSet() {
return null;
// int top = state.ctx.sp;
// IntervalSet followSet = new IntervalSet();
// for (int i=top; i>=0; i--) { // i==0 is EOF context for start rule invocation
// IntervalSet f = (IntervalSet)state.ctx.get(i).follow;
// followSet.orInPlace(f);
// // can we see end of rule? if not, don't include follow of this rule
// if ( !f.member(Token.EOR_TOKEN_TYPE) ) break;
// // else combine with tokens that can follow this rule (rm EOR also)
// // EOR indicates we have to include follow(start rule); i.e., EOF
// followSet.remove(Token.EOR_TOKEN_TYPE);
// }
// 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(int ttype, IntervalSet follow)
throws RecognitionException
{
RecognitionException e = null;
// if next token is what we are looking for then "delete" this token
if ( mismatchIsUnwantedToken(ttype) ) {
e = new UnwantedTokenException(this, state.input, ttype);
/*
System.err.println("recoverFromMismatchedToken deleting "+
((TokenStream)state.input).LT(1)+
" since "+((TokenStream)state.input).LT(2)+" is what we want");
*/
beginResync();
state.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();
state.input.consume(); // move past ttype token as if all were ok
return matchedSymbol;
}
// can't recover with single token deletion, try insertion
if ( mismatchIsMissingToken(follow) ) {
Object inserted = getMissingSymbol(e, ttype, follow);
e = new MissingTokenException(this, state.input, ttype, 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(this, state.input, ttype);
throw e;
}
public Object recoverFromMismatchedSet(RecognitionException e,
IntervalSet follow)
throws RecognitionException
{
if ( mismatchIsMissingToken(follow) ) {
// System.out.println("missing token");
reportError(e);
// we don't know how to conjure up a token for sets yet
return getMissingSymbol(e, Token.INVALID_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.
*/
protected Object getCurrentInputSymbol() { 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(RecognitionException e,
int expectedTokenType,
IntervalSet follow)
{
return null;
}
public void consumeUntil(int tokenType) {
//System.out.println("consumeUntil "+tokenType);
int ttype = state.input.LA(1);
while (ttype != Token.EOF && ttype != tokenType) {
state.input.consume();
ttype = state.input.LA(1);
}
}
/** Consume tokens until one matches the given token set */
public void consumeUntil(IntervalSet set) {
//System.out.println("consumeUntil("+set.toString(getTokenNames())+")");
int ttype = state.input.LA(1);
while (ttype != Token.EOF && !set.member(ttype) ) {
//System.out.println("consume during recover LA(1)="+getTokenNames()[state.input.LA(1)]);
state.input.consume();
ttype = state.input.LA(1);
}
}
/** 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.v4.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;
}
/** Return whether or not a backtracking attempt failed. */
public boolean failed() { return state.failed; }
/** 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;
}
public void traceIn(String ruleName, int ruleIndex, Object inputSymbol) {
System.out.print("enter "+ruleName+" "+inputSymbol);
System.out.println();
}
public void traceOut(String ruleName,
int ruleIndex,
Object inputSymbol)
{
System.out.print("exit "+ruleName+" "+inputSymbol);
System.out.println();
}
/* In v3, programmers altered error messages by overriding
displayRecognitionError() and possibly getTokenErrorDisplay().
They overrode emitErrorMessage(String) to change where the output goes.
Now, in v4, we're going to use a listener mechanism. This makes it
easier for language applications to have parsers notify them
upon error without having to override the parsers. If you don't specify
a listener, ANTLR calls the v3 legacy displayRecognitionError()
method. All that does is format a message and call emitErrorMessage().
Otherwise, your listener will receive RecognitionException
exceptions and you can do what ever you want with them including
reproducing the same behavior by calling the legacy methods.
(In v4, RecognitionException includes the recognizer object).
Grammar tools can have a listeners without having to worry about
messing up the programmers' error handling.
*/
public void reportConflict(int startIndex, int stopIndex, Set<Integer> alts, OrderedHashSet<ATNConfig> configs) {}
public void reportContextSensitivity(int startIndex, int stopIndex, Set<Integer> alts, OrderedHashSet<ATNConfig> configs) {}
/** If context sensitive parsing, we know it's ambiguity not conflict */
public void reportAmbiguity(int startIndex, int stopIndex, Set<Integer> alts, OrderedHashSet<ATNConfig> configs) {}
}

View File

@ -0,0 +1,274 @@
/*
[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.v4.runtime;
import org.antlr.runtime.BitSet;
import java.util.ArrayList;
import java.util.List;
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);
}
}
}

View File

@ -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.v4.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();
}

View File

@ -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.v4.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 */
public int p;
/** What line number is the scanner at before processing buffer[p]? */
public int line;
/** What char position 0..n-1 in line is scanner before processing buffer[p]? */
public int charPositionInLine;
}

View File

@ -0,0 +1,193 @@
/*
[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.v4.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;
this.line = input.getLine();
this.charPositionInLine = input.getCharPositionInLine();
}
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()+"]";
}
}

View File

@ -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.v4.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;
}
}

View File

@ -0,0 +1,38 @@
/*
[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.v4.runtime;
/** The recognizer did not match anything for a (..)+ loop. */
public class EarlyExitException extends RecognitionException {
/** Used for remote debugger deserialization */
public EarlyExitException() {;}
public EarlyExitException(BaseRecognizer recognizer, IntStream input) {
super(recognizer, input, recognizer.state.ctx);
}
}

View File

@ -0,0 +1,55 @@
/*
[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.v4.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(BaseRecognizer recognizer,
IntStream input,
String ruleName,
String predicateText)
{
super(recognizer, input, recognizer.state.ctx);
this.ruleName = ruleName;
this.predicateText = predicateText;
}
public String toString() {
return "FailedPredicateException("+ruleName+",{"+predicateText+"}?)";
}
}

View File

@ -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.v4.runtime;
/** A simple stream of integers used when all I care about is the char
* or token type sequence (such as interpretation).
*
* TODO: Notes from Oli: index, seek, LA, LT, consume, getSourceName needed
* Do like Java IO and have new BufferedStream(new TokenStream) rather than
* using inheritance. line/col go into lexer
*/
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();
/** 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();
}

View File

@ -0,0 +1,315 @@
/*
[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.v4.runtime;
import org.antlr.v4.runtime.atn.LexerInterpreter;
import org.antlr.v4.runtime.misc.QStack;
import java.util.EmptyStackException;
/** 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 Recognizer<LexerSharedState, LexerInterpreter>
implements TokenSource
{
public static final int DEFAULT_MODE = 0;
public static final int MORE = -2;
public static final int SKIP = -3;
public static final int DEFAULT_TOKEN_CHANNEL = Token.DEFAULT_CHANNEL;
public static final int HIDDEN = Token.HIDDEN_CHANNEL;
public LexerSharedState state;
public Lexer(CharStream input) {
this(input, new LexerSharedState());
}
public Lexer(CharStream input, LexerSharedState state) {
if ( state==null ) {
state = new LexerSharedState();
}
this.state = state;
state.input = input;
}
public void reset() {
// wack Lexer state variables
if ( state.input!=null ) {
state.input.seek(0); // rewind the input
}
if ( state==null ) {
return; // no shared state work to do
}
state.token = null;
state.type = Token.INVALID_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() {
outer:
while (true) {
state.token = null;
state.channel = Token.DEFAULT_CHANNEL;
state.tokenStartCharIndex = state.input.index();
state.tokenStartCharPositionInLine = state.input.getCharPositionInLine();
state.tokenStartLine = state.input.getLine();
state.text = null;
do {
state.type = Token.INVALID_TYPE;
if ( state.input.LA(1)==CharStream.EOF ) {
Token eof = new CommonToken(state.input,Token.EOF,
Token.DEFAULT_CHANNEL,
state.input.index(),state.input.index());
eof.setLine(getLine());
eof.setCharPositionInLine(getCharPositionInLine());
return eof;
}
// System.out.println("nextToken at "+((char)state.input.LA(1))+
// " in mode "+state.mode+
// " at index "+state.input.index());
int ttype = _interp.match(state.input, state.mode);
// System.out.println("accepted ttype "+ttype);
if ( state.type == Token.INVALID_TYPE) state.type = ttype;
if ( state.type==SKIP ) {
continue outer;
}
} while ( state.type==MORE );
if ( state.token==null ) emit();
return state.token;
}
}
/** 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.type = SKIP;
}
public void more() {
state.type = MORE;
}
public void mode(int m) {
state.mode = m;
}
public void pushMode(int m) {
// System.out.println("pushMode "+m);
if ( state.modeStack==null ) state.modeStack = new QStack<Integer>();
state.modeStack.push(state.mode);
mode(m);
}
public int popMode() {
if ( state.modeStack==null ) throw new EmptyStackException();
// System.out.println("popMode back to "+state.modeStack.peek());
mode( state.modeStack.pop() );
return state.mode;
}
/** Set the char stream and reset the lexer */
public void setCharStream(CharStream input) {
this.state.input = null;
reset();
this.state.input = input;
}
public CharStream getCharStream() {
return ((CharStream)state.input);
}
public String getSourceName() {
return state.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) {
//System.err.println("emit "+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(((CharStream)state.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 int getLine() {
return ((CharStream)state.input).getLine();
}
public int getCharPositionInLine() {
return ((CharStream)state.input).getCharPositionInLine();
}
/** What is the index of the current character of lookahead? */
public int getCharIndex() {
return state.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 ((CharStream)state.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);
}
/** 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;
}
public String getErrorMessage(RecognitionException e) {
String msg = null;
if ( e instanceof MismatchedTokenException ) {
MismatchedTokenException mte = (MismatchedTokenException)e;
msg = "mismatched character "+getCharErrorDisplay(e.c)+" expecting "+
getCharErrorDisplay(mte.expecting.getSingleElement());
}
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)state.input.LA(1)+" during recovery");
//re.printStackTrace();
state.input.consume();
}
}

View File

@ -0,0 +1,26 @@
package org.antlr.v4.runtime;
import org.antlr.v4.analysis.ATNConfig;
import org.antlr.v4.misc.OrderedHashSet;
public class LexerNoViableAltException extends LexerRecognitionExeption {
/** Prediction began at what input index? */
public int startIndex;
/** Which configurations did we try at input.index() that couldn't match input.LT(1)? */
public OrderedHashSet<ATNConfig> deadEndConfigs;
/** Used for remote debugger deserialization */
public LexerNoViableAltException() {;}
public LexerNoViableAltException(Lexer lexer,
CharStream input,
OrderedHashSet<ATNConfig> deadEndConfigs) {
super(lexer, input);
this.deadEndConfigs = deadEndConfigs;
}
public String toString() {
return "NoViableAltException('"+(char)c+"'";
}
}

View File

@ -0,0 +1,33 @@
package org.antlr.v4.runtime;
public class LexerRecognitionExeption extends RuntimeException {
/** Who threw the exception? */
public Lexer lexer;
/** What is index of token/char were we looking at when the error occurred? */
public int index;
/** 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;
/** Used for remote debugger deserialization */
public LexerRecognitionExeption() {
}
public LexerRecognitionExeption(Lexer lexer, CharStream input) {
this.lexer = lexer;
this.index = input.index();
this.c = input.LA(1);
this.line = input.getLine();
this.charPositionInLine = input.getCharPositionInLine();
}
}

View File

@ -0,0 +1,56 @@
package org.antlr.v4.runtime;
import org.antlr.v4.runtime.misc.QStack;
public class LexerSharedState extends RecognizerSharedState<CharStream> {
//public CharStream input;
/** 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;
public QStack<Integer> modeStack;
public int mode = Lexer.DEFAULT_MODE;
/** 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 LexerSharedState() {
}
public LexerSharedState(LexerSharedState state) {
this.token = state.token;
this.tokenStartCharIndex = state.tokenStartCharIndex;
this.tokenStartLine = state.tokenStartLine;
this.tokenStartCharPositionInLine = state.tokenStartCharPositionInLine;
this.channel = state.channel;
this.type = state.type;
this.text = state.text;
}
}

View File

@ -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.v4.runtime;
public class MismatchedNotSetException extends MismatchedSetException {
/** Used for remote debugger deserialization */
public MismatchedNotSetException() {;}
public MismatchedNotSetException(BaseRecognizer recognizer, IntStream input) {
super(recognizer, input);
}
public String toString() {
return "MismatchedNotSetException("+getUnexpectedType()+"!="+expecting+")";
}
}

View File

@ -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.v4.runtime;
public class MismatchedRangeException extends RecognitionException {
public int a,b;
/** Used for remote debugger deserialization */
public MismatchedRangeException() {;}
public MismatchedRangeException(BaseRecognizer recognizer, IntStream input, int a, int b) {
super(recognizer, input, recognizer.state.ctx);
this.a = a;
this.b = b;
}
public String toString() {
return "MismatchedNotSetException("+getUnexpectedType()+" not in ["+a+","+b+"])";
}
}

View File

@ -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.v4.runtime;
public class MismatchedSetException extends RecognitionException {
/** Used for remote debugger deserialization */
public MismatchedSetException() {;}
public MismatchedSetException(BaseRecognizer recognizer, IntStream input) {
super(recognizer, input, recognizer.state.ctx);
}
public String toString() {
return "MismatchedSetException("+getUnexpectedType()+"!="+expecting+")";
}
}

View File

@ -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.v4.runtime;
/** A mismatched char or Token or tree node */
public class MismatchedTokenException extends RecognitionException {
/** Used for remote debugger deserialization */
public MismatchedTokenException() {;}
public MismatchedTokenException(BaseRecognizer recognizer, IntStream input, int expecting) {
super(recognizer, input, recognizer.state.ctx);
}
public String toString() {
return "MismatchedTokenException("+getUnexpectedType()+"!="+expecting+")";
}
}

View File

@ -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.v4.runtime;
/**
*/
public class MismatchedTreeNodeException extends RecognitionException {
public MismatchedTreeNodeException() {
}
public MismatchedTreeNodeException(BaseRecognizer recognizer,
IntStream input, int firstSet)
{
super(recognizer, input, recognizer.state.ctx);
}
public String toString() {
return "MismatchedTreeNodeException("+getUnexpectedType()+"!="+expecting+")";
}
}

View File

@ -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.v4.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(BaseRecognizer recognizer, IntStream input, int expecting, Object inserted) {
super(recognizer, input, expecting);
this.inserted = inserted;
}
public int getMissingType() {
return expecting.getSingleElement();
}
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";
}
}

View File

@ -0,0 +1,63 @@
/*
[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.v4.runtime;
import org.antlr.v4.analysis.ATNConfig;
import org.antlr.v4.misc.OrderedHashSet;
public class NoViableAltException extends RecognitionException {
/** Prediction began at what input index? */
public int startIndex;
/** Which configurations did we try at input.index() that couldn't match input.LT(1)? */
public OrderedHashSet<ATNConfig> deadEndConfigs;
/** Used for remote debugger deserialization */
public NoViableAltException() {;}
public NoViableAltException(BaseRecognizer recognizer, RuleContext ctx) { // LL(1) error
super(recognizer, recognizer.state.input, ctx);
}
public NoViableAltException(BaseRecognizer recognizer, IntStream input,
OrderedHashSet<ATNConfig> deadEndConfigs,
RuleContext ctx)
{
super(recognizer, input, ctx);
this.deadEndConfigs = deadEndConfigs;
}
public String toString() {
if ( recognizer!=null ) {
TokenStream tokens = recognizer.state.input;
String bad = tokens.toString(startIndex, index);
return "NoViableAltException(input=\""+bad+"\" last token type is "+getUnexpectedType();
}
return "NoViableAltException(last token type is "+getUnexpectedType();
}
}

View File

@ -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.v4.runtime;
import org.antlr.v4.runtime.misc.LABitSet;
/** A parser for TokenStreams. "parser grammars" result in a subclass
* of this.
*/
public class Parser extends BaseRecognizer {
public Parser(TokenStream input) {
super(input);
}
public Parser(TokenStream input, ParserSharedState state) {
super(input, state); // share the state object with another parser
}
public void reset() {
super.reset(); // reset all recognizer state variables
if ( state.input!=null ) {
state.input.seek(0); // rewind the input
}
}
protected Object getCurrentInputSymbol() {
return ((TokenStream)state.input).LT(1);
}
protected Object getMissingSymbol(RecognitionException e,
int expectedTokenType,
LABitSet 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)state.input).LT(1);
if ( current.getType() == Token.EOF ) {
current = ((TokenStream)state.input).LT(-1);
}
t.line = current.getLine();
t.charPositionInLine = current.getCharPositionInLine();
t.channel = Token.DEFAULT_CHANNEL;
return t;
}
/** Set the token stream and reset the parser */
public void setTokenStream(TokenStream input) {
this.state.input = null;
reset();
this.state.input = input;
}
public TokenStream getTokenStream() {
return (TokenStream)state.input;
}
public String getSourceName() {
return state.input.getSourceName();
}
public void traceIn(String ruleName, int ruleIndex) {
super.traceIn(ruleName, ruleIndex, ((TokenStream)state.input).LT(1));
}
public void traceOut(String ruleName, int ruleIndex) {
super.traceOut(ruleName, ruleIndex, ((TokenStream)state.input).LT(1));
}
}

View File

@ -0,0 +1,71 @@
/*
[BSD]
Copyright (c) 2010 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.v4.runtime;
import org.stringtemplate.v4.ST;
/** Rules return values in 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 ParserRuleContext extends RuleContext {
public Token start, stop;
public Object tree;
public ST st;
public ParserRuleContext() { super(); }
public ParserRuleContext(RuleContext parent, int stateNumber) {
// capture state that called us as we create this context; use later for
// return state in closure
super(parent, parent!=null ? parent.s : -1, stateNumber);
}
@Override
public Object getTree() { return tree; }
@Override
public ST getTemplate() { return st; }
@Override
public Token getStart() { return start; }
@Override
public Token getStop() { return stop; }
}

View File

@ -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.v4.runtime;
/** 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.
*/
public class ParserSharedState extends RecognizerSharedState<TokenStream> {
/** First on stack is fake a call to start rule from S' : S EOF ;
* Generated start rule does this.
*/
// public QStack<RuleContext> ctx;
public ParserRuleContext ctx; // tracks local _ctx var to see from outside
/** 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;
public ParserSharedState() {
// ctx = new RuleContext(); // implicit call to start rule
}
@Override
public ParserRuleContext getContext() {
return ctx;
}
// public RecognizerSharedState(RecognizerSharedState state) {
// this.ctx = state.ctx;
// 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);
// }
// }
}

View File

@ -0,0 +1,202 @@
/*
[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.v4.runtime;
import org.antlr.runtime.CharStream;
import org.antlr.runtime.tree.*;
import org.antlr.v4.misc.IntervalSet;
/** 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.
*/
// TODO: split out lexer one
public class RecognitionException extends RuntimeException {
/** Who threw the exception? */
public BaseRecognizer recognizer;
public RuleContext ctx; // should be what is in recognizer, but won't work when interpreting
public IntervalSet expecting;
public 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(BaseRecognizer recognizer, IntStream input,
RuleContext ctx)
{
this.recognizer = recognizer;
this.input = input;
this.ctx = ctx;
// firstSet is what can we're expecting within rule that calls this ctor.
// must combine with context-sensitive FOLLOW of that rule.
// LABitSet viableTokensFollowingThisRule = recognizer.computeNextViableTokenSet();
// this.expecting = viableTokensFollowingThisRule.or(firstSet);
if ( recognizer!=null ) expecting = recognizer._interp.atn.nextTokens(ctx);
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 ( recognizer==null ) return token.getType();
if ( recognizer.state.input instanceof TokenStream) {
return token.getType();
}
else if ( recognizer.state.input instanceof TreeNodeStream ) {
TreeNodeStream nodes = (TreeNodeStream)recognizer.state.input;
TreeAdaptor adaptor = nodes.getTreeAdaptor();
return adaptor.getType(node);
}
else {
return c;
}
}
}

View File

@ -0,0 +1,207 @@
package org.antlr.v4.runtime;
import org.antlr.v4.runtime.atn.ATN;
import java.util.*;
public class Recognizer<SharedState extends RecognizerSharedState, ATNInterpreter> {
public static final int EOF=-1;
protected List<ANTLRParserListener> listeners;
protected ATNInterpreter _interp;
/** 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.
*/
public SharedState state;
/** 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;
}
public String[] getRuleNames() {
return null;
}
public ATN getATN() { return null; }
public ATNInterpreter getInterpreter() { return _interp; }
public void displayRecognitionError(RecognitionException e) {
String hdr = getErrorHeader(e);
String msg = getErrorMessage(e);
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 = getTokenNames();
String msg = e.getMessage();
if ( e instanceof UnwantedTokenException ) {
UnwantedTokenException ute = (UnwantedTokenException)e;
String tokenName="<unknown>";
if ( ute.expecting.member(Token.EOF) ) {
tokenName = "EOF";
}
else {
tokenName = tokenNames[ute.expecting.getSingleElement()];
}
msg = "extraneous input "+getTokenErrorDisplay(ute.getUnexpectedToken())+
" expecting "+tokenName;
}
else if ( e instanceof MissingTokenException ) {
MissingTokenException mte = (MissingTokenException)e;
String tokenName="<unknown>";
if ( mte.expecting.member(Token.EOF) ) {
tokenName = "EOF";
}
else {
tokenName = tokenNames[mte.expecting.getSingleElement()];
}
msg = "missing "+tokenName+" at "+getTokenErrorDisplay(e.token);
}
else if ( e instanceof MismatchedTokenException ) {
MismatchedTokenException mte = (MismatchedTokenException)e;
String tokenName="<unknown>";
// if ( mte.expecting.member(Token.EOF) ) {
// tokenName = "EOF";
// }
// else {
// tokenName = tokenNames[mte.expecting.getSingleElement()];
// }
msg = "mismatched input "+getTokenErrorDisplay(e.token)+
" expecting "+tokenName;
}
else if ( e instanceof MismatchedTreeNodeException ) {
MismatchedTreeNodeException mtne = (MismatchedTreeNodeException)e;
String tokenName="<unknown>";
if ( mtne.expecting.member(Token.EOF) ) {
tokenName = "EOF";
}
else {
tokenName = tokenNames[mtne.expecting.getSingleElement()];
}
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 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;
}
/** What is the error header, normally line/character position information? */
public String getErrorHeader(RecognitionException e) {
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);
}
public void addListener(ANTLRParserListener pl) {
if ( listeners==null ) {
listeners =
Collections.synchronizedList(new ArrayList<ANTLRParserListener>(2));
}
if ( pl!=null ) listeners.add(pl);
}
public void removeListener(ANTLRParserListener pl) { listeners.remove(pl); }
public void removeListeners() { listeners.clear(); }
public List<ANTLRParserListener> getListeners() { return listeners; }
public void notifyListeners(RecognitionException re) {
if ( listeners==null || listeners.size()==0 ) {
// call legacy v3 func; this calls emitErrorMessage(String msg)
displayRecognitionError(re);
return;
}
for (ANTLRParserListener pl : listeners) pl.error(re);
}
// subclass needs to override these if there are sempreds or actions
// that the ATN interp needs to execute
public boolean sempred(int ruleIndex, int actionIndex) {
return true;
}
/** In lexer, both indexes are same; one action per rule. */
public void action(int ruleIndex, int actionIndex) {
}
}

View File

@ -0,0 +1,6 @@
package org.antlr.v4.runtime;
public class RecognizerSharedState<StreamType> {
public StreamType input;
public RuleContext getContext() { return null; };
}

View File

@ -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.v4.runtime;
import org.antlr.v4.runtime.atn.ATN;
import org.antlr.v4.runtime.atn.ATNState;
import org.stringtemplate.v4.ST;
/** Rules can return start/stop info as well as possible trees and templates.
* Each context knows about invoking context and pointer into ATN so we
* can compute FOLLOW for errors and lookahead.
*
* Used during parse to record stack of rule invocations and during
* ATN simulation to record invoking states.
*/
public class RuleContext {
public static final RuleContext EMPTY = new RuleContext();
/** What context invoked this rule? */
public RuleContext parent;
/** Current ATN state number we are executing.
*
* Not used during ATN simulation; only used during parse that updates
* current location in ATN.
*/
public int s;
/** What state invoked the rule associated with this context?
* The "return address" is the followState of invokingState
* If parent is null, this should be -1.
*/
public int invokingState = -1;
/** Computing the hashCode is very expensive and closureBusy()
* uses it to track when it's seen a state|ctx before to avoid
* infinite loops. As we add new contexts, record the hash code
* as this.invokingState + parent.cachedHashCode. Avoids walking
* up the tree for every hashCode(). Note that this caching works
* because a context is a monotonically growing tree of context nodes
* and nothing on the stack is ever modified...ctx just grows
* or shrinks.
*/
protected int cachedHashCode;
/** 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 */
public ST getTemplate() { return null; }
public RuleContext() {}
// public RuleContext(RuleContext parent) {
// this.parent = parent;
//// while ( p!=null ) {
//// System.out.println();
//// p = p.parent;
//// }
// }
public RuleContext(RuleContext parent, int invokingState, int stateNumber) {
this.parent = parent;
//if ( parent!=null ) System.out.println("invoke "+stateNumber+" from "+parent);
this.s = stateNumber;
this.invokingState = invokingState;
this.cachedHashCode = invokingState;
if ( parent!=null ) {
this.cachedHashCode += parent.cachedHashCode;
}
}
public int hashCode() {
// int h = 0;
// RuleContext p = this;
// while ( p!=null ) {
// h += p.stateNumber;
// p = p.parent;
// }
// return h;
return cachedHashCode; // works with tests; don't recompute.
}
public int depth() {
int n = 0;
RuleContext p = this;
while ( p!=null ) {
p = p.parent;
n++;
}
return n;
}
/** Two contexts are equals() if both have
* same call stack; walk upwards to the root.
* Note that you may be comparing contexts in different alt trees.
*
* The hashCode is cheap as it's computed once upon each context
* push on the stack. Using it to make equals() more efficient.
*/
public boolean equals(Object o) {
RuleContext other = ((RuleContext)o);
if ( this.cachedHashCode != other.cachedHashCode ) {
return false; // can't be same if hash is different
}
if ( this.hashCode() != other.hashCode() ) {
return false; // can't be same if hash is different
}
if ( this==other ) return true;
// System.out.println("comparing "+this+" with "+other);
RuleContext sp = this;
while ( sp!=null && other!=null ) {
if ( sp.invokingState != other.invokingState) return false;
sp = sp.parent;
other = other.parent;
}
if ( !(sp==null && other==null) ) {
return false; // both pointers must be at their roots after walk
}
return true;
}
/** Two contexts conflict() if they are equals() or one is a stack suffix
* of the other. For example, contexts [21 12 $] and [21 9 $] do not
* conflict, but [21 $] and [21 12 $] do conflict. Note that I should
* probably not show the $ in this case. There is a dummy node for each
* stack that just means empty; $ is a marker that's all.
*
* This is used in relation to checking conflicts associated with a
* single NFA state's configurations within a single DFA state.
* If there are configurations s and t within a DFA state such that
* s.state=t.state && s.alt != t.alt && s.ctx conflicts t.ctx then
* the DFA state predicts more than a single alt--it's nondeterministic.
* Two contexts conflict if they are the same or if one is a suffix
* of the other.
*
* When comparing contexts, if one context has a stack and the other
* does not then they should be considered the same context. The only
* way for an NFA state p to have an empty context and a nonempty context
* is the case when closure falls off end of rule without a call stack
* and re-enters the rule with a context. This resolves the issue I
* discussed with Sriram Srinivasan Feb 28, 2005 about not terminating
* fast enough upon nondeterminism.
*/
public boolean conflictsWith(RuleContext other) {
return this.suffix(other); // || this.equals(other);
}
/** [$] suffix any context
* [21 $] suffix [21 12 $]
* [21 12 $] suffix [21 $]
* [21 18 $] suffix [21 18 12 9 $]
* [21 18 12 9 $] suffix [21 18 $]
* [21 12 $] not suffix [21 9 $]
*
* Example "[21 $] suffix [21 12 $]" means: rule r invoked current rule
* from state 21. Rule s invoked rule r from state 12 which then invoked
* current rule also via state 21. While the context prior to state 21
* is different, the fact that both contexts emanate from state 21 implies
* that they are now going to track perfectly together. Once they
* converged on state 21, there is no way they can separate. In other
* words, the prior stack state is not consulted when computing where to
* go in the closure operation. ?$ and ??$ are considered the same stack.
* If ? is popped off then $ and ?$ remain; they are now an empty and
* nonempty context comparison. So, if one stack is a suffix of
* another, then it will still degenerate to the simple empty stack
* comparison case.
*/
protected boolean suffix(RuleContext other) {
RuleContext sp = this;
// if one of the contexts is empty, it never enters loop and returns true
while ( sp.parent!=null && other.parent!=null ) {
if ( sp.invokingState != other.invokingState ) {
return false;
}
sp = sp.parent;
other = other.parent;
}
//System.out.println("suffix");
return true;
}
/** A context is empty if there is no invoking state; meaning nobody call
* current context.
*/
public boolean isEmpty() {
return invokingState == -1;
}
public String toString() {
return toString(null);
}
public String toString(BaseRecognizer recog) {
StringBuffer buf = new StringBuffer();
RuleContext p = this;
buf.append("[");
while ( p != null ) {
if ( recog!=null ) {
ATN atn = recog.getATN();
ATNState s = atn.states.get(p.s);
String ruleName = recog.getRuleNames()[s.ruleIndex];
buf.append(ruleName);
if ( p.parent != null ) buf.append(" ");
// ATNState invoker = atn.states.get(ctx.invokingState);
// RuleTransition rt = (RuleTransition)invoker.transition(0);
// buf.append(recog.getRuleNames()[rt.target.ruleIndex]);
}
else {
if ( !p.isEmpty() ) buf.append(p.invokingState);
if ( p.parent != null && !p.parent.isEmpty() ) buf.append(" ");
}
p = p.parent;
}
buf.append("]");
return buf.toString();
}
}

View File

@ -0,0 +1,84 @@
package org.antlr.v4.runtime;
/*
[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.
*/
public interface Token {
/** imaginary tree navigation type; traverse "get child" link */
public static final int DOWN = 1;
/** imaginary tree navigation type; finish with a child list */
public static final int UP = 2;
public static final int MIN_TOKEN_TYPE = UP+1;
public static final int EOF = CharStream.EOF;
public static final int INVALID_TYPE = 0;
public static final Token INVALID_TOKEN = new CommonToken(INVALID_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);
}

View File

@ -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.v4.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();
}
}

View File

@ -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.v4.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();
}

View File

@ -0,0 +1,74 @@
package org.antlr.v4.runtime;
/*
[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.
*/
/** 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);
}

View File

@ -0,0 +1,50 @@
/*
[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.v4.runtime;
/** An extra token while parsing a TokenStream */
public class UnwantedTokenException extends MismatchedTokenException {
/** Used for remote debugger deserialization */
public UnwantedTokenException() {;}
public UnwantedTokenException(BaseRecognizer recognizer, IntStream input, int expecting) {
super(recognizer, input, expecting);
}
public Token getUnexpectedToken() {
return token;
}
public String toString() {
String exp = ", expected "+expecting;
if ( token==null ) {
return "UnwantedTokenException(found="+null+exp+")";
}
return "UnwantedTokenException(found="+token.getText()+exp+")";
}
}

View File

@ -0,0 +1,107 @@
package org.antlr.v4.runtime.atn;
import org.antlr.v4.analysis.LL1Analyzer;
import org.antlr.v4.automata.ATNSerializer;
import org.antlr.v4.misc.*;
import org.antlr.v4.runtime.RuleContext;
import org.antlr.v4.tool.*;
import java.util.*;
/** */
// TODO: split into runtime / analysis time?
public class ATN {
public static final int INVALID_ALT_NUMBER = -1;
public static final int INVALID_DECISION_NUMBER = -1;
public Grammar g;
public List<ATNState> states = new ArrayList<ATNState>();
public List<ATNState> rules = new ArrayList<ATNState>(); // rule index to start state
/** Each subrule/rule is a decision point and we must track them so we
* can go back later and build DFA predictors for them. This includes
* all the rules, subrules, optional blocks, ()+, ()* etc...
*/
public List<DecisionState> decisionToATNState = new ArrayList<DecisionState>();
public Map<Rule, RuleStartState> ruleToStartState = new LinkedHashMap<Rule, RuleStartState>();
public Map<Rule, RuleStopState> ruleToStopState = new LinkedHashMap<Rule, RuleStopState>();
public Map<String, TokensStartState> modeNameToStartState =
new LinkedHashMap<String, TokensStartState>();
// runtime
public int grammarType; // ANTLRParser.LEXER, ...
public List<TokensStartState> modeToStartState = new ArrayList<TokensStartState>();
// runtime for lexer
public List<Integer> ruleToTokenType = new ArrayList<Integer>();
public List<Integer> ruleToActionIndex = new ArrayList<Integer>();
public int maxTokenType;
int stateNumber = 0;
// TODO: for runtime all we need is states, decisionToATNState I think
public ATN(Grammar g) {
this.g = g;
if ( g.isLexer() ) {
ruleToTokenType.add(0); // no rule index 0
ruleToActionIndex.add(0); // no action index 0
for (Rule r : g.rules.values()) {
ruleToTokenType.add(g.getTokenType(r.name));
if ( r.actionIndex>0 ) ruleToActionIndex.add(r.actionIndex);
else ruleToActionIndex.add(0);
}
}
}
/** Used for runtime deserialization of ATNs from strings */
public ATN() { }
public IntervalSet nextTokens(RuleContext ctx) {
return nextTokens(ctx.s, ctx);
}
public IntervalSet nextTokens(int stateNumber, RuleContext ctx) {
ATNState s = states.get(stateNumber);
if ( s == null ) return null;
LL1Analyzer anal = new LL1Analyzer(this);
IntervalSet next = anal.LOOK(s, ctx);
return next;
}
public void addState(ATNState state) {
state.atn = this;
states.add(state);
state.stateNumber = stateNumber++;
}
public int defineDecisionState(DecisionState s) {
decisionToATNState.add(s);
s.decision = decisionToATNState.size()-1;
return s.decision;
}
public int getNumberOfDecisions() {
return decisionToATNState.size();
}
/** Used by Java target to encode short/int array as chars in string. */
public String getSerializedAsString() {
return new String(Utils.toCharArray(getSerialized()));
}
public List<Integer> getSerialized() {
return new ATNSerializer(this).serialize();
}
public char[] getSerializedAsChars() {
return Utils.toCharArray(new ATNSerializer(this).serialize());
}
public String getDecoded() {
return new ATNSerializer(this).decode(Utils.toCharArray(getSerialized()));
}
}

View File

@ -0,0 +1,151 @@
package org.antlr.v4.runtime.atn;
import org.antlr.v4.analysis.ATNConfig;
import org.antlr.v4.misc.*;
import org.antlr.v4.parse.ANTLRParser;
import org.antlr.v4.runtime.dfa.*;
import org.antlr.v4.tool.*;
import java.util.*;
public abstract class ATNInterpreter {
/** Must distinguish between missing edge and edge we know leads nowhere */
public static DFAState ERROR;
public ATN atn;
protected ATNConfig prevAccept; // TODO Move down? used to avoid passing int down and back up in method calls
protected int prevAcceptIndex = -1;
static {
ERROR = new DFAState(new OrderedHashSet<ATNConfig>());
ERROR.stateNumber = Integer.MAX_VALUE;
}
public ATNInterpreter(ATN atn) {
this.atn = atn;
}
public static ATN deserialize(char[] data) {
ATN atn = new ATN();
List<IntervalSet> sets = new ArrayList<IntervalSet>();
int p = 0;
atn.grammarType = toInt(data[p++]);
atn.maxTokenType = toInt(data[p++]);
int nstates = toInt(data[p++]);
for (int i=1; i<=nstates; i++) {
int stype = toInt(data[p++]);
if ( stype==0 ) continue; // ignore bad type of states
ATNState s = stateFactory(stype, i);
s.ruleIndex = toInt(data[p++]);
atn.addState(s);
}
int nrules = toInt(data[p++]);
for (int i=1; i<=nrules; i++) {
int s = toInt(data[p++]);
ATNState startState = atn.states.get(s);
atn.rules.add(startState);
if ( atn.ruleToTokenType.size()==0 ) atn.ruleToTokenType.add(0); // we're indexed from 1
if ( atn.ruleToActionIndex.size()==0 ) atn.ruleToActionIndex.add(0); // we're indexed from 1
if ( atn.grammarType==ANTLRParser.LEXER ) {
int tokenType = toInt(data[p++]);
atn.ruleToTokenType.add(tokenType);
int actionIndex = toInt(data[p++]);
atn.ruleToActionIndex.add(actionIndex);
}
else {
p += 2;
}
}
int nmodes = toInt(data[p++]);
for (int i=0; i<nmodes; i++) {
int s = toInt(data[p++]);
atn.modeToStartState.add((TokensStartState)atn.states.get(s));
}
int nsets = toInt(data[p++]);
for (int i=1; i<=nsets; i++) {
int nintervals = toInt(data[p]);
p++;
IntervalSet set = new IntervalSet();
sets.add(set);
for (int j=1; j<=nintervals; j++) {
set.add(toInt(data[p]), toInt(data[p + 1]));
p += 2;
}
}
int nedges = toInt(data[p++]);
for (int i=1; i<=nedges; i++) {
int src = toInt(data[p]);
int trg = toInt(data[p+1]);
int ttype = toInt(data[p+2]);
int arg1 = toInt(data[p+3]);
int arg2 = toInt(data[p+4]);
Transition trans = edgeFactory(atn, ttype, src, trg, arg1, arg2, sets);
ATNState srcState = atn.states.get(src);
srcState.addTransition(trans);
p += 5;
}
int ndecisions = toInt(data[p++]);
for (int i=1; i<=ndecisions; i++) {
int s = toInt(data[p++]);
DecisionState decState = (DecisionState)atn.states.get(s);
atn.decisionToATNState.add((DecisionState) decState);
decState.decision = i-1;
}
// System.out.println(atn.getDecoded());
return atn;
}
public static int toInt(char c) {
return c==65535 ? -1 : c;
}
public static Transition edgeFactory(ATN atn,
int type, int src, int trg,
int arg1, int arg2,
List<IntervalSet> sets)
{
ATNState target = atn.states.get(trg);
switch (type) {
case Transition.EPSILON : return new EpsilonTransition(target);
case Transition.RANGE : return new RangeTransition(arg1, arg2, target);
case Transition.RULE : return new RuleTransition(arg1, atn.states.get(arg1), target);
case Transition.PREDICATE : return new PredicateTransition(target, arg1, arg2);
case Transition.ATOM : return new AtomTransition(arg1, target);
case Transition.ACTION : return new ActionTransition(target, arg1, arg2);
case Transition.FORCED_ACTION : return new ActionTransition(target, arg1, arg2);
case Transition.SET : return new SetTransition(null, sets.get(arg1), target);
case Transition.NOT_ATOM : return new NotAtomTransition(arg1, target);
case Transition.NOT_SET : return new NotSetTransition(null, sets.get(arg1), target);
case Transition.WILDCARD : return new WildcardTransition(target);
}
return null;
}
public static ATNState stateFactory(int type, int stateNumber) {
ATNState s = null;
switch (type) {
case ATNState.BASIC : s = new ATNState(); break;
case ATNState.RULE_START : s = new RuleStartState(); break;
case ATNState.BLOCK_START : s = new BlockStartState(); break;
case ATNState.PLUS_BLOCK_START : s = new PlusBlockStartState(); break;
case ATNState.STAR_BLOCK_START : s = new StarBlockStartState(); break;
case ATNState.TOKEN_START : s = new TokensStartState(); break;
case ATNState.RULE_STOP : s = new RuleStopState(); break;
case ATNState.BLOCK_END : s = new BlockEndState(); break;
case ATNState.STAR_LOOP_BACK : s = new StarLoopbackState(); break;
case ATNState.PLUS_LOOP_BACK : s = new PlusLoopbackState(); break;
}
s.stateNumber = stateNumber;
return s;
}
public static void dump(DFA dfa, Grammar g) {
DOTGenerator dot = new DOTGenerator(g);
String output = dot.getDOT(dfa, false);
System.out.println(output);
}
public static void dump(DFA dfa) {
dump(dfa, null);
}
}

View File

@ -0,0 +1,75 @@
package org.antlr.v4.runtime.atn;
/** Identical to ANTLR's static grammar analysis ATNContext object */
public class ATNStack {
public static final ATNStack EMPTY = new ATNStack(null, -1);
public ATNStack parent;
/** The ATN state following state that invoked another rule's start state
* is recorded on the rule invocation context stack.
*/
public int returnAddr;
/** Computing the hashCode is very expensive and ATN.addToClosure()
* uses it to track when it's seen a state|ctx before to avoid
* infinite loops. As we add new contexts, record the hash code
* as this + parent.cachedHashCode. Avoids walking
* up the tree for every hashCode(). Note that this caching works
* because a context is a monotonically growing tree of context nodes
* and nothing on the stack is ever modified...ctx just grows
* or shrinks.
*/
protected int cachedHashCode;
public ATNStack(ATNStack parent, int returnAddr) {
this.parent = parent;
this.returnAddr = returnAddr;
if ( returnAddr >= 0 ) {
this.cachedHashCode = returnAddr;
}
if ( parent!=null ) {
this.cachedHashCode += parent.cachedHashCode;
}
}
public int hashCode() { return cachedHashCode; }
/** Two contexts are equals() if both have
* same call stack; walk upwards to the root.
* Recall that the root sentinel node has no parent.
* Note that you may be comparing contextsv in different alt trees.
*/
public boolean equals(Object o) {
ATNStack other = ((ATNStack)o);
if ( this.cachedHashCode != other.cachedHashCode ) {
return false; // can't be same if hash is different
}
if ( this==other ) return true;
// System.out.println("comparing "+this+" with "+other);
ATNStack sp = this;
while ( sp.parent!=null && other.parent!=null ) {
if ( sp.returnAddr != other.returnAddr) return false;
sp = sp.parent;
other = other.parent;
}
if ( !(sp.parent==null && other.parent==null) ) {
return false; // both pointers must be at their roots after walk
}
return true;
}
public String toString() {
StringBuffer buf = new StringBuffer();
ATNStack sp = this;
buf.append("[");
while ( sp.parent!=null ) {
buf.append(sp.returnAddr);
buf.append(" ");
sp = sp.parent;
}
buf.append("$]");
return buf.toString();
}
}

View File

@ -0,0 +1,111 @@
package org.antlr.v4.runtime.atn;
import org.antlr.v4.tool.*;
import java.util.*;
public class ATNState {
// constants for serialization
public static final int BASIC = 1;
public static final int RULE_START = 2;
public static final int BLOCK_START = 3;
public static final int PLUS_BLOCK_START = 4;
public static final int STAR_BLOCK_START = 5;
public static final int TOKEN_START = 6;
public static final int RULE_STOP = 7;
public static final int BLOCK_END = 8;
public static final int STAR_LOOP_BACK = 9;
public static final int PLUS_LOOP_BACK = 10;
public static String[] serializationNames = {
"INVALID",
"BASIC",
"RULE_START",
"BLOCK_START",
"PLUS_BLOCK_START",
"STAR_BLOCK_START",
"TOKEN_START",
"RULE_STOP",
"BLOCK_END",
"STAR_LOOP_BACK",
"PLUS_LOOP_BACK",
};
public static Map<Class, Integer> serializationTypes =
new HashMap<Class, Integer>() {{
put(ATNState.class, BASIC);
put(RuleStartState.class, RULE_START);
put(BlockStartState.class, BLOCK_START);
put(PlusBlockStartState.class, PLUS_BLOCK_START);
put(StarBlockStartState.class, STAR_BLOCK_START);
put(TokensStartState.class, TOKEN_START);
put(RuleStopState.class, RULE_STOP);
put(BlockEndState.class, BLOCK_END);
put(PlusLoopbackState.class, PLUS_LOOP_BACK);
put(StarLoopbackState.class, STAR_LOOP_BACK);
}};
public static final int INVALID_STATE_NUMBER = -1;
public int stateNumber = INVALID_STATE_NUMBER;
public Rule rule;
// TODO: split runtime / from analysis or cleanup
public int ruleIndex; // at runtime, we don't have Rule objects
/** Which ATN are we in? */
public ATN atn = null;
/** ATN state is associated with which node in AST? */
public GrammarAST ast;
public Transition transition;
/** For o-A->o type ATN tranitions, record the label that leads to this
* state. Useful for creating rich error messages when we find
* insufficiently (with preds) covered states.
*/
public Transition incidentTransition;
@Override
public int hashCode() { return stateNumber; }
@Override
public boolean equals(Object o) {
// are these states same object?
if ( o instanceof ATNState) return stateNumber==((ATNState)o).stateNumber;
return false;
}
@Override
public String toString() {
return String.valueOf(stateNumber);
}
public int getNumberOfTransitions() {
if ( transition!=null ) return 1;
return 0;
}
public void addTransition(Transition e) {
if ( transition!=null ) throw new IllegalArgumentException("only one transition");
transition = e;
}
public Transition transition(int i) {
if ( i>0 ) throw new IllegalArgumentException("only one transition");
return transition;
}
public boolean onlyHasEpsilonTransitions() {
return transition!=null && transition.isEpsilon();
}
public void setTransition(int i, Transition e) {
if ( i>0 ) throw new IllegalArgumentException("only one transition");
transition = e;
}
public void setRule(Rule r) {
this.rule = r;
if ( r!=null ) this.ruleIndex = r.index;
}
}

View File

@ -0,0 +1,37 @@
package org.antlr.v4.runtime.atn;
import org.antlr.v4.tool.*;
public class ActionTransition extends Transition {
public int ruleIndex;
public int actionIndex = -1;
public GrammarAST actionAST;
public ActionTransition(GrammarAST actionAST, ATNState target) {
super(target);
this.actionAST = actionAST;
}
public ActionTransition(ATNState target, int ruleIndex, int actionIndex) {
super(target);
this.ruleIndex = ruleIndex;
this.actionIndex = actionIndex;
}
public boolean isEpsilon() {
return true; // we are to be ignored by analysis 'cept for predicates
}
public int compareTo(Object o) {
return 0;
}
public String toString() {
if ( actionAST!=null ) return "{"+actionAST.getText()+"}";
return "action_"+ruleIndex+":"+actionIndex;
}
public String toString(Grammar g) {
return toString();
}
}

View File

@ -0,0 +1,53 @@
package org.antlr.v4.runtime.atn;
import org.antlr.v4.misc.IntervalSet;
import org.antlr.v4.tool.Grammar;
/** TODO: make all transitions sets? no, should remove set edges */
public class AtomTransition extends Transition {
/** The token type or character value; or, signifies special label. */
public int label;
public AtomTransition(int label, ATNState target) {
this.label = label;
this.target = target;
}
public AtomTransition(ATNState target) {
super(target);
}
public IntervalSet label() { return IntervalSet.of(label); }
public int hashCode() { return label; }
public boolean equals(Object o) {
if ( o==null ) return false;
if ( this == o ) return true; // equals if same object
if ( o.getClass() == SetTransition.class ) {
return IntervalSet.of(label).equals(o);
}
return label!=((AtomTransition)o).label;
}
// public boolean intersect(Label other) {
// if ( other.getClass() == AtomTransition.class ) {
// return label==((AtomTransition)other).label;
// }
// return ((SetLabel)other).label.member(this.label);
// }
public int compareTo(Object o) {
return this.label-((AtomTransition)o).label;
}
@Override
public String toString(Grammar g) {
if (g!=null ) return g.getTokenDisplayName(label);
return toString();
}
public String toString() {
return String.valueOf(label);
}
}

View File

@ -0,0 +1,5 @@
package org.antlr.v4.runtime.atn;
/** Terminal node of a simple (a|b|c) block */
public class BlockEndState extends ATNState {
}

View File

@ -0,0 +1,6 @@
package org.antlr.v4.runtime.atn;
/** The start of a regular (...) block */
public class BlockStartState extends DecisionState {
public BlockEndState endState;
}

View File

@ -0,0 +1,32 @@
package org.antlr.v4.runtime.atn;
import java.util.*;
public class DecisionState extends ATNState {
public static final int INITIAL_NUM_TRANSITIONS = 4;
/** Track the transitions emanating from this ATN state. */
public List<Transition> transitions = new ArrayList<Transition>(INITIAL_NUM_TRANSITIONS);
public int decision;
@Override
public int getNumberOfTransitions() { return transitions.size(); }
@Override
public void addTransition(Transition e) { transitions.add(e); }
public void addTransitionFirst(Transition e) { transitions.add(0, e); }
@Override
public Transition transition(int i) { return transitions.get(i); }
@Override
public boolean onlyHasEpsilonTransitions() { return true; }
@Override
public void setTransition(int i, Transition e) {
transitions.set(i, e);
}
}

View File

@ -0,0 +1,18 @@
package org.antlr.v4.runtime.atn;
import org.antlr.v4.tool.Grammar;
public class EpsilonTransition extends Transition {
public EpsilonTransition(ATNState target) { super(target); }
public boolean isEpsilon() { return true; }
public int compareTo(Object o) {
return 0;
}
@Override
public String toString(Grammar g) {
return "epsilon";
}
}

View File

@ -0,0 +1,412 @@
package org.antlr.v4.runtime.atn;
import org.antlr.v4.analysis.ATNConfig;
import org.antlr.v4.misc.OrderedHashSet;
import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.dfa.*;
/** "dup" of ParserInterpreter */
public class LexerInterpreter extends ATNInterpreter {
public static boolean debug = false;
public static boolean dfa_debug = false;
public static final int NUM_EDGES = 255;
protected Lexer recog;
protected DFA[] dfa;
protected int mode = Lexer.DEFAULT_MODE;
public static int ATN_failover = 0;
public static int match_calls = 0;
public LexerInterpreter(ATN atn) {
this(null, atn);
}
public LexerInterpreter(Lexer recog, ATN atn) {
super(atn);
dfa = new DFA[atn.modeToStartState.size()];
for (int i=0; i<atn.modeToStartState.size(); i++) {
dfa[i] = new DFA(atn.modeToStartState.get(i));
}
this.recog = recog;
}
public int match(CharStream input, int mode) {
match_calls++;
this.mode = mode;
if ( dfa[mode].s0==null ) {
return matchATN(input);
}
else {
return exec(input, dfa[mode].s0);
}
}
public int matchATN(CharStream input) {
ATNState startState = atn.modeToStartState.get(mode);
if ( debug ) System.out.println("mode "+ mode +" start: "+startState);
OrderedHashSet<ATNConfig> s0_closure = computeStartState(input, startState);
int old_mode = mode;
dfa[mode].s0 = addDFAState(s0_closure);
int predict = exec(input, s0_closure);
if ( debug ) System.out.println("DFA after matchATN: "+dfa[old_mode].toLexerString());
return predict;
}
public int exec(CharStream input, DFAState s0) {
if ( dfa_debug ) System.out.println("DFA[mode "+recog.state.mode+"] exec LA(1)=="+
(char)input.LA(1));
//System.out.println("DFA start of execDFA: "+dfa[mode].toLexerString());
int prevAcceptMarker = -1;
DFAState prevAcceptState = null;
DFAState s = s0;
int startIndex = input.index();
int t = input.LA(1);
if ( t==CharStream.EOF ) return -1; // TODO: how to match EOF in lexer rule?
loop:
while ( true ) {
if ( dfa_debug ) System.out.println("state "+s.stateNumber+" LA(1)=="+(char)t);
if ( s.isAcceptState ) {
if ( dfa_debug ) System.out.println("accept; predict "+s.prediction+
" in state "+s.stateNumber);
prevAcceptState = s;
prevAcceptMarker = input.index();
// keep going unless we're at EOF; check if something else could match
if ( t==CharStream.EOF ) break;
}
// if no edge, pop over to ATN interpreter, update DFA and return
if ( s.edges == null || t >= s.edges.length || s.edges[t] == null ) {
if ( dfa_debug ) System.out.println("no edge for "+(char)t);
int ttype = -1;
try {
if ( dfa_debug ) {
System.out.println("ATN exec upon "+
input.substring(startIndex,input.index())+
" at DFA state "+s.stateNumber+" = "+s.configs);
}
ATN_failover++;
ttype = exec(input, s.configs);
}
catch (LexerNoViableAltException nvae) {
addDFAEdge(s, t, ERROR);
}
if ( dfa_debug ) {
System.out.println("back from DFA update, ttype="+ttype+
", dfa[mode "+mode+"]=\n"+dfa[mode].toLexerString());
}
if ( ttype==-1 ) {
addDFAEdge(s, t, ERROR);
break loop; // dead end; no where to go, fall back on prev if any
}
// action already executed
return ttype; // we've updated DFA, exec'd action, and have our deepest answer
}
DFAState target = s.edges[t];
if ( target == ERROR ) break;
s = target;
input.consume();
t = input.LA(1);
}
if ( prevAcceptState==null ) {
System.out.println("!!! no viable alt in dfa");
return -1;
}
if ( recog!=null ) {
if ( dfa_debug ) {
System.out.println("ACTION "+
recog.getRuleNames()[prevAcceptState.ruleIndex]+
":"+atn.ruleToActionIndex.get(prevAcceptState.ruleIndex));
}
recog.action(prevAcceptState.ruleIndex, atn.ruleToActionIndex.get(prevAcceptState.ruleIndex));
}
input.seek(prevAcceptMarker);
return prevAcceptState.prediction;
}
public int exec(CharStream input, OrderedHashSet<ATNConfig> s0) {
//System.out.println("enter exec index "+input.index()+" from "+s0);
OrderedHashSet<ATNConfig> closure = new OrderedHashSet<ATNConfig>();
closure.addAll(s0);
if ( debug ) System.out.println("start state closure="+closure);
OrderedHashSet<ATNConfig> reach = new OrderedHashSet<ATNConfig>();
ATNConfig prevAccept = null;
int prevAcceptIndex = -1;
int t = input.LA(1);
if ( t==Token.EOF ) return Token.EOF;
do { // while more work
if ( debug ) System.out.println("in reach starting closure: " + closure);
for (int ci=0; ci<closure.size(); ci++) { // TODO: foreach
ATNConfig c = closure.get(ci);
if ( debug ) System.out.println("testing "+getTokenName(t)+" at "+c.toString(recog, true));
if ( c.state instanceof RuleStopState ) {
if ( debug ) {
System.out.println("in reach we hit accept state "+c+" index "+
input.index()+", reach="+reach+
", prevAccept="+prevAccept+", prevIndex="+prevAcceptIndex);
}
if ( input.index() > prevAcceptIndex ) {
// will favor prev accept at same index so "int" is keyword not ID
prevAccept = c;
prevAcceptIndex = input.index();
}
// move to next char, looking for longer match
// (we continue processing if there are states in reach)
}
int n = c.state.getNumberOfTransitions();
for (int ti=0; ti<n; ti++) { // for each transition
Transition trans = c.state.transition(ti);
ATNState target = getReachableTarget(trans, t);
if ( target!=null ) {
closure(new ATNConfig(c, target), reach);
}
}
}
if ( reach.size()==0 ) {
// we reached closure state for sure, make sure it's defined.
// worst case, we define s0 from start state configs.
DFAState from = addDFAState(closure);
// we got nowhere on t, don't throw out this knowledge; it'd
// cause a failover from DFA later.
if ( t!=Token.EOF ) addDFAEdge(from, t, ERROR);
break;
}
input.consume();
addDFAEdge(closure, t, reach);
t = input.LA(1);
// swap to avoid reallocating space
OrderedHashSet<ATNConfig> tmp = reach;
reach = closure;
closure = tmp;
reach.clear();
} while ( true );
if ( prevAccept==null ) {
if ( t==Token.EOF ) {
System.out.println("EOF in token at input index "+input.index());
return Token.EOF;
}
// System.out.println("no viable token at input "+getTokenName(input.LA(1))+", index "+input.index());
throw new LexerNoViableAltException(recog, input, closure); // TODO: closure is empty
}
if ( debug ) System.out.println("ACCEPT " + prevAccept.toString(recog, true) + " index " + prevAcceptIndex);
int ruleIndex = prevAccept.state.ruleIndex;
int ttype = atn.ruleToTokenType.get(ruleIndex);
if ( debug ) {
if ( recog!=null ) System.out.println("ACTION "+recog.getRuleNames()[ruleIndex]+":"+ruleIndex);
else System.out.println("ACTION "+ruleIndex+":"+ruleIndex);
}
int actionIndex = atn.ruleToActionIndex.get(ruleIndex);
if ( actionIndex>0 ) recog.action(ruleIndex, actionIndex);
return ttype;
}
public ATNState getReachableTarget(Transition trans, int t) {
if ( trans instanceof AtomTransition ) {
AtomTransition at = (AtomTransition)trans;
boolean not = trans instanceof NotAtomTransition;
if ( !not && at.label == t || not && at.label!=t ) {
if ( debug ) {
System.out.println("match "+getTokenName(at.label));
}
return at.target;
}
}
else if ( trans.getClass() == RangeTransition.class ) {
RangeTransition rt = (RangeTransition)trans;
if ( t>=rt.from && t<=rt.to ) {
if ( debug ) System.out.println("match range "+rt.toString(atn.g));
return rt.target;
}
}
else if ( trans instanceof SetTransition ) {
SetTransition st = (SetTransition)trans;
boolean not = trans instanceof NotSetTransition;
if ( !not && st.label.member(t) || not && !st.label.member(t) ) {
if ( debug ) System.out.println("match set "+st.label.toString(atn.g));
return st.target;
}
}
else if ( trans instanceof WildcardTransition && t!=Token.EOF ) {
return trans.target;
}
return null;
}
/* TODO: use if we need nongreedy
public void deleteConfigsForAlt(OrderedHashSet<ATNConfig> closure, int ci, int alt) {
int j=ci+1;
while ( j<closure.size() ) {
ATNConfig c = closure.get(j);
if ( c.alt == alt ) {
System.out.println("kill "+c);
closure.remove(j);
}
else j++;
}
}
*/
protected OrderedHashSet<ATNConfig> computeStartState(IntStream input,
ATNState p)
{
RuleContext initialContext = RuleContext.EMPTY;
OrderedHashSet<ATNConfig> configs = new OrderedHashSet<ATNConfig>();
for (int i=0; i<p.getNumberOfTransitions(); i++) {
ATNState target = p.transition(i).target;
ATNConfig c = new ATNConfig(target, i+1, initialContext);
closure(c, configs);
}
return configs;
}
protected void closure(ATNConfig config, OrderedHashSet<ATNConfig> configs) {
if ( debug ) {
System.out.println("closure("+config.toString(recog, true)+")");
}
// TODO? if ( closure.contains(t) ) return;
if ( config.state instanceof RuleStopState ) {
if ( debug ) System.out.println("closure at rule stop "+config);
if ( config.context == null || config.context.isEmpty() ) {
configs.add(config);
return;
}
RuleContext newContext = config.context.parent; // "pop" invoking state
ATNState invokingState = atn.states.get(config.context.invokingState);
RuleTransition rt = (RuleTransition)invokingState.transition(0);
ATNState retState = rt.followState;
ATNConfig c = new ATNConfig(retState, config.alt, newContext);
closure(c, configs);
return;
}
// optimization
if ( !config.state.onlyHasEpsilonTransitions() ) {
configs.add(config);
}
ATNState p = config.state;
for (int i=0; i<p.getNumberOfTransitions(); i++) {
Transition t = p.transition(i);
ATNConfig c = null;
if ( t.getClass() == RuleTransition.class ) {
RuleContext newContext =
new RuleContext(config.context, p.stateNumber, t.target.stateNumber);
c = new ATNConfig(config, t.target, newContext);
}
else if ( t.getClass() == PredicateTransition.class ) {
PredicateTransition pt = (PredicateTransition)t;
if ( recog.sempred(pt.ruleIndex, pt.predIndex) ) {
c = new ATNConfig(config, t.target);
c.traversedPredicate = true;
}
}
// ignore actions; just exec one per rule upon accept
else if ( t.getClass() == ActionTransition.class ) {
c = new ATNConfig(config, t.target);
}
// TODO: forced actions?
else if ( t.isEpsilon() ) {
c = new ATNConfig(config, t.target);
}
if ( c!=null ) closure(c, configs);
}
}
protected void addDFAEdge(OrderedHashSet<ATNConfig> p,
int t,
OrderedHashSet<ATNConfig> q)
{
// System.out.println("MOVE "+p+" -> "+q+" upon "+getTokenName(t));
DFAState from = addDFAState(p);
DFAState to = addDFAState(q);
addDFAEdge(from, t, to);
}
protected void addDFAEdge(DFAState p, int t, DFAState q) {
if ( p==null ) return;
if ( p.edges==null ) {
p.edges = new DFAState[NUM_EDGES+1]; // TODO: make adaptive
}
p.edges[t] = q; // connect
}
/** Add a new DFA state if there isn't one with this set of
configurations already. This method also detects the first
configuration containing an ATN rule stop state. Later, when
traversing the DFA, we will know which rule to accept. Also, we
detect if any of the configurations derived from traversing a
semantic predicate. If so, we cannot add a DFA state for this
because the DFA would not test the predicate again in the
future. Rather than creating collections of semantic predicates
like v3 and testing them on prediction, v4 will test them on the
fly all the time using the ATN not the DFA. This is slower but
semantically it's not use that often. One of the key elements to
this predicate mechanism is not adding DFA states that see
predicates immediately afterwards in the ATN. For example,
a : ID {p1}? | ID {p2}? ;
should create the start state for rule 'a' (to save start state
competition), but should not create target of ID state. The
collection of ATN states the following ID references includes
states reached by traversing predicates. Since this is when we
test them, we cannot cash the DFA state target of ID.
*/
protected DFAState addDFAState(OrderedHashSet<ATNConfig> configs) {
DFAState proposed = new DFAState(configs);
DFAState existing = dfa[mode].states.get(proposed);
if ( existing!=null ) return existing;
DFAState newState = proposed;
ATNConfig firstConfigWithRuleStopState = null;
boolean traversedPredicate = false;
for (ATNConfig c : configs) {
if ( firstConfigWithRuleStopState==null &&
c.state instanceof RuleStopState )
{
firstConfigWithRuleStopState = c;
}
if ( c.traversedPredicate ) traversedPredicate = true;
}
if ( firstConfigWithRuleStopState!=null ) {
newState.isAcceptState = true;
newState.ruleIndex = firstConfigWithRuleStopState.state.ruleIndex;
newState.prediction = atn.ruleToTokenType.get(newState.ruleIndex);
}
if ( traversedPredicate ) return null; // cannot cache
newState.stateNumber = dfa[mode].states.size();
newState.configs = new OrderedHashSet<ATNConfig>();
newState.configs.addAll(configs);
dfa[mode].states.put(newState, newState);
return newState;
}
public DFA getDFA(int mode) {
return dfa[mode];
}
public String getTokenName(int t) {
if ( t==-1 ) return "EOF";
//if ( atn.g!=null ) return atn.g.getTokenDisplayName(t);
return "'"+(char)t+"'";
}
}

View File

@ -0,0 +1,17 @@
package org.antlr.v4.runtime.atn;
import org.antlr.v4.tool.Grammar;
public class NotAtomTransition extends AtomTransition {
public NotAtomTransition(int label, ATNState target) {
super(label, target);
}
public NotAtomTransition(ATNState target) {
super(target);
}
@Override
public String toString(Grammar g) {
return '~'+super.toString(g);
}
}

View File

@ -0,0 +1,20 @@
package org.antlr.v4.runtime.atn;
import org.antlr.v4.misc.IntervalSet;
import org.antlr.v4.tool.Grammar;
import org.antlr.v4.tool.GrammarAST;
public class NotSetTransition extends SetTransition {
public NotSetTransition(GrammarAST ast, IntervalSet label, ATNState target) {
super(ast, label, target);
}
public NotSetTransition(ATNState target) {
super(target);
}
@Override
public String toString(Grammar g) {
return '~'+super.toString(g);
}
}

View File

@ -0,0 +1,632 @@
package org.antlr.v4.runtime.atn;
import org.antlr.runtime.CharStream;
import org.antlr.v4.analysis.ATNConfig;
import org.antlr.v4.misc.*;
import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.dfa.*;
import org.antlr.v4.tool.DOTGenerator;
import org.stringtemplate.v4.misc.MultiMap;
import java.util.*;
public class ParserInterpreter extends ATNInterpreter {
public static boolean debug = false;
public static boolean dfa_debug = false;
public static int ATN_failover = 0;
public static int predict_calls = 0;
protected BaseRecognizer parser;
public Map<RuleContext, DFA[]> ctxToDFAs;
public Map<RuleContext, DFA>[] decisionToDFAPerCtx; // TODO: USE THIS ONE
public DFA[] decisionToDFA;
protected boolean userWantsCtxSensitive = false;
protected Set<ATNConfig> closureBusy = new HashSet<ATNConfig>();
public ParserInterpreter(ATN atn) {
super(atn);
ctxToDFAs = new HashMap<RuleContext, DFA[]>();
decisionToDFA = new DFA[atn.getNumberOfDecisions()];
}
public ParserInterpreter(BaseRecognizer parser, ATN atn) {
super(atn);
this.parser = parser;
ctxToDFAs = new HashMap<RuleContext, DFA[]>();
decisionToDFA = new DFA[atn.getNumberOfDecisions()+1];
DOTGenerator dot = new DOTGenerator(null);
// System.out.println(dot.getDOT(atn.rules.get(0), parser.getRuleNames()));
// System.out.println(dot.getDOT(atn.rules.get(1), parser.getRuleNames()));
}
public int adaptivePredict(TokenStream input, int decision, RuleContext ctx) {
predict_calls++;
DFA dfa = decisionToDFA[decision];
if ( dfa==null || dfa.s0==null ) {
ATNState startState = atn.decisionToATNState.get(decision);
decisionToDFA[decision] = dfa = new DFA(startState);
dfa.decision = decision;
return predictATN(dfa, input, decision, ctx, false);
}
else {
//dump(dfa);
// start with the DFA
int m = input.mark();
int alt = execDFA(input, dfa, dfa.s0, ctx);
input.seek(m);
return alt;
}
}
public int predictATN(DFA dfa, TokenStream input,
int decision,
RuleContext originalContext,
boolean useContext)
{
if ( originalContext==null ) originalContext = RuleContext.EMPTY;
RuleContext ctx = RuleContext.EMPTY;
if ( useContext ) ctx = originalContext;
OrderedHashSet<ATNConfig> s0_closure = computeStartState(dfa.atnStartState, ctx);
dfa.s0 = addDFAState(dfa, s0_closure);
if ( prevAccept!=null ) {
dfa.s0.isAcceptState = true;
dfa.s0.prediction = prevAccept.alt;
}
int alt = 0;
int m = input.mark();
try {
alt = execATN(input, dfa, m, s0_closure, originalContext, useContext);
}
catch (NoViableAltException nvae) { dumpDeadEndConfigs(nvae); throw nvae; }
finally {
input.seek(m);
}
if ( debug ) System.out.println("DFA after predictATN: "+dfa.toString());
return alt;
}
// doesn't create DFA when matching
public int matchATN(TokenStream input, ATNState startState) {
DFA dfa = new DFA(startState);
RuleContext ctx = new ParserRuleContext();
OrderedHashSet<ATNConfig> s0_closure = computeStartState(startState, ctx);
return execATN(input, dfa, input.index(), s0_closure, ctx, false);
}
public int execDFA(TokenStream input, DFA dfa, DFAState s0, RuleContext originalContext) {
if ( dfa_debug ) System.out.println("DFA decision "+dfa.decision+" exec LA(1)=="+input.LT(1));
// dump(dfa);
DFAState prevAcceptState = null;
DFAState s = s0;
int t = input.LA(1);
int start = input.index();
loop:
while ( true ) {
if ( dfa_debug ) System.out.println("DFA state "+s.stateNumber+" LA(1)=="+t);
// TODO: ctxSensitive
if ( s.isCtxSensitive ) {
Integer predI = s.ctxToPrediction.get(originalContext);
if ( dfa_debug ) System.out.println("ctx sensitive state "+originalContext+"->"+predI+
" in "+s);
if ( predI!=null ) return predI;
// System.out.println("start all over with ATN; can't use DFA");
// start all over with ATN; can't use DFA
input.seek(start);
DFA throwAwayDFA = new DFA(dfa.atnStartState);
int alt = execATN(input, throwAwayDFA, start, s0.configs, originalContext, false);
s.ctxToPrediction.put(originalContext, alt);
return alt;
}
if ( s.isAcceptState ) {
if ( dfa_debug ) System.out.println("accept; predict "+s.prediction +" in state "+s.stateNumber);
prevAcceptState = s;
// keep going unless we're at EOF or state only has one alt number
// mentioned in configs; check if something else could match
if ( s.complete || t==CharStream.EOF ) break;
}
// if no edge, pop over to ATN interpreter, update DFA and return
if ( s.edges == null || t >= s.edges.length || s.edges[t+1] == null ) {
if ( dfa_debug ) System.out.println("no edge for "+t);
int alt = -1;
if ( dfa_debug ) {
System.out.println("ATN exec upon "+
input.toString(start,input.index())+
" at DFA state "+s.stateNumber);
}
try {
alt = execATN(input, dfa, start, s.configs, originalContext, false);
// this adds edge even if next state is accept for
// same alt; e.g., s0-A->:s1=>2-B->:s2=>2
// TODO: This next stuff kills edge, but extra states remain. :(
if ( s.isAcceptState && alt!=-1 ) {
DFAState d = s.edges[input.LA(1)+1];
if ( d.isAcceptState && d.prediction==s.prediction ) {
// we can carve it out.
s.edges[input.LA(1)+1] = ERROR; // IGNORE really not error
}
}
}
catch (NoViableAltException nvae) {
alt = -1;
}
if ( dfa_debug ) {
System.out.println("back from DFA update, alt="+alt+", dfa=\n"+dfa);
//dump(dfa);
}
if ( alt==-1 ) {
addDFAEdge(s, t, ERROR);
break loop; // dead end; no where to go, fall back on prev if any
}
// action already executed
if ( dfa_debug ) System.out.println("DFA decision "+dfa.decision+
" predicts "+alt);
return alt; // we've updated DFA, exec'd action, and have our deepest answer
}
DFAState target = s.edges[t+1];
if ( target == ERROR ) break;
s = target;
input.consume();
t = input.LA(1);
}
if ( prevAcceptState==null ) {
System.out.println("!!! no viable alt in dfa");
return -1;
}
if ( dfa_debug ) System.out.println("DFA decision "+dfa.decision+
" predicts "+prevAcceptState.prediction);
return prevAcceptState.prediction;
}
public int execATN(TokenStream input,
DFA dfa,
int startIndex,
OrderedHashSet<ATNConfig> s0,
RuleContext originalContext,
boolean useContext)
{
if ( debug ) System.out.println("ATN decision "+dfa.decision+" exec LA(1)=="+input.LT(1));
ATN_failover++;
OrderedHashSet<ATNConfig> closure = new OrderedHashSet<ATNConfig>();
closure.addAll(s0);
if ( debug ) System.out.println("start state closure="+closure);
int t = input.LA(1);
if ( t==Token.EOF && prevAccept!=null ) {
// computeStartState must have reached end of rule
return prevAccept.alt;
}
prevAccept = null;
prevAcceptIndex = -1;
OrderedHashSet<ATNConfig> reach = new OrderedHashSet<ATNConfig>();
do { // while more work
if ( debug ) System.out.println("in reach starting closure: " + closure);
int ncl = closure.size();
for (int ci=0; ci<ncl; ci++) { // TODO: foreach
ATNConfig c = closure.get(ci);
if ( debug ) System.out.println("testing "+getTokenName(t)+" at "+c.toString());
int n = c.state.getNumberOfTransitions();
for (int ti=0; ti<n; ti++) { // for each transition
Transition trans = c.state.transition(ti);
ATNState target = getReachableTarget(trans, t);
if ( target!=null ) {
closure(new ATNConfig(c, target), reach);
}
}
}
// resolve ambig in DFAState for reach
Set<Integer> ambigAlts = getAmbiguousAlts(reach);
if ( ambigAlts!=null ) {
if ( debug ) {
ATNState loc = atn.states.get(originalContext.s);
String rname = "n/a";
if ( parser !=null ) rname = parser.getRuleNames()[loc.ruleIndex];
System.out.println("AMBIG in "+rname+" for alt "+ambigAlts+" upon "+
input.toString(startIndex, input.index()));
}
dfa.conflict = true; // at least one DFA state is ambiguous
if ( !userWantsCtxSensitive ) reportConflict(startIndex, input.index(), ambigAlts, reach);
// ATNState loc = atn.states.get(originalContext.s);
// String rname = recog.getRuleNames()[loc.ruleIndex];
// System.out.println("AMBIG orig="+originalContext.toString((BaseRecognizer)recog)+" for alt "+ambigAlts+" upon "+
// input.toString(startIndex, input.index()));
if ( !userWantsCtxSensitive || useContext ) {
resolveToMinAlt(reach, ambigAlts);
}
else {
return retryWithContext(input, dfa, startIndex, originalContext,
closure, t, reach, ambigAlts);
}
}
// if reach predicts single alt, can stop
int uniqueAlt = getUniqueAlt(reach);
if ( uniqueAlt!=ATN.INVALID_ALT_NUMBER ) {
if ( debug ) System.out.println("PREDICT alt "+uniqueAlt+
" decision "+dfa.decision+
" at index "+input.index());
addDFAEdge(dfa, closure, t, reach);
makeAcceptState(dfa, reach, uniqueAlt);
return uniqueAlt;
}
if ( reach.size()==0 ) {
break;
}
// If we matched t anywhere, need to consume and add closer-t->reach DFA edge
// else error if no previous accept
input.consume();
addDFAEdge(dfa, closure, t, reach);
t = input.LA(1);
// swap to avoid reallocating space
OrderedHashSet<ATNConfig> tmp = reach;
reach = closure;
closure = tmp;
reach.clear();
} while ( true );
if ( prevAccept==null ) {
System.out.println("no viable token at input "+input.LT(1)+", index "+input.index());
NoViableAltException nvae = new NoViableAltException(parser, input, closure, originalContext);
nvae.startIndex = startIndex;
throw nvae;
}
if ( debug ) System.out.println("PREDICT " + prevAccept + " index " + prevAccept.alt);
return prevAccept.alt;
}
protected int resolveToMinAlt(OrderedHashSet<ATNConfig> reach, Set<Integer> ambigAlts) {
int min = getMinAlt(ambigAlts);
// if predicting, create DFA accept state for resolved alt
ambigAlts.remove(Utils.integer(min));
// kill dead alts so we don't chase them ever
killAlts(ambigAlts, reach);
if ( debug ) System.out.println("RESOLVED TO "+reach);
return min;
}
public int retryWithContext(TokenStream input,
DFA dfa,
int startIndex,
RuleContext originalContext,
OrderedHashSet<ATNConfig> closure,
int t,
OrderedHashSet<ATNConfig> reach,
Set<Integer> ambigAlts)
{
// ASSUMES PREDICT ONLY
// retry using context, if any; if none, kill all but min as before
if ( debug ) System.out.println("RETRY with ctx="+ originalContext);
int min = getMinAlt(ambigAlts);
if ( originalContext==RuleContext.EMPTY ) {
// no point in retrying with ctx since it's same.
// this implies that we have a true ambiguity
reportAmbiguity(startIndex, input.index(), ambigAlts, reach);
return min;
}
// otherwise we have to retry with context, filling in tmp DFA.
// if it comes back with conflict, we have a true ambiguity
input.seek(startIndex); // rewind
DFA ctx_dfa = new DFA(dfa.atnStartState);
int ctx_alt = predictATN(ctx_dfa, input, dfa.decision, originalContext, true);
if ( debug ) System.out.println("retry predicts "+ctx_alt+" vs "+getMinAlt(ambigAlts)+
" with conflict="+ctx_dfa.conflict+
" dfa="+ctx_dfa);
if ( ctx_dfa.conflict ) reportAmbiguity(startIndex, input.index(), ambigAlts, reach);
else reportContextSensitivity(startIndex, input.index(), ambigAlts, reach);
// it's not context-sensitive; true ambig. fall thru to strip dead alts
int predictedAlt = ctx_alt;
DFAState reachTarget = addDFAEdge(dfa, closure, t, reach);
reachTarget.isCtxSensitive = true;
if ( reachTarget.ctxToPrediction==null ) {
reachTarget.ctxToPrediction = new LinkedHashMap<RuleContext, Integer>();
}
reachTarget.ctxToPrediction.put(originalContext, predictedAlt);
// System.out.println("RESOLVE to "+predictedAlt);
//System.out.println(reachTarget.ctxToPrediction.size()+" size of ctx map");
return predictedAlt;
}
public OrderedHashSet<ATNConfig> computeStartState(ATNState p, RuleContext ctx) {
RuleContext initialContext = null;
initialContext = ctx; // always at least the implicit call to start rule
OrderedHashSet<ATNConfig> configs = new OrderedHashSet<ATNConfig>();
prevAccept = null; // might reach end rule; track
prevAcceptIndex = -1;
for (int i=0; i<p.getNumberOfTransitions(); i++) {
ATNState target = p.transition(i).target;
ATNConfig c = new ATNConfig(target, i+1, initialContext);
closure(c, configs);
}
return configs;
}
public ATNState getReachableTarget(Transition trans, int ttype) {
if ( trans instanceof AtomTransition ) {
AtomTransition at = (AtomTransition)trans;
boolean not = trans instanceof NotAtomTransition;
if ( !not && at.label == ttype || not && at.label!=ttype ) {
return at.target;
}
}
else if ( trans instanceof SetTransition ) {
SetTransition st = (SetTransition)trans;
boolean not = trans instanceof NotSetTransition;
if ( !not && st.label.member(ttype) || not && !st.label.member(ttype) ) {
return st.target;
}
}
// TODO else if ( trans instanceof WildcardTransition && t!=Token.EOF ) {
// ATNConfig targetConfig = new ATNConfig(c, trans.target);
// closure(input, targetConfig, reach);
// }
return null;
}
protected void closure(ATNConfig config, OrderedHashSet<ATNConfig> configs) {
closureBusy.clear();
closure(config, configs, closureBusy);
}
protected void closure(ATNConfig config,
OrderedHashSet<ATNConfig> configs,
Set<ATNConfig> closureBusy)
{
if ( debug ) System.out.println("closure("+config+")");
if ( closureBusy.contains(config) ) return; // avoid infinite recursion
closureBusy.add(config);
if ( config.state instanceof RuleStopState ) {
// We hit rule end. If we have context info, use it
if ( config.context!=null && !config.context.isEmpty() ) {
RuleContext newContext = config.context.parent; // "pop" invoking state
ATNState invokingState = atn.states.get(config.context.invokingState);
RuleTransition rt = (RuleTransition)invokingState.transition(0);
ATNState retState = rt.followState;
ATNConfig c = new ATNConfig(retState, config.alt, newContext);
closure(c, configs, closureBusy);
return;
}
// else if we have no context info, just chase follow links
}
ATNState p = config.state;
// optimization
if ( !p.onlyHasEpsilonTransitions() ) configs.add(config);
for (int i=0; i<p.getNumberOfTransitions(); i++) {
Transition t = p.transition(i);
boolean evalPreds = !config.traversedAction;
ATNConfig c = getEpsilonTarget(config, t, evalPreds);
if ( c!=null ) closure(c, configs, closureBusy);
}
}
public ATNConfig getEpsilonTarget(ATNConfig config, Transition t, boolean evalPreds) {
ATNConfig c = null;
if ( t instanceof RuleTransition ) {
ATNState p = config.state;
RuleContext newContext =
new RuleContext(config.context, p.stateNumber, t.target.stateNumber);
c = new ATNConfig(config, t.target, newContext);
}
else if ( t instanceof PredicateTransition ) {
PredicateTransition pt = (PredicateTransition)t;
if ( debug ) System.out.println("PRED (eval="+evalPreds+") "+pt.ruleIndex+":"+pt.predIndex);
// preds are epsilon if we're not doing preds.
// if we are doing preds, pred must eval to true
if ( !evalPreds ||
(evalPreds && parser.sempred(pt.ruleIndex, pt.predIndex)) ) {
c = new ATNConfig(config, t.target);
c.traversedPredicate = true;
}
}
else if ( t instanceof ActionTransition ) {
c = new ATNConfig(config, t.target);
ActionTransition at = (ActionTransition)t;
if ( debug ) System.out.println("ACTION edge "+at.ruleIndex+":"+at.actionIndex);
if ( at.actionIndex>=0 ) {
if ( debug ) System.out.println("DO ACTION "+at.ruleIndex+":"+at.actionIndex);
parser.action(at.ruleIndex, at.actionIndex);
}
else {
// non-forced action traversed to get to t.target
if ( debug && !config.traversedAction ) {
System.out.println("NONFORCED; pruning future pred eval derived from s"+
config.state.stateNumber);
}
c.traversedAction = true;
}
}
else if ( t.isEpsilon() ) {
c = new ATNConfig(config, t.target);
}
return c;
}
public void reportConflict(int startIndex, int stopIndex, Set<Integer> alts, OrderedHashSet<ATNConfig> configs) {
if ( parser!=null ) parser.reportConflict(startIndex, stopIndex, alts, configs);
}
public void reportContextSensitivity(int startIndex, int stopIndex, Set<Integer> alts, OrderedHashSet<ATNConfig> configs) {
if ( parser!=null ) parser.reportContextSensitivity(startIndex, stopIndex, alts, configs);
}
/** If context sensitive parsing, we know it's ambiguity not conflict */
public void reportAmbiguity(int startIndex, int stopIndex, Set<Integer> alts, OrderedHashSet<ATNConfig> configs) {
if ( parser!=null ) parser.reportAmbiguity(startIndex, stopIndex, alts, configs);
}
public static int getUniqueAlt(Collection<ATNConfig> configs) {
int alt = ATN.INVALID_ALT_NUMBER;
for (ATNConfig c : configs) {
if ( alt == ATN.INVALID_ALT_NUMBER ) {
alt = c.alt; // found first alt
}
else if ( c.alt!=alt ) {
return ATN.INVALID_ALT_NUMBER;
}
}
return alt;
}
public Set<Integer> getAmbiguousAlts(OrderedHashSet<ATNConfig> configs) {
// System.err.println("check ambiguous "+configs);
Set<Integer> ambigAlts = null;
int numConfigs = configs.size();
// First get a list of configurations for each state.
// Most of the time, each state will have one associated configuration.
MultiMap<Integer, ATNConfig> stateToConfigListMap =
new MultiMap<Integer, ATNConfig>();
for (ATNConfig c : configs) {
Integer stateI = Utils.integer(c.state.stateNumber);
stateToConfigListMap.map(stateI, c);
}
// potential conflicts are states with > 1 configuration and diff alts
for (List<ATNConfig> configsPerAlt : stateToConfigListMap.values()) {
ATNConfig goal = configsPerAlt.get(0);
int size = configsPerAlt.size();
for (int i=1; i< size; i++) {
ATNConfig c = configsPerAlt.get(i);
if ( c.alt!=goal.alt ) {
//System.out.println("chk stack "+goal+", "+c);
boolean sameCtx =
(goal.context==null&&c.context==null) ||
goal.context.equals(c.context) ||
c.context.conflictsWith(goal.context);
if ( sameCtx ) {
if ( debug ) {
System.out.println("we reach state "+c.state.stateNumber+
" in rule "+
(parser !=null ? parser.getRuleNames()[c.state.ruleIndex]:"n/a")+
" alts "+goal.alt+","+c.alt+" from ctx "+goal.context.toString((BaseRecognizer) parser)
+" and "+
c.context.toString((BaseRecognizer) parser));
}
if ( ambigAlts==null ) ambigAlts = new HashSet<Integer>();
ambigAlts.add(goal.alt);
ambigAlts.add(c.alt);
}
}
}
}
if ( ambigAlts!=null ) {
//System.err.println("ambig upon "+input.toString(startIndex, input.index()));
}
return ambigAlts;
}
public static int getMinAlt(Set<Integer> ambigAlts) {
int min = Integer.MAX_VALUE;
for (int alt : ambigAlts) {
if ( alt < min ) min = alt;
}
return min;
}
public static void killAlts(Set<Integer> alts, OrderedHashSet<ATNConfig> configs) {
int i = 0;
while ( i<configs.size() ) {
ATNConfig c = configs.get(i);
if ( alts.contains(c.alt) ) {
configs.remove(i);
}
else i++;
}
}
protected DFAState addDFAEdge(DFA dfa,
OrderedHashSet<ATNConfig> p,
int t,
OrderedHashSet<ATNConfig> q)
{
// System.out.println("MOVE "+p+" -> "+q+" upon "+getTokenName(t));
DFAState from = addDFAState(dfa, p);
DFAState to = addDFAState(dfa, q);
addDFAEdge(from, t, to);
return to;
}
protected void addDFAEdge(DFAState p, int t, DFAState q) {
if ( p==null ) return;
if ( p.edges==null ) {
p.edges = new DFAState[atn.maxTokenType+1+1]; // TODO: make adaptive
}
p.edges[t+1] = q; // connect
}
/** See comment on LexerInterpreter.addDFAState. */
protected DFAState addDFAState(DFA dfa, OrderedHashSet<ATNConfig> configs) {
DFAState proposed = new DFAState(configs);
DFAState existing = dfa.states.get(proposed);
if ( existing!=null ) return existing;
DFAState newState = proposed;
boolean traversedPredicate = false;
for (ATNConfig c : configs) {
if ( c.traversedPredicate ) {traversedPredicate = true; break;}
}
if ( traversedPredicate ) return null; // cannot cache
newState.stateNumber = dfa.states.size();
newState.configs = new OrderedHashSet<ATNConfig>();
newState.configs.addAll(configs);
dfa.states.put(newState, newState);
return newState;
}
public void makeAcceptState(DFA dfa, OrderedHashSet<ATNConfig> reach, int uniqueAlt) {
DFAState accept = dfa.states.get(new DFAState(reach));
if ( accept==null ) return;
accept.isAcceptState = true;
accept.prediction = uniqueAlt;
accept.complete = true;
}
public String getTokenName(int t) {
if ( t==-1 ) return "EOF";
if ( atn.g!=null ) return atn.g.getTokenDisplayName(t);
if ( parser !=null && parser.getTokenNames()!=null ) return parser.getTokenNames()[t]+"<"+t+">";
return String.valueOf(t);
}
public void setContextSensitive(boolean ctxSensitive) {
this.userWantsCtxSensitive = ctxSensitive;
}
public void dumpDeadEndConfigs(NoViableAltException nvae) {
System.err.println("dead end configs: ");
for (ATNConfig c : nvae.deadEndConfigs) {
Transition t = c.state.transition(0);
String trans = "";
if ( t instanceof AtomTransition) {
AtomTransition at = (AtomTransition)t;
trans = "Atom "+getTokenName(at.label);
}
else if ( t instanceof SetTransition ) {
SetTransition st = (SetTransition)t;
trans = "Set "+st.label.toString();
}
System.err.println(c.toString(parser, true)+":"+trans);
}
}
}

View File

@ -0,0 +1,11 @@
package org.antlr.v4.runtime.atn;
/** Start of (A|B|...)+ loop. Technically a decision state, but
* we don't use for code generation; somebody might need it, so I'm defining
* it for completeness. In reality, the PlusLoopbackState node is the
* real decision-making note for A+
*/
public class PlusBlockStartState extends BlockStartState {
public PlusLoopbackState loopBackState;
//public BlockEndState endState;
}

View File

@ -0,0 +1,10 @@
package org.antlr.v4.runtime.atn;
/** Decision state for A+ and (A|B)+. The first
* transition points at the start of the first alternative.
* The last transition is the exit transition.
*/
public class PlusLoopbackState extends DecisionState {
@Override
public boolean onlyHasEpsilonTransitions() { return true; }
}

View File

@ -0,0 +1,63 @@
package org.antlr.v4.runtime.atn;
import org.antlr.v4.analysis.SemanticContext;
import org.antlr.v4.tool.Grammar;
import org.antlr.v4.tool.GrammarAST;
/** TODO: this is old comment:
* A tree of semantic predicates from the grammar AST if label==SEMPRED.
* In the ATN, labels will always be exactly one predicate, but the DFA
* may have to combine a bunch of them as it collects predicates from
* multiple ATN configurations into a single DFA state.
*/
public class PredicateTransition extends Transition {
public int ruleIndex;
public int predIndex;
public GrammarAST predAST;
public SemanticContext semanticContext;
public PredicateTransition(GrammarAST predicateASTNode, ATNState target) {
super(target);
this.predAST = predicateASTNode;
this.semanticContext = new SemanticContext.Predicate(predicateASTNode);
}
public PredicateTransition(ATNState target, int ruleIndex, int predIndex) {
super(target);
this.ruleIndex = ruleIndex;
this.predIndex = predIndex;
}
public boolean isEpsilon() { return true; }
public int compareTo(Object o) {
return 0;
}
public int hashCode() {
return semanticContext.hashCode();
}
public boolean equals(Object o) {
if ( o==null ) {
return false;
}
if ( this == o ) {
return true; // equals if same object
}
if ( !(o instanceof PredicateTransition) ) {
return false;
}
return semanticContext.equals(((PredicateTransition)o).semanticContext);
}
public String toString() {
if ( semanticContext!=null ) return semanticContext.toString();
if ( predAST!=null ) return predAST.getText();
return "pred-"+ruleIndex+":"+predIndex;
}
public String toString(Grammar g) {
return toString();
}
}

View File

@ -0,0 +1,30 @@
package org.antlr.v4.runtime.atn;
import org.antlr.v4.misc.CharSupport;
import org.antlr.v4.misc.IntervalSet;
public class RangeTransition extends Transition {
public int from;
public int to;
public RangeTransition(int from, int to, ATNState target) {
super(target);
this.from = from;
this.to = to;
}
public RangeTransition(ATNState target) {
super(target);
}
public int compareTo(Object o) {
return 0;
}
@Override
public IntervalSet label() { return IntervalSet.of(from,to); }
@Override
public String toString() {
return CharSupport.getANTLRCharLiteralForChar(from)+".."+
CharSupport.getANTLRCharLiteralForChar(to);
}
}

View File

@ -0,0 +1,5 @@
package org.antlr.v4.runtime.atn;
public class RuleStartState extends ATNState {
public RuleStopState stopState;
}

View File

@ -0,0 +1,33 @@
package org.antlr.v4.runtime.atn;
import java.util.ArrayList;
import java.util.List;
/** The last node in the ATN for a rule, unless that rule is the start symbol.
* In that case, there is one transition to EOF. Later, we might encode
* references to all calls to this rule to compute FOLLOW sets for
* error handling.
*/
public class RuleStopState extends ATNState {
public static final int INITIAL_NUM_TRANSITIONS = 4;
//public int actionIndex; // for lexer, this is right edge action in rule
/** Track the transitions emanating from this ATN state. */
protected List<Transition> transitions =
new ArrayList<Transition>(INITIAL_NUM_TRANSITIONS);
@Override
public int getNumberOfTransitions() { return transitions.size(); }
@Override
public void addTransition(Transition e) { transitions.add(e); }
@Override
public Transition transition(int i) { return transitions.get(i); }
@Override
public void setTransition(int i, Transition e) {
transitions.set(i, e);
}
}

View File

@ -0,0 +1,41 @@
package org.antlr.v4.runtime.atn;
import org.antlr.v4.tool.Rule;
/** */
public class RuleTransition extends Transition {
/** Ptr to the rule definition object for this rule ref */
public Rule rule;
public int ruleIndex; // no Rule object at runtime
/** What node to begin computations following ref to rule */
public ATNState followState;
public RuleTransition(Rule rule,
ATNState ruleStart,
ATNState followState)
{
super(ruleStart);
this.rule = rule;
this.followState = followState;
}
public RuleTransition(int ruleIndex,
ATNState ruleStart,
ATNState followState)
{
super(ruleStart);
this.ruleIndex = ruleIndex;
this.followState = followState;
}
public RuleTransition(ATNState ruleStart) {
super(ruleStart);
}
public boolean isEpsilon() { return true; }
public int compareTo(Object o) {
return 0;
}
}

View File

@ -0,0 +1,54 @@
package org.antlr.v4.runtime.atn;
import org.antlr.v4.misc.IntervalSet;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.tool.*;
/** A transition containing a set of values */
public class SetTransition extends Transition {
public IntervalSet label;
public GrammarAST ast; // ~ of ~atom tree, wildcard node
public SetTransition(GrammarAST ast, IntervalSet label, ATNState target) {
super(target);
this.ast = ast;
if ( label==null ) label = IntervalSet.of(Token.INVALID_TYPE);
this.label = label;
}
public SetTransition(ATNState target) {
super(target);
}
public IntervalSet label() { return label; }
public int compareTo(Object o) {
return 0;
}
// public boolean intersect(Label other) {
// if ( other.getClass() == SetTransition.class ) {
// return label.and(((SetTransition)other).label).isNil();
// }
// return label.member(((AtomTransition)other).label);
// }
public int hashCode() { return label.hashCode(); }
public boolean equals(Object o) {
if ( o==null ) return false;
if ( this == o ) return true; // equals if same object
if ( o.getClass() == AtomTransition.class ) {
o = IntervalSet.of(((AtomTransition)o).label);
}
return this.label.equals(((SetTransition)o).label);
}
public String toString(Grammar g) {
return label.toString(g);
}
public String toString() {
return label.toString();
}
}

View File

@ -0,0 +1,6 @@
package org.antlr.v4.runtime.atn;
/** The block that begins a closure loop. */
public class StarBlockStartState extends BlockStartState {
// public StarLoopbackState loopBackState;
}

View File

@ -0,0 +1,4 @@
package org.antlr.v4.runtime.atn;
public class StarLoopbackState extends ATNState {
}

View File

@ -0,0 +1,41 @@
package org.antlr.v4.runtime.atn;
/** ATN simulation thread state */
public class ThreadState {
public int addr;
public int alt; // or speculatively matched token type for lexers
public ATNStack context;
public int inputIndex = -1; // char (or token?) index from 0
public int inputMarker = -1; // accept states track input markers in case we need to rewind
public ThreadState(int addr, int alt, ATNStack context) {
this.addr = addr;
this.alt = alt;
this.context = context;
}
public ThreadState(ThreadState t) {
this.addr = t.addr;
this.alt = t.alt;
this.context = t.context;
this.inputIndex = t.inputIndex;
}
public boolean equals(Object o) {
if ( o==null ) return false;
if ( this==o ) return true;
ThreadState other = (ThreadState)o;
return this.addr==other.addr &&
this.alt==other.alt &&
this.context.equals(other.context);
}
public int hashCode() { return addr + context.hashCode(); }
public String toString() {
if ( context.parent==null ) {
return "("+addr+","+alt+")";
}
return "("+addr+","+alt+","+context+")";
}
}

View File

@ -0,0 +1,5 @@
package org.antlr.v4.runtime.atn;
/** The Tokens rule start state linking to each lexer rule start state */
public class TokensStartState extends BlockStartState {
}

View File

@ -0,0 +1,80 @@
package org.antlr.v4.runtime.atn;
import org.antlr.v4.misc.IntervalSet;
import org.antlr.v4.tool.Grammar;
import java.util.HashMap;
import java.util.Map;
/** An ATN transition between any two ATN states. Subclasses define
* atom, set, epsilon, action, predicate, rule transitions.
*
* This is a one way link. It emanates from a state (usually via a list of
* transitions) and has a target state.
*
* Since we never have to change the ATN transitions once we construct it,
* we can fix these transitions as specific classes. The DFA transitions
* on the other hand need to update the labels as it adds transitions to
* the states. We'll use the term Edge for the DFA to distinguish them from
* ATN transitions.
*/
public abstract class Transition implements Comparable {
// constants for serialization
public static final int EPSILON = 1;
public static final int RANGE = 2;
public static final int RULE = 3;
public static final int PREDICATE = 4;
public static final int ATOM = 5;
public static final int ACTION = 6;
public static final int FORCED_ACTION = 7;
public static final int SET = 8; // ~(A|B) or ~atom, wildcard, which convert to next 2
public static final int NOT_ATOM = 9;
public static final int NOT_SET = 10;
public static final int WILDCARD = 11;
public static String[] serializationNames = {
"INVALID",
"EPSILON",
"RANGE",
"RULE",
"PREDICATE",
"ATOM",
"ACTION",
"FORCED_ACTION",
"SET",
"NOT_ATOM",
"NOT_SET",
"WILDCARD",
};
public static Map<Class, Integer> serializationTypes =
new HashMap<Class, Integer>() {{
put(EpsilonTransition.class, EPSILON);
put(RangeTransition.class, RANGE);
put(RuleTransition.class, RULE);
put(PredicateTransition.class, PREDICATE);
put(AtomTransition.class, ATOM);
put(ActionTransition.class, ACTION); // TODO: FORCED?
put(SetTransition.class, SET);
put(NotAtomTransition.class, NOT_ATOM);
put(NotSetTransition.class, NOT_SET);
put(WildcardTransition.class, WILDCARD);
}};
/** The target of this transition */
public ATNState target;
public Transition() { }
public Transition(ATNState target) { this.target = target; }
public int getSerializationType() { return 0; }
/** Are we epsilon, action, sempred? */
public boolean isEpsilon() { return false; }
public IntervalSet label() { return null; }
public String toString(Grammar g) { return toString(); }
}

View File

@ -0,0 +1,15 @@
package org.antlr.v4.runtime.atn;
import org.antlr.v4.tool.Grammar;
public class WildcardTransition extends Transition {
public WildcardTransition(ATNState target) { super(target); }
public int compareTo(Object o) {
return 0;
}
@Override
public String toString(Grammar g) {
return ".";
}
}

View File

@ -0,0 +1,107 @@
/*
[BSD]
Copyright (c) 2010 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.v4.runtime.dfa;
import org.antlr.v4.runtime.atn.ATNState;
import java.util.*;
public class DFA {
/** A set of all DFA states. Use Map so we can get old state back
* (Set only allows you to see if it's there).
*/
public Map<DFAState, DFAState> states = new LinkedHashMap<DFAState, DFAState>();
public DFAState s0;
public int decision;
// public int maxTokenType;
/** From which ATN state did we create this DFA? */
public ATNState atnStartState;
/** Does at least one state have a conflict? Mainly used as return value
* from predictATN()
*/
public boolean conflict;
public DFA(ATNState atnStartState) { this.atnStartState = atnStartState; }
// public DFA(int maxTokenType) { this.maxTokenType = maxTokenType; }
/*
public void addAll(Collection<DFAState> states) {
for (DFAState p : states) {
//addDFAEdge(p, t, q);
}
}
public void addDFAEdge(OrderedHashSet<ATNConfig> p,
int t,
OrderedHashSet<ATNConfig> q)
{
// System.out.println("MOVE "+p+" -> "+q+" upon "+getTokenName(t));
DFAState from = addDFAState(p);
DFAState to = addDFAState(q);
addDFAEdge(from, t, to);
}
public void addDFAEdge(DFAState p, int t, DFAState q) {
if ( p.edges==null ) {
p.edges = new DFAState[maxTokenType+1]; // TODO: make adaptive
}
p.edges[t] = q; // connect
}
protected DFAState addDFAState(OrderedHashSet<ATNConfig> configs) {
DFAState proposed = new DFAState(configs);
DFAState existing = states.get(proposed);
DFAState p;
if ( existing!=null ) p = existing;
else {
proposed.stateNumber = states.size();
proposed.configs = new OrderedHashSet<ATNConfig>();
proposed.configs.addAll(configs);
states.put(proposed, proposed);
p = proposed;
}
return p;
}
*/
public String toString() { return toString(null); }
public String toString(String[] tokenNames) {
if ( s0==null ) return "";
DFASerializer serializer = new DFASerializer(this,tokenNames);
return serializer.toString();
}
public String toLexerString() {
if ( s0==null ) return "";
DFASerializer serializer = new LexerDFASerializer(this);
return serializer.toString();
}
}

View File

@ -0,0 +1,52 @@
package org.antlr.v4.runtime.dfa;
/** A DFA walker that knows how to dump them to serialized strings. */
public class DFASerializer {
String[] tokenNames;
DFA dfa;
public DFASerializer(DFA dfa, String[] tokenNames) {
this.dfa = dfa;
this.tokenNames = tokenNames;
}
public String toString() {
if ( dfa.s0==null ) return null;
StringBuilder buf = new StringBuilder();
for (DFAState s : dfa.states.values()) {
int n = 0;
if ( s.edges!=null ) n = s.edges.length;
for (int i=0; i<n; i++) {
DFAState t = s.edges[i];
if ( t!=null && t.stateNumber != Integer.MAX_VALUE ) {
buf.append(getStateString(s));
String label = getEdgeLabel(i);
buf.append("-"+label+"->"+ getStateString(t)+'\n');
}
}
}
String output = buf.toString();
//return Utils.sortLinesInString(output);
return output;
}
protected String getEdgeLabel(int i) {
String label;
if ( i==0 ) return "EOF";
if ( tokenNames!=null ) label = tokenNames[i-1];
else label = String.valueOf(i-1);
return label;
}
String getStateString(DFAState s) {
int n = s.stateNumber;
String stateStr = "s"+n;
if ( s.isAcceptState ) {
stateStr = ":s"+n+"=>"+s.prediction;
}
if ( s.isCtxSensitive ) {
stateStr = ":s"+n+"@"+s.ctxToPrediction;
}
return stateStr;
}
}

View File

@ -0,0 +1,107 @@
package org.antlr.v4.runtime.dfa;
import org.antlr.v4.analysis.ATNConfig;
import org.antlr.v4.misc.OrderedHashSet;
import org.antlr.v4.runtime.RuleContext;
import java.util.*;
/** A DFA state represents a set of possible ATN configurations.
* As Aho, Sethi, Ullman p. 117 says "The DFA uses its state
* to keep track of all possible states the ATN can be in after
* reading each input symbol. That is to say, after reading
* input a1a2..an, the DFA is in a state that represents the
* subset T of the states of the ATN that are reachable from the
* ATN's start state along some path labeled a1a2..an."
* In conventional NFA->DFA conversion, therefore, the subset T
* would be a bitset representing the set of states the
* ATN could be in. We need to track the alt predicted by each
* state as well, however. More importantly, we need to maintain
* a stack of states, tracking the closure operations as they
* jump from rule to rule, emulating rule invocations (method calls).
* Recall that ATNs do not normally have a stack like a pushdown-machine
* so I have to add one to simulate the proper lookahead sequences for
* the underlying LL grammar from which the ATN was derived.
*
* I use a list of ATNConfig objects. An ATNConfig
* is both a state (ala normal conversion) and a RuleContext describing
* the chain of rules (if any) followed to arrive at that state.
*
* A DFA state may have multiple references to a particular state,
* but with different ATNContexts (with same or different alts)
* meaning that state was reached via a different set of rule invocations.
*/
public class DFAState {
public int stateNumber = -1;
/** The set of ATN configurations (state,alt,context) for this DFA state */
public OrderedHashSet<ATNConfig> configs = new OrderedHashSet<ATNConfig>();
/** edges[symbol] points to target of symbol */
public DFAState[] edges;
// public IntervalSet viableChars;
public boolean isAcceptState = false;
public int prediction; // if accept state, what ttype do we match?
public int ruleIndex; // if accept, exec what action?
public boolean complete; // all alts predict "prediction"
public boolean isCtxSensitive;
public Map<RuleContext, Integer> ctxToPrediction;
public DFAState() { }
public DFAState(int stateNumber) { this.stateNumber = stateNumber; }
public DFAState(OrderedHashSet<ATNConfig> configs) { this.configs = configs; }
/** Get the set of all alts mentioned by all ATN configurations in this
* DFA state.
*/
public Set<Integer> getAltSet() {
Set<Integer> alts = new HashSet<Integer>();
for (ATNConfig c : configs) {
alts.add(c.alt);
}
if ( alts.size()==0 ) return null;
return alts;
}
/** A decent hash for a DFA state is the sum of the ATN state/alt pairs. */
public int hashCode() {
int h = 0;
for (ATNConfig c : configs) {
h += c.alt;
}
return h;
}
/** Two DFAStates are equal if their ATN configuration sets are the
* same. This method is used to see if a DFA state already exists.
*
* Because the number of alternatives and number of ATN configurations are
* finite, there is a finite number of DFA states that can be processed.
* This is necessary to show that the algorithm terminates.
*
* Cannot test the DFA state numbers here because in DFA.addState we need
* to know if any other state exists that has this exact set of ATN
* configurations. The DFAState state number is irrelevant.
*/
public boolean equals(Object o) {
// compare set of ATN configurations in this set with other
if ( this==o ) return true;
DFAState other = (DFAState)o;
boolean sameSet = this.configs.equals(other.configs);
// System.out.println("DFAState.equals: "+configs+(sameSet?"==":"!=")+other.configs);
return sameSet;
}
public String toString() {
return stateNumber+":"+configs+(isAcceptState?("=>"+prediction):"");
}
}

View File

@ -0,0 +1,12 @@
package org.antlr.v4.runtime.dfa;
public class LexerDFASerializer extends DFASerializer {
public LexerDFASerializer(DFA dfa) {
super(dfa, null);
}
@Override
protected String getEdgeLabel(int i) {
return "'"+(char)i+"'";
}
}

View File

@ -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.v4.runtime.misc;
import java.util.ArrayList;
import java.util.List;
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();
}
}

View File

@ -0,0 +1,219 @@
package org.antlr.v4.runtime.misc;
import org.antlr.v4.runtime.Token;
/** */
public class LABitSet implements Cloneable {
public final static int BITS = 64; // number of bits / long
public 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.
*/
public final static int MOD_MASK = BITS - 1;
public static final LABitSet EOF_SET = LABitSet.of(Token.EOF);
/** The actual data bits */
public long bits[];
public boolean EOF; // is EOF in set (-1)?
/** Construct a bitset of size one word (64 bits) */
public LABitSet() {
this(BITS);
}
/** Construct a bitset given the size
* @param nbits The size of the bitset in bits
*/
public LABitSet(int nbits) {
bits = new long[((nbits - 1) >> LOG_BITS) + 1];
}
/** Construction from a static array of longs */
public LABitSet(long[] bits_) {
if ( bits_==null || bits_.length==0 ) bits = new long[1];
else bits = bits_;
}
/** Construction from a static array of longs */
public LABitSet(long[] bits_, boolean EOF) {
this(bits_);
this.EOF = EOF;
}
public static LABitSet of(int el) {
LABitSet s = new LABitSet(el + 1);
s.add(el);
return s;
}
/** or this element into this set (grow as necessary to accommodate) */
public void add(int el) {
//System.out.println("add("+el+")");
if ( el==Token.EOF ) { EOF = true; return; }
int n = wordNumber(el);
//System.out.println("word number is "+n);
//System.out.println("bits.length "+bits.length);
if (n >= bits.length) {
growToInclude(el);
}
bits[n] |= bitMask(el);
}
public boolean member(int el) {
if ( el == Token.EOF ) return EOF;
int n = wordNumber(el);
if (n >= bits.length) return false;
return (bits[n] & bitMask(el)) != 0;
}
/** return this | a in a new set */
public LABitSet or(LABitSet a) {
if ( a==null ) {
return this;
}
LABitSet s = (LABitSet)this.clone();
s.orInPlace((LABitSet)a);
return s;
}
public void orInPlace(LABitSet 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];
}
EOF = EOF | a.EOF;
}
// remove this element from this set
public void remove(int el) {
if ( el==Token.EOF ) { EOF = false; return; }
int n = wordNumber(el);
if (n >= bits.length) {
throw new IllegalArgumentException(el+" is outside set range of "+bits.length+" words");
}
bits[n] &= ~bitMask(el);
}
public Object clone() {
LABitSet s;
try {
s = (LABitSet)super.clone();
s.bits = new long[bits.length];
System.arraycopy(bits, 0, s.bits, 0, bits.length);
s.EOF = EOF;
return s;
}
catch (CloneNotSupportedException e) {
e.printStackTrace(System.err);
}
return null;
}
/**
* Sets the size of a set.
* @param nwords how many words the new set should be
*/
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;
}
/** Get the first element you find and return it. */
public int getSingleElement() {
for (int i = 0; i < (bits.length << LOG_BITS); i++) {
if (member(i)) {
return i;
}
}
return Token.INVALID_TYPE;
}
/** Transform a bit set into a string by formatting each element as an integer
* separator The string to put in between elements
* @return A commma-separated list of values
*/
public String toString() {
StringBuffer buf = new StringBuffer();
String separator = ",";
boolean havePrintedAnElement = false;
buf.append('{');
if ( EOF ) { buf.append("EOF"); havePrintedAnElement=true; }
for (int i = 0; i < (bits.length << LOG_BITS); i++) {
if (member(i)) {
if ( havePrintedAnElement ) {
buf.append(separator);
}
buf.append(i);
havePrintedAnElement = true;
}
}
buf.append('}');
return buf.toString();
}
// /**Create a string representation where instead of integer elements, the
// * ith element of vocabulary is displayed instead. Vocabulary is a Vector
// * of Strings.
// * separator The string to put in between elements
// * @return A commma-separated list of character constants.
// */
// public String toString(String separator, List vocabulary) {
// String str = "";
// for (int i = 0; i < (bits.length << LOG_BITS); i++) {
// if (member(i)) {
// if (str.length() > 0) {
// str += separator;
// }
// if (i >= vocabulary.size()) {
// str += "'" + (char)i + "'";
// }
// else if (vocabulary.get(i) == null) {
// str += "'" + (char)i + "'";
// }
// else {
// str += (String)vocabulary.get(i);
// }
// }
// }
// return str;
// }
/**
* 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;
}
static long bitMask(int bitNumber) {
int bitPosition = bitNumber & MOD_MASK; // bitNumber mod BITS
return 1L << bitPosition;
}
static int numWordsToHold(int el) {
return (el >> LOG_BITS) + 1;
}
static int wordNumber(int bit) {
return bit >> LOG_BITS; // bit / BITS
}
}

View File

@ -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.v4.runtime.misc;
import org.antlr.runtime.misc.FastQueue;
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");
}
}

View File

@ -0,0 +1,46 @@
package org.antlr.v4.runtime.misc;
import java.util.EmptyStackException;
/** A quicker stack than Stack */
public class QStack<T> {
T[] elements;
public int sp = -1;
public QStack() {
elements = (T[])new Object[10];
}
public QStack(QStack s) {
elements = (T[])new Object[s.elements.length];
System.arraycopy(s.elements, 0, elements, 0, s.elements.length);
this.sp = s.sp;
}
public void push(T fset) {
if ( (sp+1)>=elements.length ) {
T[] f = (T[])new Object[elements.length*2];
System.arraycopy(elements, 0, f, 0, elements.length);
elements = f;
}
elements[++sp] = fset;
}
public T peek() {
if ( sp<0 ) throw new EmptyStackException();
return elements[sp];
}
public T get(int i) {
if ( i<0 ) throw new IllegalArgumentException("i<0");
if ( i>sp ) throw new IllegalArgumentException("i>"+sp);
return elements[sp];
}
public T pop() {
if ( sp<0 ) throw new EmptyStackException();
return elements[sp--];
}
public void clear() { sp = -1; }
}

View File

@ -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.v4.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();
}

View File

@ -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.v4.runtime.tree;
import org.antlr.v4.runtime.RecognitionException;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.TokenStream;
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);
}

View File

@ -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.v4.runtime.tree;
import org.antlr.v4.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_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()+">";
}
}

View File

@ -0,0 +1,221 @@
/*
[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.v4.runtime.tree;
import org.antlr.runtime.BitSet;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.tree.gui.ASTViewer;
/** 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_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;
}
// TODO: move to basetree when i settle on how runtime works
public void inspect() {
ASTViewer viewer = new ASTViewer(this);
viewer.open();
}
// TODO: move to basetree when i settle on how runtime works
// TODO: don't include this node!!
// TODO: reuse other method
public CommonTree getFirstDescendantWithType(int type) {
if ( getType()==type ) return this;
if ( children==null ) return null;
for (Object c : children) {
CommonTree t = (CommonTree)c;
if ( t.getType()==type ) return t;
CommonTree d = t.getFirstDescendantWithType(type);
if ( d!=null ) return d;
}
return null;
}
// TODO: don't include this node!!
public CommonTree getFirstDescendantWithType(BitSet types) {
if ( types.member(getType()) ) return this;
if ( children==null ) return null;
for (Object c : children) {
CommonTree t = (CommonTree)c;
if ( types.member(t.getType()) ) return t;
CommonTree d = t.getFirstDescendantWithType(types);
if ( d!=null ) return d;
}
return null;
}
public String toString() {
if ( isNil() ) {
return "nil";
}
if ( getType()==Token.INVALID_TYPE) {
return "<errornode>";
}
if ( token==null ) {
return null;
}
return token.getText();
}
}

View File

@ -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.v4.runtime.tree;
import org.antlr.v4.runtime.*;
/** 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.
*/
@Override
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.
*/
@Override
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_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);
}
}
}

View File

@ -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.v4.runtime.tree;
import org.antlr.runtime.misc.IntArray;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.TokenStream;
import org.antlr.v4.runtime.misc.LookaheadStream;
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();
}
}

View File

@ -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.v4.runtime.tree;
import org.antlr.v4.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();
}

View File

@ -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.v4.runtime.tree;
import org.antlr.v4.runtime.RecognitionException;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.TokenStream;
/** 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);
}

View File

@ -0,0 +1,134 @@
/*
[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.v4.runtime.tree;
import org.antlr.v4.runtime.ParserSharedState;
import org.antlr.v4.runtime.RecognitionException;
import org.antlr.v4.runtime.RecognizerSharedState;
import org.antlr.v4.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);
originalAdaptor = (TreeAdaptor) 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 ParserSharedState();
input = new CommonTreeNodeStream(originalAdaptor, t);
((CommonTreeNodeStream)input).setTokenStream(originalTokenStream);
whichRule.rule();
}
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 {;}
}

View File

@ -0,0 +1,131 @@
/*
[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.v4.runtime.tree;
import org.antlr.runtime.Token;
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(); }
}

View File

@ -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.v4.runtime.tree;
import org.antlr.v4.runtime.IntStream;
import org.antlr.v4.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);
}

View File

@ -0,0 +1,240 @@
/*
[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.v4.runtime.tree;
import org.antlr.runtime.BitSet;
import org.antlr.v4.runtime.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/** 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((TokenStream)input); // highlight that we go to super to set state object
setTreeNodeStream(input);
}
public TreeParser(TreeNodeStream input, RecognizerSharedState<?> state) {
super((TokenStream)input); // 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);
return null;
}
/** 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);
}
/** Check if current node in input has a context. Context means sequence
* of nodes towards root of tree. For example, you might say context
* is "MULT" which means my parent must be MULT. "CLASS VARDEF" says
* current node must be child of a VARDEF and whose parent is a CLASS node.
* You can use "..." to mean zero-or-more nodes. "METHOD ... VARDEF"
* means my parent is VARDEF and somewhere above that is a METHOD node.
* The first node in the context is not necessarily the root. The context
* matcher stops matching and returns true when it runs out of context.
* There is no way to force the first node to be the root.
*/
public boolean inContext(String context) {
return inContext(input.getTreeAdaptor(), getTokenNames(), input.LT(1), context);
}
/** The worker for inContext. It's static and full of parameters for
* testing purposes.
*/
public static boolean inContext(TreeAdaptor adaptor,
String[] tokenNames,
Object t,
String context)
{
Matcher dotdotMatcher = dotdotPattern.matcher(context);
Matcher doubleEtcMatcher = doubleEtcPattern.matcher(context);
if ( dotdotMatcher.find() ) { // don't allow "..", must be "..."
throw new IllegalArgumentException("invalid syntax: ..");
}
if ( doubleEtcMatcher.find() ) { // don't allow double "..."
throw new IllegalArgumentException("invalid syntax: ... ...");
}
context = context.replaceAll("\\.\\.\\.", " ... "); // ensure spaces around ...
context = context.trim();
String[] nodes = context.split("\\s+");
int ni = nodes.length-1;
t = adaptor.getParent(t);
while ( ni>=0 && t!=null ) {
if ( nodes[ni].equals("...") ) {
// walk upwards until we see nodes[ni-1] then continue walking
if ( ni==0 ) return true; // ... at start is no-op
String goal = nodes[ni-1];
Object ancestor = getAncestor(adaptor, tokenNames, t, goal);
if ( ancestor==null ) return false;
t = ancestor;
ni--;
}
String name = tokenNames[adaptor.getType(t)];
if ( !name.equals(nodes[ni]) ) {
//System.err.println("not matched: "+nodes[ni]+" at "+t);
return false;
}
// advance to parent and to previous element in context node list
ni--;
t = adaptor.getParent(t);
}
if ( t==null && ni>=0 ) return false; // at root but more nodes to match
return true;
}
/** Helper for static inContext */
protected static Object getAncestor(TreeAdaptor adaptor, String[] tokenNames, Object t, String goal) {
while ( t!=null ) {
String name = tokenNames[adaptor.getType(t)];
if ( name.equals(goal) ) return t;
t = adaptor.getParent(t);
}
return null;
}
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));
}
}

View File

@ -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.v4.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;
}
}

View File

@ -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.v4.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);
}

View File

@ -0,0 +1,43 @@
package org.antlr.v4.runtime.tree.gui;
import javax.swing.*;
import java.awt.*;
/*
* Created by JFormDesigner on Mon Jan 18 14:54:16 PST 2010
*/
/**
* @author Terence Parr
*/
public class ASTViewFrame extends JFrame {
public ASTViewFrame() {
initComponents();
}
private void initComponents() {
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
// Generated using JFormDesigner non-commercial license
scrollPane1 = new JScrollPane();
tree = new JTree();
//======== this ========
setTitle("ANTLR AST Viewer");
Container contentPane = getContentPane();
contentPane.setLayout(new GridLayout(1, 1));
//======== scrollPane1 ========
{
scrollPane1.setViewportView(tree);
}
contentPane.add(scrollPane1);
pack();
setLocationRelativeTo(getOwner());
// JFormDesigner - End of component initialization //GEN-END:initComponents
}
// JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables
// Generated using JFormDesigner non-commercial license
private JScrollPane scrollPane1;
public JTree tree;
// JFormDesigner - End of variables declaration //GEN-END:variables
}

View File

@ -0,0 +1,28 @@
package org.antlr.v4.runtime.tree.gui;
import org.antlr.runtime.tree.CommonTreeAdaptor;
import org.antlr.runtime.tree.TreeAdaptor;
/** */
public class ASTViewer {
TreeAdaptor adaptor;
Object root;
public ASTViewer(TreeAdaptor adaptor, Object root) {
this.adaptor = adaptor;
this.root = root;
}
public ASTViewer(Object root) {
this.adaptor = new CommonTreeAdaptor();
this.root = root;
}
public void open() {
ASTViewFrame m = new ASTViewFrame();
m.tree.setModel(new JTreeASTModel(adaptor, root));
m.pack();
m.setSize(800,600);
m.setVisible(true);
}
}

View File

@ -0,0 +1,51 @@
package org.antlr.v4.runtime.tree.gui;
import org.antlr.runtime.tree.CommonTreeAdaptor;
import org.antlr.runtime.tree.TreeAdaptor;
import javax.swing.event.TreeModelListener;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;
public class JTreeASTModel implements TreeModel {
TreeAdaptor adaptor;
Object root;
public JTreeASTModel(TreeAdaptor adaptor, Object root) {
this.adaptor = adaptor;
this.root = root;
}
public JTreeASTModel(Object root) {
this.adaptor = new CommonTreeAdaptor();
this.root = root;
}
public int getChildCount(Object parent) {
return adaptor.getChildCount(parent);
}
public int getIndexOfChild(Object parent, Object child){
if ( parent==null ) return -1;
return adaptor.getChildIndex(child);
}
public Object getChild(Object parent, int index){
return adaptor.getChild(parent, index);
}
public boolean isLeaf(Object node) {
return getChildCount(node)==0;
}
public Object getRoot() { return root; }
public void valueForPathChanged(TreePath treePath, Object o) {
}
public void addTreeModelListener(TreeModelListener treeModelListener) {
}
public void removeTreeModelListener(TreeModelListener treeModelListener) {
}
}