# Toplevel Parser Wrapper

`Parser` (`parser.h`/`parser.cpp`, not to be confused with the generated Bison `dflparse::Parser` class) is the small, stable API the rest of the simulator actually calls to run the [lexer](dfllexer.md)+[grammar](dflparser.md) pair. It owns the long-lived `ParserTables&` output and hides the mechanics of constructing a fresh `Scanner`/Bison parser/`RpnEvaluator` for each call.

## Four entry points

One per thing that can be parsed, each pairing with one of the [lexer](dfllexer.md)'s three `InputType`s and one of the [grammar](dflparser.md)'s three top-level productions:

- `parseNetlistFile()` / `parseNetlistString()` - a whole circuit, from a file or an in-memory string (e.g. an embedded or generated netlist fragment).
- `parseExpression()` - a single standalone expression string.
- `parseParameters()` - a standalone `name=expr, ...` list.

## A throwaway evaluator per parse

Each helper (`netlistParseHelper()`, `exprParseHelper()`, `parametersParseHelper()`) constructs its own local `RpnEvaluator`. The grammar needs one to fold constant parameter expressions on the spot while parsing (see [Parser](dflparser.md)'s `parameter_list` rule, backed by [`RpnEvaluator::isConstant()`](rpneval.md)), but that evaluator's context stack has no reason to outlive the parse - unlike `Circuit`'s own two long-lived evaluators (see [Evaluator](rpneval.md)), which persist because they carry variable/parameter scope across many separate evaluations over a run.

## String ownership

Every string-input entry point registers the string with `tab_.fileStack().addStringFile(input)` *before* moving it into the `std::istringstream` actually being parsed. This gives the [`FileStack`](filestack.md) its own independent copy, so any [`Loc`](sourceloc.md) produced while parsing stays resolvable even after the caller's original string argument is gone.

## Two failure conventions, by design

`parseNetlistFile()`/`parseNetlistString()` return `bool` and report through a `Status&`, like the rest of the codebase (see [Status](status.md)). `parseExpression()`/`parseParameters()` instead *throw* `std::runtime_error` on failure - the header calls this out explicitly ("Throw on error"). These two are meant for parsing a string that is expected to already be well-formed (e.g. re-parsing something the simulator itself produced, or a control-block-internal string), where threading a `Status` through every caller for a case that "should never fail" would be more ceremony than the failure mode is worth - a genuine failure here is treated as a bug to surface loudly, not routine input to handle gracefully.
