> Agent-readable docs index: /llms.txt. Download /docs.zip to grep all markdown files locally.

---
$schema: https://holocron.so/frontmatter.json
title: Architecture
description: How RoboC++ crates parse IEC 61131-3 source, check semantics, simulate scans, and emit portable C.
icon: lucide:blocks
---

RoboC++ is a **multi-crate Rust workspace**. Each crate owns one layer of the IEC 61131-3 pipeline so you can read, test, and extend the compiler without a single monolithic binary. Compiler crates are **dependency-light**: most use only the **Rust standard library**; **`iec_plcopen`** depends on **`roxmltree`** for XML parsing and canonicalization.

This page explains **what each crate does**, **how data moves between them**, and **which CLI commands touch which stages**.

## End-to-end flow

A typical workflow looks like this:

```diagram
  .st / .xml file
        │
        ▼
   rbcpp_cli ──► load path (text or PLCopen import)
        │
        ▼
   iec_syntax ──► Project in iec_ir
        │
        ▼
   iec_semantics (+ iec_stdlib, iec_profile)
        │
        ├──► iec_diagnostics (errors stop check/run/build)
        │
        ├──► rbcpp check     (stop here)
        │
        ├──► iec_runtime     ──► rbcpp run
        │
        └──► iec_c           ──► rbcpp build-c ──► optional rbcpp_target hooks
```

<Aside>
  <Info>
    **`iec_plcopen`** can produce the same **`iec_ir` Project** as **`iec_syntax`**, so `check`, `run`, and `build-c` accept `.xml` after import as well as `.st` text.
  </Info>
</Aside>

**RoboC++ Studio** (`ide/web`) follows the same stages through **`iec_language_service`** and its WASM bridge instead of spawning **`rbcpp_cli`**. The web shell calls JSON APIs such as `analyze_document_json`, `debug_document_json`, and `generated_c_artifact_json`.

## What each CLI command uses

| Command          | Pipeline stages                 | Output                                              |
| ---------------- | ------------------------------- | --------------------------------------------------- |
| `check`          | syntax → IR → semantics         | Diagnostics only (human or `--json`)                |
| `run`            | check, then runtime interpreter | Per-cycle variable trace (human or `--json`)        |
| `build-c`        | check, then C code generator    | `.c` source for one **PROGRAM** (scan + target ABI) |
| `import-plcopen` | plcopen → IR                    | Summary of POUs discovered                          |
| `export-plcopen` | syntax → IR → plcopen           | PLCopen XML file                                    |
| `compliance`     | profile matrix only             | Feature status table                                |
| `parameters`     | profile Annex D limits          | Implementation-dependent parameters                 |
| `sfc-compliance` | profile SFC sets                | SFC compatibility report                            |

**`run`** always type-checks first. If semantics report **`error`** severity diagnostics, execution aborts before the interpreter starts.

## Crate reference

### `iec_syntax`

**Input:** IEC 61131-3 textual source: **Structured Text**, **Instruction List**, **textual SFC**, **native textual LD/FBD**, and related project forms.

**Output:** An **`iec_ir::Project`**: types, POUs, ST/IL/SFC bodies, LD/FBD networks, and configuration trees when present.

**Role:** Lexing and parsing across supported IEC textual languages. **LD/FBD** also arrive through **`iec_plcopen`** import and through native **`LADDER`** / **`FBD`** program bodies.

### `iec_ir`

**Role:** The **shared memory model** every later stage reads. Normalized enums for types, expressions, statements, SFC steps, LD/FBD networks, direct variables, and runtime **`Value`** representations.

Keeping IR separate means the interpreter and C backend both lower the **same** tree, and PLCopen import/export does not duplicate project structure logic.

### `iec_semantics`

**Input:** `Project` from IR.

**Output:** More **`iec_diagnostics`** diagnostics; enriched internal views for checking (symbol tables, types, control-flow rules).

