[= AutoGen5 Template
# AutoGen copyright 1992-2006 Bruce Korb
=][=
DEFINE emit-invalid-msg =][=
;; "defs" indexes will be diverted.
(define tmp-text "")
(define str-table (string-append "z" Pfx "Strings"))
(string-table-new str-table)
(define add-tbl-str (lambda (ent-str)
(set! index-list (string-append index-list
(number->string (string-table-add str-table ent-str)) "\n" )) ))
(string-table-add str-table "** OUT-OF-RANGE **")
(ag-fprintf 0 "\n#define %sFsmErr_off %d\n" Pfx
(string-table-add str-table
"FSM Error: in state %d (%s), event %d (%s) is invalid\n"))
(define invalid-ix (string-table-add str-table "invalid"))
(ag-fprintf 0 "#define %sEvInvalid_off %d\n" Pfx invalid-ix)
(define index-list (sprintf "%d\n" (string-table-add str-table "init")))
(ag-fprintf 0 "#define %sStInit_off %s\n" Pfx index-list)
(out-push-new)
=][=
FOR state =][=
(add-tbl-str (string-downcase! (get "state"))) =][=
ENDFOR state =][=
(ag-fprintf 0 "\nstatic const size_t asz%sStates[%d] = {\n"
Pfx (+ 1 (count "state")) )
(emit (shell (string-append
"${CLexe-columns} --spread=1 -I4 -S, <<_EOF_\n"
index-list
"_EOF_"
)))
(set! index-list "")
" };\n" =][=
FOR event =][=
(set! tmp-text (if (exist? (get "event"))
(get (get "event"))
(string-downcase! (get "event")) ))
(add-tbl-str tmp-text)
=][=
ENDFOR event =][=
(ag-fprintf 0 "\nstatic const size_t asz%sEvents[%d] = {\n"
Pfx (+ 1 (count "event")) )
(emit (shell (string-append
"${CLexe-columns} --spread=1 -I4 -S, <<_EOF_\n"
index-list
(sprintf "%d\n" invalid-ix)
"_EOF_")))
(emit " };\n")
(out-suspend "strings")
(emit-string-table str-table)
(out-resume "strings")
(emit (out-pop #t)) =]
#define [=(. PFX)
=]_EVT_NAME(t) ( (((unsigned)(t)) >= [=(+ 1 (count "event"))=]) \
? z[=(. Pfx)=]Strings : z[=(. Pfx)
=]Strings + asz[=(. Pfx)=]Events[t])
#define [=(. PFX)
=]_STATE_NAME(s) ( (((unsigned)(s)) >= [=(+ 1 (count "state"))=]) \
? z[=(. Pfx)=]Strings : z[=(. Pfx)
=]Strings + asz[=(. Pfx)=]States[s])
#ifndef EXIT_FAILURE
# define EXIT_FAILURE 1
#endif
static int [=(. pfx)=]_invalid_transition( te_[=(. pfx)=]_state st, te_[=
(. pfx)=]_event evt );
/* * * * * * * * * THE CODE STARTS HERE * * * * * * * *
*
* Print out an invalid transition message and return EXIT_FAILURE
*/
static int
[=(. pfx)=]_invalid_transition( te_[=(. pfx)=]_state st, te_[=
(. pfx)=]_event evt )
{
[=(extract fsm-source " /* %s == INVALID TRANS MSG == %s */" ""
(sprintf
" char const * const fmt = z%1$sStrings + %1$sFsmErr_off;
fprintf( stderr, fmt, st, %2$s_STATE_NAME(st), evt, %2$s_EVT_NAME(evt));"
Pfx PFX ) )=]
return EXIT_FAILURE;
}
[=
ENDDEF emit-invalid-msg =][=
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # =][=
DEFINE emit-cookie-args =][=
FOR cookie =]
[=cookie=],[=
ENDFOR =][=
ENDDEF emit-cookie-args =][=
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # =][=
DEFINE build-callback =][=
CASE cb-name =][=
= noop =][=
* =]
static te_[=(. pfx)=]_state
[=cb_prefix=]_[=cb_name=]([= emit-cookie-args =]
te_[=(. pfx)=]_state initial,
te_[=(. pfx)=]_state maybe_next,
te_[=(. pfx)=]_event trans_evt )
{
[= (extract fsm-source (string-append
"/* %s == " (string-tr! (get "cb_name") "a-z_-" "A-Z ") " == %s */" )
""
(if (= (get "cb-name") "invalid")
(sprintf " exit( %s_invalid_transition( initial, trans_evt ));" pfx)
" return maybe_next;" )) =]
}
[=
ESAC =][=
ENDDEF build-callback
# # # # # # # =][=
DEFINE run-callback
=]
if (pT != NULL)
nxtSt = (*pT)( [=
FOR cookie =][=
(shellf "echo '%s'|sed 's,.*[ \t],,'" (get "cookie")) =], [=
ENDFOR =][=(. pfx)=]_state, nxtSt, trans_evt );[=
ENDDEF run-callback
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # =][=
DEFINE build-switch =]
case [=cb_prefix=]_[=cb_name=]:[=
IF (== (get "cb_name") "NOOP") =] break;[=
ELSE =]
[=
(set! example-code (if (= (get "cb_name") "invalid") (sprintf
" exit( %1$s_invalid_transition( %1$s_state, trans_evt ));" pfx)
(string-append " nxtSt = HANDLE_" (get "cb_name") "();") ))
(extract fsm-source
(string-append " /* %s == " (get "cb_name") " == %s */")
"" example-code ) =]
break;
[=ENDIF=][=
ENDDEF build-switch
# # # # # # # =][=
DEFINE run-switch =][=
(define example-code "") =]
switch (trans) {[=
`set -- \`sed 's/,//' .fsm.xlist\`` =][=
WHILE `echo $#` =][=
invoke build-switch
cb_prefix = (string-append PFX "_TR")
cb_name = (shell "echo $1 ; shift") =][=
ENDWHILE echo $# =]
default:
[=(extract fsm-source " /* %s == BROKEN MACHINE == %s */" ""
(string-append " exit( " pfx "_invalid_transition( "
pfx "_state, trans_evt ));" ))=]
}[=
ENDDEF run-switch
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # =][=
DEFINE preamble
=][=
(if (== (suffix) "c")
(begin
(set! fsm-source ".fsm.code")
(set-writable) )
(begin
(define pfx (string->c-name! (string-downcase!
(if (exist? "prefix") (get "prefix") (base-name)) )))
(define PFX (string-upcase pfx))
(define Pfx (string-capitalize pfx))
(define t-trans (string-append "t_" pfx "_transition"))
(define fsm-source ".fsm.head") )
)
(dne " * " "/* ") =]
*
* Automated Finite State Machine
*
* Copyright (c) 2001-2006 by Bruce Korb
*
[=(bsd "AutoFSM" "Bruce Korb" " * ")=]
*/[=
ENDDEF preamble
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # =][=
DEFINE compute-transitions =][=
;;; Initialize every possible transition as invalid
;;;
(define tr_name (if (=* (get "method") "call")
(string-append "&" pfx "_do_invalid")
(string-append PFX "_TR_INVALID") ))
(shellf
"ev_list='%s' ; st_list='INIT %s'
for f in $ev_list ; do for g in $st_list
do eval FSM_TRANS_${g}_${f}=\"'{ %s_ST_INVALID, %s }'\"
export FSM_TRANS_${g}_${f}
done ; done"
(string-upcase! (join " " (stack "event")))
(string-upcase! (join " " (stack "state")))
PFX tr_name )
(define tev "")
(define tst "")
(define ttype "")
(define next "")
(define proc-ptr-type
(lambda (tp)
(if (= tp "noop") "NULL"
(string-downcase! (string-append "&" pfx "_do_" tp)) )))
=][=#
;;; Now replace the initial values with proper ones gotten from
;;; the trasition definitions.
;;;
;;; It is actually possible to have multiple specifications for a
;;; single state/event pair, however the last state/event assignment
;;; will supply the value for the transition table. Different
;;; transitions may also specify the same transition method. For
;;; that, we unique sort the list and eliminate dups that way. The
;;; unique-ified list is used to produce the callout table.
;;;
=][=
FOR transition =][=
IF (== (get "tst") "*") =][=
;; This transition applies for all states
;;
(set! tev (string-upcase! (get "tev")))
(set! ttype (if (exist? "ttype") (get "ttype")
(string-append "${f}_" tev) ))
(set! tr_name (if (=* (get "method") "call")
(proc-ptr-type ttype)
(string-upcase! (string-append PFX "_TR_" ttype)) ))
(set! next (if (exist? "next") (string-upcase! (get "next")) "${f}"))
(shellf
"for f in ${st_list} ; do F=${f}
eval FSM_TRANS_${f}_%s=\"'{ %s_ST_%s, %s }'\"
done"
tev PFX next tr_name ) =][=
ELIF (== (get "tev") "*") =][=
;; This transition applies for all transitions in a certain state
;;
(set! tst (string-upcase! (get "tst")))
(set! ttype (if (exist? "ttype")
(string-upcase! (get "ttype")) (string-append tst "_${f}") ))
(set! tr_name (if (=* (get "method") "call")
(proc-ptr-type ttype)
(string-append PFX "_TR_" ttype) ))
(set! next (if (exist? "next") (string-upcase! (get "next")) tst))
(shellf
"for f in ${ev_list} ; do
eval FSM_TRANS_%s_${f}=\"'{ %s_ST_%s, %s }'\"
done"
tst PFX next tr_name) =][=
ELSE =][=
FOR tst =][=
(set! tst (string-upcase! (get "tst")))
(set! next (if (exist? "next") (string-upcase! (get "next")) tst))
=][=
FOR tev =][=
(set! tev (string-upcase! (get "tev")))
(set! ttype (string-downcase! (if (exist? "ttype") (get "ttype")
(string-append tst "_" tev) )))
(set! tr_name (if (=* (get "method") "call")
(proc-ptr-type ttype)
(string-upcase! (string-append PFX "_TR_" ttype)) ))
(shellf "FSM_TRANS_%s_%s=\"{ %s_ST_%s, %s }\""
tst tev PFX next tr_name) =][=
ENDFOR tev =][=
ENDFOR tst =][=
ENDIF tst or ttkn as '*' =][=
ENDFOR transition =][=
(define trans-ct
(shellf
"env | egrep '^FSM_TRANS_' | \
sed '/, NULL }/d;s/^.*%s//;s/ .*$/,/' | \
sort -u > .fsm.xlist
echo `wc -l < .fsm.xlist` "
(if (=* (get "method") "call")
(string-append pfx "_do_")
(string-append PFX "_TR_"))
) ) =][=
ENDDEF compute-transitions =]