analysis_peg_realizable.tcl
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 package require page::plugin ;
00035 package require page::util::flow ;
00036 package require page::util::peg ;
00037 package require treeql
00038
00039 namespace ::page::analysis::peg::realizable {
00040 namespace import ::page::util::peg::*
00041 }
00042
00043
00044
00045
00046 ret ::page::analysis::peg::realizable::compute (type t) {
00047
00048 # Ignore call if already done before
00049
00050 if {[$t keyexists root page::analysis::peg::realizable]} return
00051
00052 # We compute the set of realizable nonterminal symbols by doing the
00053 # computation for all partial PE's in the grammar. We start at the
00054 # leaves and then iteratively propagate the property as far as
00055 # possible using the rules defining it, see the specification.
00056
00057 # --- --- --- --------- --------- ---------
00058
00059 # Initialize all nodes and the local arrays. Everything is not
00060 # realizable, except for the terminal leafs of the tree. Their parents
00061 # are scheduled to be visited as well.
00062
00063 array set realizable {} ; # Place where realizable nodes are held
00064 array set unrealizable {} ; # Place where unrealizable nodes are held
00065 array set nc {} ; # Per node, number of children.
00066 array set uc {} ; # Per node, number of realizable children.
00067
00068 set nodeset [$t leaves]
00069
00070 set q [treeql q -tree $t]
00071 $q query tree withatt op * over n {lappend nodeset $n}
00072 $q query tree withatt op ? over n {lappend nodeset $n}
00073 q destroy
00074
00075 foreach n [$t nodes] {
00076 set unrealizable($n) .
00077 set nc($n) [$t numchildren $n]
00078 set uc($n) 0
00079 }
00080
00081 # A node is visited if it _may_ have changed its status (to
00082 # realizability).
00083
00084 page::util::flow $nodeset flow n {
00085 # Realizable nodes cannot change, ignore them.
00086
00087 if {[info exists realizable($n)]} continue
00088
00089 # Determine new state of realizability, ignore a node if it is
00090 # unchanged.
00091
00092 if {![Realizable $t $n nc uc realizable]} continue
00093
00094 # Reclassify changed node, it is now realizable.
00095 unset unrealizable($n)
00096 set realizable($n) .
00097
00098 # Schedule visits to nodes which may have been affected by
00099 # this change. Update the relevant counters as well.
00100
00101 # @ root - none
00102 # @ definition - users of the definition
00103 # otherwise - parent of operator.
00104
00105 if {$n eq "root"} continue
00106
00107 if {[$t keyexists $n symbol]} {
00108 set users [$t get $n users]
00109 $flow visitl $users
00110 foreach u $users {
00111 incr uc($u)
00112 }
00113 continue
00114 }
00115
00116 set p [$t parent $n]
00117 incr uc($p)
00118 $flow visit $p
00119 }
00120
00121 # Set marker preventing future calls.
00122 $t set root page::analysis::peg::realizable [array names realizable]
00123 $t set root page::analysis::peg::unrealizable [array names unrealizable]
00124 return
00125 }
00126
00127 ret ::page::analysis::peg::realizable::remove! (type t) {
00128 # Determine which parts of the grammar are realizable
00129
00130 compute $t
00131
00132 # Remove anything which is not realizable (and all their children),
00133 # except for the root itself, should it be unrealizablel.
00134
00135 set unreal [$t get root page::analysis::peg::unrealizable]
00136 foreach n [lsort $unreal] {
00137 if {$n eq "root"} continue
00138 if {[$t exists $n]} {
00139 $t delete $n
00140 }
00141 }
00142
00143 # Notify the user of the definitions which were among the removed
00144 # nodes. Keep only the still-existing definitions.
00145
00146 set res {}
00147 foreach {sym def} [$t get root definitions] {
00148 if {![$t exists $def]} {
00149 page_warning " $sym: Nonterminal symbol is not realizable, removed."
00150 } else {
00151 lappend res $sym $def
00152 }
00153 }
00154 $t set root definitions $res
00155
00156 if {![$t exists [$t get root start]]} {
00157 page_warning " <Start expression>: Is not realizable, removed."
00158 $t set root start {}
00159 }
00160
00161 # Find and cut operator chains, very restricted. Cut only chains
00162 # of x- and /-operators. The other operators have only one child
00163 # by definition and are thus not chains.
00164
00165 set q [treeql q -tree $t]
00166 # q query tree over n
00167 foreach n [$t children -all root] {
00168 if {[$t keyexists $n symbol]} continue
00169 if {[llength [$t children $n]] != 1} continue
00170 set op [$t get $n op]
00171 if {($op ne "/") && ($op ne "x")} continue
00172 $t cut $n
00173 }
00174
00175 flatten $q $t
00176 q destroy
00177
00178 # Clear computation results.
00179
00180 $t unset root page::analysis::peg::realizable
00181 $t unset root page::analysis::peg::unrealizable
00182
00183 updateUndefinedDueRemoval $t
00184 return
00185 }
00186
00187 ret ::page::analysis::peg::realizable::reset (type t) {
00188 # Remove marker, allow recalculation of realizability after changes.
00189
00190 $t unset root page::analysis::peg::realizable
00191 return
00192 }
00193
00194
00195
00196
00197 ret ::page::analysis::peg::realizable::First (type v) {
00198 upvar 1 $v visit
00199
00200 set id [array startsearch visit]
00201 set first [array nextelement visit $id]
00202 array donesearch visit $id
00203
00204 unset visit($first)
00205 return $first
00206 }
00207
00208 ret ::page::analysis::peg::realizable::Realizable (type t , type node , type ncv , type ucv , type uv) {
00209 upvar 1 $ncv nc $ucv uc $uv realizable
00210
00211 if {$node eq "root"} {
00212 # Root inherits realizability of the start expression.
00213
00214 return [info exists realizable([$t get root start])]
00215 }
00216
00217 if {[$t keyexists $node symbol]} {
00218 # Symbol definitions inherit the realizability of their
00219 # expression.
00220
00221 return [expr {$uc($node) >= $nc($node)}]
00222 }
00223
00224 switch -exact -- [$t get $node op] {
00225 t - .. - epsilon - alpha - alnum - dot - * - ? {
00226 # The terminal symbols are all realizable.
00227 return 1
00228 }
00229 n {
00230 # Symbol invokation inherits realizability of its definition.
00231 # Calls to undefined symbols are not realizable.
00232
00233 set def [$t get $node def]
00234 if {$def eq ""} {return 0}
00235 return [info exists realizable($def)]
00236 }
00237 / - | {
00238 # Choice, ordered and unordered. Realizable if we have at
00239 # least one realizable branch. A quick test based on the count
00240 # of realizable children is used.
00241
00242 return [expr {$uc($node) > 0}]
00243 }
00244 default {
00245 # Sequence, and all other operators, are realizable if and
00246 # only if all its children are realizable. A quick test based
00247 # on the count of realizable children is used.
00248
00249 return [expr {$uc($node) >= $nc($node)}]
00250 }
00251 }
00252 }
00253
00254
00255
00256
00257 package provide page::analysis::peg::realizable 0.1
00258