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
using getopt

GCC's
Fixincludes

fixincludes

Automated
FSM

description
example
usagefsm

Addons
addon

Project GNU
Home Page

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>

/*
 *  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

/**
 *  State transition handling map.  Map the state enumeration and 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] =
/*     0 */ "** OUT-OF-RANGE **\0"
/*    19 */ "FSM Error:  in state %d (%s), event %d (%s) is invalid\n\0"
/*    75 */ "invalid\0"
/*    83 */ "init\0"
/*    88 */ "lonum\0"
/*    94 */ "dash\0"
/*    99 */ "hinum\0"
/*   105 */ ",\0"
/*   107 */ "num\0"
/*   111 */ "-\0"
/*   113 */ "!\0"
/*   115 */ "End-Of-Line";

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;
    void* saved_cookie = cookie;
    (void)saved_cookie;

    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 */

#ifndef __COVERITY__
        if (trans_evt >= EX_EV_INVALID) {
            nxtSt = EX_ST_INVALID;
            trans = EX_TR_INVALID;
        } else
#endif /* __COVERITY__ */
        {
            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  Valid XHTML 1.0!


AutoGen, AutoOpts, columns, getdefs, AutoFSM, AutoXDR and these web pages copyright (c) 1999-2012 Bruce Korb, all rights reserved.

Return to GNU's home page.

Please send FSF & GNU inquiries & questions to gnu@gnu.org. There are also other ways to contact the FSF.

Please send comments on these web pages to webmasters@www.gnu.org, send other questions to gnu@gnu.org.

This article, Copyright © 2000-2002 by Bruce Korb

Verbatim copying and distribution of this entire article is permitted in any medium, provided this notice is preserved. Last modified: Sun Sep 8 12:45:40 PDT 2013