got wildcard working properly with recursion now!!! new unit test.

This commit is contained in:
Terence Parr 2012-09-27 12:22:16 -07:00
parent 4d8158c6f3
commit c8a51ccfad
4 changed files with 47 additions and 28 deletions

View File

@ -5,15 +5,24 @@ import org.antlr.v4.runtime.misc.Nullable;
public class LexerATNConfig extends ATNConfig { public class LexerATNConfig extends ATNConfig {
/** Capture lexer action we traverse */ /** Capture lexer action we traverse */
public int lexerActionIndex = -1; // TOOD: move to subclass public int lexerActionIndex = -1;
public LexerATNConfig(@NotNull ATNState state, public LexerATNConfig(@NotNull ATNState state,
int alt, int alt,
@Nullable PredictionContext context) @Nullable PredictionContext context)
{ {
super(state, alt, context, SemanticContext.NONE); super(state, alt, context, SemanticContext.NONE);
} }
public LexerATNConfig(@NotNull ATNState state,
int alt,
@Nullable PredictionContext context,
int actionIndex)
{
super(state, alt, context, SemanticContext.NONE);
this.lexerActionIndex = actionIndex;
}
public LexerATNConfig(@NotNull LexerATNConfig c, @NotNull ATNState state) { public LexerATNConfig(@NotNull LexerATNConfig c, @NotNull ATNState state) {
super(c, state, c.context, c.semanticContext); super(c, state, c.context, c.semanticContext);
this.lexerActionIndex = c.lexerActionIndex; this.lexerActionIndex = c.lexerActionIndex;

View File

@ -534,7 +534,7 @@ public class LexerATNSimulator extends ATNSimulator {
* [..., (2,1,[$]), ..., (7,1,[[$, 6 $]])] * [..., (2,1,[$]), ..., (7,1,[[$, 6 $]])]
* *
* That means wacking (7,1,[$]) but not (7,1,[6 $]). If incoming config * That means wacking (7,1,[$]) but not (7,1,[6 $]). If incoming config
* has multiple stacks, must look for each one in other configs. :( * has multiple stacks, must look for each one in other configs.
* *
* Closure is unmodified; copy returned. * Closure is unmodified; copy returned.
*/ */
@ -550,39 +550,40 @@ public class LexerATNSimulator extends ATNSimulator {
// collect ctxs from incoming config; must wack all of those. // collect ctxs from incoming config; must wack all of those.
Set<SingletonPredictionContext> contextsToKill = Set<SingletonPredictionContext> contextsToKill =
new HashSet<SingletonPredictionContext>(); new HashSet<SingletonPredictionContext>();
if ( config.context!=null && !config.context.isEmpty() ) { for (SingletonPredictionContext ctx : config.context) {
for (SingletonPredictionContext ctx : config.context) { contextsToKill.add(ctx);
contextsToKill.add(ctx);
}
} }
ATNConfigSet dup = new ATNConfigSet(closure); ATNConfigSet dup = new ATNConfigSet(); // build up as we go thru loop
for (int j=0; j<=ci; j++) dup.add(closure.get(j)); // add stuff up to ci
int j=ci+1; int j=ci+1;
while ( j < dup.size() ) { while ( j < closure.size() ) {
ATNConfig c = dup.get(j); LexerATNConfig c = (LexerATNConfig)closure.get(j);
boolean isWildcard = c.state.getClass() == ATNState.class && // plain state only, not rulestop etc.. boolean isWildcard = c.state.getClass() == ATNState.class && // plain state only, not rulestop etc..
c.state.transition(0) instanceof WildcardTransition; c.state.transition(0) instanceof WildcardTransition;
boolean killed = false;
if ( c.alt == alt && isWildcard ) { if ( c.alt == alt && isWildcard ) {
// found config to kill but must check stack. // found config to kill but only if same stack.
// find c stacks that are in contextsToKill // find c stacks that are in contextsToKill
if ( c.context!=null && !c.context.isEmpty() ) { for (SingletonPredictionContext ctx : c.context) {
for (SingletonPredictionContext ctx : c.context) { if ( contextsToKill.contains(ctx) ) {
if ( !ctx.isEmpty() ) { // c.alt, c.ctx matches and j > ci => kill it
if ( contextsToKill.contains(ctx) ) { if ( debug ) {
// c.alt, c.ctx matches and j > ci => kill it System.out.format("delete config %s since alt %d and %d leads to wildcard\n",
if ( debug ) { c, c.alt, c.state.stateNumber);
System.out.format("delete config %s since alt %d and %d leads to wildcard\n",
c, c.alt, c.state.stateNumber);
}
dup.remove(j);
killed = true;
}
} }
// don't add
}
else {
LexerATNConfig splitConfig =
new LexerATNConfig(c.state, c.alt, ctx, c.lexerActionIndex);
dup.add(splitConfig);
} }
} }
} }
if ( !killed ) j++; else {
dup.add(c); // add entire config
}
j++;
} }
return dup; return dup;
} }

View File

@ -189,7 +189,7 @@ public abstract class PredictionContext implements Iterable<SingletonPredictionC
if ( a.parent == EMPTY ) singleParent = EMPTY; // $ + b = $ if ( a.parent == EMPTY ) singleParent = EMPTY; // $ + b = $
if ( b.parent == EMPTY ) singleParent = EMPTY; // a + $ = $ if ( b.parent == EMPTY ) singleParent = EMPTY; // a + $ = $
} }
if ( a==b || a.parent.equals(b.parent) ) { // ax + bx = [a,b]x if ( a==b || (a.parent!=null && a.parent.equals(b.parent)) ) { // ax + bx = [a,b]x
singleParent = a.parent; singleParent = a.parent;
} }
if ( singleParent!=null ) { // parents are same if ( singleParent!=null ) { // parents are same

View File

@ -148,6 +148,15 @@ public class TestATNLexerInterpreter extends BaseTest {
checkLexerMatches(lg, "/* ick */\n/* /*nested*/ */", expecting); checkLexerMatches(lg, "/* ick */\n/* /*nested*/ */", expecting);
} }
@Test public void testRecursiveLexerRuleRefWithWildcard() throws Exception {
LexerGrammar lg = new LexerGrammar(
"lexer grammar L;\n"+
"CMT : '/*' (CMT | .)+ '*/' ;\n" +
"WS : (' '|'\n')+ ;");
String expecting = "CMT, WS, CMT, EOF";
checkLexerMatches(lg, "/* ick */\n/* /*nested*/ */", expecting);
}
@Test public void testLexerWildcardNonGreedyLoopByDefault() throws Exception { @Test public void testLexerWildcardNonGreedyLoopByDefault() throws Exception {
LexerGrammar lg = new LexerGrammar( LexerGrammar lg = new LexerGrammar(
"lexer grammar L;\n"+ "lexer grammar L;\n"+