analysis_peg_reachable.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 package require page::plugin ;
00033 package require page::util::flow ;
00034 package require page::util::peg ;
00035
00036 namespace ::page::analysis::peg::reachable {
00037 namespace import ::page::util::peg::*
00038 }
00039
00040
00041
00042
00043 ret ::page::analysis::peg::reachable::compute (type t) {
00044
00045 # Ignore call if already done before
00046 if {[$t keyexists root page::analysis::peg::reachable]} return
00047
00048 # We compute the set of all nodes which are reachable from the
00049 # root node of the start expression. This is a simple topdown walk
00050 # where the children of all reachable nodes are mode reachable as
00051 # well, and invokations of nonterminals symbols are treated as
00052 # children as well. At the end of the flow all reachable non-
00053 # terminal symbols and their expressions are marked, and none
00054 # other.
00055
00056 # Initialize walking state: 2 arrays, all nodes (except root) are
00057 # in or the other array, and their location tells if they are
00058 # reachable or not. In the beginning no node is reachable. The
00059 # goal array (reach) also serves as minder of which nodes have
00060 # been seen, to cut multiple visits short.
00061
00062 array set unreach {} ; foreach n [$t nodes] {set unreach($n) .}
00063 unset unreach(root)
00064 array set reach {}
00065
00066 # A node is visited if it has been determined that it is indeed
00067 # reachable.
00068
00069 page::util::flow [list [$t get root start]] flow n {
00070 # Ignore nodes already reached.
00071 if {[info exists reach($n)]} continue
00072
00073 # Reclassify node, has been reached now.
00074 unset unreach($n)
00075 set reach($n) .
00076
00077 # Schedule children for visit --> topdown flow.
00078 $flow visitl [$t children $n]
00079
00080 # Treat n-Nodes as special, their definition as indirect
00081 # child. But ignore invokations of undefined nonterminal
00082 # symbols, or those already marked as reachable.
00083
00084 if {![$t keyexists $n op]} continue
00085 if {[$t get $n op] ne "n"} continue
00086
00087 set def [$t get $n def]
00088 if {$def eq ""} continue
00089 if {[info exists reach($def)]} continue
00090 $flow visit $def
00091 }
00092
00093 # Store results. This also serves as marker.
00094
00095 $t set root page::analysis::peg::reachable [array names reach]
00096 $t set root page::analysis::peg::unreachable [array names unreach]
00097 return
00098 }
00099
00100 ret ::page::analysis::peg::reachable::remove! (type t) {
00101
00102 # Determine which nonterminal symbols are reachable from the root
00103 # of the start expression.
00104
00105 compute $t
00106
00107 # Remove all nodes which are not reachable.
00108
00109 set unreach [$t get root page::analysis::peg::unreachable]
00110 foreach n [lsort $unreach] {
00111 if {[$t exists $n]} {
00112 $t delete $n
00113 }
00114 }
00115
00116 # Notify the user of the definitions which were among the removed
00117 # nodes. Keep only the still-existing definitions.
00118
00119 set res {}
00120 foreach {sym def} [$t get root definitions] {
00121 if {![$t exists $def]} {
00122 page_warning " $sym: Unreachable nonterminal symbol, deleting"
00123 } else {
00124 lappend res $sym $def
00125 }
00126 }
00127
00128 # Clear computation results.
00129
00130 $t unset root page::analysis::peg::reachable
00131 $t unset root page::analysis::peg::unreachable
00132
00133 $t set root definitions $res
00134 updateUndefinedDueRemoval $t
00135 return
00136 }
00137
00138 ret ::page::analysis::peg::reachable::reset (type t) {
00139 # Remove marker, allow recalculation of reachability after
00140 # changes.
00141
00142 $t unset root page::analysis::peg::reachable
00143 $t unset root page::analysis::peg::unreachable
00144 return
00145 }
00146
00147
00148
00149
00150 package provide page::analysis::peg::reachable 0.1
00151