about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik Agaram <vc@akkartik.com>2019-02-14 16:24:20 -0800
committerKartik Agaram <vc@akkartik.com>2019-02-14 16:24:20 -0800
commit1639687ba098aa81b0584f7dd609cb9690dc5a04 (patch)
tree1a5ee40c30bf906c6ba5e55b8c5138a467022105
parent1ab48a69ccfa4ddaa2e1fa803ea6fe568b890abc (diff)
downloadmu-1639687ba098aa81b0584f7dd609cb9690dc5a04.tar.gz
4961
-rw-r--r--subx/051test.subx2
-rw-r--r--subx/052kernel-string-equal.subx54
-rw-r--r--subx/054string-equal.subx43
-rw-r--r--subx/055stream.subx4
-rw-r--r--subx/056trace.subx15
-rw-r--r--subx/057write.subx2
-rw-r--r--subx/058stream-equal.subx36
-rw-r--r--subx/059stop.subx7
-rw-r--r--subx/061read-byte.subx2
-rw-r--r--subx/065hex.subx6
-rw-r--r--subx/067write-buffered.subx4
-rw-r--r--subx/069allocate.subx2
-rw-r--r--subx/071read-line.subx8
-rw-r--r--subx/072slice.subx40
-rwxr-xr-xsubx/apps/crenshaw2-1bin17612 -> 17607 bytes
-rw-r--r--subx/apps/crenshaw2-1.subx16
-rwxr-xr-xsubx/apps/crenshaw2-1bbin18171 -> 18166 bytes
-rw-r--r--subx/apps/crenshaw2-1b.subx22
-rwxr-xr-xsubx/apps/factorialbin16530 -> 16525 bytes
-rw-r--r--subx/apps/factorial.subx2
-rwxr-xr-xsubx/apps/handlebin17323 -> 17318 bytes
-rwxr-xr-xsubx/apps/hexbin20591 -> 20586 bytes
-rw-r--r--subx/apps/hex.subx32
-rwxr-xr-xsubx/apps/packbin20768 -> 20763 bytes
-rw-r--r--subx/apps/pack.subx24
-rw-r--r--subx/examples/ex10.subx1
-rwxr-xr-xsubx/examples/ex11bin1117 -> 1111 bytes
-rw-r--r--subx/examples/ex11.subx135
-rw-r--r--subx/examples/ex3.subx2
-rw-r--r--subx/examples/ex8.subx2
-rw-r--r--subx/opcodes1
31 files changed, 253 insertions, 209 deletions
diff --git a/subx/051test.subx b/subx/051test.subx
index 08d1d6f6..2ae907c1 100644
--- a/subx/051test.subx
+++ b/subx/051test.subx
@@ -32,7 +32,7 @@ check-ints-equal:  # (a : int, b : int, msg : (address array byte)) -> <void>
     # load first 2 args into EAX and EBX
     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           0/r32/EAX   8/disp8         .                 # copy *(EBP+8) to EAX
     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           3/r32/EBX   0xc/disp8       .                 # copy *(EBP+12) to EBX
-    # if EAX == EBX success
+    # if (EAX == EBX) success
     39/compare                      3/mod/direct    0/rm32/EAX    .           .             .           3/r32/EBX   .               .                 # compare EAX and EBX
     75/jump-if-unequal  $check-ints-equal:else/disp8
     # . _write(2/stderr, '.')
diff --git a/subx/052kernel-string-equal.subx b/subx/052kernel-string-equal.subx
index b61c3303..840b4460 100644
--- a/subx/052kernel-string-equal.subx
+++ b/subx/052kernel-string-equal.subx
@@ -30,19 +30,26 @@
 # reason for the name: the only place we should have null-terminated ascii strings is from commandline args
 kernel-string-equal?:  # s : null-terminated ascii string, benchmark : length-prefixed ascii string -> EAX : boolean
     # pseudocode:
-    #   initialize n = b->length
-    #   initialize s1 = s
-    #   initialize s2 = b->data
+    #   n = benchmark->length
+    #   s1 = s
+    #   s2 = benchmark->data
     #   i = 0
-    #   for (i = 0; i < n; ++n)
+    #   while (i < n)
     #     c1 = *s1
     #     c2 = *s2
-    #     if c1 == 0
-    #       return false
-    #     if c1 != c2
-    #       return false
+    #     if (c1 == 0) return false
+    #     if (c1 != c2) return false
+    #     ++s1, ++s2, ++i
     #   return *s1 == 0
     #
+    # registers:
+    #   i: ECX
+    #   n: EDX
+    #   s1: EDI
+    #   s2: ESI
+    #   c1: EAX
+    #   c2: EBX
+    #
     # . prolog
     55/push-EBP
     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
@@ -52,24 +59,25 @@ kernel-string-equal?:  # s : null-terminated ascii string, benchmark : length-pr
     53/push-EBX
     56/push-ESI
     57/push-EDI
-    # initialize s into EDI
+    # s1/EDI = s
     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           7/r32/EDI   8/disp8         .                 # copy *(EBP+8) to EDI
-    # initialize benchmark length n into EDX
+    # n/EDX = benchmark->length
     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           2/r32/EDX   0xc/disp8       .                 # copy *(EBP+12) to EDX
     8b/copy                         0/mod/indirect  2/rm32/EDX    .           .             .           2/r32/EDX   .               .                 # copy *EDX to EDX
-    # initialize benchmark data into ESI
+    # s2/ESI = benchmark->data
     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           6/r32/ESI   0xc/disp8       .                 # copy *(EBP+12) to ESI
     81          0/subop/add         3/mod/direct    6/rm32/ESI    .           .             .           .           .               4/imm32           # add to ESI
-    # initialize loop counter i into ECX
+    # i/ECX = c1/EAX = c2/EBX = 0
     b9/copy-to-ECX  0/imm32/exit
-    # while (i/ECX < n/EDX)
+    b8/copy-to-EAX  0/imm32
+    bb/copy-to-EBX  0/imm32
 $kernel-string-equal?:loop:
+    # if (i >= n) break
     39/compare                      3/mod/direct    1/rm32/ECX    .           .             .           2/r32/EDX   .               .                 # compare ECX with EDX
-    74/jump-if-equal  $kernel-string-equal?:break/disp8
-    # c1/EAX, c2/EBX = *s, *benchmark
-    b8/copy-to-EAX  0/imm32
+    7d/jump-if-greater-or-equal  $kernel-string-equal?:break/disp8
+    # c1 = *s1
     8a/copy                         0/mod/indirect  7/rm32/EDI    .           .             .           0/r32/EAX   .               .                 # copy byte at *EDI to lower byte of EAX
-    bb/copy-to-EBX  0/imm32
+    # c2 = *s2
     8a/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           3/r32/EBX   .               .                 # copy byte at *ESI to lower byte of EBX
     # if (c1 == 0) return false
     3d/compare-EAX  0/imm32
@@ -77,22 +85,21 @@ $kernel-string-equal?:loop:
     # if (c1 != c2) return false
     39/compare                      3/mod/direct    0/rm32/EAX    .           .             .           3/r32/EBX   .               .                 # compare EAX with EBX
     75/jump-if-not-equal  $kernel-string-equal?:false/disp8
-    # ++s1, ++s2, ++i
+    # ++i
     41/inc-ECX
-    46/inc-ESI
+    # ++s1
     47/inc-EDI
-    # end while
+    # ++s2
+    46/inc-ESI
     eb/jump  $kernel-string-equal?:loop/disp8
 $kernel-string-equal?:break:
-    # if (*s/EDI == 0) return true
-    b8/copy-to-EAX  0/imm32
+    # return *s1 == 0
     8a/copy                         0/mod/indirect  7/rm32/EDI    .           .             .           0/r32/EAX   .               .                 # copy byte at *EDI to lower byte of EAX
     3d/compare-EAX  0/imm32
     75/jump-if-not-equal  $kernel-string-equal?:false/disp8
 $kernel-string-equal?:true:
     b8/copy-to-EAX  1/imm32
     eb/jump  $kernel-string-equal?:end/disp8
-    # return false
 $kernel-string-equal?:false:
     b8/copy-to-EAX  0/imm32
 $kernel-string-equal?:end:
