specifying states only once 
Author Message
 specifying states only once

I am working on a program that deals with finite state machines
(FSM's).  I am using something like this in my code:

        #define TABLE_ITEM( a ) { a, #a }

        enum FSMState { idle = 5,
                        wait_on = 99,
                        wait_d1 = 3,
                        /* etc... */ };

        struct StateIdName { FSMState    State;
                             const char *StateName; }
               StateTable[] = { TABLE_ITEM( idle ),
                                TABLE_ITEM( wait_on ),
                                TABLE_ITEM( wait_d1 ),
                                /* etc... */ };

so when something goes wrong with a state I can print the state's
name in an error message by searching the StateTable array.  The
potential problem with this method is that some time down the road
when someone (that could be me) adds new states to the enum he may
forget to add the same states to the StateTable array.  Does anyone
know how to avoid this problem?  Perhaps with some clever macros
the states need to be specified only once?  Note that with the
TABLE_ITEM macro I am already saving myself some work and possible
grief.  Or perhaps I should use an entire different approach?

Thanks for any help.

Larry



Tue, 18 May 1999 03:00:00 GMT  
 specifying states only once

Quote:

> I am working on a program that deals with finite state machines
> (FSM's).  I am using something like this in my code:

>         #define TABLE_ITEM( a ) { a, #a }

>         enum FSMState { idle = 5,
>                         wait_on = 99,
>                         wait_d1 = 3,
>                         /* etc... */ };

>         struct StateIdName { FSMState    State;
>                              const char *StateName; }
>                StateTable[] = { TABLE_ITEM( idle ),
>                                 TABLE_ITEM( wait_on ),
>                                 TABLE_ITEM( wait_d1 ),
>                                 /* etc... */ };

> so when something goes wrong with a state I can print the state's
> name in an error message by searching the StateTable array.  The
> potential problem with this method is that some time down the road
> when someone (that could be me) adds new states to the enum he may
> forget to add the same states to the StateTable array.  Does anyone
> know how to avoid this problem?  Perhaps with some clever macros
> the states need to be specified only once?  Note that with the
> TABLE_ITEM macro I am already saving myself some work and possible
> grief.  Or perhaps I should use an entire different approach?

We had a similar problem where I worked before, and solved
it by means of machine-generating the equivalent to your
StateTable array, aong these lines:

- We #define'd all states in header files.

Something like this

states.h:

#define Idle 0
#define Waiting 1
#define Finished 2

(a rather simplistic example)

We declared the equivalent to your StateIdName structure in
another header file

state_defs.h:

struct state_name
{
        int state;
        const char *name;

Quote:
}

extern struct state_name state_name_table[];

- We wrote a program that processed the states.h file and produced
an output file state_names.c (the input/output file names were given
at the command line).
This file contained the equivalent to your StateTable[] array.
This can be done using plain C, yacc/lex, awk, or whatever you
prefer. The output can  look something like this:

/* MACHINE GENERATED CODE - DO NOT EDIT */
/* File: state_names.c  Generated: Fri Nov 29 16:37:55 MET 1996 */

#include "state_defs.h"
#include "states.h"

struct state_name state_name_table[] =
{
        { Idle, "Idle" },
        { Waiting, "Waiting" },
        { Finished, "Finished" },
        { -1, NULL }  /* End of list */

Quote:
}

- We set up a Makefile that automatically regenereated and recompiled
the state_names.c file whenever states.h was changed. The resulting
code was included in a library. In this manner, the state definitions
are maintained only one place (states.h).

(We did the same thing with message definitions, the resulting
info was used in a trace monitor that displayed symbolic state
and message names. We also had a set of library functions to
look up the state_name_table. This description is rather simplified.)

The concept can relatively easily be used for enums rather than
#defines, at least if you always specify the numeric value for
each state.

Hope this helps,

Roland Kruse



Tue, 18 May 1999 03:00:00 GMT  
 specifying states only once

|> I am working on a program that deals with finite state machines
|> (FSM's).  I am using something like this in my code:

|>         #define TABLE_ITEM( a ) { a, #a }

|>         enum FSMState { idle = 5,
|>                         wait_on = 99,
|>                         wait_d1 = 3,
|>                         /* etc... */ };

|>         struct StateIdName { FSMState    State;
|>                              const char *StateName; }
|>                StateTable[] = { TABLE_ITEM( idle ),
|>                                 TABLE_ITEM( wait_on ),
|>                                 TABLE_ITEM( wait_d1 ),
|>                                 /* etc... */ };

|> so when something goes wrong with a state I can print the state's
|> name in an error message by searching the StateTable array.  The
|> potential problem with this method is that some time down the road
|> when someone (that could be me) adds new states to the enum he may
|> forget to add the same states to the StateTable array.  Does anyone
|> know how to avoid this problem?  Perhaps with some clever macros
|> the states need to be specified only once?  Note that with the
|> TABLE_ITEM macro I am already saving myself some work and possible
|> grief.  Or perhaps I should use an entire different approach?

Prepare a file which contain something like this:

/* enums.def */
DEFINE_FSMState(idle, 5)
DEFINE_FSMState(wait_on, 99)
DEFINE_FSMState(wait_d1, 3)
/* etc */

Then use it like this:

enum FSMState {
#define DEFINE_FSMState(name, value) name = value,
#include "enums.def"
#undef DEFINE_FSMState
bogus_enum_for_standard_conformance

Quote:
};

struct StateIdName {
  FSMState State;
  const char *StateName;
Quote:
} StateTable[] = {

#define DEFINE_FSMState(name,value) { name, #name },
#include "enums.def"
#undef DEFINE_FSMState

Quote:
};

Then you only have to change enums.def, everything else is updated
automagically.
--
Andreas Schwab                                      "And now for something



Tue, 18 May 1999 03:00:00 GMT  
 specifying states only once

Quote:

> I am working on a program that deals with finite state machines
> (FSM's).  I am using something like this in my code:

<example omitted>

> so when something goes wrong with a state I can print the state's
> name in an error message by searching the StateTable array.

To identify where an error occurred isn't it easier just to have an
old-fashioned diagnostic statement like:

  if (error)  fputs("buffer overflow in routine #xx\n",stderr);

perhaps extended with __FILE__ and __LINE__ ?



Wed, 19 May 1999 03:00:00 GMT  
 specifying states only once




 >
 > |> I am working on a program that deals with finite state machines
 > |> (FSM's).  I am using something like this in my code:
 >
 >
 > |>         #define TABLE_ITEM( a ) { a, #a }
 >
 > |>         enum FSMState { idle = 5,
 > |>                         wait_on = 99,
 > |>                         wait_d1 = 3,
 > |>                         /* etc... */ };
 >
 > |>         struct StateIdName { FSMState    State;
 > |>                              const char *StateName; }
 > |>                StateTable[] = { TABLE_ITEM( idle ),
 > |>                                 TABLE_ITEM( wait_on ),
 > |>                                 TABLE_ITEM( wait_d1 ),
 > |>                                 /* etc... */ };
 >
 > |> so when something goes wrong with a state I can print the state's
 > |> name in an error message by searching the StateTable array.  The
 > |> potential problem with this method is that some time down the road
 > |> when someone (that could be me) adds new states to the enum he may
 > |> forget to add the same states to the StateTable array.  Does anyone
 > |> know how to avoid this problem?  Perhaps with some clever macros
 > |> the states need to be specified only once?  Note that with the
 > |> TABLE_ITEM macro I am already saving myself some work and possible
 > |> grief.  Or perhaps I should use an entire different approach?
 >
 > Prepare a file which contain something like this:
 >
 > /* enums.def */
 > DEFINE_FSMState(idle, 5)
 > DEFINE_FSMState(wait_on, 99)
 > DEFINE_FSMState(wait_d1, 3)
 > /* etc */
 >
 > Then use it like this:
 >
 > enum FSMState {
 > #define DEFINE_FSMState(name, value) name = value,
 > #include "enums.def"
 > #undef DEFINE_FSMState
 > bogus_enum_for_standard_conformance
 > };
 >
 > struct StateIdName {
 >   FSMState State;
 >   const char *StateName;
 > } StateTable[] = {
 > #define DEFINE_FSMState(name,value) { name, #name },
 > #include "enums.def"
 > #undef DEFINE_FSMState
 > };

I have used a similar technique which avoids the need for an include
file.  It uses a "macro of macro calls". e.g. In your case, in place of
the file enums.def, I might have a macro:

#define enums_def               \
DEFINE_FSMState(idle, 5)        \
DEFINE_FSMState(wait_on, 99)    \
DEFINE_FSMState(wait_d1, 3)     \
/* etc */

and I might replace #include "enums.def" with enums_def.  Of course, I
would heavily comment the definition of the "macro of macro calls".
The code is obfuscated at first sight.  The technique is seriously
useful in those cases where one has parallel lists.  ISTR, I once had
more than 10 parameters in the macro equivalent to DEFINE_FSMState
above.  (I hate mixed case identifiers as I find typing them difficult.
Wirth and MicroSoft have a lot to answer for.)
--
Walter Briscoe



Wed, 19 May 1999 03:00:00 GMT  
 specifying states only once

Quote:

>        #define TABLE_ITEM( a ) { a, #a }

>        enum FSMState { idle = 5,
>                        wait_on = 99,
>                        wait_d1 = 3,
>                        /* etc... */ };

>        struct StateIdName { FSMState    State;
>                             const char *StateName; }
>               StateTable[] = { TABLE_ITEM( idle ),
>                                TABLE_ITEM( wait_on ),
>                                TABLE_ITEM( wait_d1 ),
>                                /* etc... */ };

>so when something goes wrong with a state I can print the state's
>name in an error message by searching the StateTable array.  The
>potential problem with this method is that some time down the road
>when someone (that could be me) adds new states to the enum he may
>forget to add the same states to the StateTable array.  Does anyone
>know how to avoid this problem?

My usual solution is to create a separate file listing the items, in
the form of macro invocations.  In this case it would look like

TABLE_ITEM(idle, 5)
TABLE_ITEM(wait_on, 99)
TABLE_ITEM(wait_d1, 3)
/* etc */

and your code then becomes

enum FSMState {
#define TABLE_ITEM(name, val) name = val,
#include "states.list"
#undef TABLE_ITEM
  cant_have_a_trailing_comma

Quote:
};

struct StateIdName { FSMState State; const char *StateName; } StateTable[] = {
#define TABLE_ITEM(name, val) { name, #name },
#include "states.list"
#undef TABLE_ITEM

Quote:
};

-zefram
--



Sat, 22 May 1999 03:00:00 GMT  
 specifying states only once

Quote:


>> I am working on a program that deals with finite state machines
>> (FSM's).  I am using something like this in my code:

><example omitted>

>> so when something goes wrong with a state I can print the state's
>> name in an error message by searching the StateTable array.

>To identify where an error occurred isn't it easier just to have an
>old-fashioned diagnostic statement like:

>  if (error)  fputs("buffer overflow in routine #xx\n",stderr);

>perhaps extended with __FILE__ and __LINE__ ?

The above is OK if you are only interested in finding out WHERE in your
code an error occured.  In my case I also have to know WHAT input causes
the error.  A message like

        "FSM.c, line 129: Bad signal SS_D2 received at State wait_d1"

is a lot more convenient than

        "FSM.c, line 129: Bad signal 39 received at State 3"

when I have to refer back to the state diagram.

And thanks to those who gave me suggestions.

Larry



Sat, 22 May 1999 03:00:00 GMT  
 
 [ 7 post ] 

 Relevant Pages 

1. Need Help: Submit Form Only Once

2. #pragma once and #ifndef/#endif

3. reading a file at once

4. Once again ATL Server

5. Analog of #pargma once for C#

6. 2 Things Running at Once?

7. audio in c# once again

8. Memory Address Reserved once variable is declared??

9. float division (once again)

10. sos once again!

11. NET Interop and ATL DCOM Server Events (once more)

12. Help me once again

 

 
Powered by phpBB® Forum Software