A minimal library to implement Finite State Machines in C
A tiny, zero-overhead set of C macros to write clear, explicit finite-state machines using plain goto and labels—without big switch statements or function trampolines.
- Single-header. Drop the header in your project and
#includeit. - Zero runtime overhead. Compiles to straight branches.
- Readable control-flow. Named states, explicit transitions.
- Portable. Standard C (C99+), no deps.
Full documentation is in the Programmers manual.
#include <stdio.h>
#include <ctype.h>
#include "fsm.h"
void classify(const char *s) {
size_t i = 0;
fsm {
fsmstate(START) {
if (!s[i]) fsmexit;
int c = (unsigned char)s[i++];
if (!isalpha(c)) fsmgoto(START);
switch (c | 32) { // tolower
case 'a': case 'e': case 'i': case 'o': case 'u': fsmgoto(VOWEL);
default: fsmgoto(CONSONANT);
}
}
fsmstate(VOWEL) { puts("vowel"); fsmgoto(START); }
fsmstate(CONSONANT) { puts("consonant"); fsmgoto(START); }
}
}
int main(void) { classify("aZ?!e"); }Output:
vowel
consonant
vowel
fsm { … }starts the machine and jumps tofsmstate(START).fsmstate(NAME) { … }defines a state you can jump to.fsmgoto(NAME)transitions to another state.fsmexitleaves the FSM and continues after thefsm { … }block.
Under the hood it’s just labels and goto, arranged so:
- entering the FSM always begins at
START; - falling off the end of a state exits the FSM (no silent fall-through);
break/continueinside a state also exit the FSM (preferfsmgoto/fsmexitfor clarity).
fsm { /* states only */ } // open an FSM block (one per function)
fsmstate(START) { /* ... */ } // required entry state (exactly one)
fsmstate(Name) { /* ... */ } // more states
fsmgoto(Name); // transition to a state
fsmexit; // exit the FSM- One FSM per function.
STARTmust exist exactly once. - Put only states inside
fsm { … }. Any code between states won’t execute. - Declare and initialize variables before
fsmor inside a state (so initializers run). - If you need to “stay” in a state, explicitly
fsmgoto(ThisState);.
- You get the clarity of named states and transitions.
- You keep tight, predictable codegen (no function call overhead).
- You avoid fragile
switchfall-throughs and huge nested loops.
- Copy
fsm.hinto your project. The file in thedist/directory is identical to the one in thesrc/directory, excepet for having all comments removed. #include "fsm.h"where you implement the machine.- Write your
fsmwith aSTARTstate and explicitfsmgototransitions.