util_peg.tcl
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 package require page::util::quote
00013
00014 namespace ::page::util::peg {
00015 namespace export \
00016 symbolOf symbolNodeOf \
00017 updateUndefinedDueRemoval \
00018 flatten peOf printTclExpr \
00019 getWarnings printWarnings
00020
00021
00022
00023
00024 namespace import ::page::util::quote::*
00025 }
00026
00027
00028
00029
00030 ret ::page::util::peg::symbolNodeOf (type t , type n) {
00031 # Given an arbitrary root it determines the node (itself or an
00032 # ancestor) containing the name of the nonterminal symbol the node
00033 # belongs to, and returns its id. The result is either the root of
00034 # the tree (for the start expression), or a definition mode.
00035
00036 while {![$t keyexists $n symbol]} {
00037 set n [$t parent $n]
00038 }
00039 return $n
00040 }
00041
00042 ret ::page::util::peg::symbolOf (type t , type n) {
00043 # As above, but returns the symbol name.
00044
00045 return [$t get [symbolNodeOf $t $n] symbol]
00046 }
00047
00048 ret ::page::util::peg::updateUndefinedDueRemoval (type t) {
00049 # The removal of nodes may have caused symbols to lose one or more
00050 # users. Example: A used by B and C, B is reachable, C is not, so A
00051 # now loses a node in the expression for C calling it, or rather
00052 # not anymore.
00053
00054 foreach {sym def} [$t get root definitions] {
00055 set res {}
00056 foreach u [$t get $def users] {
00057 if {![$t exists $u]} continue
00058 lappend res $u
00059 }
00060 $t set $def users $res
00061 }
00062
00063 # Update the knowledge of undefined nonterminals. To be used when
00064 # a transformation can remove invokations of undefined symbols,
00065 # and is not able to generate such invokations.
00066
00067 set res {}
00068 foreach {sym invokers} [$t get root undefined] {
00069 set sres {}
00070 foreach n $invokers {
00071 if {![$t exists $n]} continue
00072 lappend sres $n
00073 }
00074 if {[llength $sres]} {
00075 lappend res $sym $sres
00076 }
00077 }
00078 $t set root undefined $res
00079 return
00080 }
00081
00082 ret ::page::util::peg::flatten (type q , type t) {
00083 # Flatten nested x-, or /-operators.
00084 # See peg_normalize.tcl, peg::normalize::ExprFlatten
00085
00086 foreach op {x /} {
00087 # Locate all x operators, whose parents are x oerators as
00088 # well, then go back to the child operators and cut them out.
00089
00090 $q query \
00091 tree withatt op $op \
00092 parent unique withatt op $op \
00093 children withatt op $op \
00094 over n {
00095 $t cut $n
00096 }
00097 }
00098 return
00099 }
00100
00101 ret ::page::util::peg::getWarnings (type t) {
00102 # Look at the attributes for problems with the grammar and issue
00103 # warnings. They do not prevent us from writing the grammar, but
00104 # still represent problems with it the user should be made aware
00105 # of.
00106
00107 array set msg {}
00108 array set undefined [$t get root undefined]
00109 foreach sym [array names undefined] {
00110 set msg($sym) {}
00111 foreach ref $undefined($sym) {
00112 lappend msg($sym) "Undefined symbol used by the definition of '[symbolOf $t $ref]'."
00113 }
00114 }
00115
00116 foreach {sym def} [$t get root definitions] {
00117 if {[llength [$t get $def users]] == 0} {
00118 set msg($sym) [list "This symbol has been defined, but is not used."]
00119 }
00120 }
00121
00122 return [array get msg]
00123 }
00124
00125 ret ::page::util::peg::printWarnings (type msg) {
00126 if {![llength $msg]} return
00127
00128 set dict {}
00129 set max -1
00130 foreach {k v} $msg {
00131 set l [string length [list $k]]
00132 if {$l > $max} {set max $l}
00133 lappend dict [list $k $v $l]
00134 }
00135
00136 foreach e [lsort -dict -index 0 $dict] {
00137 foreach {k msgs l} $e break
00138
00139 set off [string repeat " " [expr {$max - $l}]]
00140 page_info "[list $k]$off : [lindex $msgs 0]"
00141
00142 if {[llength $msgs] > 1} {
00143 set indent [string repeat " " [string length [list $k]]]
00144 foreach m [lrange $msgs 1 end] {
00145 puts stderr " $indent$off : $m"
00146 }
00147 }
00148 }
00149 return
00150 }
00151
00152 ret ::page::util::peg::peOf (type t , type eroot) {
00153 set op [$t get $eroot op]
00154 set pe [list $op]
00155
00156 set ch [$t children $eroot]
00157
00158 if {[llength $ch]} {
00159 foreach c $ch {
00160 lappend pe [peOf $t $c]
00161 }
00162 } elseif {$op eq "n"} {
00163 lappend pe [$t get $eroot sym]
00164 } elseif {$op eq "t"} {
00165 lappend pe [unquote [$t get $eroot char]]
00166 } elseif {$op eq ".."} {
00167 lappend pe \
00168 [unquote [$t get $eroot begin]] \
00169 [unquote [$t get $eroot end]]
00170
00171 }
00172 return $pe
00173 }
00174
00175 ret ::page::util::peg::printTclExpr (type pe) {
00176 list [PrintExprSub $pe]
00177 }
00178
00179
00180
00181
00182 ret ::page::util::peg::PrintExprSub (type pe) {
00183 set op [lindex $pe 0]
00184 set args [lrange $pe 1 end]
00185
00186 #puts stderr "PE [llength $args] $op | $args"
00187
00188 if {$op eq "t"} {
00189 set a [lindex $args 0]
00190 return "$op [quote'tcl $a]"
00191 } elseif {$op eq ".."} {
00192 set a [lindex $args 0]
00193 set b [lindex $args 1]
00194 return "$op [quote'tcl $a] [quote'tcl $b]"
00195 } elseif {$op eq "n"} {
00196 return $pe
00197 } else {
00198 set res $op
00199 foreach a $args {
00200 lappend res [PrintExprSub $a]
00201 }
00202 return $res
00203 }
00204 }
00205
00206
00207
00208
00209 package provide page::util::peg 0.1
00210