added in Sam's popAll to deal with loop end push/pop stuff. passes LR tests and all but 2 sempred tests. does some JavaLR.g4 parsing too.

This commit is contained in:
Terence Parr 2012-03-20 18:06:00 -07:00
parent 9318391664
commit 0f969af947
5 changed files with 82 additions and 49 deletions

View File

@ -71,20 +71,35 @@ public class ArrayPredictionContext extends PredictionContext {
return Arrays.binarySearch(invokingStates, invokingState); return Arrays.binarySearch(invokingStates, invokingState);
} }
public ArrayPredictionContext trim() { /** Find invokingState parameter (call it x) in this.invokingStates,
int i = parents.length-1; * if present. Call pop on all x's parent(s) and then pull other
while ( i>=0 && parents[i]==null ) { i--; } * elements from this context and merge into new context.
// i is last non-null index */
if ( i < parents.length-1 ) { @Override
int n = i+1; public PredictionContext popAll(int invokingState, boolean fullCtx) {
return new ArrayPredictionContext( int index = Arrays.binarySearch(this.invokingStates, invokingState);
Arrays.copyOf(parents, n), if ( index < 0 ) {
Arrays.copyOf(invokingStates, n)
);
}
return this; return this;
} }
PredictionContext newCtx = this.parents[index].popAll(invokingState, fullCtx);
for (int i = 0; i < this.invokingStates.length; i++) {
if (i == index) continue;
PredictionContext next;
if ( this.invokingStates[i] == EMPTY_FULL_CTX_INVOKING_STATE ) {
next = PredictionContext.EMPTY;
}
else {
next = new SingletonPredictionContext(this.parents[i],
this.invokingStates[i]);
}
boolean rootIsWildcard = fullCtx;
newCtx = merge(newCtx, next, rootIsWildcard);
}
return newCtx;
}
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) { if (this == o) {

View File

@ -956,19 +956,21 @@ public class ParserATNSimulator<Symbol extends Token> extends ATNSimulator {
// run thru all possible stack tops in ctx // run thru all possible stack tops in ctx
if ( config.context!=null && !config.context.isEmpty() ) { if ( config.context!=null && !config.context.isEmpty() ) {
for (SingletonPredictionContext ctx : config.context) { for (SingletonPredictionContext ctx : config.context) {
if ( !ctx.isEmpty() ) { // if ( !ctx.isEmpty() ) {
ATNState invokingState = atn.states.get(ctx.invokingState); ATNState invokingState = atn.states.get(ctx.invokingState);
RuleTransition rt = (RuleTransition)invokingState.transition(0); RuleTransition rt = (RuleTransition)invokingState.transition(0);
ATNState retState = rt.followState; ATNState retState = rt.followState;
PredictionContext newContext = ctx.parent; // "pop" invoking state PredictionContext newContext = ctx.parent; // "pop" invoking state
ATNConfig c = new ATNConfig(retState, config.alt, newContext, config.semanticContext); ATNConfig c = new ATNConfig(retState, config.alt, newContext,
config.semanticContext);
// While we have context to pop back from, we may have // While we have context to pop back from, we may have
// gotten that context AFTER having falling off a rule. // gotten that context AFTER having falling off a rule.
// Make sure we track that we are now out of context. // Make sure we track that we are now out of context.
c.reachesIntoOuterContext = config.reachesIntoOuterContext; c.reachesIntoOuterContext = config.reachesIntoOuterContext;
assert depth > Integer.MIN_VALUE; assert depth > Integer.MIN_VALUE;
closure(c, configs, closureBusy, collectPredicates, greedy, loopsSimulateTailRecursion, depth - 1); closure(c, configs, closureBusy, collectPredicates, greedy,
} loopsSimulateTailRecursion, depth - 1);
// }
return; return;
} }
} }
@ -989,16 +991,9 @@ public class ParserATNSimulator<Symbol extends Token> extends ATNSimulator {
} }
else if ( config.state.getClass()==LoopEndState.class ) { else if ( config.state.getClass()==LoopEndState.class ) {
if ( debug ) System.out.println("Loop end; pop, stack="+config.context); if ( debug ) System.out.println("Loop end; pop, stack="+config.context);
// run thru all possible stack tops in ctx LoopEndState end = (LoopEndState)config.state;
for (SingletonPredictionContext ctx : config.context) {
SingletonPredictionContext p = ctx;
LoopEndState end = (LoopEndState) config.state;
// pop all the way back until we don't see the loopback state anymore // pop all the way back until we don't see the loopback state anymore
while ( !p.isEmpty() && p.invokingState == end.loopBackStateNumber ) { config.context = config.context.popAll(end.loopBackStateNumber, configs.fullCtx);
// TODO: BROKEN. can't figure out how to leave config.context
// p = config.context = config.context.parent; // "pop"
}
}
} }
} }