**Role:** Symbol resolution, type checking, IEC-specific rules (illegal `RETAIN` placement, `VAR_IN_OUT` actuals, `CASE` overlaps, enum compatibility, `VAR_EXTERNAL`/`VAR_ACCESS`/`R_EDGE` rules, and similar). Calls into **`iec_stdlib`** to validate standard function and FB usage and into **`iec_profile`** for edition limits.

Embedders can pass **`CheckOptions { profile, implementation }`** to **`check_project`**. The CLI always uses default **`ImplementationParameters`** for limits and pragma policy.

### `iec_stdlib`

**Role:** Catalog of **standard functions and function blocks** plus the **evaluator** used by the interpreter (and parity expectations for C). Not a separate CLI stage: semantics and runtime both depend on it.

When you **`run`** `examples/function_blocks.st`, timer and counter behavior comes from here.

### `iec_runtime`

**Input:** Checked `Project`, selected program or configuration, scan options (cycle count, access-path writes). Library APIs also support warm restart and **`CommunicationHooks`**.

**Output:** Deterministic **scan-cycle traces**: variable snapshots per cycle, configuration scheduling metadata when applicable.

**Role:** Simulate IEC logic without generating C. State for function block instances and program variables persists across cycles within one **`run`** invocation.

### `iec_c`

**Input:** Checked `Project`, selected program name.

**Output:** Portable **C source** for a single **PROGRAM**: state struct, scan function, cold/warm init, **`rbcpp_io_symbols`**, **`_set_target_hooks`**, retained load/save, comm hooks, **`VAR_ACCESS`** helpers. Configuration schedulers are not emitted; use **`run --configuration`** for configuration simulation.

**Role:** Backend for deployment. Emits SPDX-licensed C (`MIT OR Apache-2.0`). See [Targets and Generated C](/targets) and [License](/license).

### `iec_plcopen`

**Input / output:** PLCopen XML **2.01**.

**Role:** Import XML into IR (with LD/FBD/SFC lowering) and export IR back to XML. Preserves vendor metadata and graphical networks.

### `iec_profile`

**Role:** **Edition profiles** (`2003-strict`, placeholders for 2013/2025), **implementation limits** (max string length, scan cycles, expression depth), and the **compliance matrix** behind `rbcpp compliance` and `rbcpp todos`.

Semantics and runtime consult profile data when enforcing limits or reporting **`RBCPP-COMPLIANCE`** diagnostics.

### `iec_diagnostics`

**Role:** Shared **diagnostic type**, stable **`RBCPP-*`** codes, human rendering to stderr, JSON rendering for tooling. Every crate appends diagnostics; **`rbcpp_cli`** prints or serializes them.

### `rbcpp_target`

**Role:** Optional **HAL adapters** for experiments on generated C. Provides file-backed I/O, in-memory and transport-backed **Modbus**, **EtherCAT PDO**, and **ROS 2** mapping, target-side **`VAR_ACCESS`** bindings through **`AccessRuntime`**, retained-state files, cycle watchdogs, **`TargetSupervisor`** cycle reports, and non-certified **safety gating**. Exposes **`parse_ide_mapping`** for Studio **`target/mapping.toml`** lines (file bindings and Modbus point strings). Not on the hot path for `check` or `run`; used when integrating **`build-c`** output on a host, simulator, or robot bridge.

### `rbcpp_target_bridge`

**Role:** Local HTTP service binary **`rbcpp-target-bridge`** (default **`127.0.0.1:8787`**) that connects [RoboC++ Studio](/studio) to **`rbcpp_target`** through session, deploy, I/O, and control endpoints (`/health`, `/api/v1/session`, `/api/v1/deploy`, `/api/v1/io`, `/api/v1/session/control`). Supports Simulator file-backed I/O and Modbus TCP hardware targets. Not part of the **`rbcpp`** CLI.

### `rbcpp_cli`

**Role:** Thin **orchestration**: parse CLI flags, load files, call the pipeline stages above, format output. No IEC language logic lives here.

### `iec_language_service`

