The fsm module implements a Finite State Machine. Use fsm-new-state to add states to the machine. Then use fsm-new-transition to add transitions between the states. fsm-new-transition returns the new transition. Use ftr-condition@ on this new transition to get a reference to the condition in the transition. This is actually a bit array, see [bar]. Use the words of the bar module to set the condition. When the whole FSM is built, start using the machine by calling fsm-start. By default the first created state is the start state, but this can be changed by fsm-start! After starting the machine, feed events to the machine by fsm-feed. This word returns the new, current state or nil if no transition matched. The machine can be converted to graphviz's dot files by fsm-to-dot. This word uses the labels of the states and transitions to build the dot representation. It also set the shape of the states (double circle for start and end states, circles for the others). Use fst-attributes! and ftr-attributes! to set additional graphviz attributes. During the feeding of events, the optional actions are called. When a state is left, the exit action is called, when a state is entered the entry state is called. If a transition matched, the action of this transition is also called. The stack usage for those actions:
state entry action: fst -- = State fst is entered state exit action: fst -- = State fst is left transition action: n ftr -- = Transition fst matched for event n
include ffl/fsm.fs include ffl/enm.fs \ Example: vending machine \ Enumerate the events begin-enumeration enum: voilence enum: coin enum: choice enum: refuse enum: #events end-enumeration \ Create the finite state machine on the heap with #events events #events fsm-new value machine \ Create the entry and exit action words : say-thank-you ( fst -- = Say 'thank you' after a coin or choice ) drop ." Thank you" cr ; : say-choice? ( fst -- = Ask for choice after the coin ) drop ." Please make your choice" cr ; : say-coin? ( fst -- = Ask for coin after the choice ) drop ." Please enter your coin" cr ; : call-support ( fst -- = Call support after voilence, states data contains the phone number ) ." Voilence against the machine, calling: " fst-data@ . cr ; \ Create the states in the state machine 0 nil ' say-thank-you s" start" machine fsm-new-state value start 0 ' say-choice? ' say-thank-you s" choice?" machine fsm-new-state value choice? 0 ' say-coin? ' say-thank-you s" coin?" machine fsm-new-state value coin? 112 ' call-support nil s" support" machine fsm-new-state value support \ Set extra dot attributes for the support state s" color=red" support fst-attributes! \ Create the transitions for state start, use the bit array to set the condition 0 nil s" coin" start choice? machine fsm-new-transition ftr-condition@ coin swap bar-set-bit 0 nil s" choice" start coin? machine fsm-new-transition ftr-condition@ choice swap bar-set-bit 0 nil s" voilence" start support machine fsm-new-transition ftr-condition@ voilence swap bar-set-bit s" voilence" start fst-find-transition s" color=yellow" rot ftr-attributes! \ Create the transition actions for choice? and coin? states : deliver-choice ( n ftr -- = Deliver the choosen product ) 2drop ." Deliver choice" cr ; : do-refund ( n ftr -- = Refused the product, refund the coin ) 2drop ." Refund coin" cr ; \ Create the transitions for state choice? 0 ' deliver-choice s" choice" choice? start machine fsm-new-transition ftr-condition@ choice swap bar-set-bit 0 ' do-refund s" refuse" choice? start machine fsm-new-transition ftr-condition@ refuse swap bar-set-bit 0 nil s" voilence" choice? support machine fsm-new-transition ftr-condition@ voilence swap bar-set-bit \ Set extra dot attributes for the voilence transition s" voilence" choice? fst-find-transition s" color=yellow" rot ftr-attributes! \ Create the transitions for state coin? 0 ' deliver-choice s" coin" coin? start machine fsm-new-transition ftr-condition@ coin swap bar-set-bit 0 nil s" refuse" coin? start machine fsm-new-transition ftr-condition@ refuse swap bar-set-bit 0 nil s" voilence" coin? support machine fsm-new-transition ftr-condition@ voilence swap bar-set-bit s" voilence" coin? fst-find-transition s" color=yellow" rot ftr-attributes! \ Start the state machine and feed it events machine fsm-start coin machine fsm-feed drop choice machine fsm-feed drop coin machine fsm-feed drop refuse machine fsm-feed drop choice machine fsm-feed drop coin machine fsm-feed drop voilence machine fsm-feed drop \ Create a text output stream for writing the state machine to dot tos-new value dot-tos \ Create the writer word : write-dot ( c-addr u file-id -- flag = Write the string ) write-line 0= ; \ Create the output file s" out.dot" w/o create-file throw value dot-file \ Set the writer word and the file in the stream dot-file ' write-dot dot-tos tos-set-writer \ Write the state machine to the dot-file with graph name "Machine" s" Machine" dot-tos machine fsm-to-dot \ Free the dot stream dot-tos tos-free \ Close the dot file dot-file close-file throw \ To generate an image, use for example: dot -Tpng -o fsm.png out.dot \ ==============================================================================