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 \ ==============================================================================