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:
Terence Parr 2012-07-22 16:09:45 -07:00
parent eb78593469
commit f7eeca274f
5 changed files with 105 additions and 112 deletions

View File

@ -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);
}
}
}

View File

@ -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;
}

View File

@ -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 ;

View File

@ -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");
}
}

View File

@ -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));