Skip to content

Instantly share code, notes, and snippets.

@exbotanical
Last active January 22, 2023 07:25
Show Gist options
  • Save exbotanical/877fd5529cf75ac145a97d76f0c334d2 to your computer and use it in GitHub Desktop.
Save exbotanical/877fd5529cf75ac145a97d76f0c334d2 to your computer and use it in GitHub Desktop.
A simple finite state machine manager written in C
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct transition_t {
char* name;
char* target;
void (*action)(void);
} Transition;
typedef struct state_t {
char* name;
int num_transitions;
Transition* transitions[1];
} StateDescriptor;
typedef struct state_machine_t {
char* name;
int num_states;
char* state;
StateDescriptor* states[1];
} StateMachine;
StateDescriptor* fsm_get_state(StateMachine* fsm, char* name);
StateMachine* fsm_create(char* name) {
StateMachine* fsm = malloc(sizeof(*fsm));
fsm->name = name;
return fsm;
}
void fsm_register_state(StateMachine* fsm, StateDescriptor* s) {
fsm->states[fsm->num_states] = malloc(sizeof(s));
fsm->states[fsm->num_states++] = s;
}
void fsm_register_transition(StateMachine* fsm, char* state_name,
Transition* t) {
StateDescriptor* state = fsm_get_state(fsm, state_name);
state->transitions[state->num_transitions] = malloc(sizeof(t));
state->transitions[state->num_transitions++] = t;
}
Transition* fsm_transition_create(char* name, char* target,
void*(action)(void)) {
Transition* t = malloc(sizeof(*t));
t->action = action;
t->name = name;
t->target = target;
return t;
}
StateDescriptor* fsm_state_create(char* name) {
StateDescriptor* s = malloc(sizeof(*s));
s->name = name;
return s;
}
StateDescriptor* fsm_get_state(StateMachine* fsm, char* name) {
for (int i = 0; i < fsm->num_states; i++) {
if (strcmp(fsm->states[i]->name, name) == 0) {
return fsm->states[i];
}
}
return NULL;
}
void fsm_transition(StateMachine* fsm, char* event) {
StateDescriptor* s = fsm_get_state(fsm, fsm->state);
for (int k = 0; k < s->num_transitions; k++) {
Transition* transition = s->transitions[k];
printf("transition\n");
if (strcmp(transition->name, event) == 0) {
transition->action();
fsm->state = transition->target;
}
}
}
void off_action_handler() { printf("OFF HANDLER\n"); }
void on_action_handler() { printf("ON HANDLER\n"); }
int main() {
// Let's build the following state machine
// off : {
// transitions : {
// switch : {
// target: 'on'
// action : fn
// }
// }
// }
// on : {
// transitions : {
// switch : {
// target: 'off'
// action : fn
// }
// }
// }
StateMachine* fsm = fsm_create("test");
fsm->state = "off";
Transition* t1 = fsm_transition_create("switch", "on", on_action_handler);
Transition* t2 = fsm_transition_create("switch", "off", off_action_handler);
StateDescriptor* off_s = fsm_state_create("off");
StateDescriptor* on_s = fsm_state_create("on");
fsm_register_state(fsm, off_s);
fsm_register_state(fsm, on_s);
fsm_register_transition(fsm, off_s->name, t1);
fsm_register_transition(fsm, on_s->name, t2);
printf("starting state: %s\n", fsm->state);
fsm_transition(fsm, "switch");
printf("ending state: %s\n", fsm->state);
fsm_transition(fsm, "switch");
printf("ending state: %s\n", fsm->state);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment