Finite state machine: Difference between revisions

Content added Content deleted
Line 72: Line 72:


=={{header|C}}==
=={{header|C}}==
Here is a manually-constructed table-driven finite state machine that implements the same algorithm as the previous spaghetti code version.
Here is a manually-constructed table-driven finite state machine that is fairly general and could be adapted to different applications.
<lang C>
<lang C>
#include <stdio.h>
#include <stdio.h>
#include <ctype.h>
#include <ctype.h>
#include <stdlib.h>


int main(int argc, char **argv)
int main(int argc, char **argv)
{
{
typedef enum State { READY, WAITING, REFUND, DISPENSE, COLLECT, QUIT, EXIT } State;
typedef enum State { READY, WAITING, REFUND, DISPENSE, COLLECT, QUIT } State;


typedef struct statechange {
typedef struct statechange {
Line 86: Line 87:
} statechange;
} statechange;


#define MAXINPUTS 3
typedef struct FSM {
typedef struct FSM {
const State state;
const State state;
const char *prompt;
void (*Action)(void);
const statechange table[MAXINPUTS]; // would be nice if could be [] ...
const int inputs;
const statechange table[3]; // hacky. would be dynamic in a real program.
} FSM;
} FSM;


const FSM fsm[6] = {
char str[10];
{ READY, "\nMachine is READY. (D)eposit or (Q)uit :", 3, {{'D', WAITING}, {'Q', QUIT }, {-1, READY}} },
void Ready(void) { fprintf(stderr, "\nMachine is READY. (D)eposit or (Q)uit :"); scanf("%s", str); }
{ WAITING, "(S)elect product or choose to (R)efund :", 3, {{'S', DISPENSE}, {'R', REFUND}, {-1, WAITING}} },
void Waiting(void) { fprintf(stderr, "(S)elect product or choose to (R)efund :"); scanf("%s", str); }
{ REFUND, "Please collect refund.\nMachine is READY. (D)eposit or (Q)uit :", 3, {{'D', WAITING}, {'Q', QUIT }, {-1, REFUND}} },
void Refund(void) { fprintf(stderr, "Please collect refund.\n"); }
{ DISPENSE, "Dispensing product...\nPlease (C)ollect product. :", 3, {{'C', READY}, { -1, COLLECT }, {-1, DISPENSE}} },
void Dispense(void) { fprintf(stderr, "Dispensing product...\n"); }
{ COLLECT, "Please (C)ollect product. :", 2, {{'C', READY}, { -1, COLLECT }, {-1, COLLECT}} },
void Collect(void) { fprintf(stderr, "Please (C)ollect product. :"); scanf("%s", str); }
{ QUIT, "Thank you, shutting down now.\n", 1, {{ -1, EXIT}, { -1, EXIT }, {-1, EXIT}} },
void Quit(void) { fprintf(stderr, "Thank you, shutting down now.\n"); exit(0); }

const FSM fsm[] = {
{ READY, &Ready, {{'D', WAITING}, {'Q', QUIT }, {-1, READY} }},
{ WAITING, &Waiting, {{'S', DISPENSE}, {'R', REFUND}, {-1, WAITING} }},
{ REFUND, &Refund, {{ -1, READY} }},
{ DISPENSE, &Dispense, {{ -1, COLLECT} }},
{ COLLECT, &Collect, {{'C', READY}, { -1, COLLECT } }},
{ QUIT, &Quit, {{ -1, QUIT} }},
};
};


char str[10]; // hacky. from prev Rosetta Code example before rewriting.
int each;
int each;
State state = READY;
State state = READY;


do {
for (;;) {
fprintf(stderr, "%s", fsm[state].prompt); fflush(stderr);
fsm[state].Action();
each = 0;
if (fsm[state].table[0].in < 0 && fsm[state].table[0].out == EXIT) break; else scanf("%s", str);
for (each = 0; each < fsm[state].inputs; each++) {
while (!( ((fsm[state].table[each].in == -1)
// -1 comes last and is catchall: exit, or loop to self, on no valid input.
if (fsm[state].table[each].in < 0) { state = fsm[state].table[each].out; break; }
else if (isalpha(str[0]) && toupper(str[0]) == fsm[state].table[each].in) { state = fsm[state].table[each].out; break; }
|| (isalpha(str[0]) && fsm[state].table[each].in == toupper(str[0]) )))) each++;
state = fsm[state].table[each].out;
}
}
} while (state != EXIT);

return 0;
return 0;
}
}