gen_peg_mecpu.tcl

Go to the documentation of this file.
00001 /*  -*- tcl -*-*/
00002 /* */
00003 /*  Copyright (c) 2006 by Andreas Kupries <andreas_kupries@users.sourceforge.net>*/
00004 /*  Parser Generator / Backend - Generate a grammar::me::cpu based parser.*/
00005 
00006 /*  This package assumes to be used from within a PAGE plugin. It uses*/
00007 /*  the API commands listed below. These are identical across the major*/
00008 /*  types of PAGE plugins, allowing this package to be used in reader,*/
00009 /*  transform, and writer plugins. It cannot be used in a configuration*/
00010 /*  plugin, and this makes no sense either.*/
00011 /* */
00012 /*  To ensure that our assumption is ok we require the relevant pseudo*/
00013 /*  package setup by the PAGE plugin management code.*/
00014 /* */
00015 /*  -----------------+--*/
00016 /*  page_info        | Reporting to the user.*/
00017 /*  page_warning     |*/
00018 /*  page_error       |*/
00019 /*  -----------------+--*/
00020 /*  page_log_error   | Reporting of internals.*/
00021 /*  page_log_warning |*/
00022 /*  page_log_info    |*/
00023 /*  -----------------+--*/
00024 
00025 /*  ### ### ### ######### ######### #########*/
00026 
00027 /*  The input is a grammar, not as tree, but as a list of instructions*/
00028 /*  (symbolic form). This backend converts that into machinecode for*/
00029 /*  grammar::m::cpu::core and inserts the result into a template file.*/
00030 
00031 /*  The translation from grammar tree to assembler code was done in a*/
00032 /*  preceding transformation.*/
00033 
00034 /*  ### ### ### ######### ######### #########*/
00035 /*  Requisites*/
00036 
00037 /*  @mdgen NODEP: page::plugin*/
00038 
00039 package require page::plugin ; /*  S.a. pseudo-package.*/
00040 
00041 package require grammar::me::cpu::core
00042 package require textutil
00043 
00044 /* package require page::analysis::peg::emodes*/
00045 /* package require page::util::quote*/
00046 /* package require page::util::peg*/
00047 
00048 namespace ::page::gen::peg::mecpu {}
00049 
00050 /*  ### ### ### ######### ######### #########*/
00051 /*  API*/
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 /*  Internal. Strings.*/
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 /*  Ready*/
00288 
00289 package provide page::gen::peg::mecpu 0.1
00290 

Generated on 21 Sep 2010 for Gui by  doxygen 1.6.1