fsmc Compiler Architecture & Formal IR Infrastructure¶
This document details the internal design, modular compiler pipeline, Intermediate Representation (IR), middle-end pass manager, diagnostic engine, and template metaprogramming techniques used by fsmc.
1. Modular Repository & Layer Organization¶
The repository is structured into distinct, decoupled compiler layers on top of a common, strongly-typed Intermediate Representation:
fsmc/
├── include/fsm/
│ ├── ir/ # Unified AST & Semantic Model (FsmIr, StateNode, TransitionEdge, FNV-1a IDs, EFSM vars, LTL/INVAR)
│ ├── middleend/ # PassManager, Dead State Pruning, Determinism, Guard Simplification, Inlining, TimedDeadlockPass & ModelChecker
│ ├── diagnostic/ # Rich DiagnosticEngine with ANSI colors, SourceSpan, and visual carets
│ ├── frontend/ # Two-Category Parser Ingestion Infrastructure & ParserFactory
│ │ ├── formal/ # High-Semantics Formal Models (SysML v2, W3C SCXML, Cameo / MagicDraw XMI, nuXmv SMV)
│ │ └── diagram/ # Visual Diagram Sketch Notations (PlantUML, Mermaid, Graphviz DOT, XState JSON)
│ ├── backend/ # Target Code Generators (C++17/20 Bare-Metal) & EmitterFactory (8 Serializers including nuXmv SMV)
│ └── runtime/cpp/ # Canonical Real-Time Runtime Engine (fsm, lock-free SPSC FIFO, static buffer, timers, trait introspection)
├── tools/
│ ├── fsmc/ # Primary Multi-Format Compiler Driver CLI
│ └── fsm-opt/ # Standalone Formal IR Optimizer, Linter & Roundtrip Formatter CLI
├── playground/ # Interactive WebAssembly Browser Playground (fsmc.wasm)
├── examples/ # Aerospace, Automotive ECU, and Resilient IoT Showcases
├── tests/ # Modular GoogleTest Suites (49 suites, 100% pass)
│ ├── core/ # Runtime engine, HFSM, choice, history, observers, timers
│ ├── frontend/ # Frontend tests partitioned into formal/ and diagram/
│ │ ├── formal/ # Tests for SysML v2, SCXML, Cameo, and SMV parsers
│ │ └── diagram/ # Tests for PlantUML, Mermaid, DOT, and JSON parsers
│ ├── ir/ # Serialization and AST integrity
│ ├── middleend/ # PassManager, deadlocks, timed analysis, and model checking
│ ├── backend/ # Codegen, roundtrip lossless export, and emitters
│ └── integration/ # CMake build integration and multi-target suites
└── docs/ # Formal IR Specification, Architecture & Developer Guides
2. Compiler Pipeline¶
fsmc operates as a multi-stage compiler structured in three distinct tiers: Frontend Ingestion, Middle-End Pass Pipeline, and Backend Code Generators & Emitters.
Model File (.sysml / .xmi / .scxml / .puml / .mmd / .dot / .json / .smv)
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 1. Frontend Ingestion & ParserFactory │
│ • Formal Models (include/fsm/frontend/formal/): │
│ - SysML v2 Parser (Native textual .sysml grammar) │
│ - Cameo / MagicDraw Parser (OMG XMI 2.x XML parser) │
│ - W3C SCXML Parser (State Chart XML specification) │
│ - nuXmv / SMV Parser (Formal symbolic specification) │
│ • Visual Diagrams (include/fsm/frontend/diagram/): │
│ - PlantUML Parser (State diagram block tokenization) │
│ - Mermaid Parser (StateDiagram-v2 grammar) │
│ - Graphviz DOT Parser (Unix graph grammar) │
│ - XState JSON Parser (Modern JSON Statecharts) │
└──────────────────────────────┬──────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 2. Formal Intermediate Representation (FsmIr) │
│ • Strongly-typed hierarchical AST & semantic model │
│ • Deterministic 64-bit FNV-1a IDs for states & transitions │
│ • Structured Triggers: SignalTrigger, TimeTrigger, Anon │
│ • Composable boolean GuardAstNode (AND, OR, NOT) │
│ • Extended finite variables with Physical Units & Types │
│ • Formal temporal properties (LTLSPEC, INVARSPEC) │
└──────────────────────────────┬──────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 3. Middle-End Optimizer & Verifier (PassManager) │
│ • DeadStatePruningPass (Prunes unreachable states & dead tr)│
│ • DeterminismEnforcementPass (Detects nondeterministic br) │
│ • GuardSimplificationPass (Algebraic boolean optimization) │
│ • SubmachineInliningPass (Inlines modular submachines) │
│ • TimedDeadlockPass (Detects 0ms timeouts & racing timers) │
│ • OrthogonalInterferencePass (Detects concurrent races) │
│ • Formal ModelChecker (Temporal LTL/CTL & Safety Invariants)│
│ • Rich DiagnosticEngine (Rust/Clang-style visual carets) │
└──────────────────────────────┬──────────────────────────────┘
│
┌──────────────────┴──────────────────┐
▼ ▼
┌───────────────────────────────┐ ┌───────────────────────────┐
│ 4a. C++ Code Generator Engine │ │ 4b. Diagram & SMV Emitters│
│ • Bounded Choice Flattening │ │ • SysML v2 Serializer │
│ • Standalone (SSOT bundled) │ │ • PlantUML Serializer │
│ • Modular C++ (.hpp/.cpp) │ │ • Mermaid Serializer │
│ • C++17 (SFINAE) / C++20 │ │ • Cameo XMI Serializer │
│ • Zero-heap embedded runtime │ │ • SCXML Serializer │
│ • Thread-safe async wrappers │ │ • Graphviz DOT Serializer│
│ • Deterministic timer manager│ │ • JSON IR Serializer │
│ • Ring buffer overflow policy│ │ • nuXmv / SMV Serializer │
└───────────────┬───────────────┘ └─────────────┬─────────────┘
▼ ▼
Generated C++ Header Exported Diagram / SMV
3. Frontend Classification (FrontendKind)¶
fsmc classifies parsers into two distinct categories defined in include/fsm/frontend/parser_interface.hpp:
enum class FrontendKind : std::uint8_t {
Formal, ///< Strict formal metamodel: SysML v2, W3C SCXML, Cameo/MagicDraw XMI, nuXmv/SMV
Diagram ///< Visual diagram notation: PlantUML, Mermaid, Graphviz DOT, XState JSON
};
FrontendKind::Formal(include/fsm/frontend/formal/):- Backed by formal specifications where variables, types, units, and transitions have precise mathematical semantics.
- Code generation proceeds directly without heuristic warnings.
FrontendKind::Diagram(include/fsm/frontend/diagram/):- Visual sketching notations where state charts are descriptive. Types and payloads are inferred or supplemented via lossless
@fsm:directives. - Codegen requires explicit confirmation via
--allow-diagram-codegenand emits warningwarning[W0301]: Untyped or inferred symbol in diagram source.
- Visual sketching notations where state charts are descriptive. Types and payloads are inferred or supplemented via lossless
4. Middle-End Pass Pipeline (PassManager)¶
The middle-end decouples graph transformations, semantic checks, and optimizations into independent, composable IPass components:
class IPass {
public:
virtual ~IPass() = default;
[[nodiscard]] virtual std::string name() const = 0;
[[nodiscard]] virtual std::string description() const = 0;
virtual bool run(FsmIr& ir, DiagnosticEngine& diag) = 0;
};
Standard Passes¶
HierarchyCanonicalizationPass:- Computes deterministic FNV-1a identifiers for all states and transitions.
- Reconciles parent-child relationships and fully qualified names (
FQN). - Sorts nodes and transitions into canonical, reproducible order.
ChoiceCompletenessPass:- Inspects UML 2.5
<<choice>>pseudostates. - Detects missing unconditional fallback branches (
else/default), preventing runtime state machine stalls. - Flags conflicting duplicate guard conditions on choice branches.
- Inspects UML 2.5
TimedDeadlockPass:- Analyzes all
TimeTriggertransitions in the state hierarchy. - Flags zero-duration timeouts (
after(0ms)) which cause instantaneous livelocks. - Detects racing timeouts originating from the same source state with identical or overlapping durations without explicit priority guards.
- Analyzes all
ModelSafetyVerifierPass:- Performs formal graph reachability from the root initial state.
- Flags unreachable state islands (
W0201). - Detects deadlock / trap states (
W0202) that possess incoming transitions but lack outgoing transitions.
5. Rich Compiler Diagnostic Engine (DiagnosticEngine)¶
fsmc incorporates a diagnostic engine providing colored terminal formatting with visual carets and suggestions:
warning[W0103]: Choice pseudostate 'ClearanceChoice' lacks an unconditional else/default fallback branch (potential stall).
--> mission.puml:42:7
|
42 | state ClearanceChoice <<choice>>
| ^~~~~~~~~~~~~~~
= help: add an unconditional fallback transition 'ClearanceChoice --> DefaultState'
6. Bounded Dynamic Choice Node Flattening¶
In UML 2.5, a choice pseudostate C conditionally directs control from an incoming transition Tin: Ssrc -> C to several outgoing branches Tout_i: C -> [Gi] / Ai -> Sdst_i.
Flattening Strategies & Cardinality Evaluation¶
In cpp_model_emitter.hpp, the compiler evaluates the Cartesian product cardinality for each choice pseudostate:
where Nin is the number of incoming transitions and Nout is the number of outgoing choice branches.
-
Small Cardinality (K <= 16) — Combinatorial Template Expansion:
-
Synthesizes direct atomic transitions:
-
Advantage: Single-cycle atomic dispatch with zero intermediate states and O(1) dispatch execution.
- Large Cardinality (K > 16) — Direct Choice Node Routing:
- Bypasses combinatorial multiplication by routing incoming transitions to the choice pseudostate and evaluating prioritized choice guards sequentially.
- Advantage: Prevents exponential compilation times, excessive template instantiation depth, and binary size growth in embedded environments.
-
7. Hard Real-Time, Zero-Heap C++ Runtime Architecture¶
The C++ runtime engine (include/fsm/runtime/cpp/) is designed for mission-critical, hard real-time embedded environments:
- Deterministic Ring Buffers & Overflow Policies:
fsm::static_ring_buffer<T, Capacity, Policy>provides fixed-capacity zero-heap event buffering with configurable overflow policies:OverflowPolicy::DropOldest: Overwrites oldest unconsumed event (telemetry/streaming mode).OverflowPolicy::DropIncoming: Discards new event on full queue (resilient backpressure).OverflowPolicy::AssertOnOverflow: Traps execution immediately (hard real-time safety critical).
- Lock-Free SPSC Engine (
fsm::spsc_fsm):fsm::spsc_fsm<Table, Context, Capacity, InitialState>combines compile-time state machine folding with fixed-capacity static ring buffers, providing wait-free O(1) ISR event production and lock-free seqlock context reading.
- Synchronous Deterministic Timer Manager:
fsm::deterministic_timer_manager<MaxTimers>manages state machine timeout events via discretetick(delta_ms, callback)invocations, perfectly matching hardware tick timers (SysTick) without background threads.
8. Composite Guard AST & Recursive Parser¶
To support complex boolean logic in model diagrams (e.g. [PowerOk && (!Fault || Override)]), fsmc incorporates an expression tokenizer and recursive-descent parser (GuardExpressionParser):
- Generates a nested C++ type representation using variadic templates:
fsm::and_<PowerOk, fsm::or_<fsm::not_<Fault>, Override>>. - Extracts unique atomic guard identifiers to generate forward-declared stubs only for leaf predicates.
- Short-circuits evaluations at runtime with zero temporary objects.
9. HFSM Hierarchy & History State Resolution¶
- Parent Transition Inheritance (Flattening):
- Outgoing transitions defined on parent macro-states are automatically propagated to all child sub-states during code generation, unless a child explicitly overrides the triggering event.
- Dynamic History Restoration:
- For composite states targeted with shallow history
State[H]or deep historyState[H*], the runtime tracks the last active child sub-state and dynamically restores it upon re-entry. - If the macro-state has never been visited before, the machine defaults to the initial sub-state.
- For composite states targeted with shallow history
10. Thread-Safe Concurrency & Polling Architecture¶
fsm::thread_safe_fsm delivers high-throughput concurrent event handling while strictly preventing data races, deadlocks, and use-after-free conditions:
- Dual Mutex Model:
dispatch_mutex_: Serializes state mutations and action execution.queue_mutex_: Protects the internal event FIFO queue independently from dispatch execution.
- Snapshot-Based Notification Dispatch:
- Transition information and observer callbacks are captured under
dispatch_mutex_and invoked outside the lock, preventing deadlocks when observers self-post events.
- Transition information and observer callbacks are captured under
- Single-Consumer Polling Guard & O(1) Queue:
- Backed by
std::deque<event_handler>,process_one()achieves deterministic O(1) front popping. - Guarded by atomic test-and-set (
is_polling_), enforcing single-consumer sequential event consumption.
- Backed by
- Deterministic Lifecycle & Safe Shutdown:
- Worker thread ID (
worker_thread_id_) and stopping thread ID (stopping_thread_id_) are tracked via lock-free atomics. - External event enqueueing is safely rejected during shutdown (
is_stopping_), while cascading events generated by active actions are fully drained before destruction.
- Worker thread ID (
11. Multi-Format Model Ecosystem & Formal Verification Role¶
fsmc establishes a clear architectural boundary between Executable Statechart Modeling and Formal Symbolic Verification:
┌─────────────────────────────────────────────────────────────────────────────────┐
│ Authoring & Visual Statechart Formats │
│ • OMG SysML v2 (.sysml) • W3C SCXML (.scxml) • Cameo XMI (.cameo) │
│ • PlantUML (@startuml) • Mermaid (stateDiagram) • XState JSON (.json) │
│ • Graphviz DOT (.dot) │
│ │
│ Semantics: Hierarchical HFSM, Typed Signals, Abstract Action Signatures, │
│ Deferred Events, Physical Quantity Constraints, Target Codegen. │
└───────────────────────────────────────┬─────────────────────────────────────────┘
│
▼
┌───────────────────────────────────┐
│ fsmc Core Compiler & IR │
│ (Semantic Validation & Optimizer) │
└─────────────────┬─────────────────┘
│
┌─────────────────────┴─────────────────────┐
▼ ▼
┌───────────────────────────────────┐ ┌───────────────────────────────────┐
│ Target Runtime Codegen Engines │ │ Formal Model Checking Target │
│ (e.g., C++17 / C++20 Zero-Alloc) │ │ (nuXmv / NuSMV Symbolic Verifier) │
│ • Header-only standalone library │ │ • Kripke Structure (S, S0, R, L) │
│ • Lock-free SPSC / Ring Buffer │ │ • Discrete Timed Automata clocks │
│ • Async Future / Polling Engine │ │ • LTLSPEC / INVARSPEC / CTLSPEC │
│ • Extensible for future targets │ │ │
└───────────────────────────────────┘ └───────────────────────────────────┘
Distinct Roles in the Compiler Architecture¶
- Authoring & Executable Modeling (Language-Agnostic Frontends & Emitters):
- SysML v2, SCXML, Cameo XMI, PlantUML, Mermaid, JSON, DOT: Designed to model operational behavior with rich, language-agnostic software semantics (composite state trees, abstract entry/exit/do action signatures, event deferrals, physical unit constraints).
-
Serve as primary authoring languages for continuous roundtrip, semantic analysis, and target code generation (such as C++17/20 bare-metal runtimes).
-
Formal Verification Sink (
nuXmv / SMV): - Role: Serves as a pure, standard Symbolic Model Checking Target for mission-critical and safety-critical verification (DO-178C, ISO 26262, ECSS).
- Mathematical Formalism: Emits a standard finite Kripke structure
M = <S, S0, R, L>with explicit transition relations (ASSIGN next(state) := case ... esac;), finite-domain variables (0..100,boolean), discrete clock counters (timer_<state> : 0..N), and temporal logic goals (LTLSPEC,INVARSPEC). - Design Philosophy: SMV is kept clean and canonical—free of unnatural pseudo-directives—so that emitted files are immediately verifiable by external tools (
nuxmv,NuSMV,MathSAT) without preprocessing.