View File

@ -15,7 +15,7 @@ import java.util.Map;
public abstract class PredictionContext implements Iterable<SingletonPredictionContext> { public abstract class PredictionContext implements Iterable<SingletonPredictionContext> {
public static final EmptyPredictionContext EMPTY = new EmptyPredictionContext(); public static final EmptyPredictionContext EMPTY = new EmptyPredictionContext();
public static final int EMPTY_FULL_INVOKING_STATE = Integer.MAX_VALUE; public static final int EMPTY_FULL_CTX_INVOKING_STATE = Integer.MAX_VALUE;
public static int globalNodeCount = 0; public static int globalNodeCount = 0;
public final int id = globalNodeCount++; public final int id = globalNodeCount++;
@ -61,9 +61,14 @@ public abstract class PredictionContext implements Iterable<SingletonPredictionC
return this == EMPTY; return this == EMPTY;
} }
public abstract PredictionContext popAll(int invokingState, boolean fullCtx);
protected static int calculateParentHashCode(PredictionContext[] parents) { protected static int calculateParentHashCode(PredictionContext[] parents) {
int hashCode = 1; int hashCode = 1;
for (PredictionContext context : parents) { for (PredictionContext context : parents) {
if ( context==null ) {
System.out.println("WHAT!? "+parents.toString());
}
hashCode = hashCode * 31 ^ context.hashCode(); hashCode = hashCode * 31 ^ context.hashCode();
} }
@ -184,7 +189,7 @@ public abstract class PredictionContext implements Iterable<SingletonPredictionC
String ruleName = recognizer.getRuleNames()[s.ruleIndex]; String ruleName = recognizer.getRuleNames()[s.ruleIndex];
localBuffer.append(ruleName); localBuffer.append(ruleName);
} }
else if ( p.getInvokingState(index)!=EMPTY_FULL_INVOKING_STATE ) { else if ( p.getInvokingState(index)!= EMPTY_FULL_CTX_INVOKING_STATE) {
if ( !p.isEmpty() ) { if ( !p.isEmpty() ) {
if (localBuffer.length() > 1) { if (localBuffer.length() > 1) {
// first char is '[', if more than that this isn't the first rule // first char is '[', if more than that this isn't the first rule
@ -277,14 +282,14 @@ public abstract class PredictionContext implements Iterable<SingletonPredictionC
else { else {
if ( a == EMPTY && b == EMPTY ) return EMPTY; // $ + $ = $ if ( a == EMPTY && b == EMPTY ) return EMPTY; // $ + $ = $
if ( a == EMPTY ) { // $ + x = [$,x] if ( a == EMPTY ) { // $ + x = [$,x]
int[] payloads = {EMPTY_FULL_INVOKING_STATE, b.invokingState}; int[] payloads = {EMPTY_FULL_CTX_INVOKING_STATE, b.invokingState};
PredictionContext[] parents = {null, b.parent}; PredictionContext[] parents = {null, b.parent};
ArrayPredictionContext joined = ArrayPredictionContext joined =
new ArrayPredictionContext(parents, payloads); new ArrayPredictionContext(parents, payloads);
return joined; return joined;
} }
if ( b == EMPTY ) { // x + $ = [$,x] ($ is always first if present) if ( b == EMPTY ) { // x + $ = [$,x] ($ is always first if present)
int[] payloads = {EMPTY_FULL_INVOKING_STATE, a.invokingState}; int[] payloads = {EMPTY_FULL_CTX_INVOKING_STATE, a.invokingState};
PredictionContext[] parents = {null, a.parent}; PredictionContext[] parents = {null, a.parent};
ArrayPredictionContext joined = ArrayPredictionContext joined =
new ArrayPredictionContext(parents, payloads); new ArrayPredictionContext(parents, payloads);
@ -302,9 +307,9 @@ public abstract class PredictionContext implements Iterable<SingletonPredictionC
int i = 0; // walks a int i = 0; // walks a
int j = 0; // walks b int j = 0; // walks b
int k = 0; // walks M target array int k = 0; // walks M target array
int[] mergedPayloads = new int[a.invokingStates.length + b.invokingStates.length];
int[] mergedInvokingStates = new int[a.invokingStates.length + b.invokingStates.length];
PredictionContext[] mergedParents = new PredictionContext[a.invokingStates.length + b.invokingStates.length]; PredictionContext[] mergedParents = new PredictionContext[a.invokingStates.length + b.invokingStates.length];
ArrayPredictionContext M = new ArrayPredictionContext(mergedParents, mergedPayloads);
while ( i<a.invokingStates.length && j<b.invokingStates.length ) { while ( i<a.invokingStates.length && j<b.invokingStates.length ) {
if ( a.invokingStates[i]==b.invokingStates[j] ) { if ( a.invokingStates[i]==b.invokingStates[j] ) {
// same payload; stack tops are equal // same payload; stack tops are equal
@ -315,28 +320,28 @@ public abstract class PredictionContext implements Iterable<SingletonPredictionC
SingletonPredictionContext r = (SingletonPredictionContext)mergeSingletons(a_, b_, rootIsWildcard); SingletonPredictionContext r = (SingletonPredictionContext)mergeSingletons(a_, b_, rootIsWildcard);
// if r is same as a_ or b_, we get to keep existing, else new // if r is same as a_ or b_, we get to keep existing, else new
if ( r==a_ ) { if ( r==a_ ) {
M.parents[k] = a.parents[i]; mergedParents[k] = a.parents[i];
M.invokingStates[k] = a.invokingStates[i]; mergedInvokingStates[k] = a.invokingStates[i];
} }
else if ( r==b_ ) { else if ( r==b_ ) {
M.parents[k] = b.parents[j]; mergedParents[k] = b.parents[j];
M.invokingStates[k] = b.invokingStates[j]; mergedInvokingStates[k] = b.invokingStates[j];
} }
else { else {
M.parents[k] = r.parent; mergedParents[k] = r.parent;
M.invokingStates[k] = r.invokingState; mergedInvokingStates[k] = r.invokingState;
} }
i++; // hop over left one as usual i++; // hop over left one as usual
j++; // but also skip one in right side since we merge j++; // but also skip one in right side since we merge
} }
else if ( a.invokingStates[i]<b.invokingStates[j] ) { else if ( a.invokingStates[i]<b.invokingStates[j] ) {
M.parents[k] = a.parents[i]; mergedParents[k] = a.parents[i];
M.invokingStates[k] = a.invokingStates[i]; mergedInvokingStates[k] = a.invokingStates[i];
i++; i++;
} }
else { else {
M.parents[k] = a.parents[j]; mergedParents[k] = a.parents[j];
M.invokingStates[k] = b.invokingStates[j]; mergedInvokingStates[k] = b.invokingStates[j];
j++; j++;
} }
k++; k++;
@ -344,22 +349,33 @@ public abstract class PredictionContext implements Iterable<SingletonPredictionC
// copy over any payloads remaining in either array // copy over any payloads remaining in either array
if (i < a.invokingStates.length) { if (i < a.invokingStates.length) {
for (int p = i; p < a.invokingStates.length; p++) { for (int p = i; p < a.invokingStates.length; p++) {
M.parents[k] = a.parents[p]; mergedParents[k] = a.parents[p];
M.invokingStates[k] = a.invokingStates[p]; mergedInvokingStates[k] = a.invokingStates[p];
k++; k++;
} }
} }
else { else {
for (int p = j; p < b.invokingStates.length; p++) { for (int p = j; p < b.invokingStates.length; p++) {
M.parents[k] = b.parents[p]; mergedParents[k] = b.parents[p];
M.invokingStates[k] = b.invokingStates[p]; mergedInvokingStates[k] = b.invokingStates[p];
k++; k++;
} }
} }
// trim merged // trim merged
if ( k < M.size() ) { // write index < last position; trim if ( k < mergedParents.length ) { // write index < last position; trim
M = M.trim(); int p = mergedParents.length-1;
while ( p>=0 && mergedParents[p]==null ) { p--; }
// p is now last non-null index
if ( p < mergedParents.length-1 ) {
int n = p+1;
mergedParents = Arrays.copyOf(mergedParents, n);
mergedInvokingStates = Arrays.copyOf(mergedInvokingStates, n);
} }
}
ArrayPredictionContext M =
new ArrayPredictionContext(mergedParents, mergedInvokingStates);
// TODO: if we created same array as a or b, return that instead // TODO: if we created same array as a or b, return that instead

View File

@ -50,6 +50,14 @@ public class SingletonPredictionContext extends PredictionContext {
return this.invokingState == invokingState ? 0 : -1; return this.invokingState == invokingState ? 0 : -1;
} }
@Override
public PredictionContext popAll(int invokingState, boolean fullCtx) {
if ( invokingState == this.invokingState ) {
return parent.popAll(invokingState, fullCtx);
}
return this;
}
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) { if (this == o) {

View File

@ -1,8 +1,7 @@
grammar T; grammar T;
s : a a a; s : a+ ;
a : {false}? ID {System.out.println("alt 1");} a : {false}? ID {System.out.println("alt 1");}
| {true}? ID {System.out.println("alt 2");} | {true}? ID {System.out.println("alt 2");}
| INT {System.out.println("alt 3");}
; ;
ID : 'a'..'z'+ ; ID : 'a'..'z'+ ;
INT : '0'..'9'+; INT : '0'..'9'+;