caching more operations in mergeCache, updated comments, added null chk in front of mergeCache ops.

This commit is contained in:
Terence Parr 2012-08-04 11:04:21 -07:00
parent 5455813145
commit b160a3b14d
2 changed files with 34 additions and 5 deletions

View File

@ -103,10 +103,21 @@ import java.util.Set;
simple. By launching multiple threads, we can improve the speed of
parsing across a large number of files.
This strategy is complex because we bounce back and forth from
the ATN to the DFA, simultaneously performing predictions and
extending the DFA according to previously unseen input
sequences.
There is no strict ordering between the amount of input used by
SLL vs LL, which makes it really hard to build a cache for full
context. Let's say that we have input A B C that leads to an SLL
conflict with full context X. That implies that using X we
might only use A B but we could also use A B C D to resolve
conflict. Input A B C D could predict alternative 1 in one
position in the input and A B C E could predict alternative 2 in
another position in input. The conflicting SLL configurations
could still be non-unique in the full context prediction, which
would lead us to requiring more input than the original A B C. To
make a prediction cache work, we have to track the exact input used
during the previous prediction. That amounts to a cache that maps X
to a specific DFA for that context.
AVOIDING FULL CONTEXT PREDICTION
We avoid doing full context retry when the outer context is empty,
we did not dip into the outer context by falling off the end of the
@ -263,6 +274,9 @@ public class ParserATNSimulator<Symbol extends Token> extends ATNSimulator {
* Don't keep around as it wastes huge amounts of memory. DoubleKeyMap
* isn't synchronized but we're ok since two threads shouldn't reuse same
* parser/atnsim object because it can only handle one input at a time.
* This maps graphs a and b to merged result c. (a,b)->c. We can avoid
* the merge if we ever see a and b again. Note that (b,a)->c should
* also be examined during cache lookup.
*/
protected DoubleKeyMap<PredictionContext,PredictionContext,PredictionContext> mergeCache;

View File

@ -156,8 +156,18 @@ public abstract class PredictionContext implements Iterable<SingletonPredictionC
boolean rootIsWildcard,
DoubleKeyMap<PredictionContext,PredictionContext,PredictionContext> mergeCache)
{
if ( mergeCache!=null ) {
PredictionContext previous = mergeCache.get(a,b);
if ( previous!=null ) return previous;
previous = mergeCache.get(b,a);
if ( previous!=null ) return previous;
}
PredictionContext rootMerge = mergeRoot(a, b, rootIsWildcard);
if ( rootMerge!=null ) return rootMerge;
if ( rootMerge!=null ) {
if ( mergeCache!=null ) mergeCache.put(a, b, rootMerge);
return rootMerge;
}
if ( a.invokingState==b.invokingState ) { // a == b
PredictionContext parent = merge(a.parent, b.parent, rootIsWildcard, mergeCache);
@ -169,6 +179,7 @@ public abstract class PredictionContext implements Iterable<SingletonPredictionC
// of those graphs. dup a, a' points at merged array
// new joined parent so create new singleton pointing to it, a'
PredictionContext a_ = new SingletonPredictionContext(parent, a.invokingState);
if ( mergeCache!=null ) mergeCache.put(a, b, a_);
return a_;
}
else { // a != b payloads differ
@ -190,6 +201,7 @@ public abstract class PredictionContext implements Iterable<SingletonPredictionC
}
PredictionContext[] parents = {singleParent, singleParent};
PredictionContext a_ = new ArrayPredictionContext(parents, payloads);
if ( mergeCache!=null ) mergeCache.put(a, b, a_);
return a_;
}
// parents differ and can't merge them. Just pack together
@ -203,6 +215,7 @@ public abstract class PredictionContext implements Iterable<SingletonPredictionC
parents = new PredictionContext[] {b.parent, a.parent};
}
PredictionContext a_ = new ArrayPredictionContext(parents, payloads);
if ( mergeCache!=null ) mergeCache.put(a, b, a_);
return a_;
}
}
@ -248,6 +261,8 @@ public abstract class PredictionContext implements Iterable<SingletonPredictionC
if ( mergeCache!=null ) {
PredictionContext previous = mergeCache.get(a,b);
if ( previous!=null ) return previous;
previous = mergeCache.get(b,a);
if ( previous!=null ) return previous;
}
// merge sorted payloads a + b => M