forked from jasder/antlr
Initialize DFA.precedenceDfa when the DFA instance is created
This commit is contained in:
parent
84fb456aac
commit
bc98e5b687
|
@ -369,12 +369,17 @@ public class ParserATNSimulator extends ATNSimulator {
|
|||
// But, do we still need an initial state?
|
||||
try {
|
||||
DFAState s0;
|
||||
/* Threading note: dfa.s0 is the final value set on the DFA instance
|
||||
* which affects branch choice in this method. If dfa.s0 is null
|
||||
* (i.e. it has not been set), then we take the "slow" path through
|
||||
* the initialization code to ensure a correct start state is used.
|
||||
*/
|
||||
if (dfa.s0 == null) {
|
||||
if (dfa.isPrecedenceDfa()) {
|
||||
// the start state for a precedence DFA depends on the current
|
||||
// parser precedence, and is provided by a DFA method.
|
||||
s0 = dfa.getPrecedenceStartState(parser.getPrecedence());
|
||||
}
|
||||
else {
|
||||
// the start state for a "regular" DFA is just s0
|
||||
s0 = dfa.s0;
|
||||
}
|
||||
|
||||
if (s0 == null) {
|
||||
if ( outerContext ==null ) outerContext = ParserRuleContext.EMPTY;
|
||||
if ( debug || debug_list_atn_decisions ) {
|
||||
System.out.println("predictATN decision "+ dfa.decision+
|
||||
|
@ -382,25 +387,6 @@ public class ParserATNSimulator extends ATNSimulator {
|
|||
", outerContext="+ outerContext.toString(parser));
|
||||
}
|
||||
|
||||
/* If this is not a precedence DFA, we check the ATN start state
|
||||
* to determine if this ATN start state is the decision for the
|
||||
* closure block that determines whether a precedence rule
|
||||
* should continue or complete.
|
||||
*
|
||||
* Threading note: cannot check the dfa.isPrecedenceDfa()
|
||||
* condition here, because it's possible for that value to
|
||||
* return true prior to dfa.s0 being set to the precedence start
|
||||
* state. Calling dfa.setPrecedenceDfa(true) multiple times is
|
||||
* safe, and the one-time performance overhead only occurs if
|
||||
* multiple threads try to initialize the same DFA start state
|
||||
* at the same time.
|
||||
*/
|
||||
if (dfa.atnStartState instanceof StarLoopEntryState) {
|
||||
if (((StarLoopEntryState)dfa.atnStartState).precedenceRuleDecision) {
|
||||
dfa.setPrecedenceDfa(true);
|
||||
}
|
||||
}
|
||||
|
||||
boolean fullCtx = false;
|
||||
ATNConfigSet s0_closure =
|
||||
computeStartState(dfa.atnStartState,
|
||||
|
@ -422,19 +408,6 @@ public class ParserATNSimulator extends ATNSimulator {
|
|||
s0 = addDFAState(dfa, new DFAState(s0_closure));
|
||||
dfa.s0 = s0;
|
||||
}
|
||||
} else if (dfa.isPrecedenceDfa()) {
|
||||
/* Threading note: if dfa.s0 was not null, then
|
||||
* dfa.isPrecedenceDfa() must have already been set to the
|
||||
* correct value.
|
||||
*/
|
||||
|
||||
// the start state for a precedence DFA depends on the current
|
||||
// parser precedence, and is provided by a DFA method.
|
||||
s0 = dfa.getPrecedenceStartState(parser.getPrecedence());
|
||||
}
|
||||
else {
|
||||
// the start state for a "regular" DFA is just s0
|
||||
s0 = dfa.s0;
|
||||
}
|
||||
|
||||
int alt = execATN(dfa, s0, input, index, outerContext);
|
||||
|
|
|
@ -34,6 +34,7 @@ import org.antlr.v4.runtime.Vocabulary;
|
|||
import org.antlr.v4.runtime.VocabularyImpl;
|
||||
import org.antlr.v4.runtime.atn.ATNConfigSet;
|
||||
import org.antlr.v4.runtime.atn.DecisionState;
|
||||
import org.antlr.v4.runtime.atn.StarLoopEntryState;
|
||||
import org.antlr.v4.runtime.misc.NotNull;
|
||||
import org.antlr.v4.runtime.misc.Nullable;
|
||||
|
||||
|
@ -63,10 +64,9 @@ public class DFA {
|
|||
|
||||
/**
|
||||
* {@code true} if this DFA is for a precedence decision; otherwise,
|
||||
* {@code false}. This is the backing field for {@link #isPrecedenceDfa},
|
||||
* {@link #setPrecedenceDfa}.
|
||||
* {@code false}. This is the backing field for {@link #isPrecedenceDfa}.
|
||||
*/
|
||||
private volatile boolean precedenceDfa;
|
||||
private final boolean precedenceDfa;
|
||||
|
||||
public DFA(DecisionState atnStartState) {
|
||||
this(atnStartState, 0);
|
||||
|
@ -75,6 +75,20 @@ public class DFA {
|
|||
public DFA(DecisionState atnStartState, int decision) {
|
||||
this.atnStartState = atnStartState;
|
||||
this.decision = decision;
|
||||
|
||||
boolean precedenceDfa = false;
|
||||
if (atnStartState instanceof StarLoopEntryState) {
|
||||
if (((StarLoopEntryState)atnStartState).precedenceRuleDecision) {
|
||||
precedenceDfa = true;
|
||||
DFAState precedenceState = new DFAState(new ATNConfigSet());
|
||||
precedenceState.edges = new DFAState[0];
|
||||
precedenceState.isAcceptState = false;
|
||||
precedenceState.requiresFullContext = false;
|
||||
this.s0 = precedenceState;
|
||||
}
|
||||
}
|
||||
|
||||
this.precedenceDfa = precedenceDfa;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -149,43 +163,20 @@ public class DFA {
|
|||
}
|
||||
|
||||
/**
|
||||
* Sets whether this is a precedence DFA. If the specified value differs
|
||||
* from the current DFA configuration, the following actions are taken;
|
||||
* otherwise no changes are made to the current DFA.
|
||||
*
|
||||
* <ul>
|
||||
* <li>The {@link #states} map is cleared</li>
|
||||
* <li>If {@code precedenceDfa} is {@code false}, the initial state
|
||||
* {@link #s0} is set to {@code null}; otherwise, it is initialized to a new
|
||||
* {@link DFAState} with an empty outgoing {@link DFAState#edges} array to
|
||||
* store the start states for individual precedence values.</li>
|
||||
* <li>The {@link #precedenceDfa} field is updated</li>
|
||||
* </ul>
|
||||
* Sets whether this is a precedence DFA.
|
||||
*
|
||||
* @param precedenceDfa {@code true} if this is a precedence DFA; otherwise,
|
||||
* {@code false}
|
||||
*
|
||||
* @throws UnsupportedOperationException if {@code precedenceDfa} does not
|
||||
* match the value of {@link #isPrecedenceDfa} for the current DFA.
|
||||
*
|
||||
* @deprecated This method no longer performs any action.
|
||||
*/
|
||||
@Deprecated
|
||||
public final void setPrecedenceDfa(boolean precedenceDfa) {
|
||||
// Synchronize on this.states since we alter the map and other code
|
||||
// which updates the DFA synchronizes on states, not on the DFA instance
|
||||
// itself.
|
||||
synchronized (this.states) {
|
||||
if (this.precedenceDfa != precedenceDfa) {
|
||||
this.states.clear();
|
||||
// must set precedenceDfa before s0 to ensure correct branches
|
||||
// are followed in adaptivePredict
|
||||
this.precedenceDfa = precedenceDfa;
|
||||
if (precedenceDfa) {
|
||||
DFAState precedenceState = new DFAState(new ATNConfigSet());
|
||||
precedenceState.edges = new DFAState[0];
|
||||
precedenceState.isAcceptState = false;
|
||||
precedenceState.requiresFullContext = false;
|
||||
this.s0 = precedenceState;
|
||||
}
|
||||
else {
|
||||
this.s0 = null;
|
||||
}
|
||||
}
|
||||
if (precedenceDfa != isPrecedenceDfa()) {
|
||||
throw new UnsupportedOperationException("The precedenceDfa field cannot change after a DFA is constructed.");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue