1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
|
# -*- tcl -*-
# ### ### ### ######### ######### #########
## Package description
## Utility commands for the conversion between various representations
## of abstract syntax trees.
# ### ### ### ######### ######### #########
## Requisites
namespace eval ::grammar::me::util {
namespace export ast2tree ast2etree tree2ast
}
# ### ### ### ######### ######### #########
## Implementation
# ### ### ### ######### ######### #########
## API Implementation.
proc ::grammar::me::util::ast2tree {ast tree {root {}}} {
# See grammar::me_ast for the specification of both value and tree
# representations.
if {$root eq ""} {
set root [$tree rootname]
}
# Decompose the AST value into its components.
if {[llength $ast] < 3} {
return -code error "Bad node \"$ast\", not enough elements"
}
set type [lindex $ast 0]
set range [lrange $ast 1 2]
set children [lrange $ast 3 end]
if {($type eq "") && [llength $children]} {
return -code error \
"Terminal node \"[lrange $ast 0 2]\" has children"
}
foreach {s e} $range break
if {
![string is integer -strict $s] || ($s < 0) ||
![string is integer -strict $e] || ($e < 0)
} {
return -code error "Bad range information \"$range\""
}
# Create a node for the root of the AST and fill it with the data
# from the value. Afterward recurse and build the tree for the
# children of the root.
set new [lindex [$tree insert $root end] 0]
if {$type eq ""} {
$tree set $new type terminal
} else {
$tree set $new type nonterminal
$tree set $new detail $type
}
$tree set $new range $range
foreach child $children {
ast2tree $child $tree $new
}
return
}
proc ::grammar::me::util::ast2etree {ast mcmd tree {root {}}} {
# See grammar::me_ast for the specification of both value and tree
# representations.
if {$root eq ""} {
set root [$tree rootname]
}
# Decompose the AST value into its components.
if {[llength $ast] < 3} {
return -code error "Bad node \"$ast\", not enough elements"
}
set type [lindex $ast 0]
set range [lrange $ast 1 2]
set children [lrange $ast 3 end]
if {($type eq "") && [llength $children]} {
return -code error \
"Terminal node \"[lrange $ast 0 2]\" has children"
}
foreach {s e} $range break
if {
![string is integer -strict $s] || ($s < 0) ||
![string is integer -strict $e] || ($e < 0)
} {
return -code error "Bad range information \"$range\""
}
# Create a node for the root of the AST and fill it with the data
# from the value. Afterward recurse and build the tree for the
# children of the root.
set new [lindex [$tree insert $root end] 0]
if {$type eq ""} {
set cmd $mcmd
lappend cmd tok
foreach loc $range {lappend cmd $loc}
$tree set $new type terminal
$tree set $new detail [uplevel \#0 $cmd]
} else {
$tree set $new type nonterminal
$tree set $new detail $type
}
set range_lc {}
foreach loc $range {
lappend range_lc [uplevel \#0 \
[linsert $mcmd end lc $loc]]
}
$tree set $new range $range
$tree set $new range_lc $range_lc
foreach child $children {
ast2etree $child $mcmd $tree $new
}
return
}
proc ::grammar::me::util::tree2ast {tree {root {}}} {
# See grammar::me_ast for the specification of both value and tree
# representations.
if {$root eq ""} {
set root [$tree rootname]
}
set value {}
if {![$tree keyexists $root type]} {
return -code error "Bad node \"$root\", type information is missing"
}
if {![$tree keyexists $root range]} {
return -code error "Bad node \"$root\", range information is missing"
}
set range [$tree get $root range]
if {[llength $range] != 2} {
return -code error "Bad node \"root\", bad range information \"$range\""
}
foreach {s e} $range break
if {
![string is integer -strict $s] || ($s < 0) ||
![string is integer -strict $e] || ($e < 0)
} {
return -code error "Bad node \"root\", bad range information \"$range\""
}
if {[$tree get $root type] eq "terminal"} {
lappend value {}
} else {
if {![$tree keyexists $root detail]} {
return -code error "Bad node \"$root\", nonterminal detail is missing"
}
lappend value [$tree get $root detail]
}
# Range data ...
lappend value $s $e
foreach child [$tree children $root] {
lappend value [tree2ast $tree $child]
}
return $value
}
# ### ### ### ######### ######### #########
## Package Management
package provide grammar::me::util 0.1
|