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);
}
public ArrayPredictionContext trim() {
int i = parents.length-1;
while ( i>=0 && parents[i]==null ) { i--; }
// i is last non-null index
if ( i < parents.length-1 ) {
int n = i+1;
return new ArrayPredictionContext(
Arrays.copyOf(parents, n),
Arrays.copyOf(invokingStates, n)
);
}
/** Find invokingState parameter (call it x) in this.invokingStates,
* if present. Call pop on all x's parent(s) and then pull other
* elements from this context and merge into new context.
*/
@Override
public PredictionContext popAll(int invokingState, boolean fullCtx) {
int index = Arrays.binarySearch(this.invokingStates, invokingState);
if ( index < 0 ) {
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
public boolean equals(Object 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
if ( config.context!=null && !config.context.isEmpty() ) {
for (SingletonPredictionContext ctx : config.context) {
if ( !ctx.isEmpty() ) {
// if ( !ctx.isEmpty() ) {
ATNState invokingState = atn.states.get(ctx.invokingState);
RuleTransition rt = (RuleTransition)invokingState.transition(0);
ATNState retState = rt.followState;
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
// gotten that context AFTER having falling off a rule.
// Make sure we track that we are now out of context.
c.reachesIntoOuterContext = config.reachesIntoOuterContext;
assert depth > Integer.MIN_VALUE;
closure(c, configs, closureBusy, collectPredicates, greedy, loopsSimulateTailRecursion, depth - 1);
}
closure(c, configs, closureBusy, collectPredicates, greedy,
loopsSimulateTailRecursion, depth - 1);
// }
return;
}
}
@ -989,16 +991,9 @@ public class ParserATNSimulator<Symbol extends Token> extends ATNSimulator {
}
else if ( config.state.getClass()==LoopEndState.class ) {
if ( debug ) System.out.println("Loop end; pop, stack="+config.context);
// run thru all possible stack tops in ctx
for (SingletonPredictionContext ctx : config.context) {
SingletonPredictionContext p = ctx;
LoopEndState end = (LoopEndState) config.state;
LoopEndState end = (LoopEndState)config.state;
// pop all the way back until we don't see the loopback state anymore
while ( !p.isEmpty() && p.invokingState == end.loopBackStateNumber ) {
// TODO: BROKEN. can't figure out how to leave config.context
// p = config.context = config.context.parent; // "pop"
}
}
config.context = config.context.popAll(end.loopBackStateNumber, configs.fullCtx);
}
}

View File

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

View File

@ -50,6 +50,14 @@ public class SingletonPredictionContext extends PredictionContext {
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
public boolean equals(Object o) {
if (this == o) {

View File

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