Using Simple Finite State Machines - Fsm(C++)

Displaying an Fsm in Human-Readable Form

Class Fsm provides its own stream insertion operator for displaying an Fsm in human-readable form. (For each class X, it is customary to provide an operator << which inserts an external representation of an X value into a stream, (hence the term ``stream insertion operation''.)

This function can be useful in debugging programs that use an Fsm. The display is a labeled table whose rows correspond to inputs, whose columns correspond to states, and whose entries correspond to transitions. Rows consisting entirely of default transitions are not shown, leading to a fairly compact representation.

To display the vending machine Fsm in the section, ``A Simple Vending Machine'', for example, we would write:

           Fsm v(5,zero,error);
           Define the transitions
           cout << v;

which would display the following table:

             0       1       2       3       4
       0   (1,1)   (1,2)   (1,3)   (1,4)   (0,0)
       1   (2,2)   (2,3)   (2,4)   (0,0)   (0,0)
       2   (0,0)   (0,0)   (0,0)   (3,0)   (0,0)
       3   (0,0)   (0,0)   (0,0)   (0,0)   (4,0)

Column headings are state numbers and row headings are inputs. The entry at the intersection of row i and column j is an ordered pair of the form (A,T), where A is an `action number' and T is the target state selected by input i in state j. Action numbers are explained in the next paragraph.

Each action routine is assigned a sequential `action number' according to the order in which it is first seen by a machine. Action numbers start at zero, which is always assigned to the default action routine. If the action routine parameter is omitted in the constructor or in a call to trans(), this `null' action will also be assigned action number zero. For example, the simple acceptor in the section, ``A Simple Finite State Acceptor'', did not use action routines, so all action numbers would be displayed as zero by the stream insertion operator. For the vending machine, you can verify by examining the order of calls to trans() that action numbers are assigned as follows:

       0  error
       1  click
       2  clickclick
       3  dispense_gum
       4  dispense_candy

We now know enough to interpret the above table. For example, the entry at the intersection of row 1 and column 2 is (2,4); this means that when the machine receives an input of 1 (dime) in state 2 (ten), it performs the action routine with action number 2 (clickclick) and then goes to state 4 (twenty).

For programmers who would prefer a different format (for example, if the vending machine Fsm were displayed with symbolic labels like dime instead of 1), we have designed lib++.a so that programmers can easily replace the default stream insertion operator with their own version. To do this, use the following simple procedure.

First create a file, say myprint.c, containing the definition of your stream insertion operator:

       #include <Fsm.h>
       #include <iostream.h>
       ostream& operator<<(ostream& out,const Fsm& f){
           Your definition here

Now suppose you have a file prog.c that uses your stream insertion operator:

       #include <Fsm.h>
       #include <iostream.h>
           Fsm f(10);
           cout << f;

Compile prog.c in the usual way:

       $CC -c prog.c

When you link, however, make sure to list myprint.o before the -l option on the CC line:

       $CC prog.o myprint.o -l++

This will guarantee that the link editor chooses your stream insertion operator, rather than the one in lib++.a.

Previous topic: Tracing Execution

© 2005 The SCO Group, Inc. All rights reserved.
SCO OpenServer Release 6.0.0 -- 02 June 2005