Last active
January 22, 2023 07:25
-
-
Save exbotanical/877fd5529cf75ac145a97d76f0c334d2 to your computer and use it in GitHub Desktop.
A simple finite state machine manager written in C
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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