v4: Initial tracing support in the lexer

[git-p4: depot-paths = "//depot/code/antlr4/main/": change = 9490]
This commit is contained in:
sharwell 2011-11-29 20:13:06 -08:00
parent fb3de170d1
commit 1be2e2c556
2 changed files with 272 additions and 0 deletions

View File

@ -182,6 +182,7 @@ public abstract class Lexer extends Recognizer<Integer, LexerATNSimulator>
public void pushMode(int m) { public void pushMode(int m) {
if ( LexerATNSimulator.debug ) System.out.println("pushMode "+m); if ( LexerATNSimulator.debug ) System.out.println("pushMode "+m);
if ( modeStack==null ) modeStack = new ArrayDeque<Integer>(); if ( modeStack==null ) modeStack = new ArrayDeque<Integer>();
getInterpreter().tracePushMode(m);
modeStack.push(mode); modeStack.push(mode);
mode(m); mode(m);
} }
@ -189,6 +190,7 @@ public abstract class Lexer extends Recognizer<Integer, LexerATNSimulator>
public int popMode() { public int popMode() {
if ( modeStack==null ) throw new EmptyStackException(); if ( modeStack==null ) throw new EmptyStackException();
if ( LexerATNSimulator.debug ) System.out.println("popMode back to "+modeStack.peek()); if ( LexerATNSimulator.debug ) System.out.println("popMode back to "+modeStack.peek());
getInterpreter().tracePopMode();
mode( modeStack.pop() ); mode( modeStack.pop() );
return mode; return mode;
} }
@ -217,6 +219,7 @@ public abstract class Lexer extends Recognizer<Integer, LexerATNSimulator>
* than a single variable as this implementation does). * than a single variable as this implementation does).
*/ */
public void emit(Token token) { public void emit(Token token) {
getInterpreter().traceEmit(token);
//System.err.println("emit "+token); //System.err.println("emit "+token);
this.token = token; this.token = token;
} }

View File

