analysis_peg_realizable.tcl

Go to the documentation of this file.
00001 /*  -*- tcl -*-*/
00002 /*  ### ### ### ######### ######### #########*/
00003 
00004 /*  Perform realizability analysis (x) on the PE grammar delivered by*/
00005 /*  the frontend. The grammar is in normalized form (reduced to*/
00006 /*  essentials, graph like node-x-references, expression trees).*/
00007 /* */
00008 /*  (x) = See "doc_realizable.txt".*/
00009 
00010 /*  This package assumes to be used from within a PAGE plugin. It uses*/
00011 /*  the API commands listed below. These are identical across the major*/
00012 /*  types of PAGE plugins, allowing this package to be used in reader,*/
00013 /*  transform, and writer plugins. It cannot be used in a configuration*/
00014 /*  plugin, and this makes no sense either.*/
00015 /* */
00016 /*  To ensure that our assumption is ok we require the relevant pseudo*/
00017 /*  package setup by the PAGE plugin management code.*/
00018 /* */
00019 /*  -----------------+--*/
00020 /*  page_info        | Reporting to the user.*/
00021 /*  page_warning     |*/
00022 /*  page_error       |*/
00023 /*  -----------------+--*/
00024 /*  page_log_error   | Reporting of internals.*/
00025 /*  page_log_warning |*/
00026 /*  page_log_info    |*/
00027 /*  -----------------+--*/
00028 
00029 /*  ### ### ### ######### ######### #########*/
00030 /*  Requisites*/
00031 
00032 /*  @mdgen NODEP: page::plugin*/
00033 
00034 package require page::plugin     ; /*  S.a. pseudo-package.*/
00035 package require page::util::flow ; /*  Dataflow walking.*/
00036 package require page::util::peg  ; /*  General utilities.*/
00037 package require treeql
00038 
00039 namespace ::page::analysis::peg::realizable {
00040     namespace import ::page::util::peg::*
00041 }
00042 
00043 /*  ### ### ### ######### ######### #########*/
00044 /*  API*/
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 /*  Internal*/
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 /*  Ready*/
00256 
00257 package provide page::analysis::peg::realizable 0.1
00258 

Generated on 21 Sep 2010 for Gui by  doxygen 1.6.1