# `Grammar.LRTable.Desugar`
[🔗](https://github.com/joetjen/ichor/blob/v0.3.0/lib/grammar/lr_table/desugar.ex#L1)

Flattens `grammar.rules`' PEG-shaped IR into the flat CFG production
list `Grammar.LRTable.Production` describes, for `Grammar.LRTable`'s
LR(0)/SLR(1) construction to consume.

The one representational mismatch this exists to bridge: a CFG
production's right-hand side is a flat sequence of single symbols,
while PEG's IR is a tree (`Seq`/`Choice`/`Star`/`Plus`/`Opt`/`Rep` can
all nest arbitrarily). Only a `RuleRef` (a reference to an actual
declared token or rule) is already a single symbol; everything else
gets a fresh compiler-generated helper nonterminal (`$star_1`,
`$opt_2`, ...) standing in for it -- an artifact of the CFG
representation that doesn't exist in the original grammar at all.

`:splice`-kind captures (see `Grammar.LRTable.Production`) are what
erase that artifact again at reduce time: a helper nonterminal's own
already-built captures map gets merged directly into its parent's,
so the final raw-capture tree looks exactly like what
`Grammar.VM`/`Grammar.Native` would have built for the same grammar --
the boundary a helper nonterminal introduces is purely structural
(needed so the LR table has single symbols to work with), never
semantic.

Reuses the exact same token/rule classification and implicit-capture
exclusion rules every other backend uses (`Grammar.VM.RuleCompiler`'s
own `token_names/1`/`implicit_capture_exclusions/1`) so a
`@keywords`/`@refine` target name, an anonymous auto-promoted literal
token, or the grammar's own spliced `@skip` token are all treated
identically here -- in particular, a spliced `@skip` token (already an
ordinary, uncaptured `Star[RuleRef(skip)]` node in the IR by the time
this runs -- see `Aether.Eval`'s own `splice_skip/2`) needs no special
handling at all: it desugars into an ordinary `:splice`-kind helper
nonterminal whose own body has no capture entries, so splicing its
empty map into the parent is simply a no-op.

# `end_symbol`

```elixir
@spec end_symbol() :: atom()
```

The synthetic end-of-input terminal appended by `Grammar.LRTable`'s automaton construction.

# `run`

```elixir
@spec run(Aether.Grammar.t()) ::
  {:ok, [Grammar.LRTable.Production.t()]} | {:error, [Ichor.Error.t()]}
```

Desugars `grammar.rules` (plus a fresh `$start := root` production) into
a flat production list, or every unsupported-construct error found.

# `start_symbol`

```elixir
@spec start_symbol() :: atom()
```

The augmented start nonterminal every desugared grammar's automaton is built from.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
