gen_peg_mecpu.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
00035
00036
00037
00038
00039 package require page::plugin ;
00040
00041 package require grammar::me::cpu::core
00042 package require textutil
00043
00044
00045
00046
00047
00048 namespace ::page::gen::peg::mecpu {}
00049
00050
00051
00052
00053 ret ::page::gen::peg::mecpu::package (type text) {
00054 variable package $text
00055 return
00056 }
00057
00058 ret ::page::gen::peg::mecpu::copyright (type text) {
00059 variable copyright $text
00060 return
00061 }
00062
00063 ret ::page::gen::peg::mecpu::template (type path) {
00064 variable template $path
00065 return
00066 }
00067
00068 ret ::page::gen::peg::mecpu::cmarker (type list) {
00069 variable cmarker $list
00070 return
00071 }
00072
00073 ret ::page::gen::peg::mecpu (type asmcode , type chan) {
00074
00075 # asmcode = list (name code)
00076 # code = list (instruction)
00077 # instruction = list (label name arg...)
00078
00079 variable mecpu::package
00080 variable mecpu::copyright
00081 variable mecpu::cmarker
00082 variable mecpu::template
00083 variable mecpu::template_file
00084
00085 # Import the config options, provide fallback to defaults for the
00086 # unspecified parts.
00087
00088 set gname [lindex $asmcode 0]
00089 set gcode [lindex $asmcode 1]
00090
00091 if {$package eq ""} {set package $gname}
00092
00093 page_info " Grammar: $gname"
00094 page_info " Package: $package"
00095
00096 if {$copyright ne ""} {
00097 page_info " Copyright: $copyright"
00098 set copyright "\#\# (C) $copyright\n"
00099 }
00100
00101 if {$template eq ""} {
00102 set template $template_file
00103 }
00104
00105 page_info " Template: $template"
00106
00107 # Translate the incoming assembler to machine code.
00108
00109 set mcode [grammar::me::cpu::core::asm $gcode]
00110
00111 # We know that the machine code has three parts (instructions,
00112 # string pool, token map). We take the data apart to allow separate
00113 # insertion if the template so chooses (like for readability).
00114
00115 foreach {minsn mpool mtmap} $mcode break
00116
00117 set fminsn {} ; set i 0 ; set j 19
00118 while {$i < [llength $minsn]} {
00119 append fminsn " [lrange $minsn $i $j]\n"
00120 incr i 20 ; incr j 20
00121 }
00122
00123 set fmpool {} ; set i 0 ; set j 4
00124 while {$i < [llength $mpool]} {
00125 append fmpool " [lrange $mpool $i $j]\n"
00126 incr i 5 ; incr j 5
00127 }
00128
00129 # ------------------------------------
00130 # We also generate a readable representation of the assembler
00131 # instructions for insertion into a comment area.
00132
00133 set asmp [mecpu::2readable $gcode $minsn]
00134
00135 # ------------------------------------
00136
00137 # And write the modified template
00138 puts $chan [string map [list \
00139 @NAME@ $gname \
00140 @PKG@ $package \
00141 @COPY@ $copyright \
00142 @CODE@ $mcode \
00143 @INSN@ $minsn \
00144 @FNSN@ $fminsn \
00145 @POOL@ $mpool \
00146 @FPOL@ $fmpool \
00147 @TMAP@ $mtmap \
00148 @ASMP@ $asmp \
00149 ] [mecpu::Template]]
00150 return
00151 }
00152
00153 ret ::page::gen::peg::mecpu::Template () {
00154 variable template
00155 return [string trimright [read [set ch [open $template r]]][close $ch]]
00156 }
00157
00158 ret ::page::gen::peg::mecpu::2readable (type asmcode , type mecode) {
00159 return [2print $asmcode $mecode max [widths $asmcode max]]
00160 }
00161
00162 ret ::page::gen::peg::mecpu::widths (type asmcode , type mv) {
00163 upvar 1 $mv max
00164
00165 # First iteration, column widths (instructions, and arguments).
00166 # Ignore comments, they go across all columns.
00167 # Also ignore labels (lrange 1 ..).
00168
00169 set mc 0
00170 foreach insn $asmcode {
00171 set i [lindex $insn 1]
00172 if {$i eq ".C"} continue
00173 set col 0
00174
00175 foreach x [lrange $insn 1 end] {
00176 set xlen [string length $x]
00177 if {![info exists max($col)] || ($xlen > $max($col))} {set max($col) $xlen}
00178 incr col
00179
00180 # Shift the strings of various commands into the third
00181 # column, if they are not already there.
00182
00183 if {$i eq "ier_nonterminal"} {incr col ; set i ""}
00184 if {$i eq "isv_nonterminal_leaf"} {incr col ; set i ""}
00185 if {$i eq "isv_nonterminal_range"} {incr col ; set i ""}
00186 if {$i eq "isv_nonterminal_reduce"} {incr col ; set i ""}
00187 if {$i eq "inc_save"} {incr col ; set i ""}
00188 if {$i eq "ict_advance"} {incr col ; set i ""}
00189 }
00190 if {$col > $mc} {set mc $col}
00191 }
00192
00193 set max($mc) 0
00194 return $mc
00195 }
00196
00197 ret ::page::gen::peg::mecpu::2print (type asmcode , type mecode , type mv , type mc) {
00198 variable cmarker
00199 upvar 1 $mv max
00200
00201 set lines {}
00202 set pc 0
00203
00204 foreach insn $asmcode {
00205 foreach {label name} $insn break
00206 if {$name eq ".C"} {lappend lines "" "-- [join [lrange $insn 2 end] " "]" ""}
00207 if {$label ne ""} {lappend lines " ${label}:" }
00208 if {$name eq ".C"} continue
00209
00210 set line " [format %05d $pc] "
00211
00212 set pcs $pc
00213 incr pc [llength $insn] ; incr pc -1
00214 set pce $pc ; incr pce -1
00215 set imecode [lrange $mecode $pcs $pce]
00216
00217 if {
00218 ($name eq "ier_nonterminal") ||
00219 ($name eq "isv_nonterminal_leaf") ||
00220 ($name eq "isv_nonterminal_range") ||
00221 ($name eq "isv_nonterminal_reduce") ||
00222 ($name eq "inc_save") ||
00223 ($name eq "ict_advance")
00224 } {
00225 # Shift first argument into 2nd column, and quote it as well.
00226 set insn [lreplace $insn 2 2 "" '[lindex $insn 2]']
00227 } elseif {
00228 ($name eq "inc_restore") ||
00229 ($name eq "ict_match_token") ||
00230 ($name eq "ict_match_tokclass")
00231 } {
00232 # Command with quoted arguments, no shifting.
00233 set insn [lreplace $insn 3 3 '[lindex $insn 3]']
00234 } elseif {
00235 ($name eq "ict_match_tokrange")
00236 } {
00237 # Command with quoted arguments, no shifting.
00238 set insn [lreplace $insn 4 4 '[lindex $insn 4]']
00239 }
00240
00241 while {[llength $insn] <= $mc} {lappend insn ""}
00242 lappend insn "-- $imecode"
00243
00244 set col 0
00245 foreach x [lrange $insn 1 end] {
00246 set xlen [string length $x]
00247 append line " "
00248 append line $x
00249 append line [string repeat " " [expr {$max($col) - $xlen}]]
00250 incr col
00251 }
00252
00253 lappend lines $line
00254 }
00255
00256 # Wrap the lines into a comment.
00257
00258 if {$cmarker eq ""} {set cmarker "\#"}
00259
00260 if {[llength $cmarker] > 1} {
00261 # Comments are explictly closed as well.
00262
00263 foreach {cs ce} $cmarker break
00264 return "$cs [join $lines " $ce\n$cs "] $ce"
00265 } else {
00266 # Comments are not explicitly closed. Implicit by end-of-line
00267
00268 return "$cmarker [join $lines "\n$cmarker "]"
00269 }
00270 }
00271
00272
00273
00274
00275 namespace ::page::gen::peg::mecpu {
00276
00277 variable here [file dirname [info script]]
00278 variable template_file [file join $here gen_peg_mecpu.template]
00279
00280 variable package ""
00281 variable copyright ""
00282 variable template ""
00283 variable cmarker ""
00284 }
00285
00286
00287
00288
00289 package provide page::gen::peg::mecpu 0.1
00290