@@ -253,6 +260,7 @@ test-compare-kernel-string-with-longer-array:
 
 Null-kernel-string:
     00/null
+
 _test-Abc-kernel-string:
     41/A 62/b 63/c 00/null
 
diff --git a/subx/054string-equal.subx b/subx/054string-equal.subx
index fdfca84e..f69c0c0f 100644
--- a/subx/054string-equal.subx
+++ b/subx/054string-equal.subx
@@ -13,18 +13,27 @@
     b8/copy-to-EAX  1/imm32/exit
     cd/syscall  0x80/imm8
 
-string-equal?:  # s : string, benchmark : string -> EAX : boolean
+string-equal?:  # s : (address string), benchmark : (address string) -> EAX : boolean
     # pseudocode:
-    #   if s->length != b->length return false
-    #   for i = 0;  i < s->length;  ++i
-    #     if s[i] != b[i] return false
+    #   lens = s->length
+    #   if (lens != benchmark->length) return false
+    #   i = 0
+    #   currs = s->data
+    #   currb = benchmark->data
+    #   while (i < s->length)
+    #     c1 = *currs
+    #     c2 = *currb
+    #     if (c1 != c2) return false
+    #     ++i, ++currs, ++currb
     #   return true
+    #
     # registers:
     #   i: ECX
-    #   s->length: EDX
-    #   b->length: EBX
-    #   b[i]: EBX
-    #   s[i]: EAX
+    #   lens: EDX
+    #   currs: EAX
+    #   currb: EBX
+    #   c1: ESI
+    #   c2: EDI
     #
     # . prolog
     55/push-EBP
@@ -34,17 +43,16 @@ string-equal?:  # s : string, benchmark : string -> EAX : boolean
     52/push-EDX
     53/push-EBX
     56/push-ESI
-    # var s/EAX : (address array byte)
+    # EAX = s
     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           0/r32/EAX   8/disp8         .                 # copy *(EBP+8) to EAX
-    # var benchmark/EBX : (address array byte)
+    # EBX = benchmark
     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           3/r32/EBX   0xc/disp8       .                 # copy *(EBP+12) to EBX
-    # if s->length != b->length return false
-    # EDX = s->length
+    # lens/EDX = s->length
     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           2/r32/EDX   .               .                 # copy *EAX to EDX
-    # compare s->length and b->length
+$string-equal?:lengths:
+    # if (lens != benchmark->length) return false
     39/compare                      0/mod/indirect  3/rm32/EBX    .           .             .           2/r32/EDX   .               .                 # compare *EBX with EDX
     75/jump-if-not-equal  $string-equal?:false/disp8
-$string-equal?:lengths:
     # var i/ECX : int = 0
     b9/copy-to-ECX  0/imm32
     # EBX = &b[i]
@@ -52,7 +60,7 @@ $string-equal?:lengths:
     # EAX = &s[i]
     40/inc-EAX
 $string-equal?:loop:
-    # if i >= s->length return true
+    # if (i >= lens) return true
     39/compare                      3/mod/direct    1/rm32/ECX    .           .             .           2/r32/EDX   .               .                 # compare ECX with EDX
     7d/jump-if-greater-or-equal  $string-equal?:true/disp8
     # if b[i] != s[i] return false
@@ -63,16 +71,15 @@ $string-equal?:loop:
     75/jump-if-not-equal  $string-equal?:false/disp8
     # ++i
     41/inc-ECX
+    # ++c1
     40/inc-EAX
+    # ++c2
     43/inc-EBX
-    # loop
     eb/jump  $string-equal?:loop/disp8
 $string-equal?:true:
-    # return true
     b8/copy-to-EAX  1/imm32
     eb/jump  $string-equal?:end/disp8
 $string-equal?:false:
-    # return false
     b8/copy-to-EAX  0/imm32
 $string-equal?:end:
     # . restore registers
diff --git a/subx/055stream.subx b/subx/055stream.subx
index 0d196311..f5d24876 100644
--- a/subx/055stream.subx
+++ b/subx/055stream.subx
@@ -42,7 +42,7 @@ clear-stream:  # f : (address stream) -> <void>
     81          0/subop/add         3/mod/direct    0/rm32/EAX    .           .             .           .           .               0xc/imm32         # add to EAX
     # while (true)
 $clear-stream:loop:
-    # if EAX >= ECX break
+    # if (EAX >= ECX) break
     39/compare                      3/mod/direct    0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # compare EAX with ECX
     7d/jump-if-greater-or-equal  $clear-stream:end/disp8
     # *EAX = 0
@@ -76,3 +76,5 @@ $rewind-stream:end:
     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
     5d/pop-to-EBP
     c3/return
+
+# . . vim:nowrap:textwidth=0
diff --git a/subx/056trace.subx b/subx/056trace.subx
index 96e5646b..aa73bbdd 100644
--- a/subx/056trace.subx
+++ b/subx/056trace.subx
@@ -99,7 +99,7 @@ trace:  # t : (address trace-stream), line : string
     e8/call  _append-3/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
-    # if EAX == 0 return
+    # if (EAX == 0) return
     81          7/subop/compare     3/mod/direct    0/rm32/EAX    .           .             .           .           .               0/imm32           # compare EDX
     74/jump-if-equal  $trace:end/disp8
     # t->write += EAX
