# Program Entry Point

`main.cpp` is the simulator executable's entry point: it parses command-line arguments, brings up every subsystem documented elsewhere in this section and in [Common Facilities](index.md#1-common-facilities), parses the input netlist, builds the `Circuit`, and hands off control to a [`CommandInterpreter`](cmd.md). It is intentionally thin - almost everything it calls is implemented and documented as its own unit; `main()` is the sequencing of those calls.

## Command-line arguments

`main()` accepts a single positional argument (the netlist file name) plus flags:

| Flag | Effect |
| --- | --- |
| `-h`, `--help` | print usage and exit |
| `-dp`, `--dump-paths` | print resolved module/include paths and tool locations |
| `-df`, `--debug-files` | turn on debug output for file operations |
| `-dt`, `--dump-tables` | dump parser tables after parsing |
| `-se`, `--skip-embed` | do not write out embedded files |
| `-sp`, `--skip-postprocess` | disable the `postprocess` command |
| `-qp`, `--quiet-progress` | disable analysis progress-bar output |
| `--no-output` | suppress output file writing |
| `--extra-tomlfile <file>` | read this TOML file in addition to the normal candidates, last |
| `--tomlfile <file>` | read only this TOML file, skipping the normal candidates |

Arguments are parsed left to right in a single pass; anything not starting with `-` must be the last argument and is taken as the netlist file name. With no arguments at all, `main()` prints a hint to run with `-h` and exits with status `1`.

## Startup sequence

1. Print the startup banner (`Platform::programName`/`programVersion`/`programCopyright`/`programHomepage`, see [Platform Entry Support](platform.md)), plus a warning line if this is a debug (`SIMDEBUG`) or profiling (`SIMPROFILE`) build.
2. Parse arguments (above); set `Simulator`'s `fileDebug`/`noOutput` flags from them.
3. `Platform::setup()` - seed default OpenVAF/Python tool paths; then apply a `SIM_OPENVAF` environment-variable override if set.
4. Resolve default module and include directories from `Platform::libraryPath()`, overridable via the `SIM_MODULE_PATH`/`SIM_INCLUDE_PATH` environment variables, and call `Simulator::setup()` with them.
5. Build the list of candidate config files - `Platform::systemConfig()`, `userConfig()`, `localConfig()`, plus `--extra-tomlfile`'s file appended, or `--tomlfile`'s file replacing the whole list - and, once the input file's location is known (step 7), an additional `.vacaskrc.toml` next to it. Each candidate that exists and hasn't already been read is passed to [`readConfig()`](config.md); duplicates are tracked in a set so the same path is never read twice even if it appears in the list more than once (which can happen if the input file lives next to, say, the local config).
6. If `-dp`/`--dump-paths` was given, print the resolved executable path, startup path, module/include search paths, and OpenVAF/Python tool locations.
7. If no netlist file was given, print "No input file specified." and exit `0` (this is after config loading and path dumping, so `-dp` alone still reports useful information without a netlist).
8. Add the input file to the `ParserTables`' [`FileStack`](filestack.md) (`addFile()`); a lookup failure is a fatal error.
9. Parse the netlist (`Parser::parseNetlistFile()`, see [Toplevel Parser Wrapper](parser.md)), then `ParserTables::verify()`, then `ParserTables::processBehaviorals()` (compiles/loads Verilog-A modules), each a fatal error on failure.
10. Optionally dump parser tables (`-dt`) and write out embedded files (unless `-se`).
11. Construct the `Circuit` from the parsed tables and an `OpenvafCompiler` (see [OpenVAF Compiler Wrapper](openvafcomp.md)) wired to `Platform::openVaf()`/`openVafArgs()`.
12. Construct a [`CommandInterpreter`](cmd.md) around the tables, the parsed control block (`tab.control()`), and the circuit; configure it from `-qp` and `-sp` (`setPrintProgress()`/`setRunPostprocess()`).
13. Run the interpreter from the start of the control block (`interp.run(0, status)`); any exit status other than `EndReached` is treated as failure.

Every fatal condition follows the same shape: print `status.message()` (or a fixed message) via `Simulator::err()`/`Simulator::out()`, and `return 1` (`return 0` for the no-input-file and `-h` cases) - `main()` does no cleanup of its own beyond returning, relying on normal C++ destruction of its local objects (`ParserTables`, `Parser`, `Circuit`, `CommandInterpreter`) as the stack unwinds.

## What `main()` deliberately doesn't do

Argument parsing, config loading, and path resolution stay inside `main()` itself rather than being factored into `Platform` or `Simulator`, because they are genuinely one-shot, entry-point-specific sequencing - `Platform` and `Simulator` expose the pieces (`setup()`, `systemConfig()`, and so on) that `main()` composes, but neither owns the composition. This mirrors how `CommandInterpreter` ([Command Interpreter](cmd.md)) owns control-block execution once `main()` has finished wiring everything up: after step 13, `main()`'s job is done.
