v4: Reusable ATN simulator objects
[git-p4: depot-paths = "//depot/code/antlr4/main/": change = 9448]
This commit is contained in:
parent
89ebd369f9
commit
898138a5e2
|
@ -56,7 +56,8 @@ public abstract class BaseRecognizer<Symbol> extends Recognizer<Symbol, ParserAT
|
|||
/** Did the recognizer encounter a syntax error? Track how many. */
|
||||
protected int syntaxErrors = 0;
|
||||
|
||||
public BaseRecognizer(IntStream input) {
|
||||
public BaseRecognizer(IntStream input, ParserATNSimulator<Symbol> interpreter) {
|
||||
super(interpreter);
|
||||
setInputStream(input);
|
||||
}
|
||||
|
||||
|
|
|
@ -93,8 +93,12 @@ public abstract class Lexer extends Recognizer<Integer, LexerATNSimulator>
|
|||
*/
|
||||
public String text;
|
||||
|
||||
public Lexer(CharStream input) {
|
||||
protected LexerATNSimulator.State state;
|
||||
|
||||
public Lexer(CharStream input, LexerATNSimulator interpreter) {
|
||||
super(interpreter);
|
||||
this.input = input;
|
||||
this.state = new LexerATNSimulator.State(this);
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
|
@ -116,7 +120,7 @@ public abstract class Lexer extends Recognizer<Integer, LexerATNSimulator>
|
|||
modeStack.clear();
|
||||
}
|
||||
|
||||
getInterpreter().reset();
|
||||
getInterpreter().reset(state);
|
||||
}
|
||||
|
||||
/** Return a token from this source; i.e., match a token on the char
|
||||
|
@ -131,8 +135,8 @@ public abstract class Lexer extends Recognizer<Integer, LexerATNSimulator>
|
|||
token = null;
|
||||
channel = Token.DEFAULT_CHANNEL;
|
||||
tokenStartCharIndex = input.index();
|
||||
tokenStartCharPositionInLine = getInterpreter().getCharPositionInLine();
|
||||
tokenStartLine = getInterpreter().getLine();
|
||||
tokenStartCharPositionInLine = getInterpreter().getCharPositionInLine(state);
|
||||
tokenStartLine = getInterpreter().getLine(state);
|
||||
text = null;
|
||||
do {
|
||||
type = Token.INVALID_TYPE;
|
||||
|
@ -141,7 +145,7 @@ public abstract class Lexer extends Recognizer<Integer, LexerATNSimulator>
|
|||
// " at index "+input.index());
|
||||
int ttype;
|
||||
try {
|
||||
ttype = getInterpreter().match(input, mode);
|
||||
ttype = getInterpreter().match(state, mode);
|
||||
}
|
||||
catch (LexerNoViableAltException e) {
|
||||
notifyListeners(e); // report error
|
||||
|
@ -259,12 +263,12 @@ public abstract class Lexer extends Recognizer<Integer, LexerATNSimulator>
|
|||
|
||||
@Override
|
||||
public int getLine() {
|
||||
return getInterpreter().getLine();
|
||||
return getInterpreter().getLine(state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCharPositionInLine() {
|
||||
return getInterpreter().getCharPositionInLine();
|
||||
return getInterpreter().getCharPositionInLine(state);
|
||||
}
|
||||
|
||||
/** What is the index of the current character of lookahead? */
|
||||
|
@ -279,7 +283,7 @@ public abstract class Lexer extends Recognizer<Integer, LexerATNSimulator>
|
|||
if ( text!=null ) {
|
||||
return text;
|
||||
}
|
||||
return getInterpreter().getText(input);
|
||||
return getInterpreter().getText(state);
|
||||
// return ((CharStream)input).substring(tokenStartCharIndex,getCharIndex()-1);
|
||||
}
|
||||
|
||||
|
@ -315,7 +319,7 @@ public abstract class Lexer extends Recognizer<Integer, LexerATNSimulator>
|
|||
}
|
||||
|
||||
public void recover(LexerNoViableAltException e) {
|
||||
getInterpreter().consume(input); // skip a char and try again
|
||||
getInterpreter().consume(state); // skip a char and try again
|
||||
}
|
||||
|
||||
public void notifyListeners(LexerNoViableAltException e) {
|
||||
|
|
|
@ -28,6 +28,9 @@
|
|||
*/
|
||||
package org.antlr.v4.runtime;
|
||||
|
||||
import org.antlr.v4.runtime.atn.ATNSimulator;
|
||||
import org.antlr.v4.runtime.atn.ParserATNSimulator;
|
||||
import org.antlr.v4.runtime.atn.ParserATNSimulator.State;
|
||||
|
||||
/** A parser for TokenStreams. "parser grammars" result in a subclass
|
||||
* of this.
|
||||
|
@ -35,10 +38,17 @@ package org.antlr.v4.runtime;
|
|||
public class Parser extends BaseRecognizer<Token> {
|
||||
protected TokenStream _input;
|
||||
|
||||
public Parser(TokenStream input) {
|
||||
super(input);
|
||||
protected ParserATNSimulator.State<Token> state;
|
||||
|
||||
public Parser(TokenStream input, ParserATNSimulator<Token> interpreter) {
|
||||
super(input, interpreter);
|
||||
state = new ParserATNSimulator.State<Token>(this);
|
||||
}
|
||||
|
||||
public ParserATNSimulator.State<Token> getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
super.reset(); // reset all recognizer state variables
|
||||
|
|
|
@ -47,7 +47,12 @@ public abstract class Recognizer<Symbol, ATNInterpreter extends ATNSimulator> {
|
|||
|
||||
private static final ANTLRErrorListener[] EMPTY_LISTENERS = new ANTLRErrorListener[0];
|
||||
|
||||
protected ATNInterpreter _interp;
|
||||
@NotNull
|
||||
private final ATNInterpreter _interp;
|
||||
|
||||
protected Recognizer(@NotNull ATNInterpreter interpreter) {
|
||||
this._interp = interpreter;
|
||||
}
|
||||
|
||||
/** Used to print out token names like ID during debugging and
|
||||
* error reporting. The generated parsers implement a method
|
||||
|
@ -63,6 +68,7 @@ public abstract class Recognizer<Symbol, ATNInterpreter extends ATNSimulator> {
|
|||
|
||||
public ATN getATN() { return null; }
|
||||
|
||||
@NotNull
|
||||
public ATNInterpreter getInterpreter() { return _interp; }
|
||||
|
||||
/** What is the error header, normally line/character position information? */
|
||||
|
|
|
@ -89,98 +89,116 @@ public class LexerATNSimulator extends ATNSimulator {
|
|||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected final Lexer recog;
|
||||
public static class State {
|
||||
@Nullable
|
||||
protected final Lexer recog;
|
||||
|
||||
/** The current token's starting index into the character stream.
|
||||
* Shared across DFA to ATN simulation in case the ATN fails and the
|
||||
* DFA did not have a previous accept state. In this case, we use the
|
||||
* ATN-generated exception object.
|
||||
*/
|
||||
protected int startIndex = -1;
|
||||
@Nullable
|
||||
private final CharStream input;
|
||||
|
||||
/** line number 1..n within the input */
|
||||
protected int line = 1;
|
||||
/** The current token's starting index into the character stream.
|
||||
* Shared across DFA to ATN simulation in case the ATN fails and the
|
||||
* DFA did not have a previous accept state. In this case, we use the
|
||||
* ATN-generated exception object.
|
||||
*/
|
||||
protected int startIndex = -1;
|
||||
|
||||
/** The index of the character relative to the beginning of the line 0..n-1 */
|
||||
protected int charPositionInLine = 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;
|
||||
|
||||
protected int mode = Lexer.DEFAULT_MODE;
|
||||
|
||||
/** Used during DFA/ATN exec to record the most recent accept configuration info */
|
||||
@NotNull
|
||||
protected final DFAExecState dfaPrevAccept = new DFAExecState();
|
||||
|
||||
@NotNull
|
||||
protected final ATNExecState atnPrevAccept = new ATNExecState();
|
||||
|
||||
public State(@NotNull Lexer recog) {
|
||||
this.recog = recog;
|
||||
this.input = null;
|
||||
}
|
||||
|
||||
public State(@NotNull CharStream input) {
|
||||
this.recog = null;
|
||||
this.input = input;
|
||||
}
|
||||
|
||||
public CharStream getInput() {
|
||||
if (recog != null) {
|
||||
return recog.getInputStream();
|
||||
}
|
||||
|
||||
return input;
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
protected DFA[] dfa;
|
||||
protected int mode = Lexer.DEFAULT_MODE;
|
||||
|
||||
/** Used during DFA/ATN exec to record the most recent accept configuration info */
|
||||
@NotNull
|
||||
protected final DFAExecState dfaPrevAccept = new DFAExecState();
|
||||
@NotNull
|
||||
protected final ATNExecState atnPrevAccept = new ATNExecState();
|
||||
|
||||
public static int ATN_failover = 0;
|
||||
public static int match_calls = 0;
|
||||
|
||||
public LexerATNSimulator(@NotNull ATN atn) {
|
||||
this(null, atn);
|
||||
}
|
||||
|
||||
public LexerATNSimulator(@Nullable Lexer recog, @NotNull 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(@NotNull CharStream input, int mode) {
|
||||
public int match(@NotNull State state, int mode) {
|
||||
match_calls++;
|
||||
this.mode = mode;
|
||||
state.mode = mode;
|
||||
if ( dfa[mode].s0==null ) {
|
||||
return matchATN(input);
|
||||
return matchATN(state);
|
||||
}
|
||||
else {
|
||||
return exec(input, dfa[mode].s0);
|
||||
return exec(state, dfa[mode].s0);
|
||||
}
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
dfaPrevAccept.reset();
|
||||
atnPrevAccept.reset();
|
||||
startIndex = -1;
|
||||
line = 1;
|
||||
charPositionInLine = 0;
|
||||
mode = Lexer.DEFAULT_MODE;
|
||||
public void reset(@NotNull State state) {
|
||||
state.dfaPrevAccept.reset();
|
||||
state.atnPrevAccept.reset();
|
||||
state.startIndex = -1;
|
||||
state.line = 1;
|
||||
state.charPositionInLine = 0;
|
||||
state.mode = Lexer.DEFAULT_MODE;
|
||||
}
|
||||
|
||||
// only called from test code from outside
|
||||
public int matchATN(@NotNull CharStream input) {
|
||||
int mark = input.mark();
|
||||
public int matchATN(@NotNull State state) {
|
||||
int mark = state.getInput().mark();
|
||||
try {
|
||||
startIndex = input.index();
|
||||
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);
|
||||
state.startIndex = state.getInput().index();
|
||||
ATNState startState = atn.modeToStartState.get(state.mode);
|
||||
if ( debug ) System.out.println("mode "+ state.mode +" start: "+startState);
|
||||
OrderedHashSet<ATNConfig> s0_closure = computeStartState(state, startState);
|
||||
int old_mode = state.mode;
|
||||
dfa[state.mode].s0 = addDFAState(state, s0_closure);
|
||||
int predict = exec(state, s0_closure);
|
||||
if ( debug ) System.out.println("DFA after matchATN: "+dfa[old_mode].toLexerString());
|
||||
return predict;
|
||||
}
|
||||
finally {
|
||||
if (mark >= 0) {
|
||||
input.release(mark);
|
||||
}
|
||||
state.getInput().release(mark);
|
||||
}
|
||||
}
|
||||
|
||||
protected int exec(@NotNull CharStream input, @NotNull DFAState s0) {
|
||||
if ( dfa_debug ) System.out.println("DFA[mode "+(recog==null?0:recog.mode)+"] exec LA(1)=="+
|
||||
(char)input.LA(1));
|
||||
protected int exec(@NotNull State state, @NotNull DFAState s0) {
|
||||
if ( dfa_debug ) System.out.println("DFA[mode "+(state.recog==null?0:state.recog.mode)+"] exec LA(1)=="+
|
||||
(char)state.getInput().LA(1));
|
||||
//System.out.println("DFA start of execDFA: "+dfa[mode].toLexerString());
|
||||
startIndex = input.index();
|
||||
dfaPrevAccept.reset();
|
||||
state.startIndex = state.getInput().index();
|
||||
state.dfaPrevAccept.reset();
|
||||
LexerNoViableAltException atnException = null;
|
||||
DFAState s = s0;
|
||||
int t = input.LA(1);
|
||||
int t = state.getInput().LA(1);
|
||||
loop:
|
||||
while ( true ) {
|
||||
if ( dfa_debug ) System.out.println("state "+s.stateNumber+" LA(1)=="+(char)t);
|
||||
|
@ -190,7 +208,7 @@ public class LexerATNSimulator extends ATNSimulator {
|
|||
{
|
||||
try {
|
||||
ATN_failover++;
|
||||
return failOverToATN(input, s);
|
||||
return failOverToATN(state, s);
|
||||
}
|
||||
catch (LexerNoViableAltException nvae) {
|
||||
atnException = nvae;
|
||||
|
@ -205,31 +223,31 @@ public class LexerATNSimulator extends ATNSimulator {
|
|||
if ( s.isAcceptState ) {
|
||||
if ( dfa_debug ) System.out.println("accept; predict "+s.prediction+
|
||||
" in state "+s.stateNumber);
|
||||
markAcceptState(dfaPrevAccept, input);
|
||||
dfaPrevAccept.state = s;
|
||||
markAcceptState(state.dfaPrevAccept, state);
|
||||
state.dfaPrevAccept.state = s;
|
||||
// keep going unless we're at EOF; check if something else could match
|
||||
// EOF never in DFA
|
||||
if ( t==CharStream.EOF ) break;
|
||||
}
|
||||
|
||||
consume(input);
|
||||
t = input.LA(1);
|
||||
consume(state);
|
||||
t = state.getInput().LA(1);
|
||||
}
|
||||
if ( dfaPrevAccept.state==null ) {
|
||||
if ( state.dfaPrevAccept.state==null ) {
|
||||
// if no accept and EOF is first char, return EOF
|
||||
if ( t==CharStream.EOF && input.index()==startIndex ) {
|
||||
if ( t==CharStream.EOF && state.getInput().index()==state.startIndex ) {
|
||||
return Token.EOF;
|
||||
}
|
||||
if ( atnException!=null ) throw atnException;
|
||||
throw new LexerNoViableAltException(recog, input, startIndex, s.configs);
|
||||
throw new LexerNoViableAltException(state.recog, state.getInput(), state.startIndex, s.configs);
|
||||
}
|
||||
|
||||
int ruleIndex = dfaPrevAccept.state.ruleIndex;
|
||||
accept(input, ruleIndex, dfaPrevAccept);
|
||||
return dfaPrevAccept.state.prediction;
|
||||
int ruleIndex = state.dfaPrevAccept.state.ruleIndex;
|
||||
accept(state, ruleIndex, state.dfaPrevAccept);
|
||||
return state.dfaPrevAccept.state.prediction;
|
||||
}
|
||||
|
||||
protected int exec(@NotNull CharStream input, @NotNull OrderedHashSet<ATNConfig> s0) {
|
||||
protected int exec(@NotNull State state, @NotNull OrderedHashSet<ATNConfig> s0) {
|
||||
//System.out.println("enter exec index "+input.index()+" from "+s0);
|
||||
@NotNull
|
||||
OrderedHashSet<ATNConfig> closure = new OrderedHashSet<ATNConfig>();
|
||||
|
@ -238,22 +256,22 @@ public class LexerATNSimulator extends ATNSimulator {
|
|||
|
||||
@NotNull
|
||||
OrderedHashSet<ATNConfig> reach = new OrderedHashSet<ATNConfig>();
|
||||
atnPrevAccept.reset();
|
||||
state.atnPrevAccept.reset();
|
||||
|
||||
int t = input.LA(1);
|
||||
int t = state.getInput().LA(1);
|
||||
|
||||
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 ( debug ) System.out.println("testing "+getTokenName(t)+" at "+c.toString(state.recog, true));
|
||||
|
||||
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);
|
||||
closure(state, new ATNConfig(c, target), reach);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -262,7 +280,7 @@ public class LexerATNSimulator extends ATNSimulator {
|
|||
// we reached state associated with closure for sure, so
|
||||
// make sure it's defined. worst case, we define s0 from
|
||||
// start state configs.
|
||||
DFAState from = addDFAState(closure);
|
||||
DFAState from = addDFAState(state, closure);
|
||||
// we got nowhere on t, don't throw out this knowledge; it'd
|
||||
// cause a failover from DFA later.
|
||||
addDFAEdge(from, t, ERROR);
|
||||
|
@ -270,11 +288,11 @@ public class LexerATNSimulator extends ATNSimulator {
|
|||
}
|
||||
|
||||
// Did we hit a stop state during reach op?
|
||||
processAcceptStates(input, reach);
|
||||
processAcceptStates(state, reach);
|
||||
|
||||
consume(input);
|
||||
addDFAEdge(closure, t, reach);
|
||||
t = input.LA(1);
|
||||
consume(state);
|
||||
addDFAEdge(state, closure, t, reach);
|
||||
t = state.getInput().LA(1);
|
||||
|
||||
// swap to avoid reallocating space
|
||||
// TODO: faster to reallocate?
|
||||
|
@ -286,37 +304,37 @@ public class LexerATNSimulator extends ATNSimulator {
|
|||
} while ( true );
|
||||
|
||||
|
||||
if ( atnPrevAccept.config==null ) {
|
||||
if ( state.atnPrevAccept.config==null ) {
|
||||
// if no accept and EOF is first char, return EOF
|
||||
if ( t==CharStream.EOF && input.index()==startIndex ) {
|
||||
if ( t==CharStream.EOF && state.getInput().index()==state.startIndex ) {
|
||||
return Token.EOF;
|
||||
}
|
||||
throw new LexerNoViableAltException(recog, input, startIndex, reach);
|
||||
throw new LexerNoViableAltException(state.recog, state.getInput(), state.startIndex, reach);
|
||||
}
|
||||
|
||||
int ruleIndex = atnPrevAccept.config.state.ruleIndex;
|
||||
accept(input, ruleIndex, atnPrevAccept);
|
||||
int ruleIndex = state.atnPrevAccept.config.state.ruleIndex;
|
||||
accept(state, ruleIndex, state.atnPrevAccept);
|
||||
return atn.ruleToTokenType[ruleIndex];
|
||||
}
|
||||
|
||||
protected void processAcceptStates(@NotNull CharStream input, @NotNull OrderedHashSet<ATNConfig> reach) {
|
||||
protected void processAcceptStates(@NotNull State state, @NotNull OrderedHashSet<ATNConfig> reach) {
|
||||
for (int ci=0; ci<reach.size(); ci++) {
|
||||
ATNConfig c = reach.get(ci);
|
||||
if ( c.state instanceof RuleStopState) {
|
||||
if ( debug ) {
|
||||
System.out.println("in reach we hit accept state "+c+" index "+
|
||||
input.index()+", reach="+reach+
|
||||
", prevAccept="+atnPrevAccept.config+
|
||||
", prevIndex="+atnPrevAccept.index);
|
||||
state.getInput().index()+", reach="+reach+
|
||||
", prevAccept="+state.atnPrevAccept.config+
|
||||
", prevIndex="+state.atnPrevAccept.index);
|
||||
}
|
||||
int index = input.index();
|
||||
if ( index > atnPrevAccept.index ) {
|
||||
int index = state.getInput().index();
|
||||
if ( index > state.atnPrevAccept.index ) {
|
||||
// will favor prev accept at same index so "int" is keyword not ID
|
||||
markAcceptState(atnPrevAccept, input);
|
||||
atnPrevAccept.config = c;
|
||||
markAcceptState(state.atnPrevAccept, state);
|
||||
state.atnPrevAccept.config = c;
|
||||
if ( debug ) {
|
||||
System.out.println("mark "+c+" @ index="+index+", "+
|
||||
atnPrevAccept.line+":"+atnPrevAccept.charPos);
|
||||
state.atnPrevAccept.line+":"+state.atnPrevAccept.charPos);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -331,21 +349,21 @@ public class LexerATNSimulator extends ATNSimulator {
|
|||
}
|
||||
}
|
||||
|
||||
protected void accept(@NotNull CharStream input, int ruleIndex, @NotNull ExecState prevAccept) {
|
||||
protected void accept(@NotNull State state, int ruleIndex, @NotNull ExecState prevAccept) {
|
||||
if ( debug ) {
|
||||
if ( recog!=null ) System.out.println("ACTION "+
|
||||
recog.getRuleNames()[ruleIndex]+
|
||||
if ( state.recog!=null ) System.out.println("ACTION "+
|
||||
state.recog.getRuleNames()[ruleIndex]+
|
||||
":"+ruleIndex);
|
||||
else System.out.println("ACTION "+ruleIndex+":"+ruleIndex);
|
||||
}
|
||||
int actionIndex = atn.ruleToActionIndex[ruleIndex];
|
||||
if ( actionIndex>=0 && recog!=null ) recog.action(null, ruleIndex, actionIndex);
|
||||
if ( actionIndex>=0 && state.recog!=null ) state.recog.action(null, ruleIndex, actionIndex);
|
||||
|
||||
// seek to after last char in token
|
||||
input.seek(prevAccept.index);
|
||||
line = prevAccept.line;
|
||||
charPositionInLine = prevAccept.charPos;
|
||||
consume(input);
|
||||
state.getInput().seek(prevAccept.index);
|
||||
state.line = prevAccept.line;
|
||||
state.charPositionInLine = prevAccept.charPos;
|
||||
consume(state);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
@ -397,7 +415,7 @@ public class LexerATNSimulator extends ATNSimulator {
|
|||
}
|
||||
|
||||
@NotNull
|
||||
protected OrderedHashSet<ATNConfig> computeStartState(@NotNull IntStream input,
|
||||
protected OrderedHashSet<ATNConfig> computeStartState(@NotNull State state,
|
||||
@NotNull ATNState p)
|
||||
{
|
||||
RuleContext initialContext = RuleContext.EMPTY;
|
||||
|
@ -405,22 +423,22 @@ public class LexerATNSimulator extends ATNSimulator {
|
|||
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);
|
||||
closure(state, c, configs);
|
||||
}
|
||||
return configs;
|
||||
}
|
||||
|
||||
protected void closure(@NotNull ATNConfig config, @NotNull OrderedHashSet<ATNConfig> configs) {
|
||||
protected void closure(@NotNull State state, @NotNull ATNConfig config, @NotNull OrderedHashSet<ATNConfig> configs) {
|
||||
if ( debug ) {
|
||||
System.out.println("closure("+config.toString(recog, true)+")");
|
||||
System.out.println("closure("+config.toString(state.recog, true)+")");
|
||||
}
|
||||
|
||||
// TODO? if ( closure.contains(t) ) return;
|
||||
|
||||
if ( config.state instanceof RuleStopState ) {
|
||||
if ( debug ) {
|
||||
if ( recog!=null ) System.out.println("closure at "+
|
||||
recog.getRuleNames()[config.state.ruleIndex]+
|
||||
if ( state.recog!=null ) System.out.println("closure at "+
|
||||
state.recog.getRuleNames()[config.state.ruleIndex]+
|
||||
" rule stop "+config);
|
||||
else System.out.println("closure at rule stop "+config);
|
||||
}
|
||||
|
@ -433,7 +451,7 @@ public class LexerATNSimulator extends ATNSimulator {
|
|||
RuleTransition rt = (RuleTransition)invokingState.transition(0);
|
||||
ATNState retState = rt.followState;
|
||||
ATNConfig c = new ATNConfig(retState, config.alt, newContext);
|
||||
closure(c, configs);
|
||||
closure(state, c, configs);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -445,13 +463,13 @@ public class LexerATNSimulator extends ATNSimulator {
|
|||
ATNState p = config.state;
|
||||
for (int i=0; i<p.getNumberOfTransitions(); i++) {
|
||||
Transition t = p.transition(i);
|
||||
ATNConfig c = getEpsilonTarget(config, t);
|
||||
if ( c!=null ) closure(c, configs);
|
||||
ATNConfig c = getEpsilonTarget(state, config, t);
|
||||
if ( c!=null ) closure(state, c, configs);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ATNConfig getEpsilonTarget(@NotNull ATNConfig config, @NotNull Transition t) {
|
||||
public ATNConfig getEpsilonTarget(@NotNull State state, @NotNull ATNConfig config, @NotNull Transition t) {
|
||||
ATNState p = config.state;
|
||||
ATNConfig c = null;
|
||||
if ( t.getClass() == RuleTransition.class ) {
|
||||
|
@ -461,7 +479,7 @@ public class LexerATNSimulator extends ATNSimulator {
|
|||
}
|
||||
else if ( t.getClass() == PredicateTransition.class ) {
|
||||
PredicateTransition pt = (PredicateTransition)t;
|
||||
if ( recog.sempred(null, pt.ruleIndex, pt.predIndex) ) {
|
||||
if ( state.recog.sempred(null, pt.ruleIndex, pt.predIndex) ) {
|
||||
c = new ATNConfig(config, t.target);
|
||||
c.traversedPredicate = true;
|
||||
}
|
||||
|
@ -476,37 +494,38 @@ public class LexerATNSimulator extends ATNSimulator {
|
|||
return c;
|
||||
}
|
||||
|
||||
int failOverToATN(@NotNull CharStream input, @NotNull DFAState s) {
|
||||
if ( dfa_debug ) System.out.println("no edge for "+(char)input.LA(1));
|
||||
int failOverToATN(@NotNull State state, @NotNull DFAState s) {
|
||||
if ( dfa_debug ) System.out.println("no edge for "+(char)state.getInput().LA(1));
|
||||
if ( dfa_debug ) {
|
||||
System.out.println("ATN exec upon "+
|
||||
input.substring(startIndex,input.index())+
|
||||
state.getInput().substring(state.startIndex, state.getInput().index())+
|
||||
" at DFA state "+s.stateNumber+" = "+s.configs);
|
||||
}
|
||||
int ttype = exec(input, s.configs);
|
||||
int ttype = exec(state, s.configs);
|
||||
if ( dfa_debug ) {
|
||||
System.out.println("back from DFA update, ttype="+ttype+
|
||||
", dfa[mode "+mode+"]=\n"+
|
||||
dfa[mode].toLexerString());
|
||||
", dfa[mode "+state.mode+"]=\n"+
|
||||
dfa[state.mode].toLexerString());
|
||||
}
|
||||
// action already executed by ATN
|
||||
// we've updated DFA, exec'd action, and have our deepest answer
|
||||
return ttype;
|
||||
}
|
||||
|
||||
protected void markAcceptState(@NotNull ExecState state, @NotNull CharStream input) {
|
||||
state.index = input.index();
|
||||
state.line = line;
|
||||
state.charPos = charPositionInLine;
|
||||
protected void markAcceptState(@NotNull ExecState execState, @NotNull State state) {
|
||||
execState.index = state.getInput().index();
|
||||
execState.line = state.line;
|
||||
execState.charPos = state.charPositionInLine;
|
||||
}
|
||||
|
||||
protected void addDFAEdge(@NotNull OrderedHashSet<ATNConfig> p,
|
||||
protected void addDFAEdge(@NotNull State state,
|
||||
@NotNull OrderedHashSet<ATNConfig> p,
|
||||
int t,
|
||||
@NotNull OrderedHashSet<ATNConfig> q)
|
||||
{
|
||||
// System.out.println("MOVE "+p+" -> "+q+" upon "+getTokenName(t));
|
||||
DFAState from = addDFAState(p);
|
||||
DFAState to = addDFAState(q);
|
||||
DFAState from = addDFAState(state, p);
|
||||
DFAState to = addDFAState(state, q);
|
||||
addDFAEdge(from, t, to);
|
||||
}
|
||||
|
||||
|
@ -547,9 +566,9 @@ public class LexerATNSimulator extends ATNSimulator {
|
|||
test them, we cannot cash the DFA state target of ID.
|
||||
*/
|
||||
@Nullable
|
||||
protected DFAState addDFAState(@NotNull OrderedHashSet<ATNConfig> configs) {
|
||||
protected DFAState addDFAState(@NotNull State state, @NotNull OrderedHashSet<ATNConfig> configs) {
|
||||
DFAState proposed = new DFAState(configs);
|
||||
DFAState existing = dfa[mode].states.get(proposed);
|
||||
DFAState existing = dfa[state.mode].states.get(proposed);
|
||||
if ( existing!=null ) return existing;
|
||||
|
||||
DFAState newState = proposed;
|
||||
|
@ -573,10 +592,10 @@ public class LexerATNSimulator extends ATNSimulator {
|
|||
|
||||
if ( traversedPredicate ) return null; // cannot cache
|
||||
|
||||
newState.stateNumber = dfa[mode].states.size();
|
||||
newState.stateNumber = dfa[state.mode].states.size();
|
||||
newState.configs = new OrderedHashSet<ATNConfig>();
|
||||
newState.configs.addAll(configs);
|
||||
dfa[mode].states.put(newState, newState);
|
||||
dfa[state.mode].states.put(newState, newState);
|
||||
return newState;
|
||||
}
|
||||
|
||||
|
@ -587,27 +606,27 @@ public class LexerATNSimulator extends ATNSimulator {
|
|||
|
||||
/** Get the text of the current token */
|
||||
@NotNull
|
||||
public String getText(@NotNull CharStream input) {
|
||||
return input.substring(this.startIndex, input.index());
|
||||
public String getText(@NotNull State state) {
|
||||
return state.getInput().substring(state.startIndex, state.getInput().index());
|
||||
}
|
||||
|
||||
public int getLine() {
|
||||
return line;
|
||||
public int getLine(@NotNull State state) {
|
||||
return state.line;
|
||||
}
|
||||
|
||||
public int getCharPositionInLine() {
|
||||
return charPositionInLine;
|
||||
public int getCharPositionInLine(@NotNull State state) {
|
||||
return state.charPositionInLine;
|
||||
}
|
||||
|
||||
public void consume(@NotNull CharStream input) {
|
||||
int curChar = input.LA(1);
|
||||
public void consume(@NotNull State state) {
|
||||
int curChar = state.getInput().LA(1);
|
||||
if ( curChar=='\n' ) {
|
||||
line++;
|
||||
charPositionInLine=0;
|
||||
state.line++;
|
||||
state.charPositionInLine=0;
|
||||
} else {
|
||||
charPositionInLine++;
|
||||
state.charPositionInLine++;
|
||||
}
|
||||
input.consume();
|
||||
state.getInput().consume();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
|
|
@ -46,127 +46,151 @@ public class ParserATNSimulator<Symbol> extends ATNSimulator {
|
|||
public static int retry_with_context = 0;
|
||||
public static int retry_with_context_indicates_no_conflict = 0;
|
||||
|
||||
@Nullable
|
||||
protected final BaseRecognizer<Symbol> parser;
|
||||
public static class State<Symbol> {
|
||||
@Nullable
|
||||
protected final BaseRecognizer<Symbol> parser;
|
||||
|
||||
private final SymbolStream<Symbol> input;
|
||||
|
||||
public boolean userWantsCtxSensitive = false;
|
||||
|
||||
/** This is the original context upon entry to the ATN simulator.
|
||||
* ATNConfig objects carry on tracking the new context derived from
|
||||
* the decision point. This field is used instead of passing the value
|
||||
* around to the various functions, which would be confusing. Its
|
||||
* value is reset upon prediction call to adaptivePredict() or the
|
||||
* predictATN/DFA methods.
|
||||
*
|
||||
* The full stack at any moment is [config.outerContext + config.context].
|
||||
*/
|
||||
@NotNull
|
||||
public RuleContext outerContext = RuleContext.EMPTY;
|
||||
|
||||
@Nullable
|
||||
public ATNConfig prevAccept; // TODO Move down? used to avoid passing int down and back up in method calls
|
||||
|
||||
public int prevAcceptIndex = -1;
|
||||
|
||||
public State(@NotNull BaseRecognizer<Symbol> parser) {
|
||||
this.parser = parser;
|
||||
this.input = null;
|
||||
}
|
||||
|
||||
public State(@NotNull SymbolStream<Symbol> input) {
|
||||
this.parser = null;
|
||||
this.input = input;
|
||||
}
|
||||
|
||||
public BaseRecognizer<Symbol> getParser() {
|
||||
return parser;
|
||||
}
|
||||
|
||||
public SymbolStream<Symbol> getInput() {
|
||||
if (parser != null) {
|
||||
return parser.getInputStream();
|
||||
} else {
|
||||
return input;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public final Map<RuleContext, DFA[]> ctxToDFAs;
|
||||
public Map<RuleContext, DFA>[] decisionToDFAPerCtx; // TODO: USE THIS ONE
|
||||
@NotNull
|
||||
public final DFA[] decisionToDFA;
|
||||
protected boolean userWantsCtxSensitive = false;
|
||||
|
||||
/** This is the original context upon entry to the ATN simulator.
|
||||
* ATNConfig objects carry on tracking the new context derived from
|
||||
* the decision point. This field is used instead of passing the value
|
||||
* around to the various functions, which would be confusing. Its
|
||||
* value is reset upon prediction call to adaptivePredict() or the
|
||||
* predictATN/DFA methods.
|
||||
*
|
||||
* The full stack at any moment is [config.outerContext + config.context].
|
||||
*/
|
||||
@NotNull
|
||||
protected RuleContext outerContext = RuleContext.EMPTY;
|
||||
@Nullable
|
||||
protected ATNConfig prevAccept; // TODO Move down? used to avoid passing int down and back up in method calls
|
||||
protected int prevAcceptIndex = -1;
|
||||
|
||||
public ParserATNSimulator(@NotNull ATN atn) {
|
||||
this(null, atn);
|
||||
}
|
||||
|
||||
public ParserATNSimulator(@Nullable BaseRecognizer<Symbol> parser, @NotNull ATN atn) {
|
||||
super(atn);
|
||||
this.parser = parser;
|
||||
ctxToDFAs = new HashMap<RuleContext, DFA[]>();
|
||||
// TODO (sam): why distinguish on parser != null?
|
||||
decisionToDFA = new DFA[atn.getNumberOfDecisions() + (parser != null ? 1 : 0)];
|
||||
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(@NotNull SymbolStream<Symbol> input, int decision, @Nullable RuleContext outerContext) {
|
||||
public int adaptivePredict(@NotNull State<Symbol> state, int decision, @Nullable RuleContext outerContext) {
|
||||
predict_calls++;
|
||||
DFA dfa = decisionToDFA[decision];
|
||||
if ( dfa==null || dfa.s0==null ) {
|
||||
ATNState startState = atn.decisionToState.get(decision);
|
||||
decisionToDFA[decision] = dfa = new DFA(startState);
|
||||
dfa.decision = decision;
|
||||
return predictATN(dfa, input, outerContext, false);
|
||||
return predictATN(dfa, state, outerContext, false);
|
||||
}
|
||||
else {
|
||||
//dump(dfa);
|
||||
// start with the DFA
|
||||
int m = input.mark();
|
||||
int index = input.index();
|
||||
int m = state.getInput().mark();
|
||||
int index = state.getInput().index();
|
||||
try {
|
||||
int alt = execDFA(input, dfa, dfa.s0, outerContext);
|
||||
int alt = execDFA(state, dfa, dfa.s0, outerContext);
|
||||
return alt;
|
||||
}
|
||||
finally {
|
||||
input.seek(index);
|
||||
input.release(m);
|
||||
state.getInput().seek(index);
|
||||
state.getInput().release(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int predictATN(@NotNull DFA dfa, @NotNull SymbolStream<Symbol> input,
|
||||
public int predictATN(@NotNull DFA dfa, @NotNull State<Symbol> state,
|
||||
@Nullable RuleContext outerContext,
|
||||
boolean useContext)
|
||||
{
|
||||
if ( outerContext==null ) outerContext = RuleContext.EMPTY;
|
||||
this.outerContext = outerContext;
|
||||
state.outerContext = outerContext;
|
||||
if ( debug ) System.out.println("ATN decision "+dfa.decision+
|
||||
" exec LA(1)=="+ getLookaheadName(input) +
|
||||
", outerContext="+outerContext.toString(parser));
|
||||
" exec LA(1)=="+ getLookaheadName(state) +
|
||||
", outerContext="+outerContext.toString(state.parser));
|
||||
RuleContext ctx = RuleContext.EMPTY;
|
||||
if ( useContext ) ctx = outerContext;
|
||||
OrderedHashSet<ATNConfig> s0_closure =
|
||||
computeStartState(dfa.decision, dfa.atnStartState, ctx);
|
||||
computeStartState(state, dfa.decision, dfa.atnStartState, ctx);
|
||||
dfa.s0 = addDFAState(dfa, s0_closure);
|
||||
if ( prevAccept!=null ) {
|
||||
if ( state.prevAccept!=null ) {
|
||||
dfa.s0.isAcceptState = true;
|
||||
dfa.s0.prediction = prevAccept.alt;
|
||||
dfa.s0.prediction = state.prevAccept.alt;
|
||||
}
|
||||
|
||||
int alt = 0;
|
||||
int m = input.mark();
|
||||
int index = input.index();
|
||||
int m = state.getInput().mark();
|
||||
int index = state.getInput().index();
|
||||
try {
|
||||
alt = execATN(input, dfa, m, s0_closure, useContext);
|
||||
alt = execATN(state, dfa, m, s0_closure, useContext);
|
||||
}
|
||||
catch (NoViableAltException nvae) {
|
||||
if ( debug ) dumpDeadEndConfigs(nvae);
|
||||
if ( debug ) dumpDeadEndConfigs(state, nvae);
|
||||
throw nvae;
|
||||
}
|
||||
finally {
|
||||
input.seek(index);
|
||||
input.release(m);
|
||||
state.getInput().seek(index);
|
||||
state.getInput().release(m);
|
||||
}
|
||||
if ( debug ) System.out.println("DFA after predictATN: "+dfa.toString());
|
||||
return alt;
|
||||
}
|
||||
|
||||
// doesn't create DFA when matching
|
||||
public int matchATN(@NotNull SymbolStream<Symbol> input, @NotNull ATNState startState) {
|
||||
public int matchATN(@NotNull State<Symbol> state, @NotNull ATNState startState) {
|
||||
DFA dfa = new DFA(startState);
|
||||
RuleContext ctx = RuleContext.EMPTY;
|
||||
OrderedHashSet<ATNConfig> s0_closure = computeStartState(dfa.decision, startState, ctx);
|
||||
return execATN(input, dfa, input.index(), s0_closure, false);
|
||||
OrderedHashSet<ATNConfig> s0_closure = computeStartState(state, dfa.decision, startState, ctx);
|
||||
return execATN(state, dfa, state.getInput().index(), s0_closure, false);
|
||||
}
|
||||
|
||||
public int execDFA(@NotNull SymbolStream<Symbol> input, @NotNull DFA dfa, @NotNull DFAState s0, @Nullable RuleContext outerContext) {
|
||||
public int execDFA(@NotNull State<Symbol> state, @NotNull DFA dfa, @NotNull DFAState s0, @Nullable RuleContext outerContext) {
|
||||
// dump(dfa);
|
||||
if ( outerContext==null ) outerContext = RuleContext.EMPTY;
|
||||
this.outerContext = outerContext;
|
||||
state.outerContext = outerContext;
|
||||
if ( dfa_debug ) System.out.println("DFA decision "+dfa.decision+
|
||||
" exec LA(1)=="+ getLookaheadName(input) +
|
||||
", outerContext="+outerContext.toString(parser));
|
||||
" exec LA(1)=="+ getLookaheadName(state) +
|
||||
", outerContext="+outerContext.toString(state.parser));
|
||||
DFAState prevAcceptState = null;
|
||||
DFAState s = s0;
|
||||
int t = input.LA(1);
|
||||
int startIndex = input.index();
|
||||
int t = state.getInput().LA(1);
|
||||
int startIndex = state.getInput().index();
|
||||
loop:
|
||||
while ( true ) {
|
||||
if ( dfa_debug ) System.out.println("DFA state "+s.stateNumber+" LA(1)=="+t);
|
||||
|
@ -178,9 +202,9 @@ public class ParserATNSimulator<Symbol> extends ATNSimulator {
|
|||
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(startIndex);
|
||||
state.getInput().seek(startIndex);
|
||||
DFA throwAwayDFA = new DFA(dfa.atnStartState);
|
||||
int alt = execATN(input, throwAwayDFA, startIndex, s0.configs, false);
|
||||
int alt = execATN(state, throwAwayDFA, startIndex, s0.configs, false);
|
||||
s.ctxToPrediction.put(outerContext, alt);
|
||||
return alt;
|
||||
}
|
||||
|
@ -197,19 +221,19 @@ public class ParserATNSimulator<Symbol> extends ATNSimulator {
|
|||
int alt = -1;
|
||||
if ( dfa_debug ) {
|
||||
System.out.println("ATN exec upon "+
|
||||
getInputString(input, startIndex) +
|
||||
getInputString(state.getInput(), startIndex) +
|
||||
" at DFA state "+s.stateNumber);
|
||||
}
|
||||
try {
|
||||
alt = execATN(input, dfa, startIndex, s.configs, false);
|
||||
alt = execATN(state, dfa, startIndex, s.configs, 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];
|
||||
DFAState d = s.edges[state.getInput().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
|
||||
s.edges[state.getInput().LA(1)+1] = ERROR; // IGNORE really not error
|
||||
}
|
||||
}
|
||||
if ( dfa_debug ) {
|
||||
|
@ -228,11 +252,11 @@ public class ParserATNSimulator<Symbol> extends ATNSimulator {
|
|||
}
|
||||
DFAState target = s.edges[t+1];
|
||||
if ( target == ERROR ) {
|
||||
throw noViableAlt(input, outerContext, s.configs, startIndex);
|
||||
throw noViableAlt(state, outerContext, s.configs, startIndex);
|
||||
}
|
||||
s = target;
|
||||
input.consume();
|
||||
t = input.LA(1);
|
||||
state.getInput().consume();
|
||||
t = state.getInput().LA(1);
|
||||
}
|
||||
if ( prevAcceptState==null ) {
|
||||
if ( debug ) System.out.println("!!! no viable alt in dfa");
|
||||
|
@ -253,13 +277,13 @@ public class ParserATNSimulator<Symbol> extends ATNSimulator {
|
|||
return "n/a";
|
||||
}
|
||||
|
||||
public int execATN(@NotNull SymbolStream<Symbol> input,
|
||||
public int execATN(@NotNull State<Symbol> state,
|
||||
@NotNull DFA dfa,
|
||||
int startIndex,
|
||||
@NotNull OrderedHashSet<ATNConfig> s0,
|
||||
boolean useContext)
|
||||
{
|
||||
if ( debug ) System.out.println("execATN decision "+dfa.decision+" exec LA(1)=="+ getLookaheadName(input));
|
||||
if ( debug ) System.out.println("execATN decision "+dfa.decision+" exec LA(1)=="+ getLookaheadName(state));
|
||||
ATN_failover++;
|
||||
OrderedHashSet<ATNConfig> closure = new OrderedHashSet<ATNConfig>();
|
||||
|
||||
|
@ -267,18 +291,18 @@ public class ParserATNSimulator<Symbol> extends ATNSimulator {
|
|||
|
||||
if ( debug ) System.out.println("start state closure="+closure);
|
||||
|
||||
int t = input.LA(1);
|
||||
if ( t==Token.EOF && prevAccept!=null ) {
|
||||
int t = state.getInput().LA(1);
|
||||
if ( t==Token.EOF && state.prevAccept!=null ) {
|
||||
// computeStartState must have reached end of rule
|
||||
return prevAccept.alt;
|
||||
return state.prevAccept.alt;
|
||||
}
|
||||
|
||||
DecisionState decState = null;
|
||||
if ( atn.decisionToState.size()>0 ) decState = atn.decisionToState.get(dfa.decision);
|
||||
if ( debug ) System.out.println("decision state = "+decState);
|
||||
|
||||
prevAccept = null;
|
||||
prevAcceptIndex = -1;
|
||||
state.prevAccept = null;
|
||||
state.prevAcceptIndex = -1;
|
||||
OrderedHashSet<ATNConfig> reach = new OrderedHashSet<ATNConfig>();
|
||||
|
||||
do { // while more work
|
||||
|
@ -286,39 +310,39 @@ public class ParserATNSimulator<Symbol> extends ATNSimulator {
|
|||
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());
|
||||
if ( debug ) System.out.println("testing "+getTokenName(state, 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 ) {
|
||||
Set<ATNConfig> closureBusy = new HashSet<ATNConfig>();
|
||||
closure(new ATNConfig(c, target), reach, decState, closureBusy);
|
||||
closure(state, new ATNConfig(c, target), reach, decState, closureBusy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// resolve ambig in DFAState for reach
|
||||
Set<Integer> ambigAlts = getAmbiguousAlts(reach);
|
||||
Set<Integer> ambigAlts = getAmbiguousAlts(state, reach);
|
||||
if ( ambigAlts!=null ) {
|
||||
if ( debug ) {
|
||||
int i = -1;
|
||||
if ( outerContext!=null && outerContext.s>=0 ) {
|
||||
i = atn.states.get(outerContext.s).ruleIndex;
|
||||
if ( state.outerContext!=null && state.outerContext.s>=0 ) {
|
||||
i = atn.states.get(state.outerContext.s).ruleIndex;
|
||||
}
|
||||
String rname = getRuleName(i);
|
||||
String rname = getRuleName(state, i);
|
||||
System.out.println("AMBIG dec "+dfa.decision+" in "+rname+" for alt "+ambigAlts+" upon "+
|
||||
getInputString(input, startIndex));
|
||||
getInputString(state.getInput(), startIndex));
|
||||
System.out.println("REACH="+reach);
|
||||
}
|
||||
dfa.conflict = true; // at least one DFA state is ambiguous
|
||||
if ( !userWantsCtxSensitive ) reportConflict(startIndex, input.index(), ambigAlts, reach);
|
||||
if ( !state.userWantsCtxSensitive ) reportConflict(state, startIndex, state.getInput().index(), ambigAlts, reach);
|
||||
|
||||
// ATNState loc = atn.states.get(outerContext.s);
|
||||
// String rname = recog.getRuleNames()[loc.ruleIndex];
|
||||
// System.out.println("AMBIG orig="+outerContext.toString((BaseRecognizer)recog)+" for alt "+ambigAlts+" upon "+
|
||||
// input.toString(startIndex, input.index()));
|
||||
if ( !userWantsCtxSensitive || useContext ) {
|
||||
if ( !state.userWantsCtxSensitive || useContext ) {
|
||||
// resolve ambiguity
|
||||
if ( decState.isGreedy ) {
|
||||
// if greedy, resolve in favor of alt coming first
|
||||
|
@ -331,7 +355,7 @@ public class ParserATNSimulator<Symbol> extends ATNSimulator {
|
|||
}
|
||||
}
|
||||
else {
|
||||
return retryWithContext(input, dfa, startIndex, outerContext,
|
||||
return retryWithContext(state, dfa, startIndex, state.outerContext,
|
||||
closure, t, reach, ambigAlts);
|
||||
}
|
||||
}
|
||||
|
@ -342,7 +366,7 @@ public class ParserATNSimulator<Symbol> extends ATNSimulator {
|
|||
if ( uniqueAlt!=ATN.INVALID_ALT_NUMBER ) {
|
||||
if ( debug ) System.out.println("PREDICT alt "+uniqueAlt+
|
||||
" decision "+dfa.decision+
|
||||
" at index "+input.index());
|
||||
" at index "+state.getInput().index());
|
||||
addDFAEdge(dfa, closure, t, reach);
|
||||
makeAcceptState(dfa, reach, uniqueAlt);
|
||||
return uniqueAlt;
|
||||
|
@ -354,8 +378,8 @@ public class ParserATNSimulator<Symbol> extends ATNSimulator {
|
|||
ATNConfig cstop = configWithAltAtStopState(reach, exitAlt);
|
||||
if ( cstop!=null ) {
|
||||
if ( debug ) System.out.println("nongreedy at stop state for exit branch");
|
||||
prevAccept = cstop;
|
||||
prevAcceptIndex = input.index();
|
||||
state.prevAccept = cstop;
|
||||
state.prevAcceptIndex = state.getInput().index();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -366,9 +390,9 @@ public class ParserATNSimulator<Symbol> extends ATNSimulator {
|
|||
|
||||
// If we matched t anywhere, need to consume and add closer-t->reach DFA edge
|
||||
// else error if no previous accept
|
||||
input.consume();
|
||||
state.getInput().consume();
|
||||
addDFAEdge(dfa, closure, t, reach);
|
||||
t = input.LA(1);
|
||||
t = state.getInput().LA(1);
|
||||
|
||||
// swap to avoid reallocating space
|
||||
OrderedHashSet<ATNConfig> tmp = reach;
|
||||
|
@ -377,13 +401,13 @@ public class ParserATNSimulator<Symbol> extends ATNSimulator {
|
|||
reach.clear(); // TODO: THIS MIGHT BE SLOW! kills each element; realloc might be faster
|
||||
} while ( true );
|
||||
|
||||
if ( prevAccept==null ) {
|
||||
if ( state.prevAccept==null ) {
|
||||
// System.out.println("no viable token at input "+ getLookaheadName(input) +", index "+input.index());
|
||||
throw noViableAlt(input, outerContext, closure, startIndex);
|
||||
throw noViableAlt(state, state.outerContext, closure, startIndex);
|
||||
}
|
||||
|
||||
if ( debug ) System.out.println("PREDICT " + prevAccept + " index " + prevAccept.alt);
|
||||
return prevAccept.alt;
|
||||
if ( debug ) System.out.println("PREDICT " + state.prevAccept + " index " + state.prevAccept.alt);
|
||||
return state.prevAccept.alt;
|
||||
}
|
||||
|
||||
protected int resolveToMinAlt(@NotNull OrderedHashSet<ATNConfig> reach, @NotNull Set<Integer> ambigAlts) {
|
||||
|
@ -407,7 +431,7 @@ public class ParserATNSimulator<Symbol> extends ATNSimulator {
|
|||
return exitAlt;
|
||||
}
|
||||
|
||||
public int retryWithContext(@NotNull SymbolStream<Symbol> input,
|
||||
public int retryWithContext(@NotNull State<Symbol> state,
|
||||
@NotNull DFA dfa,
|
||||
int startIndex,
|
||||
@NotNull RuleContext originalContext,
|
||||
|
@ -418,39 +442,39 @@ public class ParserATNSimulator<Symbol> extends ATNSimulator {
|
|||
{
|
||||
// ASSUMES PREDICT ONLY
|
||||
retry_with_context++;
|
||||
int old_k = input.index();
|
||||
int old_k = state.getInput().index();
|
||||
// retry using context, if any; if none, kill all but min as before
|
||||
if ( debug ) System.out.println("RETRY "+ getInputString(input, startIndex) +
|
||||
if ( debug ) System.out.println("RETRY "+ getInputString(state.getInput(), startIndex) +
|
||||
" 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);
|
||||
reportAmbiguity(state, startIndex, state.getInput().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
|
||||
state.getInput().seek(startIndex); // rewind
|
||||
DFA ctx_dfa = new DFA(dfa.atnStartState);
|
||||
int ctx_alt = predictATN(ctx_dfa, input, originalContext, true);
|
||||
int ctx_alt = predictATN(ctx_dfa, state, 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 ) {
|
||||
// System.out.println("retry gives ambig for "+input.toString(startIndex, input.index()));
|
||||
reportAmbiguity(startIndex, input.index(), ambigAlts, reach);
|
||||
// System.out.println("retry gives ambig for "+state.getInput().toString(startIndex, state.getInput().index()));
|
||||
reportAmbiguity(state, startIndex, state.getInput().index(), ambigAlts, reach);
|
||||
}
|
||||
else {
|
||||
// System.out.println("NO ambig for "+input.toString(startIndex, input.index()));
|
||||
// System.out.println("NO ambig for "+state.getInput().toString(startIndex, state.getInput().index()));
|
||||
// System.out.println(ctx_dfa.toString(parser.getTokenNames()));
|
||||
if ( old_k != input.index() ) {
|
||||
System.out.println("ACK!!!!!!!! diff k; old="+(old_k-startIndex+1)+", new="+(input.index()-startIndex+1));
|
||||
if ( old_k != state.getInput().index() ) {
|
||||
System.out.println("ACK!!!!!!!! diff k; old="+(old_k-startIndex+1)+", new="+(state.getInput().index()-startIndex+1));
|
||||
}
|
||||
retry_with_context_indicates_no_conflict++;
|
||||
reportContextSensitivity(startIndex, input.index(), ambigAlts, reach);
|
||||
reportContextSensitivity(state, startIndex, state.getInput().index(), ambigAlts, reach);
|
||||
}
|
||||
// it's not context-sensitive; true ambig. fall thru to strip dead alts
|
||||
|
||||
|
@ -469,11 +493,11 @@ public class ParserATNSimulator<Symbol> extends ATNSimulator {
|
|||
}
|
||||
|
||||
@NotNull
|
||||
public OrderedHashSet<ATNConfig> computeStartState(int decision, @NotNull ATNState p, @Nullable RuleContext ctx) {
|
||||
public OrderedHashSet<ATNConfig> computeStartState(@NotNull State<Symbol> state, int decision, @NotNull ATNState p, @Nullable RuleContext ctx) {
|
||||
RuleContext 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;
|
||||
state.prevAccept = null; // might reach end rule; track
|
||||
state.prevAcceptIndex = -1;
|
||||
|
||||
DecisionState decState = null;
|
||||
if ( atn.decisionToState.size()>0 ) decState = atn.decisionToState.get(decision);
|
||||
|
@ -482,7 +506,7 @@ public class ParserATNSimulator<Symbol> extends ATNSimulator {
|
|||
ATNState target = p.transition(i).target;
|
||||
ATNConfig c = new ATNConfig(target, i+1, initialContext);
|
||||
Set<ATNConfig> closureBusy = new HashSet<ATNConfig>();
|
||||
closure(c, configs, decState, closureBusy);
|
||||
closure(state, c, configs, decState, closureBusy);
|
||||
}
|
||||
|
||||
return configs;
|
||||
|
@ -520,7 +544,8 @@ public class ParserATNSimulator<Symbol> extends ATNSimulator {
|
|||
ambig detection thought :(
|
||||
*/
|
||||
|
||||
protected void closure(@NotNull ATNConfig config,
|
||||
protected void closure(@NotNull State<Symbol> state,
|
||||
@NotNull ATNConfig config,
|
||||
@NotNull OrderedHashSet<ATNConfig> configs,
|
||||
@Nullable DecisionState decState,
|
||||
@NotNull Set<ATNConfig> closureBusy)
|
||||
|
@ -542,7 +567,7 @@ public class ParserATNSimulator<Symbol> extends ATNSimulator {
|
|||
// gotten that context AFTER having fallen off a rule.
|
||||
// Make sure we track that we are now out of context.
|
||||
c.reachesIntoOuterContext = config.reachesIntoOuterContext;
|
||||
closure(c, configs, decState, closureBusy);
|
||||
closure(state, c, configs, decState, closureBusy);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
|
@ -550,13 +575,13 @@ public class ParserATNSimulator<Symbol> extends ATNSimulator {
|
|||
if ( decState!=null && !decState.isGreedy ) {
|
||||
if ( debug ) System.out.println("nongreedy decision state = "+decState);
|
||||
if ( debug ) System.out.println("NONGREEDY at stop state of "+
|
||||
getRuleName(config.state.ruleIndex));
|
||||
getRuleName(state, config.state.ruleIndex));
|
||||
// don't purse past end of a rule for any nongreedy decision
|
||||
configs.add(config);
|
||||
return;
|
||||
}
|
||||
if ( debug ) System.out.println("FALLING off rule "+
|
||||
getRuleName(config.state.ruleIndex));
|
||||
getRuleName(state, config.state.ruleIndex));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -567,7 +592,7 @@ public class ParserATNSimulator<Symbol> extends ATNSimulator {
|
|||
for (int i=0; i<p.getNumberOfTransitions(); i++) {
|
||||
Transition t = p.transition(i);
|
||||
boolean ignorePreds = config.traversedAction;
|
||||
ATNConfig c = getEpsilonTarget(config, t, ignorePreds);
|
||||
ATNConfig c = getEpsilonTarget(state, config, t, ignorePreds);
|
||||
if ( c!=null ) {
|
||||
if ( config.state instanceof RuleStopState ) {
|
||||
// fell off end of rule.
|
||||
|
@ -576,24 +601,24 @@ public class ParserATNSimulator<Symbol> extends ATNSimulator {
|
|||
// preds if this is > 0.
|
||||
c.reachesIntoOuterContext++;
|
||||
}
|
||||
closure(c, configs, decState, closureBusy);
|
||||
closure(state, c, configs, decState, closureBusy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private String getRuleName(int index) {
|
||||
if ( parser!=null && index>=0 ) return parser.getRuleNames()[index];
|
||||
private String getRuleName(State<Symbol> state, int index) {
|
||||
if ( state.parser!=null && index>=0 ) return state.parser.getRuleNames()[index];
|
||||
return "<rule "+index+">";
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ATNConfig getEpsilonTarget(@NotNull ATNConfig config, @NotNull Transition t, boolean ignorePreds) {
|
||||
public ATNConfig getEpsilonTarget(@NotNull State<Symbol> state, @NotNull ATNConfig config, @NotNull Transition t, boolean ignorePreds) {
|
||||
if ( t instanceof RuleTransition ) {
|
||||
return ruleTransition(config, t);
|
||||
return ruleTransition(state, config, t);
|
||||
}
|
||||
else if ( t instanceof PredicateTransition ) {
|
||||
return predTransition(config, (PredicateTransition)t, ignorePreds);
|
||||
return predTransition(state, config, (PredicateTransition)t, ignorePreds);
|
||||
}
|
||||
else if ( t instanceof ActionTransition ) {
|
||||
return actionTransition(config, (ActionTransition)t);
|
||||
|
@ -618,14 +643,14 @@ public class ParserATNSimulator<Symbol> extends ATNSimulator {
|
|||
}
|
||||
|
||||
@Nullable
|
||||
public ATNConfig predTransition(@NotNull ATNConfig config, @NotNull PredicateTransition pt,
|
||||
public ATNConfig predTransition(@NotNull State<Symbol> state, @NotNull ATNConfig config, @NotNull PredicateTransition pt,
|
||||
boolean ignorePreds)
|
||||
{
|
||||
if ( debug ) {
|
||||
System.out.println("PRED (ignore="+ignorePreds+") "+pt.ruleIndex+":"+pt.predIndex+
|
||||
", ctx dependent="+pt.isCtxDependent);
|
||||
if ( parser != null ) System.out.println("rule surrounding pred is "+
|
||||
parser.getRuleNames()[pt.ruleIndex]);
|
||||
if ( state.parser != null ) System.out.println("rule surrounding pred is "+
|
||||
state.parser.getRuleNames()[pt.ruleIndex]);
|
||||
}
|
||||
// We know the correct context and exactly one spot: in the original
|
||||
// rule that invokes the ATN simulation. We know we are in this rule
|
||||
|
@ -634,7 +659,7 @@ public class ParserATNSimulator<Symbol> extends ATNSimulator {
|
|||
boolean inContext =
|
||||
config.context==RuleContext.EMPTY && config.reachesIntoOuterContext==0;
|
||||
RuleContext ctx = null;
|
||||
if ( inContext ) ctx = outerContext;
|
||||
if ( inContext ) ctx = state.outerContext;
|
||||
|
||||
// We see through the predicate if:
|
||||
// 1) we are ignoring them
|
||||
|
@ -645,8 +670,8 @@ public class ParserATNSimulator<Symbol> extends ATNSimulator {
|
|||
ATNConfig c = null;
|
||||
boolean seeThroughPred =
|
||||
ignorePreds ||
|
||||
(!ignorePreds&&!pt.isCtxDependent&&parser.sempred(ctx, pt.ruleIndex, pt.predIndex))||
|
||||
(!ignorePreds&&pt.isCtxDependent&&inContext&&parser.sempred(ctx, pt.ruleIndex, pt.predIndex));
|
||||
(!ignorePreds&&!pt.isCtxDependent&&state.parser.sempred(ctx, pt.ruleIndex, pt.predIndex))||
|
||||
(!ignorePreds&&pt.isCtxDependent&&inContext&&state.parser.sempred(ctx, pt.ruleIndex, pt.predIndex));
|
||||
if ( seeThroughPred ) {
|
||||
c = new ATNConfig(config, pt.target);
|
||||
c.traversedPredicate = true;
|
||||
|
@ -655,9 +680,9 @@ public class ParserATNSimulator<Symbol> extends ATNSimulator {
|
|||
}
|
||||
|
||||
@NotNull
|
||||
public ATNConfig ruleTransition(@NotNull ATNConfig config, @NotNull Transition t) {
|
||||
public ATNConfig ruleTransition(@NotNull State<Symbol> state, @NotNull ATNConfig config, @NotNull Transition t) {
|
||||
if ( debug ) {
|
||||
System.out.println("CALL rule "+getRuleName(t.target.ruleIndex)+
|
||||
System.out.println("CALL rule "+getRuleName(state, t.target.ruleIndex)+
|
||||
", ctx="+config.context);
|
||||
}
|
||||
ATNState p = config.state;
|
||||
|
@ -666,17 +691,17 @@ public class ParserATNSimulator<Symbol> extends ATNSimulator {
|
|||
return new ATNConfig(config, t.target, newContext);
|
||||
}
|
||||
|
||||
public void reportConflict(int startIndex, int stopIndex, @NotNull Set<Integer> alts, @NotNull OrderedHashSet<ATNConfig> configs) {
|
||||
if ( parser!=null ) parser.reportConflict(startIndex, stopIndex, alts, configs);
|
||||
public void reportConflict(@NotNull State<Symbol> state, int startIndex, int stopIndex, @NotNull Set<Integer> alts, @NotNull OrderedHashSet<ATNConfig> configs) {
|
||||
if ( state.parser!=null ) state.parser.reportConflict(startIndex, stopIndex, alts, configs);
|
||||
}
|
||||
|
||||
public void reportContextSensitivity(int startIndex, int stopIndex, @NotNull Set<Integer> alts, @NotNull OrderedHashSet<ATNConfig> configs) {
|
||||
if ( parser!=null ) parser.reportContextSensitivity(startIndex, stopIndex, alts, configs);
|
||||
public void reportContextSensitivity(@NotNull State<Symbol> state, int startIndex, int stopIndex, @NotNull Set<Integer> alts, @NotNull OrderedHashSet<ATNConfig> configs) {
|
||||
if ( state.parser!=null ) state.parser.reportContextSensitivity(startIndex, stopIndex, alts, configs);
|
||||
}
|
||||
|
||||
/** If context sensitive parsing, we know it's ambiguity not conflict */
|
||||
public void reportAmbiguity(int startIndex, int stopIndex, @NotNull Set<Integer> alts, @NotNull OrderedHashSet<ATNConfig> configs) {
|
||||
if ( parser!=null ) parser.reportAmbiguity(startIndex, stopIndex, alts, configs);
|
||||
public void reportAmbiguity(@NotNull State<Symbol> state, int startIndex, int stopIndex, @NotNull Set<Integer> alts, @NotNull OrderedHashSet<ATNConfig> configs) {
|
||||
if ( state.parser!=null ) state.parser.reportAmbiguity(startIndex, stopIndex, alts, configs);
|
||||
}
|
||||
|
||||
public static int getUniqueAlt(@NotNull Collection<ATNConfig> configs) {
|
||||
|
@ -705,7 +730,7 @@ public class ParserATNSimulator<Symbol> extends ATNSimulator {
|
|||
}
|
||||
|
||||
@Nullable
|
||||
public Set<Integer> getAmbiguousAlts(@NotNull OrderedHashSet<ATNConfig> configs) {
|
||||
public Set<Integer> getAmbiguousAlts(@NotNull State<Symbol> state, @NotNull OrderedHashSet<ATNConfig> configs) {
|
||||
// System.err.println("check ambiguous "+configs);
|
||||
Set<Integer> ambigAlts = null;
|
||||
int numConfigs = configs.size();
|
||||
|
@ -732,9 +757,9 @@ public class ParserATNSimulator<Symbol> extends ATNSimulator {
|
|||
if ( debug ) {
|
||||
System.out.println("we reach state "+c.state.stateNumber+
|
||||
" in rule "+
|
||||
(parser !=null ? getRuleName(c.state.ruleIndex) :"n/a")+
|
||||
" alts "+goal.alt+","+c.alt+" from ctx "+goal.context.toString(parser)
|
||||
+" and "+ c.context.toString(parser));
|
||||
(state.parser !=null ? getRuleName(state, c.state.ruleIndex) :"n/a")+
|
||||
" alts "+goal.alt+","+c.alt+" from ctx "+goal.context.toString(state.parser)
|
||||
+" and "+ c.context.toString(state.parser));
|
||||
}
|
||||
if ( ambigAlts==null ) ambigAlts = new HashSet<Integer>();
|
||||
ambigAlts.add(goal.alt);
|
||||
|
@ -820,13 +845,13 @@ public class ParserATNSimulator<Symbol> extends ATNSimulator {
|
|||
}
|
||||
|
||||
@NotNull
|
||||
public String getTokenName(int t) {
|
||||
public String getTokenName(@NotNull State<Symbol> state, int t) {
|
||||
if ( t==-1 ) return "EOF";
|
||||
if ( parser!=null && parser.getTokenNames()!=null ) {
|
||||
String[] tokensNames = parser.getTokenNames();
|
||||
if ( state.parser!=null && state.parser.getTokenNames()!=null ) {
|
||||
String[] tokensNames = state.parser.getTokenNames();
|
||||
if ( t>=tokensNames.length ) {
|
||||
System.err.println(t+" ttype out of range: "+Arrays.toString(tokensNames));
|
||||
System.err.println(((CommonTokenStream)parser.getInputStream()).getTokens());
|
||||
System.err.println(((CommonTokenStream)state.parser.getInputStream()).getTokens());
|
||||
}
|
||||
else {
|
||||
return tokensNames[t]+"<"+t+">";
|
||||
|
@ -835,52 +860,52 @@ public class ParserATNSimulator<Symbol> extends ATNSimulator {
|
|||
return String.valueOf(t);
|
||||
}
|
||||
|
||||
public String getLookaheadName(SymbolStream<Symbol> input) {
|
||||
return getTokenName(input.LA(1));
|
||||
public String getLookaheadName(State<Symbol> state) {
|
||||
return getTokenName(state, state.getInput().LA(1));
|
||||
}
|
||||
|
||||
public void setContextSensitive(boolean ctxSensitive) {
|
||||
this.userWantsCtxSensitive = ctxSensitive;
|
||||
public void setContextSensitive(@NotNull State<Symbol> state, boolean ctxSensitive) {
|
||||
state.userWantsCtxSensitive = ctxSensitive;
|
||||
}
|
||||
|
||||
public void dumpDeadEndConfigs(@NotNull NoViableAltException nvae) {
|
||||
public void dumpDeadEndConfigs(@NotNull State<Symbol> state, @NotNull 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);
|
||||
trans = "Atom "+getTokenName(state, at.label);
|
||||
}
|
||||
else if ( t instanceof SetTransition ) {
|
||||
SetTransition st = (SetTransition)t;
|
||||
boolean not = st instanceof NotSetTransition;
|
||||
trans = (not?"~":"")+"Set "+st.set.toString();
|
||||
}
|
||||
System.err.println(c.toString(parser, true)+":"+trans);
|
||||
System.err.println(c.toString(state.parser, true)+":"+trans);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public NoViableAltException noViableAlt(@NotNull SymbolStream<Symbol> input, @NotNull RuleContext outerContext,
|
||||
public NoViableAltException noViableAlt(@NotNull State<Symbol> state, @NotNull RuleContext outerContext,
|
||||
@NotNull OrderedHashSet<ATNConfig> configs, int startIndex)
|
||||
{
|
||||
if ( parser instanceof TreeParser) {
|
||||
if ( state.parser instanceof TreeParser) {
|
||||
Symbol startNode = null;
|
||||
if ( input instanceof BufferedASTNodeStream ) {
|
||||
startNode = input.get(startIndex);
|
||||
if ( state.getInput() instanceof BufferedASTNodeStream ) {
|
||||
startNode = state.getInput().get(startIndex);
|
||||
}
|
||||
return new NoViableTreeGrammarAltException(parser,
|
||||
(ASTNodeStream<Symbol>)input,
|
||||
return new NoViableTreeGrammarAltException(state.parser,
|
||||
(ASTNodeStream<Symbol>)state.getInput(),
|
||||
startNode,
|
||||
input.LT(1),
|
||||
state.getInput().LT(1),
|
||||
configs, outerContext);
|
||||
}
|
||||
else {
|
||||
return new NoViableAltException(parser, input,
|
||||
(Token)input.get(startIndex),
|
||||
(Token)input.LT(1),
|
||||
input.LT(1),
|
||||
return new NoViableAltException(state.parser, state.getInput(),
|
||||
(Token)state.getInput().get(startIndex),
|
||||
(Token)state.getInput().LT(1),
|
||||
state.getInput().LT(1),
|
||||
configs, outerContext);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
package org.antlr.v4.runtime.tree;
|
||||
|
||||
import org.antlr.v4.runtime.*;
|
||||
import org.antlr.v4.runtime.atn.ParserATNSimulator;
|
||||
|
||||
/**
|
||||
Cut-n-paste from material I'm not using in the book anymore (edit later
|
||||
|
@ -83,8 +84,8 @@ public class TreeFilter<T> extends TreeParser<T> {
|
|||
protected TokenStream originalTokenStream;
|
||||
protected ASTAdaptor<T> originalAdaptor;
|
||||
|
||||
public TreeFilter(ASTNodeStream<T> input) {
|
||||
super(input);
|
||||
public TreeFilter(ASTNodeStream<T> input, ParserATNSimulator<T> interpreter) {
|
||||
super(input, interpreter);
|
||||
originalAdaptor = input.getTreeAdaptor();
|
||||
originalTokenStream = input.getTokenStream();
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
package org.antlr.v4.runtime.tree;
|
||||
|
||||
import org.antlr.v4.runtime.*;
|
||||
import org.antlr.v4.runtime.atn.ParserATNSimulator;
|
||||
|
||||
import java.util.regex.*;
|
||||
|
||||
|
@ -51,9 +52,16 @@ public class TreeParser<T> extends BaseRecognizer<T> {
|
|||
|
||||
protected ASTNodeStream<T> _input;
|
||||
|
||||
public TreeParser(ASTNodeStream<T> input) {
|
||||
super(input);
|
||||
protected ParserATNSimulator.State<T> state;
|
||||
|
||||
public TreeParser(ASTNodeStream<T> input, ParserATNSimulator<T> interpreter) {
|
||||
super(input, interpreter);
|
||||
_errHandler = new DefaultTreeGrammarErrorStrategy<T>();
|
||||
state = new ParserATNSimulator.State<T>(this);
|
||||
}
|
||||
|
||||
public ParserATNSimulator.State<T> getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -143,15 +143,21 @@ case <f.ruleIndex> : return <f.name>_sempred((<f.ctxType>)_localctx, predIndex);
|
|||
|
||||
parser_ctor(p) ::= <<
|
||||
public <p.name>(TokenStream input) {
|
||||
super(input);
|
||||
_interp = new ParserATNSimulator\<Token>(this,_ATN);
|
||||
this(input, new ParserATNSimulator\<Token>(_ATN));
|
||||
}
|
||||
|
||||
public <p.name>(TokenStream input, ParserATNSimulator\<Token> interpreter) {
|
||||
super(input, interpreter);
|
||||
}
|
||||
>>
|
||||
|
||||
treeparser_ctor(p) ::= <<
|
||||
public <p.name>(ASTNodeStream\<<ASTLabelType()>\> input) {
|
||||
super(input);
|
||||
_interp = new ParserATNSimulator\<<ASTLabelType()>\>(this,_ATN);
|
||||
this(input, new ParserATNSimulator\<<ASTLabelType()>\>(_ATN));
|
||||
}
|
||||
|
||||
public <p.name>(ASTNodeStream\<<ASTLabelType()>\> input, ParserATNSimulator\<<ASTLabelType()>\> interpreter) {
|
||||
super(input, interpreter);
|
||||
}
|
||||
>>
|
||||
|
||||
|
@ -319,7 +325,7 @@ setState(<choice.stateNumber>);
|
|||
_errHandler.sync(this);
|
||||
<if(choice.label)><labelref(choice.label)> = _input.LT(1);<endif>
|
||||
<preamble; separator="\n">
|
||||
switch ( getInterpreter().adaptivePredict(_input,<choice.decision>,_ctx) ) {
|
||||
switch ( getInterpreter().adaptivePredict(state,<choice.decision>,_ctx) ) {
|
||||
<alts:{alt |
|
||||
case <i>:
|
||||
<alt>
|
||||
|
@ -330,7 +336,7 @@ case <i>:
|
|||
OptionalBlock(choice, alts, error) ::= <<
|
||||
setState(<choice.stateNumber>);
|
||||
_errHandler.sync(this);
|
||||
switch ( getInterpreter().adaptivePredict(_input,<choice.decision>,_ctx) ) {
|
||||
switch ( getInterpreter().adaptivePredict(state,<choice.decision>,_ctx) ) {
|
||||
<alts:{alt |
|
||||
case <i>:
|
||||
<alt>
|
||||
|
@ -343,7 +349,7 @@ case <i>:
|
|||
StarBlock(choice, alts, sync) ::= <<
|
||||
setState(<choice.stateNumber>);
|
||||
_errHandler.sync(this);
|
||||
int _alt<choice.uniqueID> = getInterpreter().adaptivePredict(_input,<choice.decision>,_ctx);
|
||||
int _alt<choice.uniqueID> = getInterpreter().adaptivePredict(state,<choice.decision>,_ctx);
|
||||
while ( _alt<choice.uniqueID>!=<choice.exitAlt> && _alt<choice.uniqueID>!=-1 ) {
|
||||
switch ( _alt<choice.uniqueID> ) {
|
||||
<alts:{alt|
|
||||
|
@ -353,14 +359,14 @@ case <i>:
|
|||
}
|
||||
setState(<choice.loopBackStateNumber>);
|
||||
_errHandler.sync(this);
|
||||
_alt<choice.uniqueID> = getInterpreter().adaptivePredict(_input,<choice.decision>,_ctx);
|
||||
_alt<choice.uniqueID> = getInterpreter().adaptivePredict(state,<choice.decision>,_ctx);
|
||||
}
|
||||
>>
|
||||
|
||||
PlusBlock(choice, alts, error) ::= <<
|
||||
setState(<choice.blockStartStateNumber>); <! alt block decision !>
|
||||
_errHandler.sync(this);
|
||||
int _alt<choice.uniqueID> = getInterpreter().adaptivePredict(_input,<choice.decision>,_ctx);
|
||||
int _alt<choice.uniqueID> = getInterpreter().adaptivePredict(state,<choice.decision>,_ctx);
|
||||
do {
|
||||
switch ( _alt<choice.uniqueID> ) {
|
||||
<alts:{alt|
|
||||
|
@ -372,7 +378,7 @@ case <i>:
|
|||
}
|
||||
setState(<choice.loopBackStateNumber>); <! loopback/exit decision !>
|
||||
_errHandler.sync(this);
|
||||
_alt<choice.uniqueID> = getInterpreter().adaptivePredict(_input,<choice.decision>,_ctx);
|
||||
_alt<choice.uniqueID> = getInterpreter().adaptivePredict(state,<choice.decision>,_ctx);
|
||||
} while ( _alt<choice.uniqueID>!=<choice.exitAlt> && _alt<choice.uniqueID>!=-1 );
|
||||
>>
|
||||
|
||||
|
@ -754,8 +760,11 @@ public class <lexer.name> extends Lexer {
|
|||
<namedActions.members>
|
||||
|
||||
public <lexer.name>(CharStream input) {
|
||||
super(input);
|
||||
_interp = new LexerATNSimulator(this,_ATN);
|
||||
this(input, new LexerATNSimulator(_ATN));
|
||||
}
|
||||
|
||||
public <lexer.name>(CharStream input, LexerATNSimulator interpreter) {
|
||||
super(input, interpreter);
|
||||
}
|
||||
|
||||
public String getGrammarFileName() { return "<lexerFile.fileName>"; }
|
||||
|
|
|
@ -37,7 +37,7 @@ import org.antlr.v4.tool.LexerGrammar;
|
|||
public class LexerInterpreter implements TokenSource {
|
||||
protected LexerGrammar g;
|
||||
protected LexerATNSimulator interp;
|
||||
protected CharStream input;
|
||||
protected LexerATNSimulator.State state;
|
||||
|
||||
public LexerInterpreter(LexerGrammar g, String inputString) {
|
||||
this(g);
|
||||
|
@ -51,11 +51,11 @@ public class LexerInterpreter implements TokenSource {
|
|||
}
|
||||
|
||||
public void setInput(String inputString) {
|
||||
input = new ANTLRInputStream(inputString);
|
||||
setInput(new ANTLRInputStream(inputString));
|
||||
}
|
||||
|
||||
public void setInput(CharStream input) {
|
||||
this.input = input;
|
||||
this.state = new LexerATNSimulator.State(input);
|
||||
}
|
||||
|
||||
public String getSourceName() { return g.name; }
|
||||
|
@ -69,16 +69,16 @@ public class LexerInterpreter implements TokenSource {
|
|||
}
|
||||
|
||||
public CharStream getInputStream() {
|
||||
return input;
|
||||
return state.getInput();
|
||||
}
|
||||
|
||||
public Token nextToken() {
|
||||
// TODO: Deal with off channel tokens
|
||||
int start = input.index();
|
||||
int tokenStartCharPositionInLine = interp.getCharPositionInLine();
|
||||
int tokenStartLine = interp.getLine();
|
||||
int ttype = interp.match(input, Lexer.DEFAULT_MODE);
|
||||
int stop = input.index()-1;
|
||||
int start = state.getInput().index();
|
||||
int tokenStartCharPositionInLine = interp.getCharPositionInLine(state);
|
||||
int tokenStartLine = interp.getLine(state);
|
||||
int ttype = interp.match(state, Lexer.DEFAULT_MODE);
|
||||
int stop = state.getInput().index()-1;
|
||||
WritableToken t = new CommonToken(this, ttype, Token.DEFAULT_CHANNEL, start, stop);
|
||||
t.setLine(tokenStartLine);
|
||||
t.setCharPositionInLine(tokenStartCharPositionInLine);
|
||||
|
|
|
@ -56,6 +56,7 @@ import java.util.*;
|
|||
|
||||
|
||||
public abstract class BaseTest {
|
||||
public static boolean FORCE_ATN = false;
|
||||
public static final String newline = System.getProperty("line.separator");
|
||||
public static final String pathSep = System.getProperty("path.separator");
|
||||
|
||||
|
@ -90,14 +91,18 @@ public abstract class BaseTest {
|
|||
|
||||
}
|
||||
|
||||
protected org.antlr.v4.Tool newTool(String[] args) {
|
||||
protected org.antlr.v4.Tool newTool(String... args) {
|
||||
Tool tool = new Tool(args);
|
||||
return tool;
|
||||
}
|
||||
|
||||
protected Tool newTool() {
|
||||
org.antlr.v4.Tool tool = new Tool(new String[] {"-o", tmpdir});
|
||||
return tool;
|
||||
if (FORCE_ATN) {
|
||||
return newTool("-Xforceatn", "-o", tmpdir);
|
||||
}
|
||||
else {
|
||||
return newTool("-o", tmpdir);
|
||||
}
|
||||
}
|
||||
|
||||
ATN createATN(Grammar g) {
|
||||
|
@ -152,10 +157,11 @@ public abstract class BaseTest {
|
|||
|
||||
public List<Integer> getTokenTypesViaATN(String input, LexerATNSimulator lexerATN) {
|
||||
ANTLRInputStream in = new ANTLRInputStream(input);
|
||||
LexerATNSimulator.State state = new LexerATNSimulator.State(in);
|
||||
List<Integer> tokenTypes = new ArrayList<Integer>();
|
||||
int ttype = 0;
|
||||
do {
|
||||
ttype = lexerATN.matchATN(in);
|
||||
ttype = lexerATN.matchATN(state);
|
||||
tokenTypes.add(ttype);
|
||||
} while ( ttype!= Token.EOF );
|
||||
return tokenTypes;
|
||||
|
@ -167,6 +173,7 @@ public abstract class BaseTest {
|
|||
boolean adaptive)
|
||||
{
|
||||
LexerATNSimulator interp = new LexerATNSimulator(atn);
|
||||
LexerATNSimulator.State state = new LexerATNSimulator.State(input);
|
||||
List<String> tokenTypes = new ArrayList<String>();
|
||||
int ttype;
|
||||
boolean hitEOF = false;
|
||||
|
@ -176,8 +183,8 @@ public abstract class BaseTest {
|
|||
break;
|
||||
}
|
||||
int t = input.LA(1);
|
||||
if ( adaptive ) ttype = interp.match(input, Lexer.DEFAULT_MODE);
|
||||
else ttype = interp.matchATN(input);
|
||||
if ( adaptive ) ttype = interp.match(state, Lexer.DEFAULT_MODE);
|
||||
else ttype = interp.matchATN(state);
|
||||
if ( ttype == Token.EOF ) {
|
||||
tokenTypes.add("EOF");
|
||||
}
|
||||
|
|
|
@ -277,8 +277,9 @@ public class TestATNInterpreter extends BaseTest {
|
|||
ParserATNFactory f = new ParserATNFactory(g);
|
||||
ATN atn = f.createATN();
|
||||
|
||||
ParserATNSimulator interp = new ParserATNSimulator(atn);
|
||||
ParserATNSimulator<Token> interp = new ParserATNSimulator<Token>(atn);
|
||||
TokenStream input = new IntTokenStream(types);
|
||||
ParserATNSimulator.State<Token> state = new ParserATNSimulator.State<Token>(input);
|
||||
ATNState startState = atn.ruleToStartState[g.getRule("a").index];
|
||||
if ( startState.transition(0).target instanceof BlockStartState ) {
|
||||
startState = startState.transition(0).target;
|
||||
|
@ -289,7 +290,7 @@ public class TestATNInterpreter extends BaseTest {
|
|||
Rule r = g.getRule("e");
|
||||
if ( r!=null ) System.out.println(dot.getDOT(atn.ruleToStartState[r.index]));
|
||||
|
||||
int result = interp.matchATN(input, startState);
|
||||
int result = interp.matchATN(state, startState);
|
||||
assertEquals(expected, result);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -285,12 +285,13 @@ public class TestATNParserPrediction extends BaseTest {
|
|||
RuleContext a_e_ctx = new RuleContext(a_ctx, a_e_invoke.stateNumber, bStart.stateNumber);
|
||||
RuleContext b_e_ctx = new RuleContext(b_ctx, b_e_invoke.stateNumber, bStart.stateNumber);
|
||||
|
||||
ParserATNSimulator interp = new ParserATNSimulator(atn);
|
||||
interp.setContextSensitive(true);
|
||||
ParserATNSimulator<Token> interp = new ParserATNSimulator<Token>(atn);
|
||||
List<Integer> types = getTokenTypesViaATN("ab", lexInterp);
|
||||
System.out.println(types);
|
||||
TokenStream input = new IntTokenStream(types);
|
||||
int alt = interp.adaptivePredict(input, 0, b_e_ctx);
|
||||
ParserATNSimulator.State<Token> state = new ParserATNSimulator.State<Token>(input);
|
||||
interp.setContextSensitive(state, true);
|
||||
int alt = interp.adaptivePredict(state, 0, b_e_ctx);
|
||||
assertEquals(alt, 2);
|
||||
DFA dfa = interp.decisionToDFA[0];
|
||||
String expecting =
|
||||
|
@ -299,7 +300,7 @@ public class TestATNParserPrediction extends BaseTest {
|
|||
"s2-EOF->:s3@{[10]=2}\n";
|
||||
assertEquals(expecting, dfa.toString(g.getTokenDisplayNames()));
|
||||
|
||||
alt = interp.adaptivePredict(input, 0, b_e_ctx); // cached
|
||||
alt = interp.adaptivePredict(state, 0, b_e_ctx); // cached
|
||||
assertEquals(alt, 2);
|
||||
expecting =
|
||||
"s0-'a'->s1\n" +
|
||||
|
@ -307,7 +308,7 @@ public class TestATNParserPrediction extends BaseTest {
|
|||
"s2-EOF->:s3@{[10]=2}\n";
|
||||
assertEquals(expecting, dfa.toString(g.getTokenDisplayNames()));
|
||||
|
||||
alt = interp.adaptivePredict(input, 0, a_e_ctx); // forces new context-sens ATN match
|
||||
alt = interp.adaptivePredict(state, 0, a_e_ctx); // forces new context-sens ATN match
|
||||
assertEquals(alt, 1);
|
||||
expecting =
|
||||
"s0-'a'->s1\n" +
|
||||
|
@ -315,7 +316,7 @@ public class TestATNParserPrediction extends BaseTest {
|
|||
"s2-EOF->:s3@{[10]=2, [6]=1}\n";
|
||||
assertEquals(expecting, dfa.toString(g.getTokenDisplayNames()));
|
||||
|
||||
alt = interp.adaptivePredict(input, 0, b_e_ctx); // cached
|
||||
alt = interp.adaptivePredict(state, 0, b_e_ctx); // cached
|
||||
assertEquals(alt, 2);
|
||||
expecting =
|
||||
"s0-'a'->s1\n" +
|
||||
|
@ -323,7 +324,7 @@ public class TestATNParserPrediction extends BaseTest {
|
|||
"s2-EOF->:s3@{[10]=2, [6]=1}\n";
|
||||
assertEquals(expecting, dfa.toString(g.getTokenDisplayNames()));
|
||||
|
||||
alt = interp.adaptivePredict(input, 0, a_e_ctx); // cached
|
||||
alt = interp.adaptivePredict(state, 0, a_e_ctx); // cached
|
||||
assertEquals(alt, 1);
|
||||
expecting =
|
||||
"s0-'a'->s1\n" +
|
||||
|
@ -334,7 +335,8 @@ public class TestATNParserPrediction extends BaseTest {
|
|||
types = getTokenTypesViaATN("b", lexInterp);
|
||||
System.out.println(types);
|
||||
input = new IntTokenStream(types);
|
||||
alt = interp.adaptivePredict(input, 0, null); // ctx irrelevant
|
||||
state = new ParserATNSimulator.State<Token>(input);
|
||||
alt = interp.adaptivePredict(state, 0, null); // ctx irrelevant
|
||||
assertEquals(alt, 2);
|
||||
expecting =
|
||||
"s0-'a'->s1\n" +
|
||||
|
@ -346,7 +348,8 @@ public class TestATNParserPrediction extends BaseTest {
|
|||
types = getTokenTypesViaATN("aab", lexInterp);
|
||||
System.out.println(types);
|
||||
input = new IntTokenStream(types);
|
||||
alt = interp.adaptivePredict(input, 0, null);
|
||||
state = new ParserATNSimulator.State<Token>(input);
|
||||
alt = interp.adaptivePredict(state, 0, null);
|
||||
assertEquals(alt, 1);
|
||||
expecting =
|
||||
"s0-'a'->s1\n" +
|
||||
|
@ -512,11 +515,12 @@ public class TestATNParserPrediction extends BaseTest {
|
|||
if ( r!=null) System.out.println(dot.getDOT(atn.ruleToStartState[r.index]));
|
||||
|
||||
// Check ATN prediction
|
||||
ParserATNSimulator interp = new ParserATNSimulator(atn);
|
||||
ParserATNSimulator<Token> interp = new ParserATNSimulator<Token>(atn);
|
||||
TokenStream input = new IntTokenStream(types);
|
||||
ATNState startState = atn.decisionToState.get(decision);
|
||||
DFA dfa = new DFA(startState);
|
||||
int alt = interp.predictATN(dfa, input, RuleContext.EMPTY, false);
|
||||
ParserATNSimulator.State<Token> state = new ParserATNSimulator.State<Token>(input);
|
||||
int alt = interp.predictATN(dfa, state, RuleContext.EMPTY, false);
|
||||
|
||||
System.out.println(dot.getDOT(dfa, false));
|
||||
|
||||
|
@ -524,11 +528,11 @@ public class TestATNParserPrediction extends BaseTest {
|
|||
|
||||
// Check adaptive prediction
|
||||
input.seek(0);
|
||||
alt = interp.adaptivePredict(input, decision, null);
|
||||
alt = interp.adaptivePredict(state, decision, null);
|
||||
assertEquals(expectedAlt, alt);
|
||||
// run 2x; first time creates DFA in atn
|
||||
input.seek(0);
|
||||
alt = interp.adaptivePredict(input, decision, null);
|
||||
alt = interp.adaptivePredict(state, decision, null);
|
||||
assertEquals(expectedAlt, alt);
|
||||
}
|
||||
|
||||
|
@ -551,16 +555,17 @@ public class TestATNParserPrediction extends BaseTest {
|
|||
// System.out.println(dot.getDOT(atn.ruleToStartState.get(g.getRule("b"))));
|
||||
// System.out.println(dot.getDOT(atn.ruleToStartState.get(g.getRule("e"))));
|
||||
|
||||
ParserATNSimulator interp = new ParserATNSimulator(atn);
|
||||
ParserATNSimulator<Token> interp = new ParserATNSimulator<Token>(atn);
|
||||
List<Integer> types = getTokenTypesViaATN(inputString, lexInterp);
|
||||
System.out.println(types);
|
||||
TokenStream input = new IntTokenStream(types);
|
||||
ParserATNSimulator.State<Token> state = new ParserATNSimulator.State<Token>(input);
|
||||
try {
|
||||
ATNState startState = atn.decisionToState.get(0);
|
||||
DFA dfa = new DFA(startState);
|
||||
// Rule r = g.getRule(ruleName);
|
||||
//ATNState startState = atn.ruleToStartState.get(r);
|
||||
interp.predictATN(dfa, input, ctx, false);
|
||||
interp.predictATN(dfa, state, ctx, false);
|
||||
}
|
||||
catch (NoViableAltException nvae) {
|
||||
nvae.printStackTrace(System.err);
|
||||
|
@ -582,14 +587,15 @@ public class TestATNParserPrediction extends BaseTest {
|
|||
ParserATNFactory f = new ParserATNFactory(g);
|
||||
ATN atn = f.createATN();
|
||||
|
||||
ParserATNSimulator interp = new ParserATNSimulator(atn);
|
||||
ParserATNSimulator<Token> interp = new ParserATNSimulator<Token>(atn);
|
||||
for (int i=0; i<inputString.length; i++) {
|
||||
// Check DFA
|
||||
List<Integer> types = getTokenTypesViaATN(inputString[i], lexInterp);
|
||||
System.out.println(types);
|
||||
TokenStream input = new IntTokenStream(types);
|
||||
ParserATNSimulator.State<Token> state = new ParserATNSimulator.State<Token>(input);
|
||||
try {
|
||||
interp.adaptivePredict(input, decision, RuleContext.EMPTY);
|
||||
interp.adaptivePredict(state, decision, RuleContext.EMPTY);
|
||||
}
|
||||
catch (NoViableAltException nvae) {
|
||||
nvae.printStackTrace(System.err);
|
||||
|
|
Loading…
Reference in New Issue