Here is a simple example. It decides whether or not the input
properly represents a list of value ranges. The input syntax is
approximately:
[ '!' ] [ <lo-num> ] [ '-' [ <hi-num> ] ] [ ',' \ [ '!' ] [ <lo-num> ] [ '-' [ <hi-num> ] ] ... ]If there is no hyphen, then a number must be present. You should not have more than one "bang" operator, but this FSM does not check for that.
AutoGen Definitions fsm;
event = comma, num, dash, bang, eol;
state = lonum, dash, hinum;
type = looping;
method = case;
prefix = ex;
cookie = "void* cookie";
/*
* Define a transition for every valid transition.
* Specify the Transition_STate, the TransitionEVent and
* what the NEXT state will be. A unique transition
* enumeration will be produced for each defined transition.
*/
transition = { tst = init; tev = num; next = lonum; };
transition = { tst = init; tev = bang; next = init; };
transition = { tst = dash; tev = num; next = hinum; };
/*
* Dash transition. Always go to 'dash' state, except when we are in
* the 'hinum' or 'dash' state. Then, do the 'invalid' transition.
*/
transition = { tst = "*"; tev = dash; next = dash; },
{ tst = hinum, dash; tev = dash; ttype = invalid; next = invalid; };
/*
* Comma transition, other than in 'init'. You cannot have two
* commas together and you cannot start with one.
*/
transition = { tst = "*"; tev = comma; next = init; },
{ tst = init; tev = comma; ttype = invalid; next = invalid; };
/*
* End of line transition, other than in 'init'.
* You cannot end with a comma or without any ranges specified.
*/
transition = { tst = "*"; tev = eol; next = done; },
{ tst = init; tev = eol; ttype = invalid; next = invalid; };
#ifndef EXAMPLE_FSM_H_GUARD
#define EXAMPLE_FSM_H_GUARD
/*
* Finite State machine States
*
* Count of non-terminal states. EX_ST_INVALID and EX_ST_DONE
* are terminal, EX_ST_INIT is not :-).
*/
#define EX_STATE_CT 4
typedef enum {
EX_ST_INIT, EX_ST_LONUM, EX_ST_DASH, EX_ST_HINUM, EX_ST_INVALID,
EX_ST_DONE
} te_ex_state;
/*
* Finite State machine transition Events.
*
* Count of the valid transition events
*/
#define EX_EVENT_CT 5
typedef enum {
EX_EV_COMMA, EX_EV_NUM, EX_EV_DASH, EX_EV_BANG, EX_EV_EOL,
EX_EV_INVALID
} te_ex_event;
/*
* Call the FSM. Will return EX_ST_DONE or EX_ST_INVALID
*/
extern te_ex_state ex_run_fsm( void* cookie );
#endif /* EXAMPLE_FSM_H_GUARD */
#define DEFINE_FSM
#include "example-fsm.h"
#include <stdio.h>
/*
* Do not make changes to this file, except between the START/END
* comments, or it will be removed the next time it is generated.
*/
/* START === USER HEADERS === DO NOT CHANGE THIS COMMENT */
/* END === USER HEADERS === DO NOT CHANGE THIS COMMENT */
#ifndef NULL
# define NULL 0
#endif
#ifndef tSCC
# define tSCC static const char
#endif
/*
* Enumeration of the valid transition types
* Some transition types may be common to several transitions.
*/
typedef enum {
EX_TR_DASH_COMMA,
EX_TR_DASH_EOL,
EX_TR_DASH_NUM,
EX_TR_HINUM_COMMA,
EX_TR_HINUM_EOL,
EX_TR_INIT_BANG,
EX_TR_INIT_DASH,
EX_TR_INIT_NUM,
EX_TR_INVALID,
EX_TR_LONUM_COMMA,
EX_TR_LONUM_DASH,
EX_TR_LONUM_EOL
} te_ex_trans;
#define EX_TRANSITION_CT 12
/*
* the state transition handling map
* This table maps the state enumeration + the event enumeration to
* the new state and the transition enumeration code (in that order).
* It is indexed by first the current state and then the event code.
*/
typedef struct transition t_transition;
struct transition {
te_ex_state next_state;
te_ex_trans transition;
};
static const t_transition ex_trans_table[ EX_STATE_CT ][ EX_EVENT_CT ] = {
{ { EX_ST_INVALID, EX_TR_INVALID }, /* init state */
{ EX_ST_LONUM, EX_TR_INIT_NUM },
{ EX_ST_DASH, EX_TR_INIT_DASH },
{ EX_ST_INIT, EX_TR_INIT_BANG },
{ EX_ST_INVALID, EX_TR_INVALID } },
{ { EX_ST_INIT, EX_TR_LONUM_COMMA }, /* lonum state */
{ EX_ST_INVALID, EX_TR_INVALID },
{ EX_ST_DASH, EX_TR_LONUM_DASH },
{ EX_ST_INVALID, EX_TR_INVALID },
{ EX_ST_DONE, EX_TR_LONUM_EOL } },
{ { EX_ST_INIT, EX_TR_DASH_COMMA }, /* dash state */
{ EX_ST_HINUM, EX_TR_DASH_NUM },
{ EX_ST_INVALID, EX_TR_INVALID },
{ EX_ST_INVALID, EX_TR_INVALID },
{ EX_ST_DONE, EX_TR_DASH_EOL } },
{ { EX_ST_INIT, EX_TR_HINUM_COMMA }, /* hinum state */
{ EX_ST_INVALID, EX_TR_INVALID },
{ EX_ST_INVALID, EX_TR_INVALID },
{ EX_ST_INVALID, EX_TR_INVALID },
{ EX_ST_DONE, EX_TR_HINUM_EOL } }
};
/*
* Define all the event and state names
*/
tSCC zBogus[] = "** OUT-OF-RANGE **";
tSCC zStInit[] = "init";
tSCC zEvInvalid[] = "* Invalid Event *";
tSCC zFsmErr[] =
"FSM Error: in state %d (%s), event %d (%s) is invalid\n";
tSCC zStLonum[] = "lonum";
tSCC zStDash[] = "dash";
tSCC zStHinum[] = "hinum";
tSCC* apzStates[] = {
zStInit, zStLonum, zStDash, zStHinum };
tSCC zEvComma[] = "comma";
tSCC zEvNum[] = "num";
tSCC zEvDash[] = "dash";
tSCC zEvBang[] = "bang";
tSCC zEvEol[] = "eol";
tSCC* apzEvents[] = {
zEvComma, zEvNum, zEvDash, zEvBang, zEvEol, zEvInvalid };
#define EX_EVT_NAME(t) ( (((unsigned)(t)) >= EX_EV_INVALID) \
? zBogus : apzEvents[ t ])
#define EX_STATE_NAME(s) ( (((unsigned)(s)) > EX_ST_INVALID) \
? zBogus : apzStates[ s ])
#ifndef EXIT_FAILURE
# define EXIT_FAILURE 1
#endif
/* * * * * * * * * THE CODE STARTS HERE * * * * * * * *
*
* Print out an invalid transition message and return EXIT_FAILURE
*/
int
ex_invalid_transition( te_ex_state st, te_ex_event evt )
{
/* START == INVALID TRANS MSG == DO NOT CHANGE THIS COMMENT */
fprintf( stderr, zFsmErr, st, EX_STATE_NAME( st ), evt, EX_EVT_NAME( evt ));
/* END == INVALID TRANS MSG == DO NOT CHANGE THIS COMMENT */
return EXIT_FAILURE;
}
te_ex_state
ex_run_fsm( void* cookie )
{
te_ex_state ex_state = EX_ST_INIT;
te_ex_event trans_evt;
te_ex_state nxtSt, firstNext;
te_ex_trans trans;
while (ex_state < EX_ST_INVALID) {
/* START == FIND TRANSITION == DO NOT CHANGE THIS COMMENT */
trans_evt = GET_NEXT_TRANS();
/* END == FIND TRANSITION == DO NOT CHANGE THIS COMMENT */
if (trans_evt >= EX_EV_INVALID) {
nxtSt = EX_ST_INVALID;
trans = EX_TR_INVALID;
} else {
const t_transition* pTT = trans_table[ ex_state ] + trans_evt;
nxtSt = firstNext = pTT->next_state;
trans = pTT->transition;
}
#ifdef DEBUG
printf( "in state %s(%d) step %s(%d) to %s(%d)\n",
EX_STATE_NAME( ex_state ), ex_state,
EX_EVT_NAME( trans_evt ), trans_evt,
EX_STATE_NAME( nxtSt ), nxtSt );
#endif
switch (trans) {
case EX_TR_DASH_COMMA:
/* START == DASH_COMMA == DO NOT CHANGE THIS COMMENT */
nxtSt = HANDLE_DASH_COMMA();
/* END == DASH_COMMA == DO NOT CHANGE THIS COMMENT */
break;
case EX_TR_DASH_EOL:
/* START == DASH_EOL == DO NOT CHANGE THIS COMMENT */
nxtSt = HANDLE_DASH_EOL();
/* END == DASH_EOL == DO NOT CHANGE THIS COMMENT */
break;
case EX_TR_DASH_NUM:
/* START == DASH_NUM == DO NOT CHANGE THIS COMMENT */
nxtSt = HANDLE_DASH_NUM();
/* END == DASH_NUM == DO NOT CHANGE THIS COMMENT */
break;
case EX_TR_HINUM_COMMA:
/* START == HINUM_COMMA == DO NOT CHANGE THIS COMMENT */
nxtSt = HANDLE_HINUM_COMMA();
/* END == HINUM_COMMA == DO NOT CHANGE THIS COMMENT */
break;
case EX_TR_HINUM_EOL:
/* START == HINUM_EOL == DO NOT CHANGE THIS COMMENT */
nxtSt = HANDLE_HINUM_EOL();
/* END == HINUM_EOL == DO NOT CHANGE THIS COMMENT */
break;
case EX_TR_INIT_BANG:
/* START == INIT_BANG == DO NOT CHANGE THIS COMMENT */
nxtSt = HANDLE_INIT_BANG();
/* END == INIT_BANG == DO NOT CHANGE THIS COMMENT */
break;
case EX_TR_INIT_DASH:
/* START == INIT_DASH == DO NOT CHANGE THIS COMMENT */
nxtSt = HANDLE_INIT_DASH();
/* END == INIT_DASH == DO NOT CHANGE THIS COMMENT */
break;
case EX_TR_INIT_NUM:
/* START == INIT_NUM == DO NOT CHANGE THIS COMMENT */
nxtSt = HANDLE_INIT_NUM();
/* END == INIT_NUM == DO NOT CHANGE THIS COMMENT */
break;
case EX_TR_INVALID:
/* START == INVALID == DO NOT CHANGE THIS COMMENT */
exit( ex_invalid_transition( ex_state, trans_evt ));
/* END == INVALID == DO NOT CHANGE THIS COMMENT */
break;
case EX_TR_LONUM_COMMA:
/* START == LONUM_COMMA == DO NOT CHANGE THIS COMMENT */
nxtSt = HANDLE_LONUM_COMMA();
/* END == LONUM_COMMA == DO NOT CHANGE THIS COMMENT */
break;
case EX_TR_LONUM_DASH:
/* START == LONUM_DASH == DO NOT CHANGE THIS COMMENT */
nxtSt = HANDLE_LONUM_DASH();
/* END == LONUM_DASH == DO NOT CHANGE THIS COMMENT */
break;
case EX_TR_LONUM_EOL:
/* START == LONUM_EOL == DO NOT CHANGE THIS COMMENT */
nxtSt = HANDLE_LONUM_EOL();
/* END == LONUM_EOL == DO NOT CHANGE THIS COMMENT */
break;
default:
/* START == BROKEN MACHINE == DO NOT CHANGE THIS COMMENT */
exit( ex_invalid_transition( ex_state, trans_evt ));
/* END == BROKEN MACHINE == DO NOT CHANGE THIS COMMENT */
}
#ifdef DEBUG
if (nxtSt != firstNext)
printf( "transition code changed destination state to %s(%d)\n",
EX_STATE_NAME( nxtSt ), nxtSt );
#endif
ex_state = nxtSt;
}
return ex_state;
}
/*
* Local Variables:
* mode: C
* c-file-style: "stroustrup"
* tab-width: 4
* End:
* end of example-fsm.c */