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:
Terence Parr 2015-01-31 14:27:52 -08:00
commit 2bf3727055
2 changed files with 27 additions and 41 deletions

View File

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

View File

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