Initial
authorken <ken@mihrtec.com>
Fri, 16 Feb 2018 22:50:46 +0000 (14:50 -0800)
committerken <ken@mihrtec.com>
Fri, 16 Feb 2018 22:50:46 +0000 (14:50 -0800)
.gitignore [new file with mode: 0644]
c/c2wat [new file with mode: 0755]
c/switch_split.c [new file with mode: 0644]
c/switch_split_0.wat [new file with mode: 0644]
forth.forth [new file with mode: 0644]
forth.html [new file with mode: 0644]
forth.js [new file with mode: 0644]
forth.wat [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..0fb9098
--- /dev/null
@@ -0,0 +1,4 @@
+c/switch_split.*
+!c/switch_split.c
+*~
+forth.wasm
diff --git a/c/c2wat b/c/c2wat
new file mode 100755 (executable)
index 0000000..d2bec09
--- /dev/null
+++ b/c/c2wat
@@ -0,0 +1,6 @@
+#! /bin/bash
+clang -emit-llvm --target=wasm32 -O3 -S $1
+FNAME=${1%.c}
+llc ${FNAME}.ll -march=wasm32
+s2wasm ${FNAME}.s > ${FNAME}.wast
+wat-desugar ${FNAME}.wast > ${FNAME}.wat
diff --git a/c/switch_split.c b/c/switch_split.c
new file mode 100644 (file)
index 0000000..ba9b2af
--- /dev/null
@@ -0,0 +1,121 @@
+extern int sys_read(int,int);
+extern int sys_request(int,int);
+extern int sys_write(int,int);
+extern int vocab_get(int);
+extern int vocab_set(int,int);
+extern void push(int);
+extern int pop(void);
+extern void rpush(int);
+extern int rpop(void);
+extern void rinit(void);
+static char memseg[1024] =
+  { 0, 0, 0, 9, 'i', 'n', 't', 'e', 'r', 'p', 'r', 'e', 't', 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 2, 0, 0, 0, 16, 0, 0, 0, 13, 0, 0, 0, 1
+  };
+static int interpret(int,int);
+int main(void) {
+  /* int start, here, eax, ebx, esi, mode;
+  here = (int) memseg + 512;
+  mode = here;
+  *(int*) mode = 11; //executing
+  here += 4;
+  //string "interpret"
+  eax = here;
+  *(int*)here++ = 9;
+  *(char*)here++ = 'i';
+  *(char*)here++ = 'n';
+  *(char*)here++ = 't';
+  *(char*)here++ = 'e';
+  *(char*)here++ = 'r';
+  *(char*)here++ = 'p';
+  *(char*)here++ = 'r';
+  *(char*)here++ = 'e';
+  *(char*)here++ = 't';
+  here += 3; //align
+  //initial definition of "interpret"
+  esi = here;
+  *(int*)here++ = 4;  //WORD
+  *(int*)here++ = 2;  //LIT
+  *(int*)here++ = mode; //addr of mode var
+  *(int*)here++ = 10; //FETCH
+  *(int*)here++ = 12; //EXECUTE
+  *(int*)here++ = 13; //NOOP
+  *(int*)here++ = 1;  //RET
+  //insert into vocab
+  vocab_set(eax, esi);
+  //string "quit"
+  ebx = esi;
+  eax = here;
+  *(int*)here++ = 4;
+  *(char*)here++ = 'q';
+  *(char*)here++ = 'u';
+  *(char*)here++ = 'i';
+  *(char*)here++ = 't';
+  //initial definition of "quit"
+  esi = here;
+  *(int*)here++ = 3; //rinit
+  *(int*)here++ = ebx; //interpret
+  *(int*)here++ = 9; //JMP
+  *(int*)here++ = esi; //jmp addr 0 (interpret)
+  //insert into vocab
+  vocab_set(eax, esi); */
+  return interpret((int)memseg, (int)memseg);
+}
+static int interpret(int esi, int here) {
+  int eax = 0, ebx = 0, ecx = 0, edi = 0;
+ next:
+  eax = *(int*) esi;
+  esi += 4;
+ exec:
+  switch(eax) {
+  case 0: //interpret
+    esi = eax;
+    eax = *(int*)eax;
+    goto next;
+  case 1: // ret (exit)
+    esi = rpop();
+    goto next;
+  case 2: // pushnext (lit)
+    push(*(int*)esi);
+    esi += 4;
+    goto next;
+  case 3: // rinit
+    rinit();
+    goto next;
+  case 4: // word
+    esi += eax;
+    eax += esi;
+    goto next;
+  case 5: // sys_read
+    sys_read(pop(),pop());
+    goto next;
+  case 6: // sys_request
+    sys_request(pop(),pop());
+    goto next;
+  case 7: // sys_write
+    sys_write(pop(),pop());
+    goto next;
+  case 8: // bye
+    break;
+  case 9: // goto
+    esi = *(int*) esi;
+    goto next;
+  case 10: // @ fetch
+    push(*(int*)pop());
+    goto next;
+  case 11: // ! set
+    *(int*)pop() = pop();
+    goto next;
+  case 12: // EXECUTE
+    eax = pop();
+    goto exec;
+  case 13: // NOOP
+    push(1);
+    goto next;
+  default: // eax is an addr, jump to it and push esi
+    rpush(esi);
+    esi = eax;
+    goto next;
+  }
+  return 0;
+}
diff --git a/c/switch_split_0.wat b/c/switch_split_0.wat
new file mode 100644 (file)
index 0000000..140b820
--- /dev/null
@@ -0,0 +1,224 @@
+(module
+  (type $FUNCSIG$i (func (result i32)))
+  (type $FUNCSIG$vi (func (param i32)))
+  (type $FUNCSIG$v (func))
+  (type $FUNCSIG$iii (func (param i32 i32) (result i32)))
+  (import "env" "pop" (func $pop (result i32)))
+  (import "env" "push" (func $push (param i32)))
+  (import "env" "rinit" (func $rinit))
+  (import "env" "rpop" (func $rpop (result i32)))
+  (import "env" "rpush" (func $rpush (param i32)))
+  (import "env" "sys_read" (func $sys_read (param i32 i32) (result i32)))
+  (import "env" "sys_request" (func $sys_request (param i32 i32) (result i32)))
+  (import "env" "sys_write" (func $sys_write (param i32 i32) (result i32)))
+  (table (;0;) 0 anyfunc)
+  (memory $0 1)
+  (data (i32.const 16) "\00\00\00\09interpret\00\00\00\00\00\00\00\00\00\00\04\00\00\00\02\00\00\00\10\00\00\00\0d\00\00\00\01\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00")
+  (export "memory" (memory $0))
+  (export "main" (func $main))
+  (func $main (result i32)
+    (local $0 i32) (local $1 i32)
+    i32.const 0
+    i32.load offset=4
+    i32.const 16
+    i32.sub
+    set_local $1
+    i32.const 0
+    get_local $1
+    i32.store offset=4
+    get_local $1
+    i32.const 0
+    i32.store offset=12
+    i32.const 16
+    i32.const 16
+    call $interpret
+    set_local $0
+    i32.const 0
+    get_local $1
+    i32.const 16
+    i32.add
+    i32.store offset=4
+    get_local $0)
+  (func $interpret (param $0 i32) (param $1 i32) (result i32)
+    (local $2 i32)
+    i32.const 0
+    i32.load offset=4
+    i32.const 32
+    i32.sub
+    set_local $2
+    i32.const 0
+    get_local $2
+    i32.store offset=4
+    get_local $2
+    get_local $0
+    i32.store offset=28
+    get_local $2
+    get_local $1
+    i32.store offset=24
+    get_local $2
+    i32.const 0
+    i32.store offset=20
+    get_local $2
+    i32.const 0
+    i32.store offset=16
+    get_local $2
+    i32.const 0
+    i32.store offset=12
+    get_local $2
+    i32.const 0
+    i32.store offset=8
+    loop $label$0 (result i32)
+      get_local $2
+      get_local $2
+      i32.load offset=28
+      i32.load
+      i32.store offset=20
+      get_local $2
+      get_local $2
+      i32.load offset=28
+      i32.const 4
+      i32.add
+      i32.store offset=28
+      block $label$1
+        block $label$2
+          block $label$3
+            loop $label$4
+              get_local $2
+              i32.load offset=20
+              set_local $1
+              get_local $1
+              i32.const 13
+              i32.gt_u
+              br_if $label$3
+              block $label$5
+                block $label$6
+                  block $label$7
+                    block $label$8
+                      block $label$9
+                        block $label$10
+                          block $label$11
+                            block $label$12
+                              block $label$13
+                                block $label$14
+                                  block $label$15
+                                    block $label$16
+                                      block $label$17
+                                        block $label$18
+                                          get_local $1
+                                          br_table $label$18 $label$17 $label$16 $label$15 $label$14 $label$13 $label$12 $label$11 $label$10 $label$9 $label$8 $label$7 $label$6 $label$5 $label$18
+                                        end
+                                        get_local $2
+                                        get_local $2
+                                        i32.load offset=20
+                                        i32.store offset=28
+                                        get_local $2
+                                        get_local $2
+                                        i32.load offset=20
+                                        i32.load
+                                        i32.store offset=20
+                                        br $label$1
+                                      end
+                                      get_local $2
+                                      call $rpop
+                                      i32.store offset=28
+                                      br $label$1
+                                    end
+                                    get_local $2
+                                    i32.load offset=28
+                                    i32.load
+                                    call $push
+                                    get_local $2
+                                    get_local $2
+                                    i32.load offset=28
+                                    i32.const 4
+                                    i32.add
+                                    i32.store offset=28
+                                    br $label$1
+                                  end
+                                  call $rinit
+                                  br $label$1
+                                end
+                                get_local $2
+                                get_local $2
+                                i32.load offset=28
+                                get_local $2
+                                i32.load offset=20
+                                i32.add
+                                i32.store offset=28
+                                get_local $2
+                                get_local $2
+                                i32.load offset=20
+                                get_local $2
+                                i32.load offset=28
+                                i32.add
+                                i32.store offset=20
+                                br $label$1
+                              end
+                              call $pop
+                              call $pop
+                              call $sys_read
+                              drop
+                              br $label$1
+                            end
+                            call $pop
+                            call $pop
+                            call $sys_request
+                            drop
+                            br $label$1
+                          end
+                          call $pop
+                          call $pop
+                          call $sys_write
+                          drop
+                          br $label$1
+                        end
+                        br $label$2
+                      end
+                      get_local $2
+                      get_local $2
+                      i32.load offset=28
+                      i32.load
+                      i32.store offset=28
+                      br $label$1
+                    end
+                    call $pop
+                    i32.load
+                    call $push
+                    br $label$1
+                  end
+                  call $pop
+                  set_local $1
+                  call $pop
+                  get_local $1
+                  i32.store
+                  br $label$1
+                end
+                get_local $2
+                call $pop
+                i32.store offset=20
+                br $label$4
+              end
+            end
+            i32.const 1
+            call $push
+            br $label$1
+          end
+          get_local $2
+          i32.load offset=28
+          call $rpush
+          get_local $2
+          get_local $2
+          i32.load offset=20
+          i32.store offset=28
+          br $label$1
+        end
+        i32.const 0
+        get_local $2
+        i32.const 32
+        i32.add
+        i32.store offset=4
+        i32.const 0
+        return
+      end
+      br $label$0
+    end))
diff --git a/forth.forth b/forth.forth
new file mode 100644 (file)
index 0000000..2facfc9
--- /dev/null
@@ -0,0 +1,2 @@
+: dothings ^C dup + ; ^E
+5 dothings .
diff --git a/forth.html b/forth.html
new file mode 100644 (file)
index 0000000..b35238f
--- /dev/null
@@ -0,0 +1,10 @@
+<!doctype html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>watForth</title>
+  </head>
+  <body>
+    <script src="forth.js"></script>
+  </body>
+</html>
diff --git a/forth.js b/forth.js
new file mode 100644 (file)
index 0000000..486a50c
--- /dev/null
+++ b/forth.js
@@ -0,0 +1,210 @@
+'use strict'
+let txtdiv = document.createElement("div")
+document.body.appendChild(txtdiv)
+const output = {
+  print: (string) => txtdiv.textContent += string
+}
+let wasmMem
+let forth
+
+/* Input capture */
+let stdin = ""
+document.addEventListener('keydown', (event) => {
+  console.log(`keydown: ${event.key}`)
+  if (event.key != "F5") {
+    event.preventDefault()
+    event.stopPropagation()
+    switch (event.key) {
+    case "Enter":
+      txtdiv = document.createElement("div")
+      document.body.appendChild(txtdiv)
+      forth()
+      output.print("__ok.")
+      txtdiv = document.createElement("div")
+      document.body.appendChild(txtdiv)
+      break
+    case "Backspace":
+      stdin = stdin.substring(0, stdin.length - 1)
+      txtdiv.textContent = txtdiv.textContent.substring(0, txtdiv.textContent.length - 1)
+      break
+    default:
+      if (event.key.length == 1) {
+       stdin += event.key
+        output.print(event.key)
+      }
+      break
+    }
+  }
+})
+
+const channels = [{
+  read: (writeAddr, maxBytes) => {
+    const maxChars = maxBytes >> 1
+    const bufView = new Uint16Array(wasmMem.buffer, writeAddr, maxChars)
+    let i
+    for (i = 0; i < maxChars && i < stdin.length; i++)
+      bufView[i] = stdin.charCodeAt(i)
+    stdin = stdin.substring(maxChars)
+    return i << 1
+  },
+  write: (readAddr, maxBytes) =>
+    output.print(String.fromCharCode.apply(
+      null,
+      new Uint16Array(wasmMem.buffer, readAddr, maxBytes)
+    ))
+}]
+const simstack = []
+const rstack = []
+const dictionary = {
+  ';': 1,
+  'LIT': 2,
+  RINIT: 3,
+  WORD: 696,
+  KEY: 5,
+  DUP: 6,
+  '+': 7,
+  'NOOP2': 8,
+  '.': 9,
+  '@': 10,
+  '!': 11,
+  EXECUTE: 12,
+  NOOP: 13,
+  'JZ:': 14,
+  'JNZ:': 15,
+  DROP: 16,
+  'WS?': 17,
+  'JMP:': 18,
+  'WPUTC': 19,
+  'WB0': 20,
+  'FIND': 21,
+  'NUMBER': 22,
+  'W!LEN': 23,
+  'J-1:': 24,
+  'BYE': 25,
+  'SWAP': 26,
+  'WORDS': 27,
+  'HERE': 28,
+  'DEFINE': 29,
+  ':': 900,
+  'MODE': 384,
+  'WBUF': 256,
+  'EXECUTE-MODE': 800,
+  'QUIT': 600,
+  'INTERPRET': 512
+}
+const wasmImport = {
+  env: {
+    pop: () => simstack.pop(),
+    push: (val) => simstack.push(val),
+    rinit: () => rstack.length = 0,
+    rpop: () => rstack.pop(),
+    rpush: (val) => rstack.push(val),
+    sys_write: (channel, fromBuffer) => {
+      if (channels[channel] === undefined)
+       return
+      const maxBytes = new DataView(
+       wasmMem.buffer,
+       fromBuffer,
+       4
+      ).getUint32(0,true)
+      console.log(`write ch:${channel} addr:${fromBuffer} len:${maxBytes}`)
+      channels[channel].write(fromBuffer + 4, maxBytes)
+    },
+    sys_read: (channel, toBuffer) => {
+      console.log(`read ch:${channel} buf:${toBuffer} current: ${stdin}`)
+      const lenView = new DataView(wasmMem.buffer, toBuffer, 8)
+      const maxBytes = lenView.getUint32(0,true)
+      console.log(`read blen:${lenView.getUint32(0,true)} cstrlen:${lenView.getUint32(4,true)}`)
+      /* If the channel is undefined, or if there isn't enough room in
+       * toBuffer for even one character, then, if there is enough
+       * room for an int write a zero, exit */
+      if (channels[channel] === undefined || maxBytes < 6) {
+       if (maxBytes >= 4)
+         lenView.setUint32(4,0,true)
+      }
+      const numBytes = channels[channel].read(toBuffer + 8, maxBytes - 4)
+      lenView.setUint32(4,numBytes,true);
+      console.log(`read wrote ${lenView.getUint32(4,true)} bytes, remainder: ${stdin}`)
+      console.log(`read blen:${lenView.getUint32(0,true)} cstrlen:${lenView.getUint32(4,true)}`)   },
+    sys_listen: (reqAddr, cbAddr) => {
+      //TODO: call into the module to wasm fn "event" to push an event
+      //to forth, which pushes esi to the return stack and queues the
+      //callback function provided from listen. reqaddr could be
+      //"fetch", in which case no channel is used.  otherwise very
+      //similar to sys_fetch.
+    },
+    sys_fetch: (channel, reqAddr) => {
+      //TODO: map to fetch promise, write to channel buffer,
+      //javascript "fetch" as fallback, explicit handles for
+      //"textEntry" or any third party protocols like activitypub
+      console.log(`fetch ${channel} ${reqAddr}`)
+    },
+    sys_echo: (val) => output.print(`${val} `),
+    sys_echochar: (val) => output.print(String.fromCharCode(val)),
+    sys_reflect: (addr) => {
+      console.log(`reflect: ${addr}: ${
+        new DataView(wasmMem.buffer, addr, 4)
+              .getUint32(0,true)
+      }`)
+    },
+    vocab_get: (addr) => {
+      const bytes = new DataView(
+       wasmMem.buffer,
+       addr,
+       4
+      ).getUint32(0,true)
+      const word = String.fromCharCode.apply(
+       null,
+       new Uint16Array(wasmMem.buffer, addr + 4, bytes >> 1)
+      )
+      const answer = dictionary[word.toUpperCase()]
+      console.log(`vocab_get ${word}: ${answer}`)
+      if (answer === undefined)
+       return 0
+      return answer
+    },
+    vocab_set: (addr, num) => {
+      const bytes = new DataView(
+       wasmMem.buffer,
+       addr,
+       4
+      ).getUint32(0,true)
+      const word = String.fromCharCode.apply(
+       null,
+       new Uint16Array(wasmMem.buffer, addr + 4, bytes >> 1)
+      )
+      console.log(`vocab_set ${word}: ${num}`)
+      dictionary[word.toUpperCase()] = num
+      return 0
+    },
+    is_whitespace: (key) => /\s/.test(String.fromCharCode(key)),
+    sys_stack: () => console.log(`[${simstack}]`),
+    sys_parsenum: (addr, base) => {
+      const byteV = new DataView(
+       wasmMem.buffer,
+       addr,
+       4
+      )
+      const word = String.fromCharCode.apply(
+       null,
+       new Uint16Array(wasmMem.buffer, addr + 4, byteV.getUint32(0,true) >> 1)
+      )
+      const answer = Number.parseInt(word, base)
+      byteV.setUint32(0,Number.isNaN(answer),true)
+      return answer
+    },
+    sys_words: () => {
+      output.print(Object.getOwnPropertyNames(dictionary).toString().split(',').join('  '))
+    }
+  }
+}
+
+fetch('forth.wasm')
+  .then(re => re.arrayBuffer())
+  .then(buf => WebAssembly.instantiate(buf, wasmImport))
+  .then(result => {
+    wasmMem = result.instance.exports.memory
+    forth = result.instance.exports.main
+    console.log('wasm loaded');
+    forth()
+  })
diff --git a/forth.wat b/forth.wat
new file mode 100644 (file)
index 0000000..30bd82d
--- /dev/null
+++ b/forth.wat
@@ -0,0 +1,409 @@
+(module
+  (type $FUNCSIGi   (func (result i32)))
+  (type $FUNCSIGii  (func (param i32)))
+  (type $FUNCSIGiii (func))
+  (type $FUNCSIGiv  (func (param i32 i32) (result i32)))
+  (type $FUNCSIG$v  (func (param i32) (result i32)))
+  (import "env" "pop" (func $pop (result i32)))
+  (import "env" "push" (func $push (param i32)))
+  (import "env" "rinit" (func $rinit))
+  (import "env" "rpop" (func $rpop (result i32)))
+  (import "env" "rpush" (func $rpush (param i32)))
+  (import "env" "sys_read" (func $sys_read (param i32 i32) (result i32)))
+  (import "env" "sys_fetch" (func $sys_fetch (param i32 i32) (result i32)))
+  (import "env" "sys_listen" (func $sys_listen (param i32) (result i32)))  
+  (import "env" "sys_write" (func $sys_write (param i32 i32) (result i32)))
+  (import "env" "sys_echo" (func $sys_echo (param i32)))
+  (import "env" "sys_echochar" (func $sys_echochar (param i32)))  
+  (import "env" "sys_reflect" (func $sys_reflect (param i32)))
+  (import "env" "vocab_get" (func $vocab_get (param i32) (result i32)))
+  (import "env" "vocab_set" (func $vocab_set (param i32) (param i32) (result i32)))
+  (import "env" "is_whitespace" (func $is_whitespace (param i32) (result i32)))
+  (import "env" "sys_parsenum" (func $sys_parsenum (param i32) (result i32)))
+  (import "env" "sys_stack" (func $sys_stack))
+  (import "env" "sys_words" (func $sys_words))
+  (table (;0;) 0 anyfunc)
+  (memory $0 1)
+  (global $inbuf i32 (i32.const 8))
+  (global $inbuf_size i32 (i32.const 12))
+  (global $inbuf_data i32 (i32.const 16))
+  (global $wbuf i32 (i32.const 256))
+  (global $wbuf_data i32 (i32.const 260))
+  (data (i32.const 8)   "\f4\00\00\00") ;; STDIN buf, 244 len
+  (data (i32.const 256) "\7c\00\00\00") ;; WBUF, 124 len
+  (data (i32.const 384) "\20\03\00\00") ;; MODE
+  (data (i32.const 388) "\18\04\00\00") ;; HERE
+  (data (i32.const 392) "\58\02\00\00") ;; START
+  (data (i32.const 396) "\0a\00\00\00") ;; BASE
+  (; Interpret ;)
+  (data (i32.const 512) "\b8\02\00\00") ;; WORD xt (696)
+  (data (i32.const 516) "\06\00\00\00") ;; DUP
+  (data (i32.const 520) "\0a\00\00\00") ;; @
+  (data (i32.const 524) "\0e\00\00\00") ;; JZ:
+  (data (i32.const 528) "\2c\02\00\00") ;; INTERP-END addr (556)
+  (data (i32.const 532) "\02\00\00\00") ;; LIT xt
+  (data (i32.const 536) "\80\01\00\00") ;; MODE addr (384)
+  (data (i32.const 540) "\0a\00\00\00") ;; @ (fetch) xt
+  (data (i32.const 544) "\0c\00\00\00") ;; EXECUTE xt
+  (data (i32.const 548) "\0d\00\00\00") ;; NOOP xt
+  (data (i32.const 552) "\01\00\00\00") ;; RET
+  (data (i32.const 556) "\10\00\00\00") ;; DROP  <-- INTERP-END
+  (data (i32.const 560) "\19\00\00\00") ;; BYE
+  (; Quit ;)
+  (data (i32.const 600) "\03\00\00\00") ;; RINIT xt
+  (data (i32.const 604) "\00\02\00\00") ;; INTERPRET xt (512)
+  (data (i32.const 608) "\12\00\00\00") ;; JMP xt
+  (data (i32.const 612) "\58\02\00\00") ;; quit location (600)
+  (; Test instructions ;)
+  (data (i32.const 640) "\02\00\00\00") ;; LIT
+  (data (i32.const 644) "\02\00\00\00") ;; 2
+  (data (i32.const 648) "\06\00\00\00") ;; DUP
+  (data (i32.const 652) "\07\00\00\00") ;; +
+  (data (i32.const 656) "\09\00\00\00") ;; .
+  (data (i32.const 660) "\12\00\00\00") ;; JMP
+  (data (i32.const 664) "\58\02\00\00") ;; quit addr
+  (; Word ;)
+  (data (i32.const 696) "\14\00\00\00") ;; WB0
+  (data (i32.const 700) "\05\00\00\00") ;; KEY  <-- KEYLOOP
+  (data (i32.const 704) "\06\00\00\00") ;; DUP
+  (data (i32.const 708) "\18\00\00\00") ;; J-1: 18
+  (data (i32.const 712) "\0c\03\00\00") ;; addr of WORDEND
+  (data (i32.const 716) "\11\00\00\00") ;; WS?
+  (data (i32.const 720) "\0e\00\00\00") ;; JZ:
+  (data (i32.const 724) "\00\03\00\00") ;; addr of DOCHAR
+  (data (i32.const 728) "\10\00\00\00") ;; DROP
+  (data (i32.const 732) "\12\00\00\00") ;; JMP:
+  (data (i32.const 736) "\bc\02\00\00") ;; addr of KEYLOOP
+  (data (i32.const 740) "\05\00\00\00") ;; KEY <-- WORDLOOP
+  (data (i32.const 744) "\11\00\00\00") ;; WS?
+  (data (i32.const 748) "\0f\00\00\00") ;; JNZ:
+  (data (i32.const 752) "\0c\03\00\00") ;; addr of WORDEND
+  (data (i32.const 756) "\06\00\00\00") ;; DUP
+  (data (i32.const 760) "\18\00\00\00") ;; J-1:
+  (data (i32.const 764) "\0c\03\00\00") ;; addr of WORDEND
+  (data (i32.const 768) "\13\00\00\00") ;; WPUTC <-- DOCHAR
+  (data (i32.const 772) "\12\00\00\00") ;; JMP:
+  (data (i32.const 776) "\e4\02\00\00") ;; addr of WORDLOOP
+  (data (i32.const 780) "\10\00\00\00") ;; DROP <-- WORDEND
+  (data (i32.const 784) "\02\00\00\00") ;; LIT (push addr of wbuf, 256)
+  (data (i32.const 788) "\00\01\00\00") ;; wbuf addr (utf16 string)
+  (data (i32.const 792) "\17\00\00\00") ;; WB!LEN
+  (data (i32.const 796) "\01\00\00\00") ;; RET
+  (; Exec Mode ;)
+  (data (i32.const 800) "\06\00\00\00") ;; DUP
+  (data (i32.const 804) "\15\00\00\00") ;; DICT_GET
+  (data (i32.const 808) "\06\00\00\00") ;; DUP
+  (data (i32.const 812) "\0e\00\00\00") ;; JZ:
+  (data (i32.const 816) "\44\03\00\00") ;; donum (832)
+  (data (i32.const 820) "\1a\00\00\00") ;; SWAP
+  (data (i32.const 824) "\10\00\00\00") ;; DROP
+  (data (i32.const 828) "\0c\00\00\00") ;; EXECUTE
+  (data (i32.const 832) "\01\00\00\00") ;; RET
+  (data (i32.const 836) "\10\00\00\00") ;; DROP (xt from dictionary)
+  (data (i32.const 840) "\16\00\00\00") ;; NUMBER <-- donum, pushes NUM, UNPARSED
+  (data (i32.const 844) "\06\00\00\00") ;; DUP
+  (data (i32.const 848) "\0f\00\00\00") ;; JNZ:
+  (data (i32.const 852) "\60\03\00\00") ;; donum_err (864)
+  (data (i32.const 856) "\10\00\00\00") ;; DROP
+  (data (i32.const 860) "\01\00\00\00") ;; RET
+  (data (i32.const 864) "\10\00\00\00") ;; PARSE_ERR <-- donum_err
+  (data (i32.const 868) "\10\00\00\00") ;; ( DROP DROP )
+  (data (i32.const 872) "\19\00\00\00") ;; BYE
+  (; : definition ;)
+  (data (i32.const 900) "\b8\02\00\00") ;; WORD
+  (data (i32.const 904) "\1c\00\00\00") ;; HERE
+  (data (i32.const 908) "\1d\00\00\00") ;; VOCAB_SET
+  (data (i32.const 912) "\01\00\00\00") ;; RET
+  (data (i32.const 1000) "\08\00\00\00") ;; "word" size
+  (data (i32.const 1004) "w\00o\00r\00d\00") ;; utf16
+  (data (i32.const 1012) "\12\00\00\00") ;; "interpret" size
+  (data (i32.const 1016) "i\00n\00t\00e\00r\00p\00r\00e\00t\00") ;; utf16
+  (data (i32.const 1034) "\00\00") ;; align 32-bit
+  (data (i32.const 1036) "\08\00\00\00") ;; "quit" size
+  (data (i32.const 1040) "q\00u\00i\00t\00") ;; utf16
+  (;HERE ---> 1048;)
+  (export "memory" (memory $0))
+  (export "main" (func $main))
+  (func $main (result i32)
+    call $interpret
+  )
+  (func $interpret (result i32)
+    (local $here i32)
+    (local $eax i32)
+    (local $esi i32)
+    (local $inbuf_head i32)
+    (local $wbuf_head i32)
+    i32.const 388
+    i32.load
+    set_local $here
+    i32.const 392
+    i32.load
+    set_local $esi
+    i32.const 16
+    set_local $inbuf_head
+    i32.const 260
+    set_local $wbuf_head
+    block $bye
+    loop $next
+        call $sys_stack
+      get_local $esi
+      call $sys_reflect
+      get_local $esi
+      get_local $esi
+      i32.const 4
+      i32.add
+      set_local $esi
+      i32.load
+      set_local $eax
+      loop $execloop
+      block $default block $op0 block $ret block $lit block $rinit
+      block $word block $key block $dup block $plus block $noop2 block $emit
+      block $fetch block $set block $execute block $noop block $jz block $jnz
+      block $drop block $wsbool block $jmp block $wputc block $wbzero
+      block $dictget block $parsenum block $wbsetlen block $jneg1 block $swap
+      block $words block $here block $dictset
+        get_local $eax
+        br_table $op0 $ret (;2;)$lit $rinit (;4;)$word $key (;6;)$dup $plus
+        (;8;)$jmp $emit (;10;)$fetch $set (;12;)$execute $noop (;14;)$jz $jnz
+        (;16;)$drop $wsbool (;18;)$jmp $wputc (;20;)$wbzero $dictget
+       (;22;)$parsenum $wbsetlen (;24;)$jneg1 $bye (;26;)$swap $words
+        (;28;)$here $dictset $default
+      end ;; dictset
+        call $pop
+        set_local $eax
+       call $pop
+        get_local $eax
+        call $vocab_set
+        drop
+        br $next
+      end ;; here
+        get_local $here
+        call $push
+        br $next
+      end ;; words
+        call $sys_words
+        br $next
+      end ;; swap
+        call $pop
+        call $pop
+        set_local $eax
+        call $push
+        get_local $eax
+        call $push
+        br $next
+      end ;; jneg1
+        block $jneg1if
+          call $pop
+          i32.const -1
+          i32.eq
+          br_if $jneg1if
+          get_local $esi
+          i32.const 4
+          i32.add
+          set_local $esi
+          br $next
+        end
+        get_local $esi
+        i32.load
+        set_local $esi
+        br $next
+      end ;; wbsetlen
+        get_global $wbuf
+        get_local $wbuf_head
+        get_global $wbuf_data
+        i32.sub
+        i32.store
+        get_global $wbuf
+       call $sys_reflect
+        br $next
+      end ;; parsenum
+        i32.const 396 (; load BASE ;)
+        i32.load
+        call $pop
+        tee_local $eax
+        call $sys_parsenum
+        call $push
+        get_local $eax
+        i32.load
+        call $push
+       br $next
+      end ;; dictget
+        call $pop
+       call $vocab_get
+       call $push
+       br $next
+      end ;; wbzero
+        get_global $wbuf_data
+       set_local $wbuf_head
+       get_global $wbuf
+       i32.const 0
+       i32.store
+        br $next
+      end ;; wputc
+       get_local $wbuf_head
+        call $pop
+       i32.store16
+       get_local $wbuf_head
+       i32.const 2
+       i32.add
+        set_local $wbuf_head
+       br $next
+      end ;; jmp
+        get_local $esi
+       i32.load
+       set_local $esi
+       br $next
+      end ;; wsbool
+        call $pop
+       tee_local $eax
+       call $is_whitespace
+        get_local $eax
+       call $push
+       call $push
+        call $sys_stack
+        br $next
+      end ;; drop
+        call $pop
+        drop
+        br $next
+      end ;; jnz
+        block $jnzif
+          call $pop
+          i32.eqz
+          br_if $jnzif
+          get_local $esi
+          i32.load
+          set_local $esi
+          br $next
+        end
+        get_local $esi
+        i32.const 4
+        i32.add
+        set_local $esi
+        br $next
+      end ;; jz
+        block $jzif
+          call $pop
+          i32.eqz
+          br_if $jzif
+          get_local $esi
+          i32.const 4
+          i32.add
+          set_local $esi
+          br $next
+        end
+        get_local $esi
+        i32.load
+        set_local $esi
+        br $next
+      end ;; noop
+        br $next
+      end ;; execute
+        call $pop
+        tee_local $eax
+        i32.const 256
+        i32.lt_u
+        br_if $execloop
+        get_local $esi
+        call $rpush
+        get_local $eax
+        set_local $esi
+        br $next
+      end ;; set
+        call $pop
+        set_local $eax
+        call $pop
+        get_local $eax
+        i32.store
+        br $next
+      end ;; fetch
+        call $pop
+        i32.load
+        call $push
+        br $next
+      end ;; emit (.)
+        call $pop
+        call $sys_echo
+        br $next
+      end ;; noop2
+        br $next
+      end ;; plus
+        call $pop
+        call $pop
+        i32.add
+        call $push
+        br $next
+      end ;; dup
+        call $pop
+        tee_local $eax
+        get_local $eax
+        call $push
+        call $push
+        br $next
+      end ;; key
+        loop $key_loop
+          block $key_read
+            get_global $inbuf_size
+            i32.load
+            get_local $inbuf_head
+            get_global $inbuf_data
+            i32.sub
+            i32.le_u
+            br_if $key_read
+            get_local $inbuf_head
+            i32.load16_u
+            call $push
+            get_local $inbuf_head
+            i32.const 2
+            i32.add
+            set_local $inbuf_head
+            br $next
+          end ;; key_read
+          i32.const 0
+          get_global $inbuf
+          call $sys_read
+          block $nullread
+            get_global $inbuf_size
+            i32.load
+            i32.eqz
+            br_if $nullread
+            br $key_loop
+          end ;; nullread
+          i32.const -1 ;; <- keyval sent if sz == 0
+          call $push
+          br $next
+        end ;; key_loop
+      end ;; word
+        br $next
+      end ;; rinit
+        call $rinit
+        br $next
+      end ;; lit
+        get_local $esi
+        get_local $esi
+        i32.const 4
+       i32.add
+       set_local $esi
+       i32.load
+        call $push
+        br $next
+      end ;; ret
+        call $rpop
+       set_local $esi
+        br $next
+      end ;; op0
+        get_local $esi
+        call $sys_reflect
+        br $next
+      end ;; default
+        get_local $esi
+        call $rpush
+        get_local $eax
+        set_local $esi
+        br $next
+    end ;; execloop
+    end ;; nextl
+    end ;; bye
+    get_local $here
+  )
+)
\ No newline at end of file