|
Warning: this is an htmlized version!
The original is here, and the conversion rules are here. |
#!/usr/bin/tclsh
# (find-es "crim" "tclstuff2")
# (find-fline "~/CRIM1/tclstuff")
# «.variables» (to "variables")
# «.top_level» (to "top_level")
# «.run_» (to "run_")
# «.Xprims_support» (to "Xprims_support")
# «.Xprims» (to "Xprims")
# «.building_strings» (to "building_strings")
# «.file_functions» (to "file_functions")
# «.test:prims» (to "test:prims")
# «.test:prototf» (to "test:prototf")
# «.test:printing» (to "test:printing")
# «variables» (to ".variables")
# Lists:
set FIPprims_used {}
set SFprims_used {}
set Fprims_used {}
set Hprims_used {}
# Arrays:
# word_action
# prim_code
# prim_status
# Strings:
set asm_code {}
set asm_defs {}
set C_defs {}
set FIPprims_code {}
set SFprims_code {}
set Fprims_code {}
set Hprims_code {}
set SF_TO_F_code {}
# (find-node "(nasm)Section 5.4" "extern _printf")
# (find-node "(nasm)Section 5.5" "global _main")
# The section is ".data" because we want the crim code read-write.
#
set asm_headers {%macro dwhl 1.nolist
db (%1) >> 8
db (%1) & 0xFF
%endmacro
%macro dwhla 1.nolist
db ((%1)-_f0) >> 8
db ((%1)-_f0) & 0xFF
%endmacro
SECTION .data
global _f0
_f0:
}
#%%%%
#
# top-level functions
#
#%%%%
# «top_level» (to ".top_level")
# Not really written yet, but the idea is that to run a word (which
# generally means compiling the address corresponding to it) what we
# do is:
#
# uplevel #0 $word_action($word)
proc run {args} { global word_action
foreach word $args {
uplevel #0 $word_action($word)
}
}
#%%%%
#
# main "run_" functions
# (used for compiling "db"s)
#
#%%%%
# «run_» (to ".run_")
proc assert_used {listvar word} {global $listvar prim_status
if {![info exists prim_status($word)] || $prim_status($word)==""} {
lappend $listvar $word
set prim_status($word) USED
}
}
proc run_Hprim {word} {global asm_code
assert_used Hprims_used $word
append asm_code "\tdb $word\n"
}
proc run_SFprim {sfword} {global asm_code
regexp {^S(F_.*)$} $sfword -> fword
assert_used Fprims_used $fword
assert_used SFprims_used $sfword
append asm_code "\tdb $sfword\n"
}
proc run_Fprim {word} {global asm_code
assert_used Fprims_used $word
append asm_code "\tdwhl $word\n"
}
# Every FIPprim declared is treated as used, and there is no db'ing
# for them; so, no run_FIPprim.
proc run_Fadr {word} {global asm_code
append asm_code "\tdwhla $word\n"
}
#%%%%
#
# Support for the high-level defining functions
#
#%%%%
# «Xprims_support» (to ".Xprims_support")
proc nasmify {str} {
if {$str==""} { error "Tried to nasmify the null string" }
set re {[A-Za-z]}
set nasmstr {}
foreach c [split $str {}] {
if {[regexp {[0-9A-Za-z_]} $c]} {
append nasmstr $c
} else {
scan $c "%c" ord
append nasmstr [format "x%02x" $ord]
}
}
return $nasmstr
}
proc has_space {str} { expr {[string first " " $str]!=-1} }
proc nasm_namep {str} { regexp {^[0-9A-Za-z_]+$} $str }
# A function to reorder lists of arguments in a certain way.
# Args with spaces are considered as the def for the preceding args.
# Also select the first arg which is a valid nasm name.
# Example:
# untitled1 {? a b c {1 + 2} * && { hello }}
# -> {a {? a b c} {1 + 2}
# {} {* &&} { hello }}
#
proc bigreorder {list} {
set names {}
set nasmname {}
set result {}
foreach arg $list {
if {[has_space $arg]} {
if {$names==""} {
error "a def was not preceded by any names: [list $arg]"
}
lappend result $nasmname $names $arg
set names {}
set nasmname {}
} else {
if {$nasmname=="" && [nasm_namep $arg]} {
set nasmname $arg
}
lappend names $arg
}
}
if {$names!=""} {
error "there were names not followed by a def: $names"
}
return $result
}
proc bigreorder_nasm {list} {
set result {}
foreach {nasmname othernames def} [bigreorder $list] {
if {$nasmname==""} { set nasmname [nasmify [lindex $othernames 0]] }
lappend result $nasmname $othernames $def
}
return $result
}
# puts [bigreorder {? a b c {1 + 2} * && { hello }}]
# puts [bigreorder {? a b c {1 + 2} * && { hello } quux faz}]
# puts [bigreorder {? a b c {1 + 2} { hello } quux}]
#%%%%
#
# High-level functions to define primitives
#
#%%%%
# «Xprims» (to ".Xprims")
proc FIPprims {args} { global word_action prim_code
foreach {nasmname othernames def} [bigreorder_nasm $args] {
set prim_code(FIP_$nasmname) $def
assert_used FIPprims_used FIP_$nasmname
}
}
proc Fprims {args} { global word_action prim_code
foreach {nasmname othernames def} [bigreorder_nasm $args] {
set prim_code(F_$nasmname) $def
foreach word $othernames {
set word_action($word) [list run_Fprim F_$nasmname]
set word_action(F_$word) [list run_Fprim F_$nasmname]
}
}
}
proc SFprims {args} { global word_action prim_code
foreach {nasmname othernames def} [bigreorder_nasm $args] {
set prim_code(F_$nasmname) $def
foreach word $othernames {
set word_action($word) [list run_SFprim SF_$nasmname]
set word_action(SF_$word) [list run_SFprim SF_$nasmname]
set word_action(F_$word) [list run_Fprim F_$nasmname]
}
}
}
proc Hprims {args} { global word_action prim_code
foreach {nasmname othernames def} [bigreorder_nasm $args] {
set prim_code(H_$nasmname) $def
foreach word $othernames {
set word_action($word) [list run_Hprim H_$nasmname]
set word_action($word:) [list run_Hprim H_$nasmname]
}
}
}
#%%%%
#
# Functions to build strings for the
# "define"s, "switch"s, externs and arrays
#
#%%%%
# «building_strings» (to ".building_strings")
proc define%02X {word n} {global C_defs asm_defs
append C_defs [format "#define %-16s 0x%02X\n" $word $n]
append asm_defs [format "%%define %-16s 0x%02X\n" $word $n]
}
proc define%04X {word n} {global C_defs asm_defs
append C_defs [format "#define %-16s 0x%04X\n" $word $n]
append asm_defs [format "%%define %-16s 0x%04X\n" $word $n]
}
# This function "prepares" the following vars:
# C_defs asm_defs
# H_LAST FIP_LAST SF_LAST F_LAST
# Hprims_code FIPprims_code Fprims_code SF_TO_F_code
#
proc set_final_prim_data {} {
uplevel #0 {
set n [expr 0xFF]
foreach word $Hprims_used {
set prim_opcode($word) $n; define%02X $word $n; incr n -1
append Hprims_code "case $word: $prim_code($word)"
}
define%02X H_LAST [expr $n+1]
set n [expr 0xFFFF]
foreach word $FIPprims_used {
set prim_opcode($word) $n; define%04X $word $n; incr n -1
append FIPprims_code "case $word: $prim_code($word)"
}
define%02X FIP_LAST [expr $n+1]
set n [expr 0xFF]
foreach word $SFprims_used {
set prim_opcode($word) $n; define%02X $word $n; incr n -1
append SF_TO_F_code "[string range $word 1 end], "
}
define%02X SF_LAST [expr $n+1]
set n [expr ($n<<8)|255]
foreach word $Fprims_used {
set prim_opcode($word) $n; define%04X $word $n; incr n -1
append Fprims_code "case $word: $prim_code($word)"
}
define%04X F_LAST [expr $n+1]
}}
#%%%%
#
# File function (generic, asm-specific and C-specific)
#
#%%%%
# «file_functions» (to ".file_functions")
proc readfile {fname} { exec cat $fname }
proc writefile {fname str} {
if {$fname=="-"} { puts -nonewline $str; return }
set ch [open $fname w]; puts -nonewline $ch $str; close $ch
}
proc doasmfilestuff {fnameout} { global asm_headers asm_defs asm_code
writefile $fnameout $asm_headers$asm_defs$asm_code
}
proc doCfilestuff {fnamein fnameout} {
set s [readfile $fnamein]
set tail {}
while {[regexp {^(.*)/\*-- (.*) --\*/(.*)$} $s -> a b c]} {
set tail "/*--{ $b }--*/\n [uplevel #0 $b]$c$tail"
set s $a
}
writefile $fnameout $s$tail
}
#%%%%
#
# Tests, part 1: defining the C primitives
#
#%%%%
# «test:prims» (to ".test:prims")
SFprims EXIT \; { RS--; goto forth;
} PLUS + { DS[-1]+=DS[0]; DS--; goto forth;
} DUP { DS[1]=DS[0]; DS++; goto forth;
} 2DUP { DS[1]=DS[-1]; DS[2]=DS[0]; DS+=2; goto forth;
} SWAP { itmp=DS[-1]; DS[-1]=DS[0]; DS[0]=itmp; goto forth;
} DROP { DS--; goto forth;
} SBRANCH { SS[0]=(int)_f0+*((ushort *)(SS[0])); goto forth;
} S0BRANCH { tmp=*((ushort *)(SS[0]))++; if(DS[0]==0) SS[0]=(int)_f0+tmp;
DS--; goto forth;
}
Fprims 1 { DS[1]=1; DS++; goto forth;
} TIMES * { DS[-1]*=DS[0]; DS--; goto forth;
} COUNT { DS[1]=*((uchar *)(DS[0]))++; DS++; goto forth;
} TYPE { fwrite((void *)(DS[-1]), 1, DS[0], stdout); DS-=2; goto forth;
} CR { printf("\n"); goto forth;
} STO S> { DS[1]=SS[0]; DS++; SS--; goto forth;
} TOS >S { SS[1]=DS[0]; SS++; DS--; goto forth;
} SGOBBLE1 { DS[1]=*((uchar *)(SS[0]))++; DS++; goto forth;
} SGOBBLE2 { DS[1]=*((ushort *)(SS[0]))++; DS++; goto forth;
} WSTORE W! { *((ushort *)(DS[0]))=DS[1]; DS-=2; goto forth;
} WFETCH W@ { DS[0]=*((ushort *)(DS[0])); goto forth;
}
FIPprims RETURN { RS--; return;
} RSREXIT { RS[0]=SS[0]-((int)_f0); SS--; goto forth;
}
Hprims COL : { goto forth;
} CON { DS[1]=*(int *)(_f0+RS[0]); DS++; RS--; goto forth;
} TO { *(int *)(_f0+RS[0]+1)=DS[0]; DS--; RS--; goto forth;
} AT { DS[1]=((int)_f0)+RS[0]+2; DS++; RS--; goto forth;
} RSR { SS[1]=((int)_f0)+RS[-1]; SS++; RS[-1]=FIP_RSREXIT; goto head;
} C1 { fun=*(funptr *)(_f0+RS[0]); DS[0]=(*fun)(DS[0]); RS--; goto forth;
} C2 { fun=*(funptr *)(_f0+RS[0]); DS[-1]=(*fun)(DS[-1], DS[0]);
DS--; RS--; goto forth;
} C3 { fun=*(funptr *)(_f0+RS[0]); DS[-2]=(*fun)(DS[-2], DS[-1], DS[0]);
DS-=2; RS--; goto forth;
}
#%%%%
#
# Tests, part 2: simulating a .tf
#
#%%%%
# «test:prototf» (to ".test:prototf")
# (find-fline "~/CRIM1/")
# (find-fline "~/CRIM1/demo0a.tf")
# (find-fline "~/CRIM1/demo0a.lst")
# (find-fline "~/CRIM1/tclstuff" "proc getword")
proc tick {word} { global asm_code word_action
set nasmname [nasmify $word]
append asm_code "ADR_$nasmname:\n"
set word_action($word) "append asm_code \"\\tdwhla ADR_$nasmname\\n\""
}
tick 2 ; run CON: ; append asm_code "\tdd 2\n"
tick SQUARE ; run : DUP * \;
tick CUBE ; run : DUP SQUARE * \;
append asm_code "global ADR_DEMO\n"
tick DEMO ; run : 2 CUBE \;
# «test:printing» (to ".test:printing")
proc putsvars {args} {
foreach varname $args {
puts $varname:
catch "uplevel #0 set $varname"
}
}
proc print_vars {} {
uplevel #0 {
catch {parray prim_status}
catch {parray word_action}
catch {parray prim_code}
}
putsvars FIPprims_used SFprims_used Fprims_used Hprims_used
# Strings:
putsvars asm_code asm_defs C_defs
putsvars FIPprims_code SFprims_code Fprims_code Hprims_code
}
set_final_prim_data
# print_vars
# doCfilestuff engine0.skel.c -
# doasmfilestuff -
doCfilestuff engine0.skel.c /tmp/engine.c
doasmfilestuff /tmp/x.asm
# cd /tmp; nasm -f elf -o x.o -l x.lst x.asm; gcc -c -o engine.o engine.c
# Local Variables:
# coding: no-conversion
# ee-anchor-format: "«%s»"
# ee-charset-indicator: "Ñ"
# End: