antlr/antlr4 · error · Exception

Only precedence DFAs may contain a precedence start state.

Error message

Only precedence DFAs may contain a precedence start state.

What it means

DFA.GetPrecedenceStartState(precedence) returns the per-precedence start state of a precedence DFA — a DFA built for a grammar with left-recursive rules, where the simulator caches one start state per precedence level. The getter only makes sense when IsPrecedenceDfa is true (s0 is a special state whose edges array holds the precedence start states); on a normal DFA there is no such structure, so the method refuses instead of returning a misleading value.

Source

Thrown at runtime/CSharp/src/Dfa/DFA.cs:89

				return precedenceDfa;
			}
		}

		/**
		 * Get the start state for a specific precedence value.
		 *
		 * @param precedence The current precedence.
		 * @return The start state corresponding to the specified precedence, or
		 * {@code null} if no start state exists for the specified precedence.
		 *
		 * @throws IllegalStateException if this is not a precedence DFA.
		 * @see #isPrecedenceDfa()
		 */
		public DFAState GetPrecedenceStartState(int precedence)
		{
			if (!IsPrecedenceDfa)
			{
				throw new Exception("Only precedence DFAs may contain a precedence start state.");
			}

			// s0.edges is never null for a precedence DFA
			if (precedence < 0 || precedence >= s0.edges.Length)
			{
				return null;
			}

			return s0.edges[precedence];
		}

		/**
		 * Set the start state for a specific precedence value.
		 *
		 * @param precedence The current precedence.
		 * @param startState The start state corresponding to the specified
		 * precedence.
		 *

View on GitHub (pinned to 7d5770395b)

Solutions

  1. Check dfa.IsPrecedenceDfa before calling Get/SetPrecedenceStartState
  2. When constructing or resetting DFAs yourself, set dfa.s0 = new DFAState(...) plus dfa.IsPrecedenceDfa = true only for decisions that are precedence decisions (check atn.decisionToState[i].stateType)
  3. Let ParserATNSimulator manage s0; avoid writing dfa.s0 by hand

Example fix

// before
DFAState start = dfa.GetPrecedenceStartState(prec); // throws for non-precedence DFA

// after
DFAState start = dfa.IsPrecedenceDfa ? dfa.GetPrecedenceStartState(prec) : dfa.s0;
Defensive patterns

Strategy: validation

Validate before calling

DFAState start = dfa.IsPrecedenceDfa ? dfa.GetPrecedenceStartState(precedence) : dfa.s0;

Type guard

static bool IsPrecedenceDfa(DFA dfa) => dfa != null && dfa.IsPrecedenceDfa;

Prevention

When it happens

Trigger: Calling GetPrecedenceStartState on a DFA whose start state was not marked as a precedence start state — i.e. grammars without left-recursive rules, or a precedence DFA whose s0 was replaced with a plain DFAState. Usually reached indirectly: ParserATNSimulator computes start states via this API when the decision is a precedence decision; manual DFA construction or copied s0 states can break the invariant.

Common situations: Manually building/resetting DFA objects (e.g. cache warmup that assigns dfa.s0 without setting isPrecedenceDfa); library code that assumes every parser DFA is a precedence DFA; porting Java code that manipulated dfa.s0 directly.

Related errors


AI-assisted analysis of antlr/antlr4@7d5770395b (2026-08-14). Data as JSON: /api/errors/af04f4dded542a28. Report an issue: GitHub.