|
|
A trace facility can be handy for debugging an Fsm application. Such a facility should be able to (1) capture all or part of a machine's state transition history, and (2) do so without requiring the modification of application code (such as action routines).
An Fsm can be traced by passing a programmer-defined function to function trace(), as illustrated below for the vending machine in ``A Simple Vending Machine''.
void vtrace( const Fsm&, int s1, int inp, int s2 ){ cerr << s1 << "\ t" << inp << "\ t" << s2 << "\ n" ; } main(){ ... Fsm v( 5,zero,error); ... v.trace(vtrace); }
For the example input in the section, ``A Simple Vending Machine'', the trace output (labeled for readability) would be:
source input target 0 0 1 1 0 2 2 0 3 3 0 4 4 3 0 0 0 1 1 1 3 3 2 0 0 1 2 2 0 3 3 3 0
To de-activate tracing, simply call trace with a zero argument:
v.trace(0);
Unlike an action routine, which is called in the current state, a trace function is called upon arrival in the target state. A trace routine is passed three pieces of information that tell how the machine got there: (1) the original state, (2) the input that caused the transition (if any), and (3) the target state. The constant reference to the Fsm is passed to the tracing routine as the first argument to enable the routine to obtain any additional information it might need about the context of the transition.
Since the transitions caused by functions go(), abort(), and reset() have no associated input values, a negative value is passed to the trace routine as its input argument. If an action routine cancels a state change by calling fire(), go(), abort(), or reset(), no trace call is made for the aborted transition. These two variations on `normal' trace behavior are illustrated below for the traffic light of the section ``A Simple Dynamically-Programmed Fsm''. (asterisks were printed in place of the negative input value.)
flash_off tick flash_on flash_on tick flash_off flash_off **** green go(green) aborts fire(tick) green tick green ...