Last active
June 5, 2018 13:34
-
-
Save treywelsh/43e26f8732597afc67aa0b60e32e8824 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
/* source: https://stackoverflow.com/a/1371654 | |
* Pro: The transitions appear clearly in source code | |
* Cons: need a lookup function (but could it be more cache efficient ? See data structures approach of N. Askitis) | |
*/ | |
int entry_state(void); | |
int foo_state(void); | |
int bar_state(void); | |
int exit_state(void); | |
/* array and enum below must be in sync! */ | |
int (* state[])(void) = { entry_state, foo_state, bar_state, exit_state}; | |
enum state_codes { entry, foo, bar, end}; | |
enum ret_codes { ok, fail, repeat}; | |
struct transition { | |
enum state_codes src_state; | |
enum ret_codes ret_code; | |
enum state_codes dst_state; | |
}; | |
/* transitions from end state aren't needed */ | |
struct transition state_transitions[] = { | |
{entry, ok, foo}, | |
{entry, fail, end}, | |
{foo, ok, bar}, | |
{foo, fail, end}, | |
{foo, repeat, foo}, | |
{bar, ok, end}, | |
{bar, fail, end}, | |
{bar, repeat, foo}}; | |
#define EXIT_STATE end | |
#define ENTRY_STATE entry | |
int main(int argc, char *argv[]) { | |
enum state_codes cur_state = ENTRY_STATE; | |
enum ret_codes rc; | |
int (* state_fun)(void); | |
for (;;) { | |
state_fun = state[cur_state]; | |
rc = state_fun(); | |
if (EXIT_STATE == cur_state) | |
break; | |
cur_state = lookup_transitions(cur_state, rc); | |
} | |
return EXIT_SUCCESS; | |
} |
This file contains hidden or 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
/* source: https://stackoverflow.com/a/1383453 | |
* Why this approach ? | |
* It a bit less clear than with a transition table but I don't have to run over all the table to find the right | |
* state, transition couple. | |
* | |
*/ | |
#include <stdio.h> | |
struct state; | |
typedef void state_fn(struct state *); | |
struct state | |
{ | |
state_fn * next; | |
int i; // data | |
}; | |
state_fn foo, bar; | |
void foo(struct state * state) | |
{ | |
printf("%s %i\n", __func__, ++state->i); | |
state->next = bar; | |
} | |
void bar(struct state * state) | |
{ | |
printf("%s %i\n", __func__, ++state->i); | |
state->next = state->i < 10 ? foo : 0; | |
} | |
int main(void) | |
{ | |
struct state state = { foo, 0 }; | |
while(state.next) state.next(&state); | |
} |
This file contains hidden or 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
/* source: https://yakking.branchable.com/posts/state-machines-in-c/ | |
* Pro: The transitions appear clearly in source code | |
* Cons: unused memory | |
*/ | |
#include <assert.h> | |
#include <stdlib.h> | |
#include <stdio.h> | |
enum states { | |
START, | |
LOOP, | |
END, | |
} state; | |
enum events { | |
START_LOOPING, | |
PRINT_HELLO, | |
STOP_LOOPING, | |
}; | |
typedef enum states (*event_handler)(enum states, enum events); | |
enum states start_looping(enum states state, enum events event) { | |
assert(state == START && event == START_LOOPING); | |
return LOOP; | |
} | |
enum states print_hello(enum states state, enum events event) { | |
assert(state == LOOP && event == PRINT_HELLO); | |
printf("Hello World!\n"); | |
return LOOP; | |
} | |
enum states stop_looping(enum states state, enum events event) { | |
assert(state == LOOP && event == STOP_LOOPING); | |
return END; | |
} | |
event_handler transitions[STOP_LOOPING+1][END+1] = { | |
[START] = { [START_LOOPING] = start_looping, }, | |
[LOOP] = { [PRINT_HELLO] = print_hello, | |
[STOP_LOOPING] = stop_looping, }, | |
}; | |
struct sm { | |
enum state st; | |
int ev; | |
}; | |
void sm_init(struct sm* s, enum state start_state) { | |
s->st.next = start_state; | |
s->st.i = 0; //XXX argument | |
} | |
void step_state(struct sm* s, enum events event) { | |
event_handler handler = transitions[event][s->state]; | |
if (!handler) | |
exit(1); | |
s->state = handler(s->state, event); | |
} | |
int main(void) { | |
struct sm* statem; | |
sm_init(&statem, START); | |
step_state(START_LOOPING); | |
step_state(PRINT_HELLO); | |
step_state(PRINT_HELLO); | |
step_state(STOP_LOOPING); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment