Skip to content

Instantly share code, notes, and snippets.

@treywelsh
Last active June 5, 2018 13:34
Show Gist options
  • Save treywelsh/43e26f8732597afc67aa0b60e32e8824 to your computer and use it in GitHub Desktop.
Save treywelsh/43e26f8732597afc67aa0b60e32e8824 to your computer and use it in GitHub Desktop.
/* 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;
}
/* 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);
}
/* 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