Merge branch 'fix-804'
* fix-804: Initialize DFA.precedenceDfa when the DFA instance is created Fix potential misuse of the DFA start state when initializing a decision from multiple threads
This commit is contained in:
commit
2bf3727055
|
@ -387,17 +387,6 @@ public class ParserATNSimulator extends ATNSimulator {
|
||||||
", outerContext="+ outerContext.toString(parser));
|
", 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.
|
|
||||||
*/
|
|
||||||
if (!dfa.isPrecedenceDfa() && dfa.atnStartState instanceof StarLoopEntryState) {
|
|
||||||
if (((StarLoopEntryState)dfa.atnStartState).precedenceRuleDecision) {
|
|
||||||
dfa.setPrecedenceDfa(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean fullCtx = false;
|
boolean fullCtx = false;
|
||||||
ATNConfigSet s0_closure =
|
ATNConfigSet s0_closure =
|
||||||
computeStartState(dfa.atnStartState,
|
computeStartState(dfa.atnStartState,
|
||||||
|
|
|
@ -34,6 +34,7 @@ import org.antlr.v4.runtime.Vocabulary;
|
||||||
import org.antlr.v4.runtime.VocabularyImpl;
|
import org.antlr.v4.runtime.VocabularyImpl;
|
||||||
import org.antlr.v4.runtime.atn.ATNConfigSet;
|
import org.antlr.v4.runtime.atn.ATNConfigSet;
|
||||||
import org.antlr.v4.runtime.atn.DecisionState;
|
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.NotNull;
|
||||||
import org.antlr.v4.runtime.misc.Nullable;
|
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 true} if this DFA is for a precedence decision; otherwise,
|
||||||
* {@code false}. This is the backing field for {@link #isPrecedenceDfa},
|
* {@code false}. This is the backing field for {@link #isPrecedenceDfa}.
|
||||||
* {@link #setPrecedenceDfa}.
|
|
||||||
*/
|
*/
|
||||||
private volatile boolean precedenceDfa;
|
private final boolean precedenceDfa;
|
||||||
|
|
||||||
public DFA(DecisionState atnStartState) {
|
public DFA(DecisionState atnStartState) {
|
||||||
this(atnStartState, 0);
|
this(atnStartState, 0);
|
||||||
|
@ -75,6 +75,20 @@ public class DFA {
|
||||||
public DFA(DecisionState atnStartState, int decision) {
|
public DFA(DecisionState atnStartState, int decision) {
|
||||||
this.atnStartState = atnStartState;
|
this.atnStartState = atnStartState;
|
||||||
this.decision = decision;
|
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,37 +163,20 @@ public class DFA {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets whether this is a precedence DFA. If the specified value differs
|
* Sets whether this is a precedence DFA.
|
||||||
* 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>
|
|
||||||
*
|
*
|
||||||
* @param precedenceDfa {@code true} if this is a precedence DFA; otherwise,
|
* @param precedenceDfa {@code true} if this is a precedence DFA; otherwise,
|
||||||
* {@code false}
|
* {@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.
|
||||||
*/
|
*/
|
||||||
public final synchronized void setPrecedenceDfa(boolean precedenceDfa) {
|
@Deprecated
|
||||||
if (this.precedenceDfa != precedenceDfa) {
|
public final void setPrecedenceDfa(boolean precedenceDfa) {
|
||||||
this.states.clear();
|
if (precedenceDfa != isPrecedenceDfa()) {
|
||||||
if (precedenceDfa) {
|
throw new UnsupportedOperationException("The precedenceDfa field cannot change after a DFA is constructed.");
|
||||||
DFAState precedenceState = new DFAState(new ATNConfigSet());
|
|
||||||
precedenceState.edges = new DFAState[0];
|
|
||||||
precedenceState.isAcceptState = false;
|
|
||||||
precedenceState.requiresFullContext = false;
|
|
||||||
this.s0 = precedenceState;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.s0 = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.precedenceDfa = precedenceDfa;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue