Make sure to consider context for the SLL precedence filter (fixes #509)

This commit is contained in:
Sam Harwell 2014-03-23 11:33:14 -05:00
parent cb0119e761
commit 10558a7bea
1 changed files with 30 additions and 4 deletions

View File

@ -51,8 +51,10 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
@ -987,7 +989,8 @@ public class ParserATNSimulator extends ATNSimulator {
* {@link SemanticContext#evalPrecedence}.</li>
* <li>Remove all configurations which predict an alternative greater than
* 1, for which another configuration that predicts alternative 1 is in the
* same ATN state. This transformation is valid for the following reasons:
* same ATN state with the same prediction context. This transformation is
* valid for the following reasons:
* <ul>
* <li>The closure block cannot contain any epsilon transitions which bypass
* the body of the closure, so all states reachable via alternative 1 are
@ -1002,6 +1005,28 @@ public class ParserATNSimulator extends ATNSimulator {
* </li>
* </ol>
*
* <p>
* The prediction context must be considered by this filter to address
* situations like the following.
* </p>
* <code>
* <pre>
* grammar TA;
* prog: statement* EOF;
* statement: letterA | statement letterA 'b' ;
* letterA: 'a';
* </pre>
* </code>
* <p>
* If the above grammar, the ATN state immediately before the token
* reference {@code 'a'} in {@code letterA} is reachable from the left edge
* of both the primary and closure blocks of the left-recursive rule
* {@code statement}. The prediction context associated with each of these
* configurations distinguishes between them, and prevents the alternative
* which stepped out to {@code prog} (and then back in to {@code statement}
* from being eliminated by the filter.
* </p>
*
* @param configs The configuration set computed by
* {@link #computeStartState} as the start state for the DFA.
* @return The transformed configuration set representing the start state
@ -1010,7 +1035,7 @@ public class ParserATNSimulator extends ATNSimulator {
*/
@NotNull
protected ATNConfigSet applyPrecedenceFilter(@NotNull ATNConfigSet configs) {
Set<Integer> statesFromAlt1 = new HashSet<Integer>();
Map<Integer, PredictionContext> statesFromAlt1 = new HashMap<Integer, PredictionContext>();
ATNConfigSet configSet = new ATNConfigSet(configs.fullCtx);
for (ATNConfig config : configs) {
// handle alt 1 first
@ -1024,7 +1049,7 @@ public class ParserATNSimulator extends ATNSimulator {
continue;
}
statesFromAlt1.add(config.state.stateNumber);
statesFromAlt1.put(config.state.stateNumber, config.context);
if (updatedContext != config.semanticContext) {
configSet.add(new ATNConfig(config, updatedContext), mergeCache);
}
@ -1039,7 +1064,8 @@ public class ParserATNSimulator extends ATNSimulator {
continue;
}
if (statesFromAlt1.contains(config.state.stateNumber)) {
PredictionContext context = statesFromAlt1.get(config.state.stateNumber);
if (context != null && context.equals(config.context)) {
// eliminated
continue;
}