@ -36,12 +36,21 @@ import org.antlr.v4.runtime.misc.NotNull;
import org.antlr.v4.runtime.misc.Nullable; import org.antlr.v4.runtime.misc.Nullable;
import org.antlr.v4.runtime.misc.OrderedHashSet; import org.antlr.v4.runtime.misc.OrderedHashSet;
import java.io.IOException;
import java.io.OutputStream;
import org.antlr.v4.runtime.misc.Interval;
import org.antlr.v4.runtime.misc.IntervalSet;
/** "dup" of ParserInterpreter */ /** "dup" of ParserInterpreter */
public class LexerATNSimulator extends ATNSimulator { public class LexerATNSimulator extends ATNSimulator {
public static boolean debug = false; public static boolean debug = false;
public static boolean dfa_debug = false; public static boolean dfa_debug = false;
public static final int NUM_EDGES = 255; public static final int NUM_EDGES = 255;
private boolean trace = false;
private OutputStream traceStream = null;
private boolean traceFailed = false;
/** When we hit an accept state in either the DFA or the ATN, we /** When we hit an accept state in either the DFA or the ATN, we
* have to notify the character stream to start buffering characters * have to notify the character stream to start buffering characters
* via mark() and record the current state. The current state includes * via mark() and record the current state. The current state includes
@ -131,10 +140,17 @@ public class LexerATNSimulator extends ATNSimulator {
this.recog = recog; this.recog = recog;
} }
public void setTraceStream(OutputStream traceStream) {
this.traceStream = traceStream;
this.trace = traceStream != null;
this.traceFailed = false;
}
public int match(@NotNull CharStream input, int mode) { public int match(@NotNull CharStream input, int mode) {
match_calls++; match_calls++;
this.mode = mode; this.mode = mode;
int mark = input.mark(); int mark = input.mark();
traceBeginMatch(input, mode);
try { try {
if ( dfa[mode].s0==null ) { if ( dfa[mode].s0==null ) {
return matchATN(input); return matchATN(input);
@ -144,6 +160,7 @@ public class LexerATNSimulator extends ATNSimulator {
} }
} }
finally { finally {
traceEndMatch();
input.release(mark); input.release(mark);
} }
} }
@ -159,6 +176,7 @@ public class LexerATNSimulator extends ATNSimulator {
// only called from test code from outside // only called from test code from outside
public int matchATN(@NotNull CharStream input) { public int matchATN(@NotNull CharStream input) {
traceMatchATN();
startIndex = input.index(); startIndex = input.index();
ATNState startState = atn.modeToStartState.get(mode); ATNState startState = atn.modeToStartState.get(mode);
if ( debug ) System.out.println("mode "+ mode +" start: "+startState); if ( debug ) System.out.println("mode "+ mode +" start: "+startState);
@ -167,10 +185,12 @@ public class LexerATNSimulator extends ATNSimulator {
dfa[mode].s0 = addDFAState(s0_closure); dfa[mode].s0 = addDFAState(s0_closure);
int predict = exec(input, s0_closure); int predict = exec(input, s0_closure);
if ( debug ) System.out.println("DFA after matchATN: "+dfa[old_mode].toLexerString()); if ( debug ) System.out.println("DFA after matchATN: "+dfa[old_mode].toLexerString());
tracePredict(predict);
return predict; return predict;
} }
protected int exec(@NotNull CharStream input, @NotNull DFAState s0) { protected int exec(@NotNull CharStream input, @NotNull DFAState s0) {
traceMatchDFA();
if ( dfa_debug ) System.out.println("DFA[mode "+(recog==null?0:recog.mode)+"] exec LA(1)=="+ if ( dfa_debug ) System.out.println("DFA[mode "+(recog==null?0:recog.mode)+"] exec LA(1)=="+
(char)input.LA(1)); (char)input.LA(1));
//System.out.println("DFA start of execDFA: "+dfa[mode].toLexerString()); //System.out.println("DFA start of execDFA: "+dfa[mode].toLexerString());
@ -178,6 +198,7 @@ public class LexerATNSimulator extends ATNSimulator {
dfaPrevAccept.reset(); dfaPrevAccept.reset();
LexerNoViableAltException atnException = null; LexerNoViableAltException atnException = null;
DFAState s = s0; DFAState s = s0;
traceLookahead1();
int t = input.LA(1); int t = input.LA(1);
loop: loop:
while ( true ) { while ( true ) {
@ -211,6 +232,7 @@ public class LexerATNSimulator extends ATNSimulator {
} }
consume(input); consume(input);
traceLookahead1();
t = input.LA(1); t = input.LA(1);
} }
if ( dfaPrevAccept.state==null ) { if ( dfaPrevAccept.state==null ) {
@ -224,6 +246,7 @@ public class LexerATNSimulator extends ATNSimulator {
int ruleIndex = dfaPrevAccept.state.ruleIndex; int ruleIndex = dfaPrevAccept.state.ruleIndex;
accept(input, ruleIndex, dfaPrevAccept); accept(input, ruleIndex, dfaPrevAccept);
tracePredict(dfaPrevAccept.state.prediction);
return dfaPrevAccept.state.prediction; return dfaPrevAccept.state.prediction;
} }
@ -238,6 +261,7 @@ public class LexerATNSimulator extends ATNSimulator {
OrderedHashSet<ATNConfig> reach = new OrderedHashSet<ATNConfig>(); OrderedHashSet<ATNConfig> reach = new OrderedHashSet<ATNConfig>();
atnPrevAccept.reset(); atnPrevAccept.reset();
traceLookahead1();
int t = input.LA(1); int t = input.LA(1);
do { // while more work do { // while more work
@ -272,6 +296,7 @@ public class LexerATNSimulator extends ATNSimulator {
consume(input); consume(input);
addDFAEdge(closure, t, reach); addDFAEdge(closure, t, reach);
traceLookahead1();
t = input.LA(1); t = input.LA(1);
// swap to avoid reallocating space // swap to avoid reallocating space
@ -309,6 +334,7 @@ public class LexerATNSimulator extends ATNSimulator {
} }
int index = input.index(); int index = input.index();
if ( index > atnPrevAccept.index ) { if ( index > atnPrevAccept.index ) {
traceAcceptState(c.alt);
// will favor prev accept at same index so "int" is keyword not ID // will favor prev accept at same index so "int" is keyword not ID
markAcceptState(atnPrevAccept, input); markAcceptState(atnPrevAccept, input);
atnPrevAccept.config = c; atnPrevAccept.config = c;
@ -340,6 +366,7 @@ public class LexerATNSimulator extends ATNSimulator {
if ( actionIndex>=0 && recog!=null ) recog.action(null, ruleIndex, actionIndex); if ( actionIndex>=0 && recog!=null ) recog.action(null, ruleIndex, actionIndex);
// seek to after last char in token // seek to after last char in token
traceSeek(prevAccept.index);
input.seek(prevAccept.index); input.seek(prevAccept.index);
line = prevAccept.line; line = prevAccept.line;
charPositionInLine = prevAccept.charPos; charPositionInLine = prevAccept.charPos;
@ -479,6 +506,7 @@ public class LexerATNSimulator extends ATNSimulator {
} }
int failOverToATN(@NotNull CharStream input, @NotNull DFAState s) { int failOverToATN(@NotNull CharStream input, @NotNull DFAState s) {
traceFailOverToATN();
if ( dfa_debug ) System.out.println("no edge for "+(char)input.LA(1)); if ( dfa_debug ) System.out.println("no edge for "+(char)input.LA(1));
if ( dfa_debug ) { if ( dfa_debug ) {
System.out.println("ATN exec upon "+ System.out.println("ATN exec upon "+
@ -493,6 +521,7 @@ public class LexerATNSimulator extends ATNSimulator {
} }
// action already executed by ATN // action already executed by ATN
// we've updated DFA, exec'd action, and have our deepest answer // we've updated DFA, exec'd action, and have our deepest answer
tracePredict(ttype);
return ttype; return ttype;
} }
@ -610,6 +639,7 @@ public class LexerATNSimulator extends ATNSimulator {
charPositionInLine++; charPositionInLine++;
} }
input.consume(); input.consume();
traceConsume(input, curChar);
} }
@NotNull @NotNull
@ -619,4 +649,243 @@ public class LexerATNSimulator extends ATNSimulator {
return "'"+(char)t+"'"; return "'"+(char)t+"'";
} }
/*
* Trace helpers (API and file format are work in progress)
*/
public void traceEndMatch() {
if (trace) {
traceSlow(LexerOpCode.EndMatch);
}
}
public void traceMatchATN() {
if (trace) {
traceSlow(LexerOpCode.MatchATN);
}
}
public void traceMatchDFA() {
if (trace) {
traceSlow(LexerOpCode.MatchDFA);
}
}
public void traceLookahead1() {
if (trace) {
traceSlow(LexerOpCode.Lookahead1);
}
}
public void traceFailOverToATN() {
if (trace) {
traceSlow(LexerOpCode.FailOverToATN);
}
}
public void tracePredict(int prediction) {
if (trace) {
traceIntSlow(LexerOpCode.Predict, prediction);
}
}
public void traceAcceptState(int prediction) {
if (trace) {
traceIntSlow(LexerOpCode.AcceptState, prediction);
}
}
public void traceSeek(int index) {
if (trace) {
traceIntSlow(LexerOpCode.Seek, index);
}
}
public final void traceBeginMatch(CharStream input, int mode) {
if (trace) {
traceBeginMatchSlow(input, mode);
}
}
public final void traceConsume(CharStream input, int c) {
if (trace) {
traceConsumeSlow(input, c);
}
}
public final void tracePushMode(int mode) {
if (trace) {
traceByteSlow(LexerOpCode.PushMode, (byte)mode);
}
}
public final void tracePopMode() {
if (trace) {
traceSlow(LexerOpCode.PopMode);
}
}
public final void traceEmit(Token token) {
if (trace) {
traceEmitSlow(token);
}
}
private void traceSlow(LexerOpCode opcode) {
assert traceStream != null;
assert opcode.getArgumentSize() == 0;
if (!traceFailed) {
try {
traceStream.write(opcode.ordinal());
} catch (IOException e) {
e.printStackTrace();
traceFailed = true;
}
}
}
private void traceByteSlow(LexerOpCode opcode, byte arg) {
assert traceStream != null;
assert opcode.getArgumentSize() == 1;
if (!traceFailed) {
try {
traceStream.write(opcode.ordinal());
traceStream.write(arg);
} catch (IOException e) {
e.printStackTrace();
traceFailed = true;
}
}
}
private void traceByteIntSlow(LexerOpCode opcode, byte arg1, int arg2) {
assert traceStream != null;
assert opcode.getArgumentSize() == 5;
if (!traceFailed) {
try {
traceStream.write(opcode.ordinal());
traceStream.write(arg1);
traceIntSlow(arg2);
} catch (IOException e) {
e.printStackTrace();
traceFailed = true;
}
}
}
private void traceIntSlow(LexerOpCode opcode, int arg) {
assert traceStream != null;
assert opcode.getArgumentSize() == 4;
if (!traceFailed) {
try {
traceStream.write(opcode.ordinal());
traceIntSlow(arg);
} catch (IOException e) {
e.printStackTrace();
traceFailed = true;
}
}
}
private void traceIntIntSlow(LexerOpCode opcode, int arg1, int arg2) {
assert traceStream != null;
assert opcode.getArgumentSize() == 8;
if (!traceFailed) {
try {
traceStream.write(opcode.ordinal());
traceIntSlow(arg1);
traceIntSlow(arg2);
} catch (IOException e) {
e.printStackTrace();
traceFailed = true;
}
}
}
private void traceIntIntIntIntSlow(LexerOpCode opcode, int arg1, int arg2, int arg3, int arg4) {
assert traceStream != null;
assert opcode.getArgumentSize() == 16;
if (!traceFailed) {
try {
traceStream.write(opcode.ordinal());
traceIntSlow(arg1);
traceIntSlow(arg2);
traceIntSlow(arg3);
traceIntSlow(arg4);
} catch (IOException e) {
e.printStackTrace();
traceFailed = true;
}
}
}
private void traceIntSlow(int arg) {
assert traceStream != null;
if (!traceFailed) {
try {
traceStream.write(arg);
traceStream.write(arg >> 8);
traceStream.write(arg >> 16);
traceStream.write(arg >> 24);
} catch (IOException e) {
e.printStackTrace();
traceFailed = true;
}
}
}
private void traceBeginMatchSlow(CharStream input, int mode) {
traceByteIntSlow(LexerOpCode.BeginMatch, (byte)mode, input.index());
}
private void traceConsumeSlow(CharStream input, int c) {
assert traceStream != null;
if (!traceFailed) {
traceIntIntSlow(LexerOpCode.Consume, c, input.index());
}
}
private void traceEmitSlow(Token token) {
assert traceStream != null;
if (token != null && !traceFailed) {
traceIntIntIntIntSlow(LexerOpCode.Emit, token.getStartIndex(), token.getStopIndex(), token.getType(), token.getChannel());
}
}
public enum LexerOpCode {
BeginMatch(5),
EndMatch(0),
MatchATN(0),
MatchDFA(0),
FailOverToATN(0),
AcceptState(4),
Predict(4),
Seek(4),
Consume(8),
Lookahead1(0),
PushMode(1),
PopMode(0),
Emit(16);
private final int argumentSize;
private LexerOpCode(int argumentSize) {
this.argumentSize = argumentSize;
}
public int getArgumentSize() {
return argumentSize;
}
}
} }