word belts, utf16 strings, interrupt words, compiler modes
authorken <ken@mihrtec.com>
Sun, 18 Feb 2018 04:43:34 +0000 (20:43 -0800)
committerken <ken@mihrtec.com>
Sun, 18 Feb 2018 04:43:34 +0000 (20:43 -0800)
forth.forth
forth.js
forth.wat

index 2facfc9..0ffbc9c 100644 (file)
@@ -1,2 +1,12 @@
-: dothings ^C dup + ; ^E
-5 dothings .
+5 . 
+word ' here define
+word word find , word find find , word ; find ,
+word : here define
+' word , ' here , ' define , ' ; ,
+: IWRITE-MODE ' dup , ' JNZ: , here 12 + , ' 2drop , ' ; ,
+' find , ' dup , ' JZ: , here 12 + , ' , , ' ; ,
+: i ' LIT , ' MODE , ' LIT , ' IWRITE-MODE , ' ! , ' ; ,
+: e ' LIT , ' MODE , ' LIT , ' EXECUTE-MODE , ' ! , ' ; ,
+: TEST \i DUP + DUP + . ; \e
+5 TEST
+2 . 
\ No newline at end of file
index 486a50c..ffe8044 100644 (file)
--- a/forth.js
+++ b/forth.js
@@ -19,7 +19,7 @@ document.addEventListener('keydown', (event) => {
       txtdiv = document.createElement("div")
       document.body.appendChild(txtdiv)
       forth()
-      output.print("__ok.")
+      output.print("ok.")
       txtdiv = document.createElement("div")
       document.body.appendChild(txtdiv)
       break
@@ -59,7 +59,7 @@ const dictionary = {
   ';': 1,
   'LIT': 2,
   RINIT: 3,
-  WORD: 696,
+  WORD: 16500,
   KEY: 5,
   DUP: 6,
   '+': 7,
@@ -85,12 +85,19 @@ const dictionary = {
   'WORDS': 27,
   'HERE': 28,
   'DEFINE': 29,
-  ':': 900,
-  'MODE': 384,
-  'WBUF': 256,
-  'EXECUTE-MODE': 800,
-  'QUIT': 600,
-  'INTERPRET': 512
+  '2DUP': 30,
+  'ROT': 31,
+  '2DROP': 32,
+  ',': 33,
+  '-': 34,
+  'CHANNEL!': 35,
+  'HERE!': 36,
+  '=?': 37,
+  ':': 16800,
+  'MODE': 14336,
+  'EXECUTE-MODE': 16680,
+  'QUIT': 16384,
+  'INTERPRET': 16400
 }
 const wasmImport = {
   env: {
@@ -147,15 +154,10 @@ const wasmImport = {
               .getUint32(0,true)
       }`)
     },
-    vocab_get: (addr) => {
-      const bytes = new DataView(
-       wasmMem.buffer,
-       addr,
-       4
-      ).getUint32(0,true)
+    vocab_get: (addr, u) => {
       const word = String.fromCharCode.apply(
        null,
-       new Uint16Array(wasmMem.buffer, addr + 4, bytes >> 1)
+       new Uint16Array(wasmMem.buffer, addr, u >> 1)
       )
       const answer = dictionary[word.toUpperCase()]
       console.log(`vocab_get ${word}: ${answer}`)
@@ -163,15 +165,11 @@ const wasmImport = {
        return 0
       return answer
     },
-    vocab_set: (addr, num) => {
-      const bytes = new DataView(
-       wasmMem.buffer,
-       addr,
-       4
-      ).getUint32(0,true)
+    vocab_set: (addr, u, num) => {
+      console.log(`vocab set ${addr} ${u} ${num}`)
       const word = String.fromCharCode.apply(
        null,
-       new Uint16Array(wasmMem.buffer, addr + 4, bytes >> 1)
+       new Uint16Array(wasmMem.buffer, addr, u >> 1)
       )
       console.log(`vocab_set ${word}: ${num}`)
       dictionary[word.toUpperCase()] = num
@@ -179,19 +177,19 @@ const wasmImport = {
     },
     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
-      )
+    sys_parsenum: (addr, u, base) => {
       const word = String.fromCharCode.apply(
        null,
-       new Uint16Array(wasmMem.buffer, addr + 4, byteV.getUint32(0,true) >> 1)
+       new Uint16Array(wasmMem.buffer, addr, u >> 1)
       )
       const answer = Number.parseInt(word, base)
-      byteV.setUint32(0,Number.isNaN(answer),true)
-      return answer
+      console.log(`parsenum: ${addr} ${u} ${base}`)
+      console.log(`parsenum: ${word} ${answer}`)
+      console.log(`parsenum: ${Number.isNaN(answer)}`)
+      if (Number.isNaN(answer))
+        return -1
+      new DataView(wasmMem.buffer, addr, 4).setUint32(0,answer,true)
+      return 0
     },
     sys_words: () => {
       output.print(Object.getOwnPropertyNames(dictionary).toString().split(',').join('  '))
@@ -199,7 +197,9 @@ const wasmImport = {
   }
 }
 
-fetch('forth.wasm')
+fetch('forth.forth').then((re) => re.text()).then((txt) => {
+  stdin = txt
+  fetch('forth.wasm')
   .then(re => re.arrayBuffer())
   .then(buf => WebAssembly.instantiate(buf, wasmImport))
   .then(result => {
@@ -208,3 +208,4 @@ fetch('forth.wasm')
     console.log('wasm loaded');
     forth()
   })
+})
index 30bd82d..a2498a3 100644 (file)
--- a/forth.wat
+++ b/forth.wat
@@ -4,6 +4,7 @@
   (type $FUNCSIGiii (func))
   (type $FUNCSIGiv  (func (param i32 i32) (result i32)))
   (type $FUNCSIG$v  (func (param i32) (result i32)))
+  (type $FUNCSIG$vi (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" "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" "vocab_get" (func $vocab_get (param i32 i32) (result i32)))
+  (import "env" "vocab_set" (func $vocab_set (param i32 i32 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_parsenum" (func $sys_parsenum (param i32 i32 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
+  (; String Belt                       ;) ;; 0x0000 Size: 8192
+  (global $wordbelt i32 (i32.const 8192)) ;; 0x2000 Size: 4096
+  (global $inbuf i32 (i32.const 12288))   ;; 0x3000 Size: 2048
+  (global $inbuf_size i32 (i32.const 12292))
+  (global $inbuf_data i32 (i32.const 12296))
+  (global $kvars i32 (i32.const 14336))   ;; 0x3800 Size: 2048
+  (data (i32.const 12288) "\fc\07\00\00") ;; 2044 len
+  (data (i32.const 14336) "\28\41\00\00") ;; MODE
+  (data (i32.const 14340) "\04\42\00\00") ;; HERE
+  (data (i32.const 14344) "\00\40\00\00") ;; START
+  (data (i32.const 14348) "\0a\00\00\00") ;; BASE
+  (data (i32.const 14352) "\00\00\00\00") ;; STRINGBELT_TAIL
+  (data (i32.const 14356) "\00\00\00\00") ;; STRINGBELT_HEAD
+  (data (i32.const 14360) "\00\20\00\00") ;; WORDBELT_TAIL
+  (data (i32.const 14364) "\00\20\00\00") ;; WORDBELT_HEAD
+  (data (i32.const 14368) "\00\00\00\00") ;; CHANNEL
   (; 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
+  (data (i32.const 16384) "\03\00\00\00") ;; RINIT xt
+  (data (i32.const 16388) "\10\40\00\00") ;; INTERPRET xt
+  (data (i32.const 16392) "\12\00\00\00") ;; JMP xt
+  (data (i32.const 16396) "\00\40\00\00") ;; quit location (16384)
+  (; Interpret ;)
+  (data (i32.const 16400) "\74\40\00\00") ;; WORD xt (16500)
+  (data (i32.const 16404) "\06\00\00\00") ;; DUP
+  (data (i32.const 16408) "\0e\00\00\00") ;; JZ:
+  (data (i32.const 16412) "\38\40\00\00") ;; INTERP-END addr (16444)
+  (data (i32.const 16416) "\02\00\00\00") ;; LIT xt
+  (data (i32.const 16420) "\00\38\00\00") ;; MODE addr (14336)
+  (data (i32.const 16424) "\0a\00\00\00") ;; @ (fetch) xt
+  (data (i32.const 16428) "\0c\00\00\00") ;; EXECUTE xt
+  (data (i32.const 16432) "\0d\00\00\00") ;; NOOP xt
+  (data (i32.const 16436) "\01\00\00\00") ;; RET
+  (data (i32.const 16440) "\10\00\00\00") ;; DROP  <-- INTERP-END
+  (data (i32.const 16444) "\10\00\00\00") ;; DROP
+  (data (i32.const 16448) "\19\00\00\00") ;; BYE
   (; 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
+  (data (i32.const 16500) "\14\00\00\00") ;; WORDSTART
+  (data (i32.const 16504) "\05\00\00\00") ;; KEY  <-- KEYLOOP
+  (data (i32.const 16508) "\06\00\00\00") ;; DUP
+  (data (i32.const 16512) "\18\00\00\00") ;; J-1: 18
+  (data (i32.const 16516) "\f0\40\00\00") ;; addr of WORDEND
+  (data (i32.const 16520) "\11\00\00\00") ;; WS?
+  (data (i32.const 16524) "\0f\00\00\00") ;; JNZ:
+  (data (i32.const 16528) "\bc\40\00\00") ;; addr of KEYDROP
+  (data (i32.const 16532) "\02\00\00\00") ;; LIT
+  (data (i32.const 16536) "\5c\00\00\00") ;; 92 (\ character)
+  (data (i32.const 16540) "\25\00\00\00") ;; =?
+  (data (i32.const 16544) "\0e\00\00\00") ;; JZ:
+  (data (i32.const 16548) "\e4\40\00\00") ;; addr of DOCHAR
+  (data (i32.const 16552) "\10\00\00\00") ;; DROP
+  (data (i32.const 16556) "\c8\40\00\00") ;; WORDLOOP (continue using this wbuf we started)
+  (data (i32.const 16560) "\28\41\00\00") ;; EXECUTE-MODE
+  (data (i32.const 16564) "\12\00\00\00") ;; JMP:
+  (data (i32.const 16568) "\74\40\00\00") ;; addr of KEYLOOP-1 (get a new wbuf, call to wbuf+1 ate ours)
+  (data (i32.const 16572) "\10\00\00\00") ;; DROP <-- KEYDROP
+  (data (i32.const 16576) "\12\00\00\00") ;; JMP:
+  (data (i32.const 16580) "\78\40\00\00") ;; addr of KEYLOOP
+  (data (i32.const 16584) "\05\00\00\00") ;; KEY <-- WORDLOOP
+  (data (i32.const 16588) "\11\00\00\00") ;; WS?
+  (data (i32.const 16592) "\0f\00\00\00") ;; JNZ:
+  (data (i32.const 16596) "\f0\40\00\00") ;; addr of WORDEND
+  (data (i32.const 16600) "\06\00\00\00") ;; DUP
+  (data (i32.const 16604) "\18\00\00\00") ;; J-1:
+  (data (i32.const 16608) "\f0\40\00\00") ;; addr of WORDEND
+  (data (i32.const 16612) "\13\00\00\00") ;; WORDPUTC <-- DOCHAR
+  (data (i32.const 16616) "\12\00\00\00") ;; JMP:
+  (data (i32.const 16620) "\c8\40\00\00") ;; addr of WORDLOOP
+  (data (i32.const 16624) "\10\00\00\00") ;; DROP <-- WORDEND
+  (data (i32.const 16628) "\17\00\00\00") ;; WORDFINISH
+  (data (i32.const 16632) "\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
+  (data (i32.const 16680) "\1e\00\00\00") ;; DUP2
+  (data (i32.const 16684) "\15\00\00\00") ;; DICT_GET
+  (data (i32.const 16688) "\06\00\00\00") ;; DUP
+  (data (i32.const 16692) "\0e\00\00\00") ;; JZ:
+  (data (i32.const 16696) "\4c\41\00\00") ;; donum -1 (16716)
+  (data (i32.const 16700) "\1f\00\00\00") ;; ROT
+  (data (i32.const 16704) "\20\00\00\00") ;; DROP2
+  (data (i32.const 16708) "\0c\00\00\00") ;; EXECUTE
+  (data (i32.const 16712) "\01\00\00\00") ;; RET
+  (data (i32.const 16716) "\10\00\00\00") ;; DROP (xt from dictionary)
+  (data (i32.const 16720) "\16\00\00\00") ;; NUMBER <-- donum, pushes NUM, UNPARSED
+  (data (i32.const 16724) "\06\00\00\00") ;; DUP
+  (data (i32.const 16728) "\0f\00\00\00") ;; JNZ:
+  (data (i32.const 16732) "\68\41\00\00") ;; donum_err (16744)
+  (data (i32.const 16736) "\10\00\00\00") ;; DROP
+  (data (i32.const 16740) "\01\00\00\00") ;; RET
+  (data (i32.const 16744) "\10\00\00\00") ;; PARSE_ERR <-- donum_err
+  (data (i32.const 16748) "\10\00\00\00") ;; ( DROP DROP )
+  (data (i32.const 16752) "\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;)
+  (data (i32.const 16800) "\74\40\00\00") ;; WORD
+  (data (i32.const 16804) "\1c\00\00\00") ;; HERE
+  (data (i32.const 16808) "\1d\00\00\00") ;; VOCAB_SET
+  (data (i32.const 16812) "\01\00\00\00") ;; RET
   (export "memory" (memory $0))
   (export "main" (func $main))
   (func $main (result i32)
     (local $eax i32)
     (local $esi i32)
     (local $inbuf_head i32)
-    (local $wbuf_head i32)
-    i32.const 388
+    (local $stringbelt_tail i32)
+    (local $stringbelt_head i32)
+    (local $wordbelt_tail i32)
+    (local $wordbelt_head i32)
+    (local $channel i32)
+    i32.const 14340
     i32.load
     set_local $here
-    i32.const 392
+    i32.const 14344
     i32.load
     set_local $esi
-    i32.const 16
+    get_global $inbuf_data
     set_local $inbuf_head
-    i32.const 260
-    set_local $wbuf_head
+    i32.const 14352
+    i32.load
+    set_local $stringbelt_tail
+    i32.const 14356
+    i32.load
+    set_local $stringbelt_head
+    i32.const 14360
+    i32.load
+    set_local $wordbelt_tail
+    i32.const 14364
+    i32.load
+    set_local $wordbelt_head
+    i32.const 14368
+    i32.load
+    set_local $channel
     block $bye
     loop $next
         call $sys_stack
       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
+      block $drop block $wsbool block $jmp block $wordputc block $wordstart
+      block $dictget block $parsenum block $wordfinish block $jneg1 block $swap
+      block $words block $here block $dictset block $dup2 block $rot block $drop2
+      block $comma block $subtract block $keychan block $sethere block $eqbool
         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
+        (;16;)$drop $wsbool (;18;)$jmp $wordputc (;20;)$wordstart $dictget
+       (;22;)$parsenum $wordfinish (;24;)$jneg1 $bye (;26;)$swap $words
+        (;28;)$here $dictset (;30;)$dup2 $rot (;32;)$drop2 $comma
+        (;34;)$subtract $keychan (;36;)$sethere $eqbool $default
+      end ;; eqbool
+        block $equiv
+          call $pop
+          call $pop
+          tee_local $eax
+          i32.eq
+          get_local $eax
+          call $push
+          br_if $equiv
+          i32.const 0
+          call $push
+          br $next
+        end
+        i32.const 1
+        call $push
+        br $next
+      end ;; sethere
+        call $pop
+        set_local $here
+        br $next
+      end ;; keychan
+        call $pop
+        set_local $channel
+        br $next
+      end ;; subtract
+        call $pop
+        set_local $eax
+        call $pop
+        get_local $eax
+        i32.sub
+        call $push
+        br $next
+      end ;; comma
+        get_local $here
+        call $pop
+        i32.store
+        get_local $here
+        i32.const 4
+        i32.add
+        set_local $here
+        br $next
+      end ;; drop2
+        call $pop
+        call $pop
+        drop
+        drop
+        br $next
+      end ;; rot
         call $pop
         set_local $eax
+        call $pop
+        call $pop
+        get_local $eax
+        call $push
+        call $push
+        call $push
+        br $next
+      end ;; dup2
+        get_local $esi
+        call $rpush
+        call $pop
+        set_local $eax
+        call $pop
+        tee_local $esi
+        call $push
+        get_local $eax
+        call $push
+        get_local $esi
+        call $push
+        get_local $eax
+        call $push
+        call $rpop
+        set_local $esi
+        br $next
+      end ;; dictset
+        call $pop
+        call $rpush
        call $pop
+        set_local $eax
+        call $pop
         get_local $eax
+        call $rpop
         call $vocab_set
         drop
         br $next
         i32.load
         set_local $esi
         br $next
-      end ;; wbsetlen
-        get_global $wbuf
-        get_local $wbuf_head
-        get_global $wbuf_data
+      end ;; wordfinish
+        get_local $wordbelt_tail
+       get_local $wordbelt_head
+        get_local $wordbelt_tail
+       i32.const 4
+       i32.add
         i32.sub
+        tee_local $eax (; n bytes ;)
         i32.store
-        get_global $wbuf
-       call $sys_reflect
+        (; align to 32-bit ;)
+        get_local $wordbelt_head
+        i32.const 3
+        i32.add
+        i32.const 12284
+        i32.and
+        set_local $wordbelt_head
+        (; /align ;)
+        get_local $wordbelt_tail
+        i32.const 4
+        i32.add
+        call $push
+        get_local $eax
+        call $push
         br $next
       end ;; parsenum
-        i32.const 396 (; load BASE ;)
-        i32.load
+        call $pop
+        call $rpush
         call $pop
         tee_local $eax
+        call $rpop
+        i32.const 14348 (; load BASE ;)
+        i32.load
         call $sys_parsenum
-        call $push
         get_local $eax
         i32.load
         call $push
+        call $push
        br $next
       end ;; dictget
         call $pop
+        set_local $eax
+        call $pop
+        get_local $eax
        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
+      end ;; wordstart
+        block $wbhasspace
+          get_local $wordbelt_head
+          get_global $inbuf
+          i32.const 8
+          i32.sub
+          i32.le_u
+          br_if $wbhasspace
+          get_global $wordbelt
+          set_local $wordbelt_head
+        end
+        get_local $wordbelt_head
+        get_local $wordbelt_head
+        tee_local $wordbelt_tail
+        i32.const 0
+        i32.store
+        i32.const 4
+        i32.add
+        set_local $wordbelt_head
+        br $next
+      end ;; wordputc
+        block $wbhasspace2
+          get_local $wordbelt_head
+          get_global $inbuf
+          i32.lt_u
+          br_if $wbhasspace2
+          get_global $wordbelt
+          tee_local $wordbelt_head
+          get_local $wordbelt_tail
+          i32.load
+          i32.store
+          get_local $wordbelt_head
+          i32.const 4
+          i32.add
+          set_local $wordbelt_head
+          get_local $wordbelt_tail
+          i32.const 4
+          i32.add
+          set_local $wordbelt_tail
+          loop $copywordtostart
+            get_local $wordbelt_head
+            get_local $wordbelt_tail
+            i32.load16_u
+            i32.store16
+            get_local $wordbelt_head
+            i32.const 2
+            i32.add
+            set_local $wordbelt_head
+            get_local $wordbelt_tail
+            i32.const 2
+            i32.add
+            tee_local $wordbelt_tail
+            get_global $inbuf
+            i32.le_u
+            br_if $copywordtostart
+          end
+          get_global $wordbelt
+          set_local $wordbelt_tail
+        end
+       get_local $wordbelt_head
         call $pop
        i32.store16
-       get_local $wbuf_head
+       get_local $wordbelt_head
        i32.const 2
        i32.add
-        set_local $wbuf_head
+        set_local $wordbelt_head
        br $next
       end ;; jmp
         get_local $esi
             set_local $inbuf_head
             br $next
           end ;; key_read
-          i32.const 0
+          get_local $channel
           get_global $inbuf
           call $sys_read
           block $nullread
       end ;; op0
         get_local $esi
         call $sys_reflect
-        br $next
+        br $bye
       end ;; default
         get_local $esi
         call $rpush
     end ;; execloop
     end ;; nextl
     end ;; bye
+    i32.const 14340
     get_local $here
+    i32.store
+    i32.const 14352
+    get_local $stringbelt_tail
+    i32.store
+    i32.const 14356
+    get_local $stringbelt_head
+    i32.store
+    i32.const 14360
+    get_local $wordbelt_tail
+    i32.store
+    i32.const 14364
+    get_local $wordbelt_head
+    i32.store
+    i32.const 14368
+    get_local $channel
+    i32.store
+    i32.const 0
   )
-)
\ No newline at end of file
+)