| 1 | # -*- tcl -*- |
|---|
| 2 | # Grammar / Finite Automatons / Acceptance checker, DFA only |
|---|
| 3 | |
|---|
| 4 | # ### ### ### ######### ######### ######### |
|---|
| 5 | ## Package description |
|---|
| 6 | |
|---|
| 7 | ## A class whose instances take a FA and are able to check strings of |
|---|
| 8 | ## symbols for acceptance. This class is restricted to deterministic |
|---|
| 9 | ## FAs. The FA can be either a reference to some external FA container |
|---|
| 10 | ## object, or a copy of such. The latter makes the acceptor impervious |
|---|
| 11 | ## to changes in the original definition. |
|---|
| 12 | |
|---|
| 13 | # ### ### ### ######### ######### ######### |
|---|
| 14 | ## Requisites |
|---|
| 15 | |
|---|
| 16 | package require snit ; # Tcllib | OO system used |
|---|
| 17 | package require struct::set ; # Tcllib | Extended set operations. |
|---|
| 18 | |
|---|
| 19 | # ### ### ### ######### ######### ######### |
|---|
| 20 | ## Implementation |
|---|
| 21 | |
|---|
| 22 | snit::type ::grammar::fa::dacceptor { |
|---|
| 23 | # ### ### ### ######### ######### ######### |
|---|
| 24 | ## Type API. |
|---|
| 25 | |
|---|
| 26 | # ### ### ### ######### ######### ######### |
|---|
| 27 | ## Instance API. |
|---|
| 28 | |
|---|
| 29 | #constructor {fa args} {} |
|---|
| 30 | #destructor {} |
|---|
| 31 | |
|---|
| 32 | method accept? {symbolstring} {} |
|---|
| 33 | |
|---|
| 34 | option -any {} |
|---|
| 35 | |
|---|
| 36 | # ### ### ### ######### ######### ######### |
|---|
| 37 | ## Internal data structures. |
|---|
| 38 | |
|---|
| 39 | ## We take the relevant information from the FA specified during |
|---|
| 40 | ## construction, i.e. start state, final states, and transition |
|---|
| 41 | ## table in form for direct indexing and keep it local. No need to |
|---|
| 42 | ## access or even the full FA. We require a deterministic one, and |
|---|
| 43 | ## will complete it, if necessary. |
|---|
| 44 | |
|---|
| 45 | variable start ; # Name of start state. |
|---|
| 46 | variable final ; # Array, existence = state is final. |
|---|
| 47 | variable trans ; # Transition array: state x symbol -> state |
|---|
| 48 | variable sym ; # Symbol set (as array), for checking existence. |
|---|
| 49 | variable any ; # Symbol to map any unknown symbol to. If not |
|---|
| 50 | # ; # specified (eq "") then unknown symbols will cause non- |
|---|
| 51 | # ; # acceptance. |
|---|
| 52 | variable stop ; # Stop state, causing immediate non-acceptance when entered. |
|---|
| 53 | |
|---|
| 54 | # ### ### ### ######### ######### ######### |
|---|
| 55 | ## Instance API Implementation. |
|---|
| 56 | |
|---|
| 57 | constructor {fa args} { |
|---|
| 58 | set any {} |
|---|
| 59 | $self configurelist $args |
|---|
| 60 | |
|---|
| 61 | if {![$fa is deterministic]} { |
|---|
| 62 | return -code error "Source FA is not deterministic" |
|---|
| 63 | } |
|---|
| 64 | if {($any ne "") && ![$fa symbol exists $any]} { |
|---|
| 65 | return -code error "Chosen any symbol \"$any\" does not exist" |
|---|
| 66 | } |
|---|
| 67 | |
|---|
| 68 | if {![$fa is complete]} { |
|---|
| 69 | set istmp 1 |
|---|
| 70 | set tmp [grammar::fa ${selfns}::fa = $fa] |
|---|
| 71 | set before [$tmp states] |
|---|
| 72 | $tmp complete |
|---|
| 73 | # Our sink is a stop state. |
|---|
| 74 | set stop [struct::set difference [$tmp states] $before] |
|---|
| 75 | } else { |
|---|
| 76 | set istmp 0 |
|---|
| 77 | set tmp $fa |
|---|
| 78 | # We don't know if there is a sink, so no quickstop. |
|---|
| 79 | set stop {} |
|---|
| 80 | } |
|---|
| 81 | |
|---|
| 82 | set start [lindex [$tmp startstates] 0] |
|---|
| 83 | foreach s [$tmp finalstates] {set final($s) .} |
|---|
| 84 | foreach s [set syms [$tmp symbols]] {set sym($s) .} |
|---|
| 85 | |
|---|
| 86 | foreach s [$tmp states] { |
|---|
| 87 | foreach sy $syms { |
|---|
| 88 | set trans($s,$sy) [lindex [$tmp next $s $sy] 0] |
|---|
| 89 | } |
|---|
| 90 | } |
|---|
| 91 | |
|---|
| 92 | if {$istmp} {$tmp destroy} |
|---|
| 93 | return |
|---|
| 94 | } |
|---|
| 95 | |
|---|
| 96 | #destructor {} |
|---|
| 97 | |
|---|
| 98 | onconfigure -any {value} { |
|---|
| 99 | set options(-any) $value |
|---|
| 100 | set any $value |
|---|
| 101 | return |
|---|
| 102 | } |
|---|
| 103 | |
|---|
| 104 | # --- --- --- --------- --------- --------- |
|---|
| 105 | |
|---|
| 106 | method accept? {symbolstring} { |
|---|
| 107 | set state $start |
|---|
| 108 | |
|---|
| 109 | ## puts "\n====================== ($symbolstring)" |
|---|
| 110 | |
|---|
| 111 | if {$any eq ""} { |
|---|
| 112 | # No any mapping of unknown symbols. |
|---|
| 113 | |
|---|
| 114 | foreach sy $symbolstring { |
|---|
| 115 | if {![info exists sym($sy)]} { |
|---|
| 116 | # Bad symbol in input. String is not accepted, |
|---|
| 117 | # abort immediately. |
|---|
| 118 | ## puts " \[$state\] -- Unknown symbol ($sy)" |
|---|
| 119 | return 0 |
|---|
| 120 | } |
|---|
| 121 | |
|---|
| 122 | ## puts " \[$state\] --($sy)--> " |
|---|
| 123 | |
|---|
| 124 | set state $trans($state,$sy) |
|---|
| 125 | # state == "" cannot happen, as our FA is complete. |
|---|
| 126 | if {$state eq $stop} { |
|---|
| 127 | # This is a known sink, we can stop processing input now. |
|---|
| 128 | ## puts " \[$state\] FULL STOP" |
|---|
| 129 | return 0 |
|---|
| 130 | } |
|---|
| 131 | } |
|---|
| 132 | |
|---|
| 133 | } else { |
|---|
| 134 | # Mapping of unknown symbols to any. |
|---|
| 135 | |
|---|
| 136 | foreach sy $symbolstring { |
|---|
| 137 | if {![info exists sym($sy)]} {set sy $any} |
|---|
| 138 | ## puts " \[$state\] --($sy)--> " |
|---|
| 139 | set state $trans($state,$sy) |
|---|
| 140 | # state == "" cannot happen, as our FA is complete. |
|---|
| 141 | if {$state eq $stop} { |
|---|
| 142 | # This is a known sink, we can stop processing input now. |
|---|
| 143 | ## puts " \[$state\] FULL STOP" |
|---|
| 144 | return 0 |
|---|
| 145 | } |
|---|
| 146 | } |
|---|
| 147 | } |
|---|
| 148 | |
|---|
| 149 | ## puts " \[$state\][expr {[info exists final($state)] ? " ACCEPT" : ""}]" |
|---|
| 150 | |
|---|
| 151 | return [info exists final($state)] |
|---|
| 152 | } |
|---|
| 153 | |
|---|
| 154 | # ### ### ### ######### ######### ######### |
|---|
| 155 | ## Type API implementation. |
|---|
| 156 | |
|---|
| 157 | # ### ### ### ######### ######### ######### |
|---|
| 158 | ## Type Internals. |
|---|
| 159 | |
|---|
| 160 | # ### ### ### ######### ######### ######### |
|---|
| 161 | } |
|---|
| 162 | |
|---|
| 163 | # ### ### ### ######### ######### ######### |
|---|
| 164 | ## Package Management |
|---|
| 165 | |
|---|
| 166 | package provide grammar::fa::dacceptor 0.1.1 |
|---|