FCSTM simulation first run
This page is the short first-run path for the FCSTM simulator. It shows the minimum concepts you need, one reproducible batch command, and where to go next for task recipes or execution-order details.
What the simulator checks
The simulator executes the parsed model directly, before you generate target code. In a simulation run:
a leaf state can be the current stoppable state;
a composite state contains child states and chooses an initial child;
a pseudo state is an automatic routing state, not a normal stopping point;
lifecycle actions such as
enter,duringandexitupdate variables while transitions move between states.
For full execution-order details, see Execution semantics explanation. For concrete simulator commands, see Simulation tasks. For exact command, export and Python API facts, see Simulation reference.
Run one batch transcript
Batch mode uses the same command processor as the interactive REPL. Commands are separated by semicolons, so a short transcript is enough to verify initial entry, available events, event-driven transition, current state display and history output:
pyfcstm simulate -i ../cli/simple_machine.fcstm \
-e "cycle; events; cycle Start; current; cycle Stop; history 3" \
--no-color
The documentation keeps this transcript generated from a real demo script:
────────────────────────────────────────────────────────────
>>> cycle
────────────────────────────────────────────────────────────
Cycle: 1
Current State: SimpleMachine.Idle
Variables:
counter = 0
────────────────────────────────────────────────────────────
>>> events
────────────────────────────────────────────────────────────
Available Events:
• Start (SimpleMachine.Idle.Start)
────────────────────────────────────────────────────────────
>>> cycle Start
────────────────────────────────────────────────────────────
Cycle: 2
Current State: SimpleMachine.Running
Variables:
counter = 0
────────────────────────────────────────────────────────────
>>> current
────────────────────────────────────────────────────────────
Cycle: 2
Current State: SimpleMachine.Running
Variables:
counter = 0
────────────────────────────────────────────────────────────
>>> cycle Stop
────────────────────────────────────────────────────────────
Cycle: 3
Current State: SimpleMachine.Stopped
Variables:
counter = 1
────────────────────────────────────────────────────────────
>>> history 3
────────────────────────────────────────────────────────────
Cycle State counter
---------------------------------------
1 SimpleMachine.Idle 0
2 SimpleMachine.Running 0
3 SimpleMachine.Stopped 1
The first cycle initializes the machine at SimpleMachine.Idle. The
events command then shows that Start is available from the current
state. After cycle Start the current state is SimpleMachine.Running;
cycle Stop reaches SimpleMachine.Stopped and the short history table
shows the three recorded cycles.
Try one Python runtime loop
If you are embedding pyfcstm in Python tests or tools, the runtime API follows
the same model: parse DSL, build the state-machine model, construct
SimulationRuntime, and call cycle(). Each call returns a
CycleResult. Its legacy value is currently None, while
input_events, consumed_events and unconsumed_events tell you which
canonical event paths were supplied, used or left unused in that cycle.
#!/usr/bin/env python3
from pyfcstm.dsl import parse_with_grammar_entry
from pyfcstm.model import parse_dsl_node_to_state_machine
from pyfcstm.simulate import SimulationRuntime
dsl_code = """
def int counter = 0;
state System {
[*] -> Idle;
state Idle {
during {
counter = counter + 1;
}
}
state Active {
during {
counter = counter + 10;
}
}
Idle -> Active : if [counter >= 5];
Active -> Idle : if [counter >= 50];
}
"""
# Parse and create state machine
ast = parse_with_grammar_entry(dsl_code, 'state_machine_dsl')
sm = parse_dsl_node_to_state_machine(ast)
# Create runtime
runtime = SimulationRuntime(sm)
# Execute cycles
print(f"Initial: state={'.'.join(runtime.current_state.path)}, counter={runtime.vars['counter']}")
for i in range(1, 8):
runtime.cycle()
print(f"Cycle {i}: state={'.'.join(runtime.current_state.path)}, counter={runtime.vars['counter']}")
Output:
Initial: state=System, counter=0
Cycle 1: state=System.Idle, counter=1
Cycle 2: state=System.Idle, counter=2
Cycle 3: state=System.Idle, counter=3
Cycle 4: state=System.Idle, counter=4
Cycle 5: state=System.Idle, counter=5
Cycle 6: state=System.Active, counter=15
Cycle 7: state=System.Active, counter=25
The example only prints state and variables. If you need the exact
CycleResult fields, event input forms, export formats or public runtime
exceptions, use Simulation reference.
Old topic map
The previous long simulation guide mixed tutorial, how-to and explanation material. The main topics now live here:
Old topic |
New location |
|---|---|
Python API loops and event injection |
|
Batch mode, REPL commands, |
|
Hot start task usage |
|
Abstract handlers |
|
Configuration settings and command-line facts |
|
Testing, debugging and best-practice notes |
|
Business examples and long semantic walkthroughs |
|
Execution order, composite entry, aspect actions and pseudo states |
|
DSL syntax used by examples |
|
DSL semantic background |
The legacy example resources remain in this directory so old links and source-output pairs stay stable. The migration log records each resource and the final cleanup audit explains why these compatibility resources remain.