# ParserTables

The toplevel container: one `ParserTables` accumulates everything a single parse (or hand-built circuit) produces - the circuit's title, its [`FileStack`](filestack.md), [`PTLoad`](ptload.md) directives, the default (toplevel) [`PTSubcircuitDefinition`](ptsubckt.md), ground/global node lists ([`PTIdentifierList`](ptidentifier.md)), [`PTEmbed`](ptload.md) directives, the control block ([`PTControl`](ptcommand.md)), and an `Accounting` for timing/counting the parse itself. `defaultGround()` is the one piece of default-filling logic here: if no `ground` directive appeared, it inserts node `0` as the sole ground node, matching the netlist language's documented default.

`verifyAfterParse()` and `verify()` are the same worker (`verifyWorker`) run at two strictness levels. `verifyAfterParse()` (level `0`) is what the grammar's `INNETLIST ... END` rule calls immediately after parsing, and skips re-verifying the whole subcircuit-definition tree (gated by `if (level>0)`), since the grammar's own actions already checked things like parameter redefinition as each piece was built. `verify()` (level `1`) additionally re-verifies `defaultSubDef_` from scratch - needed for circuits assembled directly through this API (a C++ caller building a `ParserTables` by hand, e.g. with the [`PVv`/`PEv` helpers](ptvectorhelpers.md)) that never went through the grammar's own incremental checks. Both levels always check for duplicate analysis names across the whole control block and verify every `load` directive.

`processBehaviorals()` walks the whole `defaultSubDef_` tree (every nested subcircuit definition, every block of every `@if` arm) looking for [`PTBehavioral`](ptbehavioral.md) entries, and turns each into an auto-generated Verilog-A module: `Rpn::verilogA()` (see [Expression Format](rpnexpr.md)) translates the behavioral's expression into module source captured in an `RPNBehavioralVA`, which is appended to one accumulated `.va` file for the whole netlist and used to build a matching `PTModel`/`PTInstance` pair added back into the same block (see [`PTBlock and PTBlockSequence`](ptblock.md)); the instance keeps the `RPNBehavioralVA` attached via `addBehavioralData()` (see [`PTModel and PTInstance`](ptmodel.md)). The generated file is named after the toplevel netlist file plus a `__behavioral.va` suffix (just the extension if the circuit wasn't built from a file at all), reuses the same `needsDump()`/`.origin`-file caching described below for `writeEmbedded()` - keyed this time on the set of source files the behavioral sources came from - and, only if at least one behavioral source was found, is appended as a `PTLoad` so it gets loaded like any other OSDI module. A `behavioralsProcessed_` flag guards against calling it a second time - `Status::InternalError` if it's already run, since the first run has already mutated the tree it walks.

`writeEmbedded()` materializes `embed` directives to disk - as real files an OSDI/Verilog-A loader can then open - deferred from parse time. For each one it also writes a companion `<filename>.origin` file recording the canonical path of the netlist file the `embed` directive came from, and skips rewriting the target file if it already exists, was produced from that same origin (verified by reading `.origin` back), and is not older than the origin file - so re-running an unchanged netlist doesn't needlessly rewrite (and bump the mtime of) an unchanged generated file, while an edited origin or a first run still gets written. Failing to write the `.origin` marker itself is silently ignored, as best-effort bookkeeping; failing to write the actual embedded content is a hard `Status::CreationFailed` error. `processBehaviorals()` and `writeEmbedded()` share this dependency-file caching logic through the same file-local `needsDump()`/`writeDependencyFile()` helpers, differing only in what they consider the file's dependency set.

`dump()` renders a whole `ParserTables` back out in the netlist's own syntax - title, loads, ground/global nodes, the subcircuit-definition tree, embeds, the control block - built from the same per-type `dump()`/`operator<<` methods used throughout the [circuit representation API](parseroutput.md). It is a debugging/introspection tool, not a guaranteed round-trippable serialization format.