**Input:** Workspace files (`.st`, `.il`, `.sfc`, `.ld`, `.fbd`, `.xml`) and editor options (profile, selected program, cycle count).

**Output:** JSON-friendly analysis: diagnostics, symbol indexes, completions, hover docs, graph models, simulation and debug traces, generated C metadata, refactor plans, and service capabilities.

**Role:** **Editor and IDE backend** over the same `iec_syntax` → `iec_semantics` → `iec_runtime` / `iec_c` pipeline. Powers [RoboC++ Studio](/studio) through **`iec_language_service_wasm`**, which compiles the service to WASM for the browser. The CLI does not depend on this crate today.

### `iec_language_service_wasm`

**Role:** WASM export of **`iec_language_service`** JSON entry points. Built from `ide/web` with **`npm run wasm:build`** (`wasm-pack`). Replaces the checked-in stub under `ide/web/src/wasm/` when present.

### `xtask`

**Role:** Workspace validation and release runner (not on the hot CLI path). Commands include **`validate-corpus`**, **`validate-differential`**, **`validate-robustness`**, **`validate-sanitizers`**, **`fuzz-smoke`**, **`hardening-check`**, and **`release-report`**. CI invokes these after `cargo test`. See [Compliance](/compliance#verification-gates) and the compiler repo **`validation/`** directory.

## Language service and Studio

Studio stores projects in browser **`localStorage`**, edits multi-file workspaces, and calls the language service for:

| Studio action | Service surface                                  |
| ------------- | ------------------------------------------------ |
| Check (F7)    | Document/workspace analysis and diagnostics      |
| Run (F5)      | `debug_document_json` scan traces                |
| Build C       | `generated_c_artifact_json` metadata and preview |
| Diagram cards | `graph_model_json` with scan energization        |
| Inspector     | Symbols, completions, hover from analysis index  |

See [RoboC++ Studio](/studio) and [Studio getting started](/studio-getting-started).

## How an example file maps to crates

Take **`examples/counter.st`**:

1. **`iec_syntax`** parses `PROGRAM CounterDemo` into IR.
2. **`iec_semantics`** verifies assignments and types (`INT`, `BOOL`, comparisons).
3. **`rbcpp check`** stops after step 2 if clean.
4. **`iec_runtime`** executes the `IF` body once per cycle when you **`run --cycles 3`**.
5. **`iec_c`** emits C that performs the same logic in a generated scan function when you **`build-c`**.

Take **`examples/configuration.st`**:

1. Syntax + semantics understand **`CONFIGURATION`**, **`RESOURCE`**, **`TASK`**, **`VAR_GLOBAL`**, **`VAR_ACCESS`**, and located variables.
2. **`run --configuration Plant`** uses **`iec_runtime`** scheduling (task interval, priority, program instances) instead of a single bare program.

## Design constraints

* **Profiles are explicit.** Only **2003-strict** and **2003-plus-extensions** are claimable today; 2013/2025 entries are routing placeholders that fail semantic check.
* **Implementation parameters** (identifier length, max scan cycles, string size, pragma policy, and more) live in **`iec_profile`** and surface through **`rbcpp parameters`**.
* **Compliance matrix** is the live scope tracker. For **`2003-strict`**, all tracked leaf rows are **`implemented`** today; new rows may be added as scope grows.
* **`iec_profile::conformance_fixtures()`** maps IEC Tables 1–62 (plus Annex D/E references) to named Rust regression tests. This mapping is not exposed via CLI but documents how matrix rows tie to tests in the compiler repo.

<Aside>
  <Tip>
    The [Examples](/examples) page walks through **every** shipped example (`.st`, `.il`, `.sfc`, `.xml`) and which language features it stress-tests.
  </Tip>
</Aside>

## Related

* [CLI reference](/cli): flags and profiles
* [Execution model](/execution-model): configurations, tasks, traces
* [Targets and Generated C](/targets): generated C ABI and `rbcpp_target`
* [PLCopen](/plcopen): XML import/export and graphical lowering


---

*Powered by [holocron.so](https://holocron.so)*
