autogen_back

AutoFSM Example

Main
AutoGen
Pages

Home
Announce
FAQ
docs
XML Defs
testimonials
downloads

Automated
Options

AutoOpts
Comparison
Man example
Redistribute
Licensing
local use
I-18-N
using getopt

GCC's
Fixincludes

fixincludes

Automated
FSM

description
example
usagefsm

Addons
addon

Autoconf
Config
Tests

create form
M4 Quoting

Automated
XDR

xdr project

i

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.

This page contains:




The input definitions

See the usage page for a description of the attributes supported.


AutoGen Definitions fsm;
	
#if 0
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>]] ... ]
#endif

event  = comma, num,  dash, bang, eol;
state  = lonum, dash, hinum;
type   = looping;
method = case;
prefix = ex;
cookie = "void* cookie";

dash   = "-";
bang   = "!";
eol    = "End-Of-Line";
comma  = ",";

/*
 *  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.  Transitions out of
 *  "hinum" state require no processing.
 */
transition = { tst = "*";  tev = comma; next = init; },
  { tst = hinum; tev = comma; ttype = noop;    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 = hinum; tev = eol; ttype = noop;    next = done; },
  { tst = init;  tev = eol; ttype = invalid; next = invalid; };
back to top


The resulting header file:

#ifndef AUTOFSM_EXAMPLE_FSM_H_GUARD
#define AUTOFSM_EXAMPLE_FSM_H_GUARD 1

/*
 *  Finite State machine States
 *
 *  Count of non-terminal states.  The generated states INVALID and DONE
 *  are terminal, but 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;

/*
 *  Run the FSM.  Will return EX_ST_DONE or EX_ST_INVALID
 */
extern te_ex_state
ex_run_fsm(
    void* cookie );

#endif /* AUTOFSM_EXAMPLE_FSM_H_GUARD */
back to top


And the associated code file:

#define DEFINE_FSM
#include "example-fsm.h"
#include <stdio.h>
#include <ctype.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

/*
 *  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_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,
    EX_TR_NOOP
} te_ex_trans;
#define EX_TRANSITION_CT  11

/*
 *  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 ex_transition t_ex_transition;
struct ex_transition {
    te_ex_state  next_state;
    te_ex_trans  transition;
};
static const t_ex_transition
ex_trans_table[ EX_STATE_CT ][ EX_EVENT_CT ] = {

  /* STATE 0:  EX_ST_INIT */
  { { EX_ST_INVALID, EX_TR_INVALID },               /* EVT:  , */
    { EX_ST_LONUM, EX_TR_INIT_NUM },                /* EVT:  num */
    { EX_ST_DASH, EX_TR_INIT_DASH },                /* EVT:  - */
    { EX_ST_INIT, EX_TR_INIT_BANG },                /* EVT:  ! */
    { EX_ST_INVALID, EX_TR_INVALID }                /* EVT:  End-Of-Line */
  },


  /* STATE 1:  EX_ST_LONUM */
  { { EX_ST_INIT, EX_TR_LONUM_COMMA },              /* EVT:  , */
    { EX_ST_INVALID, EX_TR_INVALID },               /* EVT:  num */
    { EX_ST_DASH, EX_TR_LONUM_DASH },               /* EVT:  - */
    { EX_ST_INVALID, EX_TR_INVALID },               /* EVT:  ! */
    { EX_ST_DONE, EX_TR_LONUM_EOL }                 /* EVT:  End-Of-Line */
  },


  /* STATE 2:  EX_ST_DASH */
  { { EX_ST_INIT, EX_TR_DASH_COMMA },               /* EVT:  , */
    { EX_ST_HINUM, EX_TR_DASH_NUM },                /* EVT:  num */
    { EX_ST_INVALID, EX_TR_INVALID },               /* EVT:  - */
    { EX_ST_INVALID, EX_TR_INVALID },               /* EVT:  ! */
    { EX_ST_DONE, EX_TR_DASH_EOL }                  /* EVT:  End-Of-Line */
  },


  /* STATE 3:  EX_ST_HINUM */
  { { EX_ST_INIT, EX_TR_NOOP },                     /* EVT:  , */
    { EX_ST_INVALID, EX_TR_INVALID },               /* EVT:  num */
    { EX_ST_INVALID, EX_TR_INVALID },               /* EVT:  - */
    { EX_ST_INVALID, EX_TR_INVALID },               /* EVT:  ! */
    { EX_ST_DONE, EX_TR_NOOP }                      /* EVT:  End-Of-Line */
  }
};


#define ExFsmErr_off     19
#define ExEvInvalid_off  75
#define ExStInit_off     83


static char const zExStrings[127] =
    "** OUT-OF-RANGE **\0"
    "FSM Error:  in state %d (%s), event %d (%s) is invalid\n\0"
    "invalid\0"
    "init\0"
    "lonum\0"
    "dash\0"
    "hinum\0"
    ",\0"
    "num\0"
    "-\0"
    "!\0"
    "End-Of-Line\0";

static const size_t aszExStates[4] = {
    83, 88, 94, 99 };

static const size_t aszExEvents[6] = {
    105, 107, 111, 113, 115, 75 };


#define EX_EVT_NAME(t)   ( (((unsigned)(t)) >= 6) \
    ? zExStrings : zExStrings + aszExEvents[t])

#define EX_STATE_NAME(s) ( (((unsigned)(s)) >= 4) \
    ? zExStrings : zExStrings + aszExStates[s])

#ifndef EXIT_FAILURE
# define EXIT_FAILURE 1
#endif

static int ex_invalid_transition( te_ex_state st, te_ex_event evt );

/* * * * * * * * * THE CODE STARTS HERE * * * * * * * *
 *
 *  Print out an invalid transition message and return EXIT_FAILURE
 */
static int
ex_invalid_transition( te_ex_state st, te_ex_event evt )
{
    /* START == INVALID TRANS MSG == DO NOT CHANGE THIS COMMENT */
    char const * fmt = zExStrings + ExFsmErr_off;
    fprintf( stderr, fmt, st, EX_STATE_NAME(st), evt, EX_EVT_NAME(evt));
    /* END   == INVALID TRANS MSG == DO NOT CHANGE THIS COMMENT */

    return EXIT_FAILURE;
}

/*
 *  Run the FSM.  Will return EX_ST_DONE or EX_ST_INVALID
 */
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;
    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_ex_transition* pTT =
            ex_trans_table[ ex_state ] + trans_evt;
            nxtSt = pTT->next_state;
            trans = pTT->transition;
        }


        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_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;


        case EX_TR_NOOP:  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 */
        }

        ex_state = nxtSt;
    }
    return ex_state;
}

top  Viewable With Any Browser  SourceForge Logo   Support This Project   Valid XHTML 1.0!


AutoGen, AutoOpts, columns, getdefs, AutoFSM, AutoXDR and these web pages copyright (c) 1999-2002 Bruce Korb, all rights reserved.
Last modified: Sun Aug 17 16:51:06 PDT 2008