# `Ichor.EBNF.W3C`
[🔗](https://github.com/joetjen/ichor/blob/v0.3.0/lib/ichor/ebnf/w3c.ex#L1)

The W3C-style EBNF front-end -- the notation the XML 1.0 spec's own
section 6 "Notation" uses, also shared by XQuery/XPath's grammars:
`priv/grammar/ebnf-w3c.aether` parsed by Aether's own front-end,
compiled by the native codegen backend (`use Ichor`), dispatching to
`Ichor.EBNF.W3C.Actions` (`Grammar.IR` as its target category).

The `.aether` source lives under `priv/grammar/`, not `lib/`, for the
same reason as `Ichor.ABNF`'s own: `use Ichor` only ever reads it
once, at compile time.

    iex> {:ok, ruleset} = Ichor.EBNF.W3C.run("nonzero_digit ::= [0-9] - '0'\n")
    iex> ruleset[:nonzero_digit]
    %Grammar.IR.Seq{exprs: [%Grammar.IR.NotPred{expr: %Grammar.IR.Literal{value: "0"}}, %Grammar.IR.CharClass{ranges: [{48, 57}]}]}

`run/1` (generated by `use Ichor`) returns `{:ok, %{ident_atom =>
Grammar.IR.expr()}}` for a whole `grammar_file` -- every rule the
source defines. `parse/1` and `tokenize/1` (also generated) are
available for a bare recognizer or raw token stream, with no
`Ichor.EBNF.W3C.Actions` involved.

# `parse`

```elixir
@spec parse(String.t(), term()) ::
  {:ok, non_neg_integer(), Ichor.Capture.raw_captures()}
  | {:error, Ichor.Error.t()}
```

Matches `input` against the grammar's root rule, requiring the entire (tokenized) input to be consumed. A bare recognizer -- no `Ichor.Actions` involved. `context` is read-only and only ever consulted by a `Grammar.IR.Custom` `@native(...)` node, if the grammar has one.

# `run`

```elixir
@spec run(String.t(), Ichor.Actions.context()) ::
  {:ok, term()} | {:error, Ichor.Error.t() | [Ichor.Error.t()]}
```

Like `parse/1`, but runs the match through the compile-time-known Actions module, returning the grammar's actual evaluated result.

# `run_sequence`

```elixir
@spec run_sequence(String.t(), Ichor.Actions.context()) ::
  {:ok, [term()], Ichor.Actions.context()}
  | {:error, Ichor.Error.t() | [Ichor.Error.t()]}
```

Like `run/2`, but evaluates `input` as a sequence of top-level matches against the root rule, one after another, threading context from each into the next (loading a standard-library file one top-level form at a time is the motivating case -- most grammars only ever need `run/2`).

# `tokenize`

```elixir
@spec tokenize(String.t(), term()) ::
  {:ok, [Grammar.VM.Token.t()]} | {:error, Ichor.Error.t()}
```

Tokenizes `input` completely via maximal munch, applies any `@keywords`/`@refine` rules, or reports the first position nothing matches. `context` is read-only and only ever consulted by a `Grammar.IR.CustomLexeme` `@native(...)` token, if the grammar has one.

---

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