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,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) {
|
||||||
|
|
|
@ -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"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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'+;
|
||||||
|
|
Loading…
Reference in New Issue