Finite state machine: Difference between revisions

Line 72:
 
=={{header|C}}==
Here is a manually-constructed table-driven finite state machine that implements the same algorithm as the previous spaghetti code version.
This is an unapologetic implementation of goto. There have been a lot of curse words and obituaries written about it and the inventors of Java were glad to exclude it from the language, but to be fair, goto is one of the many things C inherited from languages such as Assembly or BASIC that make it truly awesome, especially when it comes to such requirements. After all, can there be a clearer and simpler implementation of a Finite State Machine (not counting BASIC ) ?
<lang C>
#include <stdio.h>
#include <ctype.h>
 
int main(int argc, char **argv)
{
typedef enum State { READY, WAITING, REFUND, DISPENSE, COLLECT, QUIT, EXIT } State;
char str[10];
 
typedef struct statechange {
ready: do{
const int in;
printf("\nMachine is READY. (D)eposit or (Q)uit :");
const State out;
scanf("%s",str);
} statechange;
}while(!(str[0]!='D'||str[0]!='d'||str[0]!='q'||str[0]!='Q'));
 
typedef struct FSM {
if(str[0]=='q'||str[0]=='Q')
const State state;
goto quit;
const char *prompt;
goto waiting;
const int inputs;
const statechange table[3]; // hacky. would be dynamic in a real program.
waiting: do{
} FSM;
printf("(S)elect product or choose to (R)efund :");
 
scanf("%s",str);
const FSM fsm[6] = {
}while(!(str[0]!='s'||str[0]!='S'||str[0]!='r'||str[0]!='R'));
{ READY, "\nMachine is READY. (D)eposit or (Q)uit :", 3, {{'D', WAITING}, {'Q', QUIT }, {-1, READY}} },
{ WAITING, "(S)elect product or choose to (R)efund :", 3, {{'S', DISPENSE}, {'R', REFUND}, {-1, WAITING}} },
if(str[0]=='s'||str[0]=='S'){
{ REFUND, "Please collect refund.\nMachine is READY. (D)eposit or (Q)uit :", 3, {{'D', WAITING}, {'Q', QUIT }, {-1, REFUND}} },
printf("Dispensing product...");
{ DISPENSE, "Dispensing product...\nPlease (C)ollect product. :", 3, {{'C', READY}, { -1, COLLECT }, {-1, DISPENSE}} },
goto dispense;
{ COLLECT, "Please (C)ollect product. :", 2, {{'C', READY}, { -1, COLLECT }, {-1, COLLECT}} },
}
{ QUIT, "Thank you, shutting down now.\n", 1, {{ -1, EXIT}, { -1, EXIT }, {-1, EXIT}} },
};
else{
 
printf("Please collect refund.");
char str[10]; // hacky. from prev Rosetta Code example before rewriting.
goto ready;
int each;
}
State state = READY;
 
dispense: do{
do {
printf("\nPlease (C)ollect product. :");
fprintf(stderr, "%s", fsm[state].prompt); fflush(stderr);
scanf("%s",str);
if (fsm[state].table[0].in < 0 && fsm[state].table[0].out == EXIT) break; else scanf("%s", str);
}while(!(str[0]!='c'||str[0]!='C'));
for (each = 0; each < fsm[state].inputs; each++) {
if (fsm[state].table[each].in < 0) { state = fsm[state].table[each].out; break; }
goto ready;
else if (isalpha(str[0]) && toupper(str[0]) == fsm[state].table[each].in) { state = fsm[state].table[each].out; break; }
}
quit: printf("Thank you, shutting down now.");
} while (state != EXIT);
 
return 0;
}
</lang>
Anonymous user