forked from jasder/antlr
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:
parent
9318391664
commit
0f969af947
|
@ -71,18 +71,33 @@ 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;
|
||||
}
|
||||
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
|
||||
|
|
|
@ -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;
|
||||
// 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"
|
||||
}
|
||||
}
|
||||
LoopEndState end = (LoopEndState)config.state;
|
||||
// pop all the way back until we don't see the loopback state anymore
|
||||
config.context = config.context.popAll(end.loopBackStateNumber, configs.fullCtx);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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,23 +349,34 @@ 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
|
||||
|
||||
// TODO: make pass over all M parents; merge any equal() ones
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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'+;
|
||||
|
|
Loading…
Reference in New Issue