forked from jasder/antlr
reorg closure and fix bug where $ in arrayctx wouldn't perform global follow. fix case in array merge that didn't check both a[i], b[i] as $ (only matters in full ctx). unit tests for graph show fewer ctx's created.
This commit is contained in:
parent
eb78593469
commit
f7eeca274f
|
@ -932,16 +932,17 @@ public class ParserATNSimulator<Symbol extends Token> extends ATNSimulator {
|
|||
boolean greedy, boolean loopsSimulateTailRecursion)
|
||||
{
|
||||
final int initialDepth = 0;
|
||||
closure_(config, configs, closureBusy, collectPredicates, greedy,
|
||||
loopsSimulateTailRecursion, initialDepth);
|
||||
closureCheckingStopStateAndLoopRecursion(config, configs, closureBusy, collectPredicates, greedy,
|
||||
loopsSimulateTailRecursion, initialDepth);
|
||||
}
|
||||
|
||||
protected void closure_(@NotNull ATNConfig config,
|
||||
@NotNull ATNConfigSet configs,
|
||||
@NotNull Set<ATNConfig> closureBusy,
|
||||
boolean collectPredicates,
|
||||
boolean greedy, boolean loopsSimulateTailRecursion,
|
||||
int depth)
|
||||
protected void closureCheckingStopStateAndLoopRecursion(@NotNull ATNConfig config,
|
||||
@NotNull ATNConfigSet configs,
|
||||
@NotNull Set<ATNConfig> closureBusy,
|
||||
boolean collectPredicates,
|
||||
boolean greedy,
|
||||
boolean loopsSimulateTailRecursion,
|
||||
int depth)
|
||||
{
|
||||
if ( debug ) System.out.println("closure("+config.toString(parser,true)+")");
|
||||
|
||||
|
@ -959,6 +960,14 @@ 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.invokingState==PredictionContext.EMPTY_FULL_CTX_INVOKING_STATE ) {
|
||||
// we have no context info, just chase follow links (if greedy)
|
||||
if ( debug ) System.out.println("FALLING off rule "+
|
||||
getRuleName(config.state.ruleIndex));
|
||||
closure_(config, configs, closureBusy, collectPredicates, greedy,
|
||||
loopsSimulateTailRecursion, depth - 1);
|
||||
continue;
|
||||
}
|
||||
ATNState invokingState = atn.states.get(ctx.invokingState);
|
||||
RuleTransition rt = (RuleTransition)invokingState.transition(0);
|
||||
ATNState retState = rt.followState;
|
||||
|
@ -970,8 +979,8 @@ public class ParserATNSimulator<Symbol extends Token> extends ATNSimulator {
|
|||
// 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);
|
||||
closureCheckingStopStateAndLoopRecursion(c, configs, closureBusy, collectPredicates, greedy,
|
||||
loopsSimulateTailRecursion, depth - 1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -999,11 +1008,22 @@ public class ParserATNSimulator<Symbol extends Token> extends ATNSimulator {
|
|||
}
|
||||
}
|
||||
|
||||
closure_(config, configs, closureBusy, collectPredicates, greedy, loopsSimulateTailRecursion, depth);
|
||||
}
|
||||
|
||||
/** Do the actual work of walking epsilon edges */
|
||||
protected void closure_(@NotNull ATNConfig config,
|
||||
@NotNull ATNConfigSet configs,
|
||||
@NotNull Set<ATNConfig> closureBusy,
|
||||
boolean collectPredicates,
|
||||
boolean greedy, boolean loopsSimulateTailRecursion,
|
||||
int depth)
|
||||
{
|
||||
ATNState p = config.state;
|
||||
// optimization
|
||||
if ( !p.onlyHasEpsilonTransitions() ) {
|
||||
configs.add(config);
|
||||
if ( config.semanticContext!=null && config.semanticContext!=SemanticContext.NONE ) {
|
||||
if ( config.semanticContext!=null && config.semanticContext!= SemanticContext.NONE ) {
|
||||
configs.hasSemanticContext = true;
|
||||
}
|
||||
if ( config.reachesIntoOuterContext>0 ) {
|
||||
|
@ -1012,14 +1032,14 @@ public class ParserATNSimulator<Symbol extends Token> extends ATNSimulator {
|
|||
if ( debug ) System.out.println("added config "+configs);
|
||||
}
|
||||
|
||||
for (int i=0; i<p.getNumberOfTransitions(); i++) {
|
||||
Transition t = p.transition(i);
|
||||
boolean continueCollecting =
|
||||
for (int i=0; i<p.getNumberOfTransitions(); i++) {
|
||||
Transition t = p.transition(i);
|
||||
boolean continueCollecting =
|
||||
!(t instanceof ActionTransition) && collectPredicates;
|
||||
ATNConfig c = getEpsilonTarget(config, t, continueCollecting, depth == 0);
|
||||
ATNConfig c = getEpsilonTarget(config, t, continueCollecting, depth == 0);
|
||||
if ( c!=null ) {
|
||||
int newDepth = depth;
|
||||
if ( config.state instanceof RuleStopState ) {
|
||||
if ( config.state instanceof RuleStopState) {
|
||||
// target fell off end of rule; mark resulting c as having dipped into outer context
|
||||
// We can't get here if incoming config was rule stop and we had context
|
||||
// track how far we dip into outer context. Might
|
||||
|
@ -1038,8 +1058,8 @@ public class ParserATNSimulator<Symbol extends Token> extends ATNSimulator {
|
|||
}
|
||||
}
|
||||
|
||||
closure_(c, configs, closureBusy, continueCollecting, greedy,
|
||||
loopsSimulateTailRecursion, newDepth);
|
||||
closureCheckingStopStateAndLoopRecursion(c, configs, closureBusy, continueCollecting, greedy,
|
||||
loopsSimulateTailRecursion, newDepth);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -321,44 +321,43 @@ public abstract class PredictionContext implements Iterable<SingletonPredictionC
|
|||
// merge sorted payloads a + b => M
|
||||
int i = 0; // walks a
|
||||
int j = 0; // walks b
|
||||
int k = 0; // walks M target array
|
||||
int k = 0; // walks target M array
|
||||
|
||||
int[] mergedInvokingStates =
|
||||
new int[a.invokingStates.length + b.invokingStates.length];
|
||||
PredictionContext[] mergedParents =
|
||||
new PredictionContext[a.invokingStates.length + b.invokingStates.length];
|
||||
// walk and merge to yield mergedParents, mergedInvokingStates
|
||||
while ( i<a.invokingStates.length && j<b.invokingStates.length ) {
|
||||
PredictionContext a_parent = a.parents[i];
|
||||
PredictionContext b_parent = b.parents[j];
|
||||
if ( a.invokingStates[i]==b.invokingStates[j] ) {
|
||||
// same payload; stack tops are equal
|
||||
// same payload (stack tops are equal), must yield merged singleton
|
||||
int payload = a.invokingStates[i];
|
||||
SingletonPredictionContext a_ = new SingletonPredictionContext(a.parents[i], payload);
|
||||
SingletonPredictionContext b_ = new SingletonPredictionContext(b.parents[j], payload);
|
||||
// if same stack tops, must yield merged singleton
|
||||
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_ ) {
|
||||
mergedParents[k] = a.parents[i];
|
||||
mergedInvokingStates[k] = a.invokingStates[i];
|
||||
// $+$ = $
|
||||
boolean both$ = payload == EMPTY_FULL_CTX_INVOKING_STATE &&
|
||||
a_parent == null && b_parent == null;
|
||||
boolean ax_ax = (a_parent!=null && b_parent!=null) &&
|
||||
a_parent.equals(b_parent); // ax+ax -> ax
|
||||
if ( both$ || ax_ax ) {
|
||||
mergedParents[k] = a_parent; // choose left
|
||||
mergedInvokingStates[k] = payload;
|
||||
}
|
||||
else if ( r==b_ ) {
|
||||
mergedParents[k] = b.parents[j];
|
||||
mergedInvokingStates[k] = b.invokingStates[j];
|
||||
}
|
||||
else {
|
||||
mergedParents[k] = r.parent;
|
||||
mergedInvokingStates[k] = r.invokingState;
|
||||
else { // ax+ay -> a'[x,y]
|
||||
PredictionContext mergedParent = merge(a_parent, b_parent, rootIsWildcard);
|
||||
mergedParents[k] = mergedParent;
|
||||
mergedInvokingStates[k] = payload;
|
||||
}
|
||||
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] ) {
|
||||
mergedParents[k] = a.parents[i];
|
||||
else if ( a.invokingStates[i]<b.invokingStates[j] ) { // copy a[i] to M
|
||||
mergedParents[k] = a_parent;
|
||||
mergedInvokingStates[k] = a.invokingStates[i];
|
||||
i++;
|
||||
}
|
||||
else { // b > a
|
||||
mergedParents[k] = b.parents[j];
|
||||
else { // b > a, copy b[j] to M
|
||||
mergedParents[k] = b_parent;
|
||||
mergedInvokingStates[k] = b.invokingStates[j];
|
||||
j++;
|
||||
}
|
||||
|
@ -381,7 +380,6 @@ public abstract class PredictionContext implements Iterable<SingletonPredictionC
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// trim merged
|
||||
if ( k < mergedParents.length ) { // write index < last position; trim
|
||||
int p = mergedParents.length-1;
|
||||
|
@ -404,6 +402,7 @@ public abstract class PredictionContext implements Iterable<SingletonPredictionC
|
|||
// TODO: if we created same array as a or b, return that instead
|
||||
|
||||
// TODO: make pass over all M parents; merge any equal() ones
|
||||
// combineCommonParents(mergedParents);
|
||||
|
||||
return M;
|
||||
}
|
||||
|
|
|
@ -1,34 +1,4 @@
|
|||
grammar T;
|
||||
s : stat ;
|
||||
stat: expr[0] NEWLINE
|
||||
| ID '=' expr[0] NEWLINE
|
||||
| NEWLINE
|
||||
;
|
||||
|
||||
expr[int _p]
|
||||
: ( INT
|
||||
| ID
|
||||
| '(' expr[0] ')'
|
||||
)
|
||||
( {5 >= $_p}? ('*'|'/') expr[6]
|
||||
| {4 >= $_p}? ('+'|'-') expr[5]
|
||||
)*
|
||||
;
|
||||
|
||||
/*
|
||||
expr: expr ('*'|'/') expr # MulDiv
|
||||
| expr ('+'|'-') expr # AddSub
|
||||
| INT # int
|
||||
| ID # id
|
||||
| '(' expr ')' # parens
|
||||
;
|
||||
*/
|
||||
|
||||
MUL : '*' ; // assigns token name to '*' used above in grammar
|
||||
DIV : '/' ;
|
||||
ADD : '+' ;
|
||||
SUB : '-' ;
|
||||
ID : [a-zA-Z]+ ; // match identifiers
|
||||
INT : [0-9]+ ; // match integers
|
||||
NEWLINE:'\r'? '\n' ; // return newlines to parser (is end-statement signal)
|
||||
WS : [ \t]+ -> skip ; // toss out whitespace
|
||||
stat : ifstat | 'x';
|
||||
ifstat : 'if' stat ('else' stat)?;
|
||||
WS : [ \n\t]+ -> skip ;
|
||||
|
|
|
@ -26,7 +26,7 @@ public class TestT {
|
|||
|
||||
parser.addErrorListener(new DiagnosticErrorListener());
|
||||
|
||||
ParserRuleContext tree = parser.s();
|
||||
ParserRuleContext tree = parser.stat();
|
||||
// tree.save(parser, "/tmp/t.ps");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -478,10 +478,10 @@ public class TestGraphNodes extends TestCase {
|
|||
String expecting =
|
||||
"digraph G {\n" +
|
||||
"rankdir=LR;\n" +
|
||||
" s8 [shape=box, label=\"[1, 2]\"];\n" +
|
||||
" s6 [shape=box, label=\"[1, 2]\"];\n" +
|
||||
" s0 [label=\"$\"];\n" +
|
||||
" s8->s0 [label=\"parent[0]\"];\n" +
|
||||
" s8->s0 [label=\"parent[1]\"];\n" +
|
||||
" s6->s0 [label=\"parent[0]\"];\n" +
|
||||
" s6->s0 [label=\"parent[1]\"];\n" +
|
||||
"}\n";
|
||||
assertEquals(expecting, PredictionContext.toDotString(r));
|
||||
}
|
||||
|
@ -494,10 +494,10 @@ public class TestGraphNodes extends TestCase {
|
|||
String expecting =
|
||||
"digraph G {\n" +
|
||||
"rankdir=LR;\n" +
|
||||
" s8 [shape=box, label=\"[1, 2]\"];\n" +
|
||||
" s6 [shape=box, label=\"[1, 2]\"];\n" +
|
||||
" s0 [label=\"$\"];\n" +
|
||||
" s8->s0 [label=\"parent[0]\"];\n" +
|
||||
" s8->s0 [label=\"parent[1]\"];\n" +
|
||||
" s6->s0 [label=\"parent[0]\"];\n" +
|
||||
" s6->s0 [label=\"parent[1]\"];\n" +
|
||||
"}\n";
|
||||
assertEquals(expecting, PredictionContext.toDotString(r));
|
||||
}
|
||||
|
@ -534,12 +534,12 @@ public class TestGraphNodes extends TestCase {
|
|||
String expecting =
|
||||
"digraph G {\n" +
|
||||
"rankdir=LR;\n" +
|
||||
" s11 [label=\"1\"];\n" +
|
||||
" s9 [shape=box, label=\"[9, 10]\"];\n" +
|
||||
" s8 [label=\"1\"];\n" +
|
||||
" s7 [shape=box, label=\"[9, 10]\"];\n" +
|
||||
" s0 [label=\"$\"];\n" +
|
||||
" s11->s9;\n" +
|
||||
" s9->s0 [label=\"parent[0]\"];\n" +
|
||||
" s9->s0 [label=\"parent[1]\"];\n" +
|
||||
" s8->s7;\n" +
|
||||
" s7->s0 [label=\"parent[0]\"];\n" +
|
||||
" s7->s0 [label=\"parent[1]\"];\n" +
|
||||
"}\n";
|
||||
assertEquals(expecting, PredictionContext.toDotString(r));
|
||||
}
|
||||
|
@ -554,14 +554,14 @@ public class TestGraphNodes extends TestCase {
|
|||
String expecting =
|
||||
"digraph G {\n" +
|
||||
"rankdir=LR;\n" +
|
||||
" s13 [shape=box, label=\"[1, 3, 4]\"];\n" +
|
||||
" s10 [shape=box, label=\"[1, 3, 4]\"];\n" +
|
||||
" s0 [label=\"$\"];\n" +
|
||||
" s11 [shape=box, label=\"[9, 10]\"];\n" +
|
||||
" s13->s11 [label=\"parent[0]\"];\n" +
|
||||
" s13->s0 [label=\"parent[1]\"];\n" +
|
||||
" s13->s0 [label=\"parent[2]\"];\n" +
|
||||
" s11->s0 [label=\"parent[0]\"];\n" +
|
||||
" s11->s0 [label=\"parent[1]\"];\n" +
|
||||
" s9 [shape=box, label=\"[9, 10]\"];\n" +
|
||||
" s10->s9 [label=\"parent[0]\"];\n" +
|
||||
" s10->s0 [label=\"parent[1]\"];\n" +
|
||||
" s10->s0 [label=\"parent[2]\"];\n" +
|
||||
" s9->s0 [label=\"parent[0]\"];\n" +
|
||||
" s9->s0 [label=\"parent[1]\"];\n" +
|
||||
"}\n";
|
||||
assertEquals(expecting, PredictionContext.toDotString(r));
|
||||
}
|
||||
|
@ -578,14 +578,17 @@ public class TestGraphNodes extends TestCase {
|
|||
String expecting =
|
||||
"digraph G {\n" +
|
||||
"rankdir=LR;\n" +
|
||||
" s13 [shape=box, label=\"[1, 2, 3]\"];\n" +
|
||||
" s5 [label=\"8\"];\n" +
|
||||
" s11 [shape=box, label=\"[1, 2, 3, 4]\"];\n" +
|
||||
" s7 [label=\"9\"];\n" +
|
||||
" s0 [label=\"$\"];\n" +
|
||||
" s5 [label=\"8\"];\n" +
|
||||
" s3 [label=\"7\"];\n" +
|
||||
" s1 [label=\"6\"];\n" +
|
||||
" s13->s1 [label=\"parent[0]\"];\n" +
|
||||
" s13->s3 [label=\"parent[1]\"];\n" +
|
||||
" s13->s5 [label=\"parent[2]\"];\n" +
|
||||
" s11->s1 [label=\"parent[0]\"];\n" +
|
||||
" s11->s3 [label=\"parent[1]\"];\n" +
|
||||
" s11->s5 [label=\"parent[2]\"];\n" +
|
||||
" s11->s7 [label=\"parent[3]\"];\n" +
|
||||
" s7->s0;\n" +
|
||||
" s5->s0;\n" +
|
||||
" s3->s0;\n" +
|
||||
" s1->s0;\n" +
|
||||
|
@ -605,15 +608,15 @@ public class TestGraphNodes extends TestCase {
|
|||
String expecting =
|
||||
"digraph G {\n" +
|
||||
"rankdir=LR;\n" +
|
||||
" s13 [shape=box, label=\"[1, 2, 3]\"];\n" +
|
||||
" s5 [label=\"8\"];\n" +
|
||||
" s11 [shape=box, label=\"[1, 2, 4]\"];\n" +
|
||||
" s7 [label=\"9\"];\n" +
|
||||
" s0 [label=\"$\"];\n" +
|
||||
" s3 [label=\"7\"];\n" +
|
||||
" s1 [label=\"6\"];\n" +
|
||||
" s13->s1 [label=\"parent[0]\"];\n" +
|
||||
" s13->s3 [label=\"parent[1]\"];\n" +
|
||||
" s13->s5 [label=\"parent[2]\"];\n" +
|
||||
" s5->s0;\n" +
|
||||
" s11->s1 [label=\"parent[0]\"];\n" +
|
||||
" s11->s3 [label=\"parent[1]\"];\n" +
|
||||
" s11->s7 [label=\"parent[2]\"];\n" +
|
||||
" s7->s0;\n" +
|
||||
" s3->s0;\n" +
|
||||
" s1->s0;\n" +
|
||||
"}\n";
|
||||
|
@ -632,16 +635,17 @@ public class TestGraphNodes extends TestCase {
|
|||
String expecting =
|
||||
"digraph G {\n" +
|
||||
"rankdir=LR;\n" +
|
||||
" s13 [shape=box, label=\"[1, 2, 3]\"];\n" +
|
||||
" s5 [label=\"8\"];\n" +
|
||||
" s12 [shape=box, label=\"[1, 2, 4]\"];\n" +
|
||||
" s7 [label=\"9\"];\n" +
|
||||
" s0 [label=\"$\"];\n" +
|
||||
" s3 [label=\"7\"];\n" +
|
||||
" s11 [shape=box, label=\"[7, 8]\"];\n" +
|
||||
" s1 [label=\"6\"];\n" +
|
||||
" s13->s1 [label=\"parent[0]\"];\n" +
|
||||
" s13->s3 [label=\"parent[1]\"];\n" +
|
||||
" s13->s5 [label=\"parent[2]\"];\n" +
|
||||
" s5->s0;\n" +
|
||||
" s3->s0;\n" +
|
||||
" s12->s1 [label=\"parent[0]\"];\n" +
|
||||
" s12->s11 [label=\"parent[1]\"];\n" +
|
||||
" s12->s7 [label=\"parent[2]\"];\n" +
|
||||
" s7->s0;\n" +
|
||||
" s11->s0 [label=\"parent[0]\"];\n" +
|
||||
" s11->s0 [label=\"parent[1]\"];\n" +
|
||||
" s1->s0;\n" +
|
||||
"}\n";
|
||||
assertEquals(expecting, PredictionContext.toDotString(r));
|
||||
|
|
Loading…
Reference in New Issue