summaryrefslogtreecommitdiffstats
path: root/tcllib/modules/grammar_me/gasm.tcl
diff options
context:
space:
mode:
Diffstat (limited to 'tcllib/modules/grammar_me/gasm.tcl')
-rw-r--r--tcllib/modules/grammar_me/gasm.tcl207
1 files changed, 207 insertions, 0 deletions
diff --git a/tcllib/modules/grammar_me/gasm.tcl b/tcllib/modules/grammar_me/gasm.tcl
new file mode 100644
index 0000000..a42fd40
--- /dev/null
+++ b/tcllib/modules/grammar_me/gasm.tcl
@@ -0,0 +1,207 @@
+# -*- tcl -*-
+# ### ### ### ######### ######### #########
+## Package description
+
+## (struct::)Graph based ME Assembler, for use in grammar
+## translations.
+
+# ### ### ### ######### ######### #########
+## Requisites
+
+namespace eval grammar::me::cpu::gasm {}
+
+# ### ### ### ######### ######### #########
+## Implementation
+
+proc ::grammar::me::cpu::gasm::begin {g n {mode okfail} {note {}}} {
+ variable gas
+ array unset gas *
+
+ # (Re)initialize the assmebler state, create the framework nodes
+ # upon which we will hang all instructions on.
+
+ set gas(mode) $mode
+ set gas(node) $n
+ set gas(grap) $g
+ array set gas {last {} cond always}
+
+ Nop $note ; /Label entry ; /Clear
+ if {$mode eq "okfail"} {
+ Nop Exit'OK ; /Label exit/ok ; /Clear
+ Nop Exit'FAIL ; /Label exit/fail ; /Clear
+ } elseif {$mode eq "halt"} {
+ Cmd icf_halt ; /Label exit/return ; /Clear
+ } else {
+ Cmd icf_ntreturn ; /Label exit/return ; /Clear
+ }
+
+ /At entry
+ return
+}
+
+proc ::grammar::me::cpu::gasm::done {__ t} {
+ variable gas
+
+ # Save the framework nodes in a grammar tree and shut the
+ # assembler down.
+
+ $t set $gas(node) gas::entry $gas(_entry)
+
+ if {$gas(mode) eq "okfail"} {
+ $t set $gas(node) gas::exit::ok $gas(_exit/ok)
+ $t set $gas(node) gas::exit::fail $gas(_exit/fail)
+ } else {
+ $t set $gas(node) gas::exit $gas(_exit/return)
+ }
+
+ # Remember the node in the grammar tree which is responsible for
+ # this entry point.
+
+ $gas(grap) node set $gas(_entry) expr $gas(node)
+
+ array unset gas *
+ return
+}
+
+proc ::grammar::me::cpu::gasm::lift {t dst __ src} {
+
+ $t set $dst gas::entry [$t get $src gas::entry]
+ $t set $dst gas::exit::ok [$t get $src gas::exit::ok]
+ $t set $dst gas::exit::fail [$t get $src gas::exit::fail]
+ return
+}
+
+proc ::grammar::me::cpu::gasm::state {} {
+ variable gas
+ return [array get gas]
+}
+
+proc ::grammar::me::cpu::gasm::state! {s} {
+ variable gas
+ array set gas $s
+}
+
+proc ::grammar::me::cpu::gasm::Inline {t node label} {
+ variable gas
+
+ set gas(_${label}/entry) [$t get $node gas::entry]
+ set gas(_${label}/exit/ok) [$t get $node gas::exit::ok]
+ set gas(_${label}/exit/fail) [$t get $node gas::exit::fail]
+
+ __Link $gas(_${label}/entry) $gas(cond)
+ /At ${label}/exit/ok
+ return
+}
+
+proc ::grammar::me::cpu::gasm::Cmd {cmd args} {
+ variable gas
+
+ # Add a new instruction, and link it to the anchor. The created
+ # instruction becomes the new anchor.
+
+ upvar 0 gas(grap) g gas(last) anchor gas(cond) cond
+
+ set node [$g node insert]
+ $g node set $node instruction $cmd
+ $g node set $node arguments $args
+
+ if {$anchor ne ""} {__Link $node $cond}
+
+ set anchor $node
+ set cond always
+ return
+}
+
+proc ::grammar::me::cpu::gasm::Bra {} {
+ Cmd .BRA
+}
+
+proc ::grammar::me::cpu::gasm::Nop {{text {}}} {
+ Cmd .NOP $text
+}
+
+proc ::grammar::me::cpu::gasm::Note {text} {
+ Cmd .C $text
+}
+
+proc ::grammar::me::cpu::gasm::Jmp {label} {
+ variable gas
+ __Link $gas(_$label) $gas(cond)
+ return
+}
+
+proc ::grammar::me::cpu::gasm::Exit {} {
+ variable gas
+ if {$gas(mode) eq "okfail"} {
+ __Link $gas(_exit/$gas(cond)) $gas(cond)
+ } else {
+ __Link $gas(_exit/return) always
+ }
+ return
+}
+
+proc ::grammar::me::cpu::gasm::Who {label} {
+ variable gas
+ return $gas(_$label)
+}
+
+proc ::grammar::me::cpu::gasm::__Link {to cond} {
+ variable gas
+ upvar 0 gas(grap) g gas(last) anchor
+
+ set arc [$g arc insert $anchor $to]
+ $g arc set $arc condition $cond
+ return
+}
+
+proc ::grammar::me::cpu::gasm::/Label {name} {
+ variable gas
+ set gas(_$name) $gas(last)
+ return
+}
+
+proc ::grammar::me::cpu::gasm::/Clear {} {
+ variable gas
+ set gas(last) {}
+ set gas(cond) always
+ return
+}
+
+proc ::grammar::me::cpu::gasm::/Ok {} {
+ variable gas
+ set gas(cond) ok
+ return
+}
+
+proc ::grammar::me::cpu::gasm::/Fail {} {
+ variable gas
+ set gas(cond) fail
+ return
+}
+
+proc ::grammar::me::cpu::gasm::/At {name} {
+ variable gas
+ set gas(last) $gas(_$name)
+ set gas(cond) always
+ return
+}
+
+proc ::grammar::me::cpu::gasm::/CloseLoop {} {
+ variable gas
+ $gas(grap) node set $gas(last) LOOP .
+ return
+}
+
+# ### ### ### ######### ######### #########
+## Interfacing
+
+namespace eval grammar::me::cpu::gasm {
+ namespace export begin done lift state state!
+ namespace export Inline Cmd Bra Nop Note Jmp Exit Who
+ namespace export /Label /Clear /Ok /Fail /At /CloseLoop
+}
+
+# ### ### ### ######### ######### #########
+## Ready
+
+package provide grammar::me::cpu::gasm 0.1