Netlist Parser

Layer 0 — netlist parsing.

Parses circuitgenome.synthesizer.netlist.to_flat_spice() output into a ParsedNetlist. This is the structural inverse of to_flat_spice’s _device_line:

{ref} {d} {g} {s} {b} {nmos|pmos}    # MOSFET   (6 tokens)
{ref} {t1} {t2} [1k]                 # resistor (3-4 tokens)
{ref} {p} {m} [1p]                   # capacitor (3-4 tokens)

wrapped in a .subckt <name> <port...> / .ends block (or .suckt for netlists with that common typo). Net and ref names are treated as arbitrary strings – the parser makes no assumptions about to_flat_spice’s own naming conventions (e.g. net_bias{N} or {ref}_{slot}).

Device lines are dispatched by the first character of the ref (SPICE convention): m → MOSFET (6 tokens), c → capacitor (3-4 tokens), r → resistor (3-4 tokens). The value token (e.g. 1k / 1p) is optional and ignored when present.

circuitgenome.recognizer.netlist_parser.parse(spice)[source]

Parse a flat SPICE .subckt block into a ParsedNetlist.

Parameters:

spice (str) – A SPICE netlist string, typically produced by circuitgenome.synthesizer.netlist.to_flat_spice() or an external SPICE tool. The header keyword may be .subckt or .suckt (common typo). The value token on capacitor/resistor lines (1p / 1k) is optional.

Returns:

A ParsedNetlist with devices in the same order as the input, and internal_nets = every net referenced by a device terminal that is not in external_ports.

Raises:

ValueError – If a MOSFET line’s trailing type token is not "nmos"/"pmos", or a device line has an unexpected token count for its prefix type.

Return type:

ParsedNetlist

Example:

from circuitgenome import synthesize
from circuitgenome.synthesizer import to_flat_spice
from circuitgenome.recognizer import parse

circuit = synthesize({"topology": "one_stage_opamp"})[0]
parsed = parse(to_flat_spice(circuit))
print(parsed.external_ports)   # ["ibias", "in1", "in2", "out", "vdd!", "gnd!"]
print(len(parsed.devices))