dexec.tcl

Go to the documentation of this file.
00001 /*  -*- tcl -*-*/
00002 /*  Grammar / Finite Automatons / Executor, DFA only*/
00003 
00004 /*  ### ### ### ######### ######### #########*/
00005 /*  Package description*/
00006 
00007 /*  Instances take a DFA, keep a current state and update it in*/
00008 /*  reaction incoming symbols. Notable events are reported via*/
00009 /*  callback. Currently notable: Reset, reached a final state,*/
00010 /*  reached an error.*/
00011 
00012 /*  From the above description it should be clear that this class is*/
00013 /*  run in a push fashion. If not the last sentence has made this*/
00014 /*  explicit, right ? Right!*/
00015 
00016 /*  ### ### ### ######### ######### #########*/
00017 /*  Requisites*/
00018 
00019 package require snit   ; /*  Tcllib | OO system used*/
00020 
00021 /*  ### ### ### ######### ######### #########*/
00022 /*  Implementation*/
00023 
00024 snit::type ::grammar::fa::dexec {
00025     /*  ### ### ### ######### ######### #########*/
00026     /*  Type API. */
00027 
00028     /*  ### ### ### ######### ######### #########*/
00029     /*  Instance API.*/
00030 
00031     /* constructor {fa args} {}*/
00032     /* destructor  {}*/
00033 
00034     ret  reset () {}
00035     ret  put  (type sy) {}
00036     ret  state () {}
00037 
00038     option -command {}
00039     option -any     {}
00040 
00041     /*  ### ### ### ######### ######### #########*/
00042     /*  Internal data structures.*/
00043 
00044     /*  We take the relevant information from the FA specified during*/
00045     /*  construction, i.e. start state, final states, and transition*/
00046     /*  table in form for direct indexing and keep it local. No need to*/
00047     /*  access or even the full FA. We require a deterministic one, and*/
00048     /*  will complete it, if necessary.*/
00049 
00050     variable start ; /*  Name of start state.*/
00051     variable final ; /*  Array, existence = state is final.*/
00052     variable trans ; /*  Transition array: state x symbol -> state*/
00053     variable sym   ; /*  Symbol set (as array), for checking existence.*/
00054     variable cmd   ; /*  Command to call for various events. Required.*/
00055     variable any   ; /*  Symbol to map any unknown symbol to. If not*/
00056     /*               ; # specified (eq "") then unknown symbols will  cause non-*/
00057     /*               ; # acceptance.*/
00058     variable curr  ; /*  State the underlying DFA is currently in.*/
00059     variable inerr ; /*  Boolean flag. Set if an error was reached.*/
00060 
00061 
00062     /*  ### ### ### ######### ######### #########*/
00063     /*  Instance API Implementation.*/
00064 
00065     constructor {fa args} {
00066      any =  {}
00067      cmd =  {}
00068     $self configurelist $args
00069 
00070     if {![$fa is deterministic]} {
00071         return -code error "Source FA is not deterministic"
00072     }
00073     if {($any ne "") && ![$fa symbol exists $any]} {
00074         return -code error "Chosen any symbol \"$any\" does not exist"
00075     }
00076     if {![llength $cmd]} {
00077         return -code error "Command callback missing"
00078     }
00079 
00080     /*  In contrast to the acceptor we do not complete the FA. We*/
00081     /*  will later report BADTRANS errors instead if a non-existing*/
00082     /*  transition is attempted. For the acceptor it made sense as*/
00083     /*  it made the accept/!accept decision easier. However here for*/
00084     /*  the generic execution it is unreasonable interference with*/
00085     /*  whatever higher levels might wish to do when encountering*/
00086     /*  this.*/
00087 
00088      start =  [lindex [$fa startstates] 0]
00089     foreach s [$fa finalstates]        { final = ($s) .}
00090     foreach s [ syms =  [$fa symbols]] { sym = ($s) .}
00091 
00092     foreach s [$fa states] {
00093         foreach sy [$fa symbols@ $s] {
00094          trans = ($s,$sy) [lindex [$fa next $s $sy] 0]
00095         }
00096     }
00097 
00098     $self re
00099     return = 
00100     }
00101 
00102     /* destructor {}*/
00103 
00104     onconfigure -command {value} {
00105      options = (-command) $value
00106      cmd =                $value
00107     return
00108     }
00109 
00110     onconfigure -any {value} {
00111      options = (-any) $value
00112      any =            $value
00113     return
00114     }
00115 
00116     /*  --- --- --- --------- --------- ---------*/
00117 
00118     ret  reset () {
00119     set curr  $start
00120     set inerr 0
00121     ## puts -nonewline " \[$curr\]" ; flush stdout
00122 
00123     uplevel #0 [linsert $cmd end \
00124         reset]
00125     return
00126     }
00127 
00128     ret  state () {
00129     return $curr
00130     }
00131 
00132     ret  put (type sy) {
00133     if {$inerr} return
00134     ## puts " --($sy)-->"
00135 
00136     if {![info exists sym($sy)]} {
00137         if {$any eq ""} {
00138         # No any mapping of unknown symbols, report as error
00139         ## puts " BAD SYMBOL"
00140 
00141         set inerr 1
00142         uplevel #0 [linsert $cmd end \
00143             error BADSYM "Bad symbol \"$sy\""]
00144         return
00145         } else {
00146         # Mapping of unknown symbols to any.
00147         set sy $any
00148         }
00149     }
00150 
00151     if {[catch {
00152         set new $trans($curr,$sy)
00153     }]} {
00154         ## puts " NO DESTINATION"
00155         set inerr 1
00156         uplevel #0 [linsert $cmd end \
00157             error BADTRANS "Bad transition (\"$curr\" \"$sy\"), no destination"]
00158         return
00159     }
00160     set curr $new
00161     
00162     uplevel #0 [linsert $cmd end \
00163         state $curr]
00164     
00165     ## puts -nonewline " \[$curr\]" ; flush stdout
00166 
00167     if {[info exists final($curr)]} {
00168         ## puts -nonewline " FINAL" ; flush stdout
00169 
00170         uplevel #0 [linsert $cmd end \
00171             final $curr]
00172     }
00173     return
00174     }
00175 
00176     /*  ### ### ### ######### ######### #########*/
00177     /*  Type API implementation.*/
00178 
00179     /*  ### ### ### ######### ######### #########*/
00180     /*  Type Internals.*/
00181 
00182     /*  ### ### ### ######### ######### #########*/
00183 }
00184 
00185 /*  ### ### ### ######### ######### #########*/
00186 /*  Package Management*/
00187 
00188 package provide grammar::fa::dexec 0.2
00189 

Generated on 21 Sep 2010 for Gui by  doxygen 1.6.1