Canonical LR(0) item-set construction (closure/goto over
Grammar.LRTable.Desugar's flat production list), plus SLR(1)
action/goto table construction on top of it.
SLR(1), not full canonical LR(1) or LALR(1) -- a deliberate, simpler
choice for a from-scratch v1 (no per-item lookahead propagation graph
needed at all): a reduce action for a complete item [A -> α ·] is
only offered on a lookahead terminal in FOLLOW(A), computed once
over the whole grammar rather than per state. This accepts every
LR(0)-unambiguous grammar plus a useful chunk of real ones, at the
cost of occasionally reporting a conflict a full LALR(1) table
wouldn't -- Grammar.GLR forks on any multi-action cell regardless
of why it's there, so a weaker table only means it forks a little more
often, never that it parses incorrectly. Strengthening this to true
LALR(1) later is a pure internal upgrade (same table shape, smarter
lookahead), not a public API change.
Summary
Functions
Builds the SLR(1) action table (%{state => %{terminal => [action]}} --
more than one action in a cell is a conflict, left for the caller to
decide whether that's fatal) and goto table
(%{state => %{nonterminal => state}}, always single-valued -- goto
transitions are deterministic by DFA construction, never a conflict).
Builds the canonical LR(0) collection for productions, starting from start_symbol's own production.
Types
@type action() :: {:shift, state_id()} | {:reduce, production_id :: non_neg_integer()} | :accept
@type item() :: {production_id :: non_neg_integer(), dot :: non_neg_integer()}
@type state_id() :: non_neg_integer()
Functions
@spec action_goto_tables( t(), [Grammar.LRTable.Production.t()], %{required(atom()) => MapSet.t(atom())}, atom(), atom() ) :: {action_table :: %{required(state_id()) => %{required(atom()) => [action()]}}, goto_table :: %{required(state_id()) => %{required(atom()) => state_id()}}}
Builds the SLR(1) action table (%{state => %{terminal => [action]}} --
more than one action in a cell is a conflict, left for the caller to
decide whether that's fatal) and goto table
(%{state => %{nonterminal => state}}, always single-valued -- goto
transitions are deterministic by DFA construction, never a conflict).
@spec build([Grammar.LRTable.Production.t()], atom()) :: t()
Builds the canonical LR(0) collection for productions, starting from start_symbol's own production.