|
#include <stdio.h> |
|
#include <stdbool.h> |
|
|
|
typedef enum state { |
|
IDLE, |
|
WORK, |
|
SUCCESS, |
|
ERROR, |
|
END, |
|
_ |
|
} state_t; |
|
|
|
typedef enum result { |
|
CONTINUE, |
|
NEXT, |
|
FAIL, |
|
} result_t; |
|
|
|
typedef result_t(*state_handler_t)(void); |
|
|
|
typedef struct transition { |
|
state_handler_t handler; |
|
state_t results[3]; |
|
} transition_t; |
|
|
|
state_t current_state = IDLE; |
|
|
|
char input = ' '; |
|
int work = 0; |
|
|
|
result_t handle_idle(void) { |
|
// wait for 's' command to start work |
|
if(input == 's') { |
|
return NEXT; |
|
} |
|
return CONTINUE; |
|
} |
|
|
|
result_t handle_work(void) { |
|
// accept 3 'w' characters while working |
|
if(input == 'w') { |
|
work++; |
|
if(work >= 3) { |
|
return NEXT; |
|
} |
|
} else { |
|
// anything else is errornous |
|
return FAIL; |
|
} |
|
return CONTINUE; |
|
} |
|
|
|
result_t handle_success(void) { |
|
printf("nice work\n"); |
|
return NEXT; |
|
} |
|
|
|
|
|
result_t handle_error(void) { |
|
printf("whoops (%c)\n", input); |
|
return NEXT; |
|
} |
|
|
|
result_t handle_end(void) { |
|
// when done, we return to exit the initial call, stopping the loop |
|
printf("we're done\n"); |
|
return NEXT; |
|
} |
|
|
|
transition_t transitions[] = { |
|
/* STATE HANDLER CONTINUE NEXT FAIL */ |
|
{ /* IDLE */ handle_idle, { IDLE, WORK, _ }}, |
|
{ /* WORK */ handle_work, { WORK, SUCCESS, ERROR }}, |
|
{ /* SUCCESS */ handle_success, { _, END, _ }}, |
|
{ /* ERROR */ handle_error, { _, END, _ }}, |
|
{ /* END */ handle_end, { _, _, _ }}, |
|
}; |
|
|
|
void get_input(void) { |
|
// get input from user when IDLE or WORKing |
|
if(current_state <= WORK) { |
|
printf("(%d)> ", current_state); |
|
input = fgetc(stdin); |
|
fgetc(stdin); // Enter |
|
} |
|
} |
|
|
|
void do_some_work() { |
|
while(true) { |
|
get_input(); |
|
result_t result = transitions[current_state].handler(); |
|
current_state = transitions[current_state].results[result]; |
|
if(current_state == _) { return; } |
|
} |
|
} |
|
|
|
int main(void) { |
|
do_some_work(); |
|
} |