@@ -153,9 +153,8 @@ clear-trace-stream:  # t : (address trace-stream)
     c7          0/subop/copy        1/mod/*+disp8   0/rm32/EAX    .           .             .           .           4/disp8         0/imm32           # copy to *(EAX+4)
     # EAX = t->data
     81          0/subop/add         3/mod/direct    0/rm32/EAX    .           .             .           .           .               0xc/imm32         # add to EAX
-    # while (true)
 $clear-trace-stream:loop:
-    # if EAX >= ECX break
+    # if (EAX >= ECX) break
     39/compare                      3/mod/direct    0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # compare EAX with ECX
     7d/jump-if-greater-or-equal  $clear-trace-stream:end/disp8
     # *EAX = 0
@@ -328,18 +327,20 @@ _append-4:  # out : address, outend : address, in : address, inend : address ->
     # ECX = inend
     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           1/r32/ECX   0x14/disp8      .                 # copy *(EBP+20) to ECX
 $_append-4:loop:
-    # if ESI/in >= ECX/inend break
+    # if (in >= inend) break
     39/compare                      3/mod/direct    6/rm32/ESI    .           .             .           1/r32/ECX   .               .                 # compare ESI with ECX
     7d/jump-if-greater-or-equal  $_append-4:end/disp8
-    # if EDI/out >= EDX/outend break  (for now silently ignore filled up buffer)
+    # if (out >= outend) break  # for now silently ignore filled up buffer
     39/compare                      3/mod/direct    7/rm32/EDI    .           .             .           2/r32/EDX   .               .                 # compare EDI with EDX
     7d/jump-if-greater-or-equal  $_append-4:end/disp8
-    # copy one byte from ESI/in to EDI/out
+    # *out = *in
     8a/copy-byte                    0/mod/indirect  6/rm32/ESI    .           .             .           3/r32/BL    .               .                 # copy byte at *ESI to BL
     88/copy-byte                    0/mod/indirect  7/rm32/EDI    .           .             .           3/r32/BL    .               .                 # copy byte at BL to *EDI
-    # updates
+    # ++num_bytes_appended
     40/increment-EAX
+    # ++in
     46/increment-ESI
+    # ++out
     47/increment-EDI
     eb/jump  $_append-4:loop/disp8
 $_append-4:end:
diff --git a/subx/057write.subx b/subx/057write.subx
index 3f2f8a11..c1712996 100644
--- a/subx/057write.subx
+++ b/subx/057write.subx
@@ -32,7 +32,7 @@ write:  # f : fd or (address stream), s : (address array byte) -> <void>
     # . prolog
     55/push-EBP
     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
-    # if (f < 0x08000000) _write(f, s), return  # f can't be a user-mode address, so treat it as a kernel file descriptor
+    # if (f < 0x08000000) _write(f, s) and return  # f can't be a user-mode address, so treat it as a kernel file descriptor
     81          7/subop/compare     1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         0x08000000/imm32  # compare *(EBP+8)
     7d/jump-if-greater-or-equal  $write:fake/disp8
     # . . push args
diff --git a/subx/058stream-equal.subx b/subx/058stream-equal.subx
index e4c1962e..203e5415 100644
--- a/subx/058stream-equal.subx
+++ b/subx/058stream-equal.subx
@@ -32,7 +32,7 @@ stream-data-equal?:  # f : (address stream), s : (address string) -> EAX : boole
     81          0/subop/add         3/mod/direct    6/rm32/ESI    .           .             .           .           .               0xc/imm32         # add to ESI
     # EDI = s
     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           7/r32/EDI   0xc/disp8       .                 # copy *(EBP+12) to EDI
-    # if (f->write != s->length) return false;
+    # if (f->write != s->length) return false
     39/compare                      0/mod/indirect  7/rm32/EDI    .           .             .           0/r32/EAX   .               .                 # compare *EDI and EAX
     75/jump-if-not-equal  $stream-data-equal?:false/disp8
     # currs/EDI = s->data
@@ -235,25 +235,25 @@ next-stream-line-equal?:  # f : (address stream), s : (address string) -> EAX :
     # pseudocode:
     #   currf = f->read  # bound: f->write
     #   currs = 0  # bound : s->length
-    #   while true
-    #     if currf >= f->write
+    #   while true:
+    #     if (currf >= f->write)
     #       return currs >= s->length
-    #     if f[currf] == '\n'
+    #     if (f[currf] == '\n')
     #       ++currf
     #       return currs >= s->length
-    #     if currs >= s->length return false  # the current line of f still has data to match
-    #     if f[currf] != s[currs] return false
+    #     if (currs >= s->length) return false  # the current line of f still has data to match
+    #     if (f[currf] != s[currs]) return false
     #     ++currf
     #     ++currs
     #
     # collapsing the two branches that can return true:
     #   currf = f->read  # bound: f->write
     #   currs = 0  # bound : s->length
-    #   while true
-    #     if currf >= f->write break
-    #     if f[currf] == '\n' break
-    #     if currs >= s->length return false  # the current line of f still has data to match
-    #     if f[currf] != s[currs] return false
+    #   while true:
+    #     if (currf >= f->write) break
+    #     if (f[currf] == '\n') break
+    #     if (currs >= s->length) return false  # the current line of f still has data to match
+    #     if (f[currf] != s[currs]) return false
     #     ++currf
     #     ++currs
     #   ++currf  # skip '\n'
@@ -261,12 +261,12 @@ next-stream-line-equal?:  # f : (address stream), s : (address string) -> EAX :
     # Here the final `++currf` is sometimes unnecessary (if we're already at the end of the stream)
     #
     # registers:
-    #   f : ESI
-    #   s : EDI
-    #   currf : ECX
-    #   currs : EDX
-    #   f[currf] : EAX
-    #   s[currs] : EBX
+    #   f: ESI
+    #   s: EDI
+    #   currf: ECX
+    #   currs: EDX
+    #   f[currf]: EAX
+    #   s[currs]: EBX
     #
     # . prolog
     55/push-EBP
@@ -312,7 +312,7 @@ $next-stream-line-equal?:loop:
 $next-stream-line-equal?:break:
     # ++currf
     41/increment-ECX
-    # if currs >= s->length return true
+    # if (currs >= s->length) return true
     3b/compare                      0/mod/indirect  7/rm32/EDI    .           .             .           2/r32/EDX   .               .                 # compare EDX with *EDI
     7c/jump-if-lesser  $next-stream-line-equal?:false/disp8
 $next-stream-line-equal?:true:
diff --git a/subx/059stop.subx b/subx/059stop.subx
index f9e67f9e..4478dab3 100644
--- a/subx/059stop.subx
+++ b/subx/059stop.subx
@@ -100,19 +100,20 @@ stop:  # ed : (address exit-descriptor), value : int
     # no prolog; one way or another, we're going to clobber registers
     # EAX = ed
     8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/ESP  4/index/none  .           0/r32/EAX   4/disp8         .                 # copy *(ESP+4) to EAX
-    # exit(value) if ed->target == 0
+    # if (ed->target == 0) really exit
     81          7/subop/compare     0/mod/indirect  0/rm32/EAX    .           .             .           .           .               0/imm32           # compare *EAX
     75/jump-if-not-equal  $stop:fake/disp8
-    # syscall(exit, value)
+    # . syscall(exit, value)
     8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/ESP  4/index/none  .           3/r32/EBX   8/disp8         .                 # copy *(ESP+8) to EBX
     b8/copy-to-EAX  1/imm32/exit
     cd/syscall  0x80/imm8
 $stop:fake:
+    # otherwise:
     # ed->value = value+1
     8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/ESP  4/index/none  .           1/r32/ECX   8/disp8         .                 # copy *(ESP+8) to ECX
     41/inc-ECX
     89/copy                         1/mod/*+disp8   0/rm32/EAX    .           .             .           1/r32/ECX   4/disp8         .                 # copy ECX to *(EAX+4)
-    # non-local jump to ed->target
+    # perform a non-local jump to ed->target
     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           4/r32/ESP   .               .                 # copy *EAX to ESP
 $stop:end:
     c3/return  # doesn't return to caller
diff --git a/subx/061read-byte.subx b/subx/061read-byte.subx
index c62b035e..a915d436 100644
--- a/subx/061read-byte.subx
+++ b/subx/061read-byte.subx
@@ -74,7 +74,7 @@ read-byte:  # f : (address buffered-file) -> byte-or-eof/EAX
     e8/call  read/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
-    # if EAX = 0 return 0xffffffff
+    # if (EAX == 0) return 0xffffffff
     81          7/subop/compare     3/mod/direct    0/rm32/EAX    .           .             .           .           .               0/imm32           # compare EAX
     75/jump-if-not-equal  $read-byte:from-stream/disp8
     b8/copy-to-EAX  0xffffffff/imm32
diff --git a/subx/065hex.subx b/subx/065hex.subx
index 6ba2ef7e..9096680b 100644
--- a/subx/065hex.subx
+++ b/subx/065hex.subx
@@ -71,7 +71,7 @@ $is-hex-int?:loop:
     e8/call  is-hex-digit?/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
-    # if EAX == false return false
+    # if (EAX == false) return false
     3d/compare-with-EAX  0/imm32
     74/jump-if-equal  $is-hex-int?:end/disp8
     # ++curr
@@ -738,7 +738,7 @@ test-hex-above-f:
 
 from-hex-char:  # in/EAX : byte -> out/EAX : num
     # no error checking; accepts argument in EAX
-    # if EAX <= '9' return EAX - '0'
+    # if (EAX <= '9') return EAX - '0'
     3d/compare-EAX  0x39/imm32/9
     7f/jump-if-greater  $from-hex-char:else/disp8
     2d/subtract-from-EAX  0x30/imm32/0
@@ -750,7 +750,7 @@ $from-hex-char:else:
 
 to-hex-char:  # in/EAX : nibble -> out/EAX : byte
     # no error checking; accepts argument in EAX
-    # if EAX <= 9 return EAX + '0'
+    # if (EAX <= 9) return EAX + '0'
     3d/compare-EAX  0x9/imm32/9
     7f/jump-if-greater  $to-hex-char:else/disp8
     05/add-to-EAX  0x30/imm32/0
diff --git a/subx/067write-buffered.subx b/subx/067write-buffered.subx
index 3825a7f3..50ec7988 100644
--- a/subx/067write-buffered.subx
+++ b/subx/067write-buffered.subx
@@ -18,8 +18,8 @@ write-buffered:  # f : (address buffered-file), msg : (address array byte) -> <v
     # pseudocode:
     #   in = msg->data
     #   inend = &msg->data[msg->length]
-    #   while in < inend
-    #     if f->write >= f->length
+    #   while (in < inend)
+    #     if (f->write >= f->length)
     #       flush(f)
     #       clear-stream(f)
     #     f->data[f->write] = *in
diff --git a/subx/069allocate.subx b/subx/069allocate.subx
index 37b01d21..1d9e043a 100644
--- a/subx/069allocate.subx
+++ b/subx/069allocate.subx
@@ -164,7 +164,7 @@ allocate-region:  # ad : (address allocation-descriptor), n : int -> new-ad : (a
     e8/call  allocate/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
-    # if EAX == 0 abort
+    # if (EAX == 0) abort
     81          7/subop/compare     3/mod/direct    0/rm32/EAX    .           .             .           .           .               0/imm32           # compare EAX
     74/jump-if-equal  $allocate-region:abort/disp8
     # earmark 8 bytes at the start for a new allocation descriptor
diff --git a/subx/071read-line.subx b/subx/071read-line.subx
index 3efa96e0..61513aa9 100644
--- a/subx/071read-line.subx
+++ b/subx/071read-line.subx
@@ -23,7 +23,7 @@ read-line:  # f : (address buffered-file), s : (address stream byte) -> eof?/EAX
     #     s->data[s->write] = AL
     #     ++f->read
     #     ++s->write
-    #     if AL == '\n' break
+    #     if (AL == '\n') break
     # . prolog
     55/push-EBP
     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
@@ -65,8 +65,8 @@ $read-line:loop:
     e8/call  read/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
-    # if f->write == 0 return true
-    # . if EAX == 0 return true
+    # if (f->write == 0) return true
+    # . if (EAX == 0) return true
     81          7/subop/compare     3/mod/direct    0/rm32/EAX    .           .             .           .           .               0/imm32           # compare EAX
     75/jump-if-not-equal  $read-line:from-stream/disp8
     b8/copy-to-EAX  0xffffffff/imm32
@@ -81,7 +81,7 @@ $read-line:from-stream:
     41/increment-ECX
     # ++s->write
     42/increment-EDX
-    # if AL == '\n' return false
+    # if (AL == '\n') return false
     81          7/subop/compare     3/mod/direct    0/rm32/EAX    .           .             .           .           .               0xa/imm32         # compare EAX
     75/jump-if-not-equal  $read-line:loop/disp8
     31/xor                          3/mod/direct    0/rm32/EAX    .           .             .           0/r32/EAX   .               .                 # clear EAX
diff --git a/subx/072slice.subx b/subx/072slice.subx
index fa244219..20a39aa4 100644
--- a/subx/072slice.subx
+++ b/subx/072slice.subx
@@ -21,7 +21,7 @@ slice-empty?:  # s : (address slice) -> EAX : boolean
     51/push-ECX
     # ECX = s
     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           1/r32/ECX   8/disp8         .                 # copy *(EBP+8) to ECX
-    # if s->start == s->end return true
+    # if (s->start == s->end) return true
     # . EAX = s->start
     8b/copy                         0/mod/indirect  1/rm32/ECX    .           .             .           0/r32/EAX   .               .                 # copy *ECX to EAX
     # . compare EAX with s->end
@@ -96,6 +96,24 @@ test-slice-empty-false:
     c3/return
 
 slice-equal?:  # s : (address slice), p : (address string) -> EAX : boolean
+    # pseudocode:
+    #   currs = s->start
+    #   maxs = s->end
+    #   if (maxs - currs != p->length) return false
+    #   currp = p->data
+    #   while (currs < maxs)
+    #     if (*currs != *currp) return false
+    #     ++currs
+    #     ++currp
+    #   return true
+    #
+    # registers:
+    #   EAX : *currs
+    #   ECX : *currp
+    #   EDX : currs
+    #   EBX : currp
+    #   ESI : maxs
+    #
     # . prolog
     55/push-EBP
     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
@@ -106,37 +124,37 @@ slice-equal?:  # s : (address slice), p : (address string) -> EAX : boolean
     56/push-ESI
     # ESI = s
     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           6/r32/ESI   8/disp8         .                 # copy *(EBP+8) to ESI
-    # curr/EDX = s->start
+    # currs/EDX = s->start
     8b/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           2/r32/EDX   .               .                 # copy *ESI to EDX
-    # max/ESI = s->end
+    # maxs/ESI = s->end
     8b/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           6/r32/ESI   4/disp8         .                 # copy *(ESI+4) to ESI
     # EBX = p
     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           3/r32/EBX   0xc/disp8       .                 # copy *(EBP+12) to EBX
-    # EAX = s->end - s->start
+    # EAX = maxs - currs
     89/copy                         3/mod/direct    0/rm32/EAX    .           .             .           6/r32/ESI   .               .                 # copy ESI to EAX
     29/subtract                     3/mod/direct    0/rm32/EAX    .           .             .           2/r32/EDX   .               .                 # subtract EDX from EAX
-    # if (EAX != p->length) return false;
+    # if (EAX != p->length) return false
     39/compare                      0/mod/indirect  3/rm32/EBX    .           .             .           0/r32/EAX   .               .                 # compare *EBX and EAX
     75/jump-if-not-equal  $slice-equal?:false/disp8
-    # skip p->length
+    # currp/EBX = p->data
     81          0/subop/add         3/mod/direct    3/rm32/EBX    .           .             .           .           .               4/imm32           # add to EBX
     # EAX = ECX = 0
     31/xor                          3/mod/direct    0/rm32/EAX    .           .             .           0/r32/EAX   .               .                 # clear EAX
     31/xor                          3/mod/direct    1/rm32/ECX    .           .             .           1/r32/ECX   .               .                 # clear ECX
 $slice-equal?:loop:
-    # if (curr >= max) return true
+    # if (currs >= maxs) return true
     39/compare                      3/mod/direct    2/rm32/EDX    .           .             .           6/r32/ESI   .               .                 # compare EDX and ESI
     7d/jump-if-greater-or-equal  $slice-equal?:true/disp8
-    # AL = *p
+    # AL = *currp
     8a/copy-byte                    0/mod/indirect  3/rm32/EBX    .           .             .           0/r32/AL    .               .                 # copy byte at *EBX to AL
-    # CL = *curr
+    # CL = *currs
     8a/copy-byte                    0/mod/indirect  2/rm32/EDX    .           .             .           1/r32/CL    .               .                 # copy byte at *EDX to CL
     # if (EAX != ECX) return false
     39/compare                      3/mod/direct    0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # compare EAX and ECX
     75/jump-if-not-equal  $slice-equal?:false/disp8
-    # ++p
+    # ++currp
     43/increment-EBX
-    # ++curr
+    # ++currs
     42/increment-EDX
     eb/jump $slice-equal?:loop/disp8
 $slice-equal?:false:
diff --git a/subx/apps/crenshaw2-1 b/subx/apps/crenshaw2-1
index 3391c314..73a34441 100755
--- a/subx/apps/crenshaw2-1
+++ b/subx/apps/crenshaw2-1
Binary files differdiff --git a/subx/apps/crenshaw2-1.subx b/subx/apps/crenshaw2-1.subx
index 7c279955..3fe51fd7 100644
--- a/subx/apps/crenshaw2-1.subx
+++ b/subx/apps/crenshaw2-1.subx
@@ -37,7 +37,7 @@
 # main: run tests if necessary, call 'compile' if not
     # . prolog
     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
-    # - if argc > 1 and argv[1] == "test" then return run_tests()
+    # - if argc > 1 and argv[1] == "test", then return run_tests()
     # . argc > 1
     81          7/subop/compare     1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0/disp8         1/imm32           # compare *EBP
     7e/jump-if-lesser-or-equal  $run-main/disp8
@@ -199,8 +199,8 @@ $compile:end:
 # 'in' into it on exit.
 get-num:  # in : (address buffered-file), out : (address stream), err : fd or (address stream), ed : (address exit-descriptor) -> <void>
     # pseudocode:
-    #   if !is-digit?(Look) expected(ed, err, "integer")
-    #   if out->write >= out->length
+    #   if (!is-digit?(Look)) expected(ed, err, "integer")
+    #   if (out->write >= out->length)
     #     write(err, "Error: too many digits in number\n")
     #     stop(ed, 1)
     #   out->data[out->write] = LSB(Look)
@@ -221,7 +221,7 @@ get-num:  # in : (address buffered-file), out : (address stream), err : fd or (a
     # . prolog
     55/push-EBP
     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
-    # - if is-digit?(Look) expected(ed, err, "integer")
+    # - if (is-digit?(Look)) expected(ed, err, "integer")
     # . EAX = is-digit?(Look)
     # . . push args
     ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Look/disp32     .                 # push *Look
@@ -229,7 +229,7 @@ get-num:  # in : (address buffered-file), out : (address stream), err : fd or (a
     e8/call  is-digit?/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
-    # . if EAX == 0
+    # . if (EAX == 0)
     3d/compare-EAX  0/imm32
     75/jump-if-not-equal  $get-num:main/disp8
     # . expected(ed, err, "integer")
@@ -259,7 +259,7 @@ $get-num:main:
     8b/copy                         0/mod/indirect  7/rm32/EDI    .           .             .           1/r32/ECX   .               .                 # copy *EDI to ECX
     # EDX = out->length
     8b/copy                         1/mod/*+disp8   7/rm32/EDI    .           .             .           2/r32/EDX   8/disp8         .                 # copy *(EDI+8) to EDX
-    # if out->write >= out->length error
+    # if (out->write >= out->length) error
     39/compare                      3/mod/direct    2/rm32/EDX    .           .             .           1/r32/ECX   .               .                 # compare EDX with ECX
     7d/jump-if-lesser  $get-num:stage2/disp8
     # . error(ed, err, msg)  # TODO: show full number
@@ -559,10 +559,10 @@ is-digit?:  # c : int -> EAX : boolean
     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
     # EAX = false
     b8/copy-to-EAX  0/imm32
-    # if c < '0' return false
+    # if (c < '0') return false
     81          7/subop/compare     1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         0x30/imm32        # compare *(EBP+8)
     7c/jump-if-lesser  $is-digit?:end/disp8
-    # if c > '9' return false
+    # if (c > '9') return false
     81          7/subop/compare     1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         0x39/imm32        # compare *(EBP+8)
     7f/jump-if-greater  $is-digit?:end/disp8
     # otherwise return true
diff --git a/subx/apps/crenshaw2-1b b/subx/apps/crenshaw2-1b
index 24c37657..80c9e4f0 100755
--- a/subx/apps/crenshaw2-1b
+++ b/subx/apps/crenshaw2-1b
Binary files differdiff --git a/subx/apps/crenshaw2-1b.subx b/subx/apps/crenshaw2-1b.subx
index 0df86a68..4fc2680b 100644
--- a/subx/apps/crenshaw2-1b.subx
+++ b/subx/apps/crenshaw2-1b.subx
@@ -37,7 +37,7 @@
 # main: run tests if necessary, call 'compile' if not
     # . prolog
     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
-    # - if argc > 1 and argv[1] == "test" then return run_tests()
+    # - if argc > 1 and argv[1] == "test", then return run_tests()
     # . argc > 1
     81          7/subop/compare     1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0/disp8         1/imm32           # compare *EBP
     7e/jump-if-lesser-or-equal  $run-main/disp8
@@ -200,15 +200,15 @@ $compile:end:
 # 'in' (rest). We leave the next byte from 'in' into 'Look' on exit.
 get-num:  # in : (address buffered-file), out : (address stream), err : fd or (address stream), ed : (address exit-descriptor) -> <void>
     # pseudocode:
-    #   if !is-digit?(Look) expected(ed, err, "integer")
+    #   if (!is-digit?(Look)) expected(ed, err, "integer")
     #   do
-    #     if out->write >= out->length
+    #     if (out->write >= out->length)
     #       write(err, "Error: too many digits in number\n")
     #       stop(ed, 1)
     #     out->data[out->write] = LSB(Look)
     #     ++out->write
     #     Look = get-char(in)
-    #   while is-digit?(Look)
+    #   while (is-digit?(Look))
     # This is complicated because I don't want to hard-code the error strategy in
     # a general helper like write-byte. Maybe I should just create a local helper.
     #
@@ -226,7 +226,7 @@ get-num:  # in : (address buffered-file), out : (address stream), err : fd or (a
     # . prolog
     55/push-EBP
     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
-    # - if is-digit?(Look) expected(ed, err, "integer")
+    # - if (is-digit?(Look)) expected(ed, err, "integer")
     # . EAX = is-digit?(Look)
     # . . push args
     ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Look/disp32     .                 # push *Look
@@ -234,7 +234,7 @@ get-num:  # in : (address buffered-file), out : (address stream), err : fd or (a
     e8/call  is-digit?/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
-    # . if EAX == 0
+    # . if (EAX == 0)
     3d/compare-EAX  0/imm32
     75/jump-if-not-equal  $get-num:main/disp8
     # . expected(ed, err, "integer")
@@ -265,7 +265,7 @@ $get-num:main:
     # EDX = out->length
     8b/copy                         1/mod/*+disp8   7/rm32/EDI    .           .             .           2/r32/EDX   8/disp8         .                 # copy *(EDI+8) to EDX
 $get-num:loop:
-    # if out->write >= out->length error
+    # if (out->write >= out->length) error
     39/compare                      3/mod/direct    2/rm32/EDX    .           .             .           1/r32/ECX   .               .                 # compare EDX with ECX
     7d/jump-if-lesser  $get-num:loop-stage2/disp8
     # . error(ed, err, msg)  # TODO: show full number
@@ -291,7 +291,7 @@ $get-num:loop-stage2:
     e8/call  get-char/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
-    # if is-digit?(Look) loop
+    # if (is-digit?(Look)) loop
     # . EAX = is-digit?(Look)
     # . . push args
     ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Look/disp32     .                 # push *Look
@@ -299,7 +299,7 @@ $get-num:loop-stage2:
     e8/call  is-digit?/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
-    # . if EAX loop
+    # . if (EAX != 0) loop
     3d/compare-EAX  0/imm32
     0f 85/jump-if-not-equal  $get-num:loop/disp32
 $get-num:loop-end:
@@ -756,10 +756,10 @@ is-digit?:  # c : int -> EAX : boolean
     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
     # EAX = false
     b8/copy-to-EAX  0/imm32
-    # if c < '0' return false
+    # if (c < '0') return false
     81          7/subop/compare     1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         0x30/imm32        # compare *(EBP+8)
     7c/jump-if-lesser  $is-digit?:end/disp8
-    # if c > '9' return false
+    # if (c > '9') return false
     81          7/subop/compare     1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         0x39/imm32        # compare *(EBP+8)
     7f/jump-if-greater  $is-digit?:end/disp8
     # otherwise return true
diff --git a/subx/apps/factorial b/subx/apps/factorial
index 01112b12..83a5e14f 100755
--- a/subx/apps/factorial
+++ b/subx/apps/factorial
Binary files differdiff --git a/subx/apps/factorial.subx b/subx/apps/factorial.subx
index a239d419..912285e2 100644
--- a/subx/apps/factorial.subx
+++ b/subx/apps/factorial.subx
@@ -21,7 +21,7 @@
 # main:
     # . prolog
     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
-    # - if argc > 1 and argv[1] == "test" then return run_tests()
+    # - if argc > 1 and argv[1] == "test", then return run_tests()
     # . argc > 1
     81          7/subop/compare     1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0/disp8         1/imm32           # compare *EBP
     7e/jump-if-lesser-or-equal  $run-main/disp8
diff --git a/subx/apps/handle b/subx/apps/handle
index 164fbd1a..d79ed98e 100755
--- a/subx/apps/handle
+++ b/subx/apps/handle
Binary files differdiff --git a/subx/apps/hex b/subx/apps/hex
index 5edc02a3..a9500830 100755
--- a/subx/apps/hex
+++ b/subx/apps/hex
Binary files differdiff --git a/subx/apps/hex.subx b/subx/apps/hex.subx
index 2c1606ed..d841fd8b 100644
--- a/subx/apps/hex.subx
+++ b/subx/apps/hex.subx
@@ -25,7 +25,7 @@
 # main: run tests if necessary, convert stdin if not
     # . prolog
     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
-    # - if argc > 1 and argv[1] == "test" then return run_tests()
+    # - if argc > 1 and argv[1] == "test", then return run_tests()
     # . argc > 1
     81          7/subop/compare     1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0/disp8         1/imm32           # compare *EBP
     7e/jump-if-lesser-or-equal  $run-main/disp8
@@ -73,7 +73,7 @@ convert:  # in : (address buffered-file), out : (address buffered-file), err : (
     # pseudocode:
     #   repeatedly
     #     EAX = convert-next-octet(in, err, ed)
-    #     if EAX == 0xffffffff break  # eof
+    #     if (EAX == 0xffffffff) break  # eof
     #     write-byte(out, AL)
     #   flush(out)
     #
@@ -92,7 +92,7 @@ $convert:loop:
     e8/call  convert-next-octet/disp32
     # . . discard first 2 args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
-    # if EAX == 0xffffffff break
+    # if (EAX == 0xffffffff) break
     81          7/subop/compare     3/mod/direct    0/rm32/EAX    .           .             .           .           .               0xffffffff/imm32  # compare EAX
     74/jump-if-equal  $convert:loop-end/disp8
     # write-byte(out, AL)
@@ -489,10 +489,10 @@ scan-next-byte:  # in : (address buffered-file), err : (address buffered-file),
     # pseudocode:
     #   repeatedly
     #     EAX = read-byte(in)
-    #     if EAX == 0xffffffff return EAX
-    #     if is-hex-digit?(EAX) return EAX
-    #     if EAX == ' ' or '\t' or '\n' continue
-    #     if EAX == '#' skip-until-newline(in)
+    #     if (EAX == 0xffffffff) return EAX
+    #     if (is-hex-digit?(EAX)) return EAX
+    #     if (EAX == ' ' or '\t' or '\n') continue
+    #     if (EAX == '#') skip-until-newline(in)
     #     else error-byte(ed, err, "invalid byte: " EAX)
     #
     # . prolog
@@ -510,7 +510,7 @@ $scan-next-byte:loop:
     # if (EAX == 0xffffffff) return EAX
     3d/compare-with-EAX  0xffffffff/imm32
     74/jump-if-equal  $scan-next-byte:end/disp8
-    # if is-hex-digit?(EAX) return EAX
+    # if (is-hex-digit?(EAX)) return EAX
     # . save EAX for now
     50/push-EAX
     # . is-hex-digit?(EAX)
@@ -527,17 +527,17 @@ $scan-next-byte:loop:
     # . check whether to return
     75/jump-if-not-equal  $scan-next-byte:end/disp8
 $scan-next-byte:check1:
-    # if EAX == ' ' continue
+    # if (EAX == ' ') continue
     81          7/subop/compare     3/mod/direct    0/rm32/EAX    .           .             .           .           .               0x20/imm32        # compare EAX
     74/jump-if-equal  $scan-next-byte:loop/disp8
-    # if EAX == '\t' continue
+    # if (EAX == '\t') continue
     81          7/subop/compare     3/mod/direct    0/rm32/EAX    .           .             .           .           .               0x9/imm32         # compare EAX
     74/jump-if-equal  $scan-next-byte:loop/disp8
-    # if EAX == '\n' continue
+    # if (EAX == '\n') continue
     81          7/subop/compare     3/mod/direct    0/rm32/EAX    .           .             .           .           .               0xa/imm32         # compare EAX
     74/jump-if-equal  $scan-next-byte:loop/disp8
 $scan-next-byte:check2:
-    # if EAX == '#' skip-until-newline(in)
+    # if (EAX == '#') skip-until-newline(in)
     3d/compare-with-EAX  0x23/imm32
     75/jump-if-not-equal  $scan-next-byte:check3/disp8
     # . skip-until-newline(in)
@@ -1413,8 +1413,8 @@ skip-until-newline:  # in : (address buffered-file) -> <void>
     #   push EAX
     #   repeatedly:
     #     EAX = read-byte(in)
-    #     if EAX == 0xffffffff break
-    #     if EAX == 0x0a break
+    #     if (EAX == 0xffffffff) break
+    #     if (EAX == 0x0a) break
     #   pop EAX
     # . prolog
     55/push-EBP
@@ -1429,10 +1429,10 @@ $skip-until-newline:loop:
     e8/call  read-byte/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
-    # . if EAX == 0xffffffff break
+    # . if (EAX == 0xffffffff) break
     81          7/subop/compare     3/mod/direct    0/rm32/EAX    .           .             .           .           .               0xffffffff/imm32  # compare EAX
     74/jump-if-equal  $skip-until-newline:end/disp8
-    # . if EAX != 0xa/newline loop
+    # . if (EAX != 0xa/newline) loop
     81          7/subop/compare     3/mod/direct    0/rm32/EAX    .           .             .           .           .               0xa/imm32         # compare EAX
     75/jump-if-not-equal  $skip-until-newline:loop/disp8
 $skip-until-newline:end:
diff --git a/subx/apps/pack b/subx/apps/pack
index 075dc69b..e55b170a 100755
--- a/subx/apps/pack
+++ b/subx/apps/pack
Binary files differdiff --git a/subx/apps/pack.subx b/subx/apps/pack.subx
index 07988399..a27d2613 100644
--- a/subx/apps/pack.subx
+++ b/subx/apps/pack.subx
@@ -28,7 +28,7 @@
 # main: run tests if necessary, convert stdin if not
     # . prolog
     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
-    # - if argc > 1 and argv[1] == "test" then return run_tests()
+    # - if argc > 1 and argv[1] == "test", then return run_tests()
     # . argc > 1
     81          7/subop/compare     1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0/disp8         1/imm32           # compare *EBP
     7e/jump-if-lesser-or-equal  $run-main/disp8
@@ -88,7 +88,7 @@ convert:  # in : (address buffered-file), out : (address buffered-file) -> <void
     #   repeatedly
     #     clear-stream(line)
     #     EAX = read-line(in, line)
-    #     if EAX == EOF break
+    #     if (EAX == EOF) break
     #     convert-instruction(line, out)
     #   flush(out)
     #
@@ -119,7 +119,7 @@ $convert:loop:
     e8/call  convert-instruction/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
-    # if EAX == 0xffffffff break
+    # if (EAX == 0xffffffff) break
     3d/compare-with-EAX  0xffffffff/imm32
     74/jump-if-equal  $convert:break/disp8
     # convert-instruction(line, out)
@@ -200,10 +200,10 @@ $convert:end:
 convert-instruction:  # line : (address stream byte), out : (address buffered-file) -> <void>
     # pseudocode:
     #   word-slice = next-word
-    #   if *word-slice->start == '#'
+    #   if (*word-slice->start == '#')
     #     write-stream-buffered(out, line)
     #     return
-    #   if starts-with(word-slice, '==')
+    #   if (starts-with(word-slice, '=='))
     #     write-stream-buffered(out, line)
     #     return
     #
@@ -599,7 +599,7 @@ next-word:  # line : (address stream byte), out : (address slice)
     8b/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           1/r32/ECX   4/disp8         .                 # copy *(ESI+4) to ECX
     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    6/base/ESI  1/index/ECX   .           0/r32/EAX   0xc/disp8       .                 # copy ESI+ECX+12 to EAX
     89/copy                         0/mod/indirect  7/rm32/EDI    .           .             .           0/r32/EAX   .               .                 # copy EAX to *EDI
-    # if line->data[line->read] == '#': out->end = &line->data[line->write]), skip rest of stream and return
+    # if (line->data[line->read] == '#') out->end = &line->data[line->write]), skip rest of stream and return
     # . EAX = line->data[line->read]
     31/xor                          3/mod/direct    0/rm32/EAX    .           .             .           0/r32/EAX   .               .                 # clear EAX
     8a/copy-byte                    1/mod/*+disp8   4/rm32/sib    6/base/ESI  1/index/ECX   .           0/r32/AL    0xc/disp8       .                 # copy byte at *(ESI+ECX+12) to AL
@@ -770,8 +770,8 @@ has-metadata?:  # word : (address slice), s : (address string) -> EAX : boolean
     #   curr = twig->end
     #   while true:
     #     twig = next-token-from-slice(curr, word->end, '/')
-    #     if twig.empty() break
-    #     if slice-equal?(twig, s) return true
+    #     if (twig.empty()) break
+    #     if (slice-equal?(twig, s)) return true
     #     curr = twig->end
     #   return false
     # . prolog
@@ -813,7 +813,7 @@ $has-metadata?:loop:
     e8/call  next-token-from-slice/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x10/imm32        # add to ESP
-    # if slice-empty?(twig) return false
+    # if (slice-empty?(twig)) return false
     # . EAX = slice-empty?(twig)
     # . . push args
     57/push-EDI
@@ -824,7 +824,7 @@ $has-metadata?:loop:
     # . if (EAX != 0) return false
     81          7/subop/compare     3/mod/direct    0/rm32/EAX    .           .             .           .           .               0/imm32           # compare EAX
     75/compare-if-not-equal  $has-metadata?:false/disp8
-    # if slice-equal?(twig, s) return true
+    # if (slice-equal?(twig, s)) return true
     # . EAX = slice-equal?(twig, s)
     # . . push args
     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
@@ -1058,7 +1058,7 @@ emit:  # out : (address buffered-file), word : (address slice), width : int
     e8/call  next-token-from-slice/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x10/imm32        # add to ESP
-    # if !is-hex-int?(name) write-slice(out, word) and return
+    # if (!is-hex-int?(name)) write-slice(out, word) and return
     # . is-hex-int?(name)
     # . . push args
     57/push-EDI
@@ -1066,7 +1066,7 @@ emit:  # out : (address buffered-file), word : (address slice), width : int
     e8/call  is-hex-int?/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
-    # . if EAX == 0
+    # . if (EAX == 0)
     81          7/subop/compare     3/mod/direct    0/rm32/EAX    .           .             .           .           .               0/imm32           # compare EAX
     75/jump-if-not-equal  $emit:hex-int/disp8
     # . write-slice(out, word)
diff --git a/subx/examples/ex10.subx b/subx/examples/ex10.subx
index 3ae1eae7..07b5b4bb 100644
--- a/subx/examples/ex10.subx
+++ b/subx/examples/ex10.subx
@@ -38,7 +38,6 @@ argv-equal:  # (s1, s2) : null-terminated ascii strings -> EAX : boolean
     # initialize s1 (ECX) and s2 (EDX)
     8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/ESP  4/index/none  .           1/r32/ECX   4/disp8         .                 # copy *(ESP+4) to ECX
     8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/ESP  4/index/none  .           2/r32/EDX   8/disp8         .                 # copy *(ESP+8) to EDX
-    # while (true)
 $argv-equal:loop:
     # c1/EAX, c2/EBX = *s1, *s2
     b8/copy-to-EAX  0/imm32
diff --git a/subx/examples/ex11 b/subx/examples/ex11
index cdabbf0a..0ffafb6f 100755
--- a/subx/examples/ex11
+++ b/subx/examples/ex11
Binary files differdiff --git a/subx/examples/ex11.subx b/subx/examples/ex11.subx
index 7fb83eb6..49e0c753 100644
--- a/subx/examples/ex11.subx
+++ b/subx/examples/ex11.subx
@@ -28,7 +28,28 @@
 
 # compare a null-terminated ascii string with a more idiomatic length-prefixed byte array
 # reason for the name: the only place we should have null-terminated ascii strings is from commandline args
-kernel-string-equal:  # s : null-terminated ascii string, benchmark : length-prefixed ascii string -> EAX : boolean
+kernel-string-equal?:  # s : null-terminated ascii string, benchmark : length-prefixed ascii string -> EAX : boolean
+    # pseudocode:
+    #   n = benchmark->length
+    #   s1 = s
+    #   s2 = benchmark->data
+    #   i = 0
+    #   while (i < n)
+    #     c1 = *s1
+    #     c2 = *s2
+    #     if (c1 == 0) return false
+    #     if (c1 != c2) return false
+    #     ++s1, ++s2, ++i
+    #   return *s1 == 0
+    #
+    # registers:
+    #   i: ECX
+    #   n: EDX
+    #   s1: EDI
+    #   s2: ESI
+    #   c1: EAX
+    #   c2: EBX
+    #
     # . prolog
     55/push-EBP
     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
@@ -38,72 +59,57 @@ kernel-string-equal:  # s : null-terminated ascii string, benchmark : length-pre
     53/push-EBX
     56/push-ESI
     57/push-EDI
-
-    # pseudocode:
-    #   initialize n = b->length
-    #   initialize s1 = s
-    #   initialize s2 = b->data
-    #   i = 0
-    #   for (i = 0; i < n; ++n)
-    #     c1 = *s1
-    #     c2 = *s2
-    #     if c1 == 0
-    #       return false
-    #     if c1 != c2
-    #       return false
-    #   return *s1 == 0
-    # initialize s into EDI
+    # s1/EDI = s
     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           7/r32/EDI   8/disp8         .                 # copy *(EBP+8) to EDI
-    # initialize benchmark length n into EDX
+    # n/EDX = benchmark->length
     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           2/r32/EDX   0xc/disp8       .                 # copy *(EBP+12) to EDX
     8b/copy                         0/mod/indirect  2/rm32/EDX    .           .             .           2/r32/EDX   .               .                 # copy *EDX to EDX
-    # initialize benchmark data into ESI
+    # s2/ESI = benchmark->data
     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           6/r32/ESI   0xc/disp8       .                 # copy *(EBP+12) to ESI
     81          0/subop/add         3/mod/direct    6/rm32/ESI    .           .             .           .           .               4/imm32           # add to ESI
-    # initialize loop counter i into ECX
+    # i/ECX = c1/EAX = c2/EBX = 0
     b9/copy-to-ECX  0/imm32/exit
-    # while (i/ECX < n/EDX)
-$kernel-string-equal:loop:
-    39/compare                      3/mod/direct    1/rm32/ECX    .           .             .           2/r32/EDX   .               .                 # compare ECX with EDX
-    74/jump-if-equal  $kernel-string-equal:break/disp8
-    # c1/EAX, c2/EBX = *s, *benchmark
     b8/copy-to-EAX  0/imm32
-    8a/copy                         0/mod/indirect  7/rm32/EDI    .           .             .           0/r32/EAX   .               .                 # copy byte at *EDI to lower byte of EAX
     bb/copy-to-EBX  0/imm32
+$kernel-string-equal?:loop:
+    # if (i >= n) break
+    39/compare                      3/mod/direct    1/rm32/ECX    .           .             .           2/r32/EDX   .               .                 # compare ECX with EDX
+    7d/jump-if-greater-or-equal  $kernel-string-equal?:break/disp8
+    # c1 = *s1
+    8a/copy                         0/mod/indirect  7/rm32/EDI    .           .             .           0/r32/EAX   .               .                 # copy byte at *EDI to lower byte of EAX
+    # c2 = *s2
     8a/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           3/r32/EBX   .               .                 # copy byte at *ESI to lower byte of EBX
     # if (c1 == 0) return false
     3d/compare-EAX  0/imm32
-    74/jump-if-equal  $kernel-string-equal:false/disp8
+    74/jump-if-equal  $kernel-string-equal?:false/disp8
     # if (c1 != c2) return false
     39/compare                      3/mod/direct    0/rm32/EAX    .           .             .           3/r32/EBX   .               .                 # compare EAX with EBX
-    75/jump-if-not-equal  $kernel-string-equal:false/disp8
-    # ++s1, ++s2, ++i
+    75/jump-if-not-equal  $kernel-string-equal?:false/disp8
+    # ++i
     41/inc-ECX
-    46/inc-ESI
+    # ++s1
     47/inc-EDI
-    # end while
-    eb/jump  $kernel-string-equal:loop/disp8
-$kernel-string-equal:break:
-    # if (*s/EDI == 0) return true
-    b8/copy-to-EAX  0/imm32
+    # ++s2
+    46/inc-ESI
+    eb/jump  $kernel-string-equal?:loop/disp8
+$kernel-string-equal?:break:
+    # return *s1 == 0
     8a/copy                         0/mod/indirect  7/rm32/EDI    .           .             .           0/r32/EAX   .               .                 # copy byte at *EDI to lower byte of EAX
-    81          7/subop/compare     3/mod/direct    0/rm32/EAX    .           .             .           .           .               0/imm32           # compare EAX
-    75/jump-if-not-equal  $kernel-string-equal:false/disp8
+    3d/compare-EAX  0/imm32
+    75/jump-if-not-equal  $kernel-string-equal?:false/disp8
+$kernel-string-equal?:true:
     b8/copy-to-EAX  1/imm32
-$kernel-string-equal:true:
-    eb/jump  $kernel-string-equal:end/disp8
-    # return false
-$kernel-string-equal:false:
+    eb/jump  $kernel-string-equal?:end/disp8
+$kernel-string-equal?:false:
     b8/copy-to-EAX  0/imm32
-
-$kernel-string-equal:end:
+$kernel-string-equal?:end:
     # . restore registers
     5f/pop-to-EDI
     5e/pop-to-ESI
     5b/pop-to-EBX
     5a/pop-to-EDX
     59/pop-to-ECX
-    # end
+    # . epilog
     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
     5d/pop-to-EBP
     c3/return
@@ -111,12 +117,12 @@ $kernel-string-equal:end:
 # - tests
 
 test-compare-null-kernel-string-with-empty-array:
-    # EAX = kernel-string-equal(Null-kernel-string, "")
+    # EAX = kernel-string-equal?(Null-kernel-string, "")
     # . . push args
     68/push  ""/imm32
     68/push  Null-kernel-string/imm32
     # . . call
-    e8/call  kernel-string-equal/disp32
+    e8/call  kernel-string-equal?/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
     # check-ints-equal(EAX, 1, msg)
@@ -131,12 +137,12 @@ test-compare-null-kernel-string-with-empty-array:
     c3/return
 
 test-compare-null-kernel-string-with-non-empty-array:
-    # EAX = kernel-string-equal(Null-kernel-string, "Abc")
+    # EAX = kernel-string-equal?(Null-kernel-string, "Abc")
     # . . push args
     68/push  "Abc"/imm32
     68/push  Null-kernel-string/imm32
     # . . call
-    e8/call  kernel-string-equal/disp32
+    e8/call  kernel-string-equal?/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
     # check-ints-equal(EAX, 0, msg)
@@ -151,12 +157,12 @@ test-compare-null-kernel-string-with-non-empty-array:
     c3/return
 
 test-compare-kernel-string-with-equal-array:
-    # EAX = kernel-string-equal(Abc-kernel-string, "Abc")
+    # EAX = kernel-string-equal?(_test-Abc-kernel-string, "Abc")
     # . . push args
     68/push  "Abc"/imm32
-    68/push  Abc-kernel-string/imm32
+    68/push  _test-Abc-kernel-string/imm32
     # . . call
-    e8/call  kernel-string-equal/disp32
+    e8/call  kernel-string-equal?/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
     # check-ints-equal(EAX, 1, msg)
@@ -171,12 +177,12 @@ test-compare-kernel-string-with-equal-array:
     c3/return
 
 test-compare-kernel-string-with-inequal-array:
-    # EAX = kernel-string-equal(Abc-kernel-string, "Adc")
+    # EAX = kernel-string-equal?(_test-Abc-kernel-string, "Adc")
     # . . push args
     68/push  "Adc"/imm32
-    68/push  Abc-kernel-string/imm32
+    68/push  _test-Abc-kernel-string/imm32
     # . . call
-    e8/call  kernel-string-equal/disp32
+    e8/call  kernel-string-equal?/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
     # check-ints-equal(EAX, 0, msg)
@@ -191,12 +197,12 @@ test-compare-kernel-string-with-inequal-array:
     c3/return
 
 test-compare-kernel-string-with-empty-array:
-    # EAX = kernel-string-equal(Abc-kernel-string, "")
+    # EAX = kernel-string-equal?(_test-Abc-kernel-string, "")
     # . . push args
     68/push  ""/imm32
-    68/push  Abc-kernel-string/imm32
+    68/push  _test-Abc-kernel-string/imm32
     # . . call
-    e8/call  kernel-string-equal/disp32
+    e8/call  kernel-string-equal?/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
     # check-ints-equal(EAX, 0, msg)
@@ -211,12 +217,12 @@ test-compare-kernel-string-with-empty-array:
     c3/return
 
 test-compare-kernel-string-with-shorter-array:
-    # EAX = kernel-string-equal(Abc-kernel-string, "Ab")
+    # EAX = kernel-string-equal?(_test-Abc-kernel-string, "Ab")
     # . . push args
     68/push  "Ab"/imm32
-    68/push  Abc-kernel-string/imm32
+    68/push  _test-Abc-kernel-string/imm32
     # . . call
-    e8/call  kernel-string-equal/disp32
+    e8/call  kernel-string-equal?/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
     # check-ints-equal(EAX, 0, msg)
@@ -231,12 +237,12 @@ test-compare-kernel-string-with-shorter-array:
     c3/return
 
 test-compare-kernel-string-with-longer-array:
-    # EAX = kernel-string-equal(Abc-kernel-string, "Abcd")
+    # EAX = kernel-string-equal?(_test-Abc-kernel-string, "Abcd")
     # . . push args
     68/push  "Abcd"/imm32
-    68/push  Abc-kernel-string/imm32
+    68/push  _test-Abc-kernel-string/imm32
     # . . call
-    e8/call  kernel-string-equal/disp32
+    e8/call  kernel-string-equal?/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
     # check-ints-equal(EAX, 0, msg)
@@ -263,7 +269,7 @@ check-ints-equal:  # (a : int, b : int, msg : (address array byte)) -> boolean
     # load args into EAX, EBX and ECX
     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           0/r32/EAX   8/disp8         .                 # copy *(EBP+8) to EAX
     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           3/r32/EBX   0xc/disp8       .                 # copy *(EBP+12) to EBX
-    # if EAX == b/EBX print('.') and return
+    # if (EAX == b/EBX) print('.') and return
     39/compare                      3/mod/direct    0/rm32/EAX    .           .             .           3/r32/EBX   .               .                 # compare EAX and EBX
     75/jump-if-unequal  $check-ints-equal:else/disp8
     # . write-stderr('.')
@@ -344,7 +350,8 @@ Newline:
 # for kernel-string-equal tests
 Null-kernel-string:
     00/null
-Abc-kernel-string:
+
+_test-Abc-kernel-string:
     41/A 62/b 63/c 00/null
 
 # . . vim:nowrap:textwidth=0
diff --git a/subx/examples/ex3.subx b/subx/examples/ex3.subx
index ceeaef00..6a4f7b01 100644
--- a/subx/examples/ex3.subx
+++ b/subx/examples/ex3.subx
@@ -18,7 +18,7 @@
     b9/copy-to-ECX  1/imm32
 
 $loop:
-    # while (counter <= 10)
+    # if (counter > 10) break
     81          7/subop/compare     3/mod/direct    1/rm32/ECX    .           .             .           .           .               0xa/imm32         # compare ECX
     7f/jump-if-greater  $exit/disp8
     # result += counter
diff --git a/subx/examples/ex8.subx b/subx/examples/ex8.subx
index 0ae75760..f45813ec 100644
--- a/subx/examples/ex8.subx
+++ b/subx/examples/ex8.subx
@@ -42,7 +42,7 @@ ascii-length:  # s : (address array byte) -> n/EAX
 $ascii-length-loop:
     # var c/ECX = *s
     8a/copy                         0/mod/*         2/rm32/EDX    .           .             .           1/r32/ECX   .               .                 # copy byte at *EDX to lower byte of ECX
-    # if c == '\0' break
+    # if (c == '\0') break
     81          7/subop/compare     3/mod/direct    1/rm32/ECX    .           .             .           .           .               0/imm32           # compare ECX
     74/jump-if-equal  $ascii-length-ret/disp8
     # ++s
diff --git a/subx/opcodes b/subx/opcodes
index 3437f30a..0eb0792b 100644
--- a/subx/opcodes
+++ b/subx/opcodes
@@ -74,6 +74,7 @@ Opcodes currently supported by SubX:
   bf: copy imm32 to EDI (mov)
   c1: shift rm32 by imm8 bits depending on subop (sal/sar/shl/shr)
   c3: return from most recent unfinished call (ret)
+  c6: copy imm8 to r8/m8-at-r32 (mov)
   c7: copy imm32 to rm32 (mov)
   cd: software interrupt (int)
   d3: shift rm32 by CL bits depending on subop (sal/sar/shl/shr)