about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--subx/052kernel-string-equal.subx22
-rw-r--r--subx/060write-stream.subx2
-rw-r--r--subx/062write-byte.subx74
-rw-r--r--subx/069slice.subx526
-rw-r--r--subx/070next-token.subx (renamed from subx/069next-token.subx)2
-rwxr-xr-xsubx/apps/crenshaw2-1bin10778 -> 12007 bytes
-rwxr-xr-xsubx/apps/crenshaw2-1bbin11337 -> 12566 bytes
-rwxr-xr-xsubx/apps/factorialbin9696 -> 10925 bytes
-rwxr-xr-xsubx/apps/handlebin10489 -> 11718 bytes
-rwxr-xr-xsubx/apps/hexbin14292 -> 15521 bytes
-rw-r--r--subx/apps/hex.subx6
-rw-r--r--subx/apps/pack.subx3
12 files changed, 611 insertions, 24 deletions
diff --git a/subx/052kernel-string-equal.subx b/subx/052kernel-string-equal.subx
index 5ee7d5ef..4568528a 100644
--- a/subx/052kernel-string-equal.subx
+++ b/subx/052kernel-string-equal.subx
@@ -150,10 +150,10 @@ 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
     # . . discard args
@@ -170,10 +170,10 @@ 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
     # . . discard args
@@ -190,10 +190,10 @@ 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
     # . . discard args
@@ -210,10 +210,10 @@ 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
     # . . discard args
@@ -230,10 +230,10 @@ 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
     # . . discard args
@@ -253,7 +253,7 @@ test-compare-kernel-string-with-longer-array:
 
 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/060write-stream.subx b/subx/060write-stream.subx
index a9859ec9..f112dee9 100644
--- a/subx/060write-stream.subx
+++ b/subx/060write-stream.subx
@@ -96,7 +96,7 @@ _write-stream:  # fd : int, s : (address stream) -> <void>
     8b/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           7/r32/EDI   4/disp8         .                 # copy *(ESI+4) to EDI
     # EDX = s->write
     8b/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           2/r32/EDX   .               .                 # copy *ESI to EDX
-    # syscall(write, fd, &s->data[s->read], s->write-s->read)
+    # syscall(write, fd, &s->data[s->read], s->write - s->read)
     # . . fd : EBX
     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           3/r32/EBX   8/disp8         .                 # copy *(EBP+8) to EBX
     # . . data : ECX = &s->data[s->read]
diff --git a/subx/062write-byte.subx b/subx/062write-byte.subx
index 2e348aa4..30e2b425 100644
--- a/subx/062write-byte.subx
+++ b/subx/062write-byte.subx
@@ -64,6 +64,8 @@ write-byte:  # f : (address buffered-file), n : int -> <void>
     e8/call  clear-stream/disp32
     # . . discard args
     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+    # . clear ECX (cached f->write)
+    31/xor                          3/mod/direct    1/rm32/ECX    .           .             .           1/r32/ECX   .               .                 # clear ECX
 $write-byte:to-stream:
     # write to stream
     # f->data[f->write] = LSB(n)
@@ -111,7 +113,7 @@ $flush:end:
 # - tests
 
 test-write-byte-single:
-    # - check that read-byte returns first byte of 'file'
+    # - check that write-byte writes to first byte of 'file'
     # setup
     # . clear-stream(_test-stream)
     # . . push args
@@ -158,4 +160,74 @@ test-write-byte-single:
     # . end
     c3/return
 
+test-write-byte-multiple-flushes:
+    # - check that write-byte correctly flushes buffered data
+    # setup
+    # . clear-stream(_test-stream)
+    # . . push args
+    68/push  _test-stream/imm32
+    # . . call
+    e8/call  clear-stream/disp32
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+    # . clear-stream(_test-buffered-file+4)
+    # . . push args
+    b8/copy-to-EAX  _test-buffered-file/imm32
+    05/add-to-EAX  4/imm32
+    50/push-EAX
+    # . . call
+    e8/call  clear-stream/disp32
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+    # fill up the buffer for _test-buffered-file
+    # . write(_test-buffered-file+4, 'abcdef')
+    # . . push args
+    68/push  "abcdef"/imm32
+    b8/copy-to-EAX  _test-buffered-file/imm32
+    05/add-to-EAX  4/imm32
+    50/push-EAX
+    # . . call
+    e8/call  write/disp32
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+    # write-byte(_test-buffered-file, 'g')
+    # . . push args
+    68/push  0x67/imm32
+    68/push  _test-buffered-file/imm32
+    # . . call
+    e8/call  write-byte/disp32
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+    # flush(_test-buffered-file)
+    # . . push args
+    68/push  _test-buffered-file/imm32
+    # . . call
+    e8/call  flush/disp32
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+    # check-ints-equal(_test-stream->data[0..3], 'abcd', msg)
+    # . . push args
+    68/push  "F - test-write-byte-multiple-flushes: 1"/imm32
+    68/push  0x64636261/imm32
+    # . . push *_test-stream->data
+    b8/copy-to-EAX  _test-stream/imm32
+    ff          6/subop/push        1/mod/*+disp8   0/rm32/EAX    .           .             .           .           0xc/disp8       .                 # push *(EAX+12)
+    # . . call
+    e8/call  check-ints-equal/disp32
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+    # check-ints-equal(_test-stream->data[4..8], 'efg', msg)
+    # . . push args
+    68/push  "F - test-write-byte-multiple-flushes"/imm32
+    68/push  0x00676665/imm32
+    # . . push *_test-stream->data
+    b8/copy-to-EAX  _test-stream/imm32
+    ff          6/subop/push        1/mod/*+disp8   0/rm32/EAX    .           .             .           .           0x10/disp8      .                 # push *(EAX+16)
+    # . . call
+    e8/call  check-ints-equal/disp32
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+    # . end
+    c3/return
+
 # . . vim:nowrap:textwidth=0
diff --git a/subx/069slice.subx b/subx/069slice.subx
new file mode 100644
index 00000000..dda19ad8
--- /dev/null
+++ b/subx/069slice.subx
@@ -0,0 +1,526 @@
+# new data structure: a slice is an open interval of addresses [start, end)
+# that includes 'start' but not 'end'
+
+== code
+#   instruction                     effective address                                                   register    displacement    immediate
+# . op          subop               mod             rm32          base        index         scale       r32
+# . 1-3 bytes   3 bits              2 bits          3 bits        3 bits      3 bits        2 bits      2 bits      0/1/2/4 bytes   0/1/2/4 bytes
+
+#? e8/call test-write-byte-multiple-flushes/disp32
+#? #? e8/call test-foo/disp32
+#? #? e8/call test-slice-equal/disp32
+#? bb/copy-to-EBX  0/imm32
+#? b8/copy-to-EAX  1/imm32/exit
+#? cd/syscall  0x80/imm8
+
+#? # stop directly - seems fine
+#? # error-byte - writing out of bounds
+#? #   drop stop - writing out of bounds
+#? 
+#? test-foo:
+#?     # This test uses exit-descriptors. Use EBP for setting up local variables.
+#?     55/push-EBP
+#?     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+#?     # initialize '_test-stream' to "a"
+#?     # . write(_test-stream, "a")
+#?     # . . push args
+#?     68/push  "a"/imm32
+#?     68/push  _test-stream/imm32
+#?     # . . call
+#?     e8/call  write/disp32
+#?     # . . discard args
+#?     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+#?     # initialize exit-descriptor 'ed' for the call to 'convert-next-octet' below
+#?     # . var ed/ECX : exit-descriptor
+#?     81          5/subop/subtract    3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # subtract from ESP
+#?     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+#?     # . tailor-exit-descriptor(ed, 12)
+#?     # . . push args
+#?     68/push  0xc/imm32/nbytes-of-args-for-convert-next-octet
+#?     51/push-ECX/ed
+#?     # . . call
+#?     e8/call  tailor-exit-descriptor/disp32
+#?     # . . discard args
+#?     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+#?     # EAX = foo(_test-buffered-file, _test-error-buffered-file, ed)
+#?     # . . push args
+#?     51/push-ECX/ed
+#?     68/push  _test-foo-error-buffered-file/imm32
+#?     68/push  _test-buffered-file/imm32
+#?     # . . call
+#?     e8/call  foo/disp32
+#?     # registers except ESP may be clobbered at this point
+#?     # pop args to convert-next-octet
+#?     # . . discard first 2 args
+#?     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+#?     # . . restore ed
+#?     59/pop-to-ECX
+#?     # . epilog
+#?     # don't restore ESP from EBP; manually reclaim locals
+#?     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+#?     5d/pop-to-EBP
+#?     c3/return
+#? 
+#? foo:  # in : (address buffered-file), err : (address buffered-file), ed : (address exit-descriptor) -> byte-or-eof/EAX
+#?     # . prolog
+#?     55/push-EBP
+#?     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+#?     # . foo-error-byte(ed, err, msg, '.')
+#?     # . . push args
+#?     68/push  0x2e/imm32/period/dummy
+#?     68/push  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"/imm32
+#?     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
+#?     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0x10/disp8      .                 # push *(EBP+16)
+#?     # . . call
+#?     e8/call  foo-error-byte/disp32  # never returns
+#?     # . . discard args
+#?     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x10/imm32        # add to ESP
+#?     # . epilog
+#?     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+#?     5d/pop-to-EBP
+#?     c3/return
+#? 
+#? # write(out, "Error: "+msg+": "+byte) then stop(ed, 1)
+#? foo-error-byte:  # ed : (address exit-descriptor), out : (address buffered-file), msg : (address array byte), n : byte -> <void>
+#?     # . prolog
+#?     55/push-EBP
+#?     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+#?     # write-buffered(out, "Error: ")
+#?     # . . push args
+#?     68/push  "Error: "/imm32
+#?     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
+#?     # . . call
+#?     e8/call  write-buffered/disp32
+#?     # . . discard args
+#?     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+#?     # write-buffered(out, msg)
+#?     # . . push args
+#?     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0x10/disp8      .                 # push *(EBP+16)
+#?     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
+#?     # . . call
+#?     e8/call  write-buffered/disp32
+#?     # . . discard args
+#?     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+#?     # write-buffered(out, ": ")
+#?     # . . push args
+#?     68/push  ": "/imm32
+#?     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
+#?     # . . call
+#?     e8/call  write-buffered/disp32
+#?     # . . discard args
+#?     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+#?     # print-byte(out, byte)
+#?     # . . push args
+#?     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0x14/disp8      .                 # push *(EBP+20)
+#?     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
+#?     # . . call
+#?     e8/call  print-byte/disp32
+#?     # . . discard args
+#?     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+#? $foo-error-byte:dead-end:
+#?     # . epilog
+#?     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+#?     5d/pop-to-EBP
+#?     c3/return
+
+# main:
+    e8/call  run-tests/disp32  # 'run-tests' is a function created automatically by SubX. It calls all functions that start with 'test-'.
+    # syscall(exit, Num-test-failures)
+    8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           3/r32/EBX   Num-test-failures/disp32          # copy *Num-test-failures to EBX
+    b8/copy-to-EAX  1/imm32/exit
+    cd/syscall  0x80/imm8
+
+slice-empty?:  # s : (address slice) -> bool/EAX
+    # . prolog
+    55/push-EBP
+    89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+    # . save registers
+    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
+    # . EAX = s->start
+    8b/copy                         0/mod/indirect  1/rm32/ECX    .           .             .           0/r32/EAX   .               .                 # copy *ECX to EAX
+    # . compare EAX with s->end
+    39/compare                      1/mod/*+disp8   1/rm32/ECX    .           .             .           0/r32/EAX   4/disp8         .                 # compare EAX and *(ECX+4)
+    b8/copy-to-EAX  1/imm32/false
+    74/jump-if-equal  $slice-empty?:end/disp8
+    b8/copy-to-EAX  0/imm32/false
+$slice-empty?:end:
+    # . restore registers
+    59/pop-to-ECX
+    # . epilog
+    89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+    5d/pop-to-EBP
+    c3/return
+
+test-slice-empty-true:
+    # . prolog
+    55/push-EBP
+    89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+    # var slice/ECX = {34, 34}
+    68/push  34/imm32/end
+    68/push  34/imm32/start
+    89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+    # slice-empty?(slice)
+    # . . push args
+    51/push-ECX
+    # . . call
+    e8/call  slice-empty?/disp32
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+    # check-ints-equal(EAX, 1, msg)
+    # . . push args
+    68/push  "F - test-slice-empty-true"/imm32
+    68/push  1/imm32
+    50/push-EAX
+    # . . call
+    e8/call  check-ints-equal/disp32
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+    # . epilog
+    89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+    5d/pop-to-EBP
+    c3/return
+
+test-slice-empty-false:
+    # . prolog
+    55/push-EBP
+    89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+    # var slice/ECX = {34, 23}
+    68/push  23/imm32/end
+    68/push  34/imm32/start
+    89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+    # slice-empty?(slice)
+    # . . push args
+    51/push-ECX
+    # . . call
+    e8/call  slice-empty?/disp32
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+    # check-ints-equal(EAX, 0, msg)
+    # . . push args
+    68/push  "F - test-slice-empty-false"/imm32
+    68/push  0/imm32
+    50/push-EAX
+    # . . call
+    e8/call  check-ints-equal/disp32
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+    # . epilog
+    89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+    5d/pop-to-EBP
+    c3/return
+
+slice-equal?:  # s : (address slice), k : (address kernel-string) -> bool/EAX
+    # . prolog
+    55/push-EBP
+    89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+    # . save registers
+    51/push-ECX
+    52/push-EDX
+    53/push-EBX
+    56/push-ESI
+    # EAX = ECX = false
+    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
+    # ESI = s
+    8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           6/r32/ESI   8/disp8         .                 # copy *(EBP+8) to ESI
+    # curr/EDX = s->start
+    8b/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           2/r32/EDX   .               .                 # copy *ESI to EDX
+    # max/ESI = s->end
+    8b/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           6/r32/ESI   4/disp8         .                 # copy *(ESI+4) to ESI
+    # EBX = k
+    8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           3/r32/EBX   0xc/disp8       .                 # copy *(EBP+12) to EBX
+$slice-equal?:loop:
+    # AL = *k
+    8a/copy-byte                    0/mod/indirect  3/rm32/EBX    .           .             .           0/r32/AL    .               .                 # copy byte at *EBX to AL
+    # if (curr >= max) return *k == 0
+    39/compare                      3/mod/direct    2/rm32/EDX    .           .             .           6/r32/ESI   .               .                 # compare EDX and ESI
+    7c/jump-if-lesser  $slice-equal?:check2/disp8
+    3d/compare-with-EAX  0/imm32
+    74/jump-if-equal  $slice-equal?:true/disp8
+    eb/jump  $slice-equal?:false/disp8
+$slice-equal?:check2:
+    # if (EAX == 0) return false
+    3d/compare-with-EAX  0/imm32
+    74/jump-if-equal  $slice-equal?:false/disp8
+    # CL = *curr
+    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
+    # ++k
+    43/increment-EBX
+    # ++curr
+    42/increment-EDX
+    eb/jump $slice-equal?:loop/disp8
+$slice-equal?:false:
+    b8/copy-to-EAX  0/imm32
+    eb/jump  $slice-equal?:end/disp8
+$slice-equal?:true:
+    b8/copy-to-EAX  1/imm32
+$slice-equal?:end:
+    # . restore registers
+    5e/pop-to-ESI
+    5b/pop-to-EBX
+    5a/pop-to-EDX
+    59/pop-to-ECX
+    # . epilog
+    89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+    5d/pop-to-EBP
+    c3/return
+
+test-slice-equal:
+    # - slice-equal?(slice("Abc"), "Abc") == 1
+    # . prolog
+    55/push-EBP
+    89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+    # var slice/ECX
+    68/push  _test-slice-data-3/imm32/end
+    68/push  _test-slice-data-0/imm32/start
+    89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+    # EAX = slice-equal?(ECX, "Abc")
+    # . . push args
+    68/push  _test-Abc-kernel-string/imm32
+    51/push-ECX
+    # . . call
+    e8/call  slice-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)
+    # . . push args
+    68/push  "F - test-slice-equal"/imm32
+    68/push  1/imm32
+    50/push-EAX
+    # . . call
+    e8/call  check-ints-equal/disp32
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+    # . epilog
+    89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+    5d/pop-to-EBP
+    c3/return
+
+test-slice-equal-false:
+    # - slice-equal?(slice("bcd"), "Abc") == 0
+    # . prolog
+    55/push-EBP
+    89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+    # var slice/ECX
+    68/push  _test-slice-data-4/imm32/end
+    68/push  _test-slice-data-1/imm32/start
+    89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+    # EAX = slice-equal?(ECX, "Abc")
+    # . . push args
+    68/push  _test-Abc-kernel-string/imm32
+    51/push-ECX
+    # . . call
+    e8/call  slice-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)
+    # . . push args
+    68/push  "F - test-slice-equal-false"/imm32
+    68/push  0/imm32
+    50/push-EAX
+    # . . call
+    e8/call  check-ints-equal/disp32
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+    # . epilog
+    89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+    5d/pop-to-EBP
+    c3/return
+
+test-slice-equal-too-long:
+    # - slice-equal?(slice("Abcd"), "Abc") == 0
+    # . prolog
+    55/push-EBP
+    89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+    # var slice/ECX
+    68/push  _test-slice-data-4/imm32/end
+    68/push  _test-slice-data-0/imm32/start
+    89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+    # EAX = slice-equal?(ECX, "Abc")
+    # . . push args
+    68/push  _test-Abc-kernel-string/imm32
+    51/push-ECX
+    # . . call
+    e8/call  slice-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)
+    # . . push args
+    68/push  "F - test-slice-equal-too-long"/imm32
+    68/push  0/imm32
+    50/push-EAX
+    # . . call
+    e8/call  check-ints-equal/disp32
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+    # . epilog
+    89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+    5d/pop-to-EBP
+    c3/return
+
+test-slice-equal-too-short:
+    # - slice-equal?(slice("A"), "Abc") == 0
+    # . prolog
+    55/push-EBP
+    89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+    # var slice/ECX
+    68/push  _test-slice-data-1/imm32/end
+    68/push  _test-slice-data-0/imm32/start
+    89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+    # EAX = slice-equal?(ECX, "Abc")
+    # . . push args
+    68/push  _test-Abc-kernel-string/imm32
+    51/push-ECX
+    # . . call
+    e8/call  slice-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)
+    # . . push args
+    68/push  "F - test-slice-equal-too-short"/imm32
+    68/push  0/imm32
+    50/push-EAX
+    # . . call
+    e8/call  check-ints-equal/disp32
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+    # . epilog
+    89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+    5d/pop-to-EBP
+    c3/return
+
+test-slice-equal-empty:
+    # - slice-equal?(slice(""), "Abc") == 0
+    # . prolog
+    55/push-EBP
+    89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+    # var slice/ECX
+    68/push  _test-slice-data-0/imm32/end
+    68/push  _test-slice-data-0/imm32/start
+    89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+    # EAX = slice-equal?(ECX, "Abc")
+    # . . push args
+    68/push  _test-Abc-kernel-string/imm32
+    51/push-ECX
+    # . . call
+    e8/call  slice-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)
+    # . . push args
+    68/push  "F - test-slice-equal-empty"/imm32
+    68/push  0/imm32
+    50/push-EAX
+    # . . call
+    e8/call  check-ints-equal/disp32
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+    # . epilog
+    89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+    5d/pop-to-EBP
+    c3/return
+
+test-slice-equal-with-empty:
+    # - slice-equal?(slice("Ab"), "") == 0
+    # . prolog
+    55/push-EBP
+    89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+    # var slice/ECX
+    68/push  _test-slice-data-2/imm32/end
+    68/push  _test-slice-data-0/imm32/start
+    89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+    # EAX = slice-equal?(ECX, "")
+    # . . push args
+    68/push  Null-kernel-string/imm32
+    51/push-ECX
+    # . . call
+    e8/call  slice-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)
+    # . . push args
+    68/push  "F - test-slice-equal-with-empty"/imm32
+    68/push  0/imm32
+    50/push-EAX
+    # . . call
+    e8/call  check-ints-equal/disp32
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+    # . epilog
+    89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+    5d/pop-to-EBP
+    c3/return
+
+test-slice-equal-empty-with-empty:
+    # - slice-equal?(slice(""), "") == 1
+    # . prolog
+    55/push-EBP
+    89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+    # var slice/ECX
+    68/push  _test-slice-data-0/imm32/end
+    68/push  _test-slice-data-0/imm32/start
+    89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+    # EAX = slice-equal?(ECX, "")
+    # . . push args
+    68/push  Null-kernel-string/imm32
+    51/push-ECX
+    # . . call
+    e8/call  slice-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)
+    # . . push args
+    68/push  "F - test-slice-equal-empty-with-empty"/imm32
+    68/push  1/imm32
+    50/push-EAX
+    # . . call
+    e8/call  check-ints-equal/disp32
+    # . . discard args
+    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+    # . epilog
+    89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+    5d/pop-to-EBP
+    c3/return
+
+== data
+
+#? _test-foo-error-stream:
+#?     # current write index
+#?     00 00 00 00
+#?     # current read index
+#?     00 00 00 00
+#?     # length (= 8)
+#?     08 00 00 00
+#?     # data
+#?     00 00 00 00 00 00 00 00  # 8 bytes
+#? 
+#? # a test buffered file for _test-stream
+#? _test-foo-error-buffered-file:
+#?     # file descriptor or (address stream)
+#?     _test-foo-error-stream/imm32
+#?     # current write index
+#?     00 00 00 00
+#?     # current read index
+#?     00 00 00 00
+#?     # length (6)
+#?     06 00 00 00
+#?     # data
+#?     00 00 00 00 00 00  # 6 bytes
+
+_test-slice-data-0:
+    41/A
+_test-slice-data-1:
+    62/b
+_test-slice-data-2:
+    63/c
+_test-slice-data-3:
+    64/d
+_test-slice-data-4:
+
+# . . vim:nowrap:textwidth=0
diff --git a/subx/069next-token.subx b/subx/070next-token.subx
index 2ec1777f..539caf95 100644
--- a/subx/069next-token.subx
+++ b/subx/070next-token.subx
@@ -10,8 +10,6 @@
     b8/copy-to-EAX  1/imm32/exit
     cd/syscall  0x80/imm8
 
-# new data structure: a slice is an open interval of addresses [start, end) that includes 'start' but not 'end'
-
 # extract the next run of characters that are different from a given 'delimiter'
 # on eof return an empty interval
 next-token:  # in : (address stream), delimiter : byte, out : (address slice)
diff --git a/subx/apps/crenshaw2-1 b/subx/apps/crenshaw2-1
index 354683d2..5d45b5fa 100755
--- a/subx/apps/crenshaw2-1
+++ b/subx/apps/crenshaw2-1
Binary files differdiff --git a/subx/apps/crenshaw2-1b b/subx/apps/crenshaw2-1b
index 37576192..b462d387 100755
--- a/subx/apps/crenshaw2-1b
+++ b/subx/apps/crenshaw2-1b
Binary files differdiff --git a/subx/apps/factorial b/subx/apps/factorial
index 72217cdd..f5c91de1 100755
--- a/subx/apps/factorial
+++ b/subx/apps/factorial
Binary files differdiff --git a/subx/apps/handle b/subx/apps/handle
index ce489c0a..61f3e1dd 100755
--- a/subx/apps/handle
+++ b/subx/apps/handle
Binary files differdiff --git a/subx/apps/hex b/subx/apps/hex
index 936ebdce..b51a79be 100755
--- a/subx/apps/hex
+++ b/subx/apps/hex
Binary files differdiff --git a/subx/apps/hex.subx b/subx/apps/hex.subx
index 2660bd54..1d306782 100644
--- a/subx/apps/hex.subx
+++ b/subx/apps/hex.subx
@@ -41,12 +41,6 @@
     3d/compare-EAX  1/imm32
     75/jump-if-not-equal  $run-main/disp8
     # . run-tests()
-#?     e8/call test-hex-below-0/disp32
-#?     e8/call test-scan-next-byte/disp32
-#?     e8/call test-scan-next-byte-handles-eof/disp32
-#?     e8/call test-scan-next-byte-skips-comment/disp32
-#?     e8/call test-scan-next-byte-aborts-on-invalid-byte/disp32
-#?     e8/call test-convert-next-octet/disp32
     e8/call  run-tests/disp32
     8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           3/r32/EBX   Num-test-failures/disp32          # copy *Num-test-failures to EBX
     eb/jump  $main:end/disp8
diff --git a/subx/apps/pack.subx b/subx/apps/pack.subx
index b5f39009..d83a5398 100644
--- a/subx/apps/pack.subx
+++ b/subx/apps/pack.subx
@@ -121,8 +121,6 @@ $main:end:
 #   slice-equal?(slice, kernel string)
 
 # helpers:
-#   slice-empty?(in : &slice) -> bool
-#   slice-equal?(in : &slice, s : &kernel-string) -> bool
 #   is-hex-int(in : &slice)
 #   parse-hex-int(in : &slice) -> int
 #   emit-maybe(out : &buffered-file, n : int, width : int)
@@ -175,7 +173,6 @@ next-word:  # line : (address stream byte), out : (address slice)
     # out->start = &line->data[line->read]
     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
-#? $watch-1:
     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
     # . EAX = line->data[line->read]
the previous revision' href='/akkartik/mu/blame/032array.cc?h=main&id=dad3bedd1ca78162f87a235c10b036a06492a5f5'>^
46026f62 ^

3473c63a ^
15936c91 ^

15936c91 ^

551d155c ^

3377364a ^
15936c91 ^
cdd6fd09 ^
795f5244 ^
fb1fcbc9 ^

3377364a ^
fb1fcbc9 ^

a55bbd06 ^


7e9c6925 ^
3377364a ^
947f06fb ^

3377364a ^
947f06fb ^
3377364a ^




7e9c6925 ^

b8348923 ^
91ec4681 ^


b8348923 ^






91ec4681 ^









551d155c ^
5f98a10c ^
1ead3562 ^
c6520d96 ^
bc643692 ^





15936c91 ^
551d155c ^
5f98a10c ^
551d155c ^
051c4738 ^
5f98a10c ^
1ead3562 ^
c6520d96 ^
bc643692 ^





15936c91 ^
551d155c ^
5f98a10c ^
a55bbd06 ^
fb85b3b4 ^
5f98a10c ^
1ead3562 ^
fb85b3b4 ^






15936c91 ^
fb85b3b4 ^
9dcbec39 ^
fb85b3b4 ^
5c6840b8 ^


1ead3562 ^
5c6840b8 ^







991d76f3 ^
1848b18f ^
991d76f3 ^
1ead3562 ^
c6520d96 ^
bc643692 ^


991d76f3 ^
1848b18f ^
991d76f3 ^
1848b18f ^

991d76f3 ^
a55bbd06 ^
991d76f3 ^
b8515e8a ^
991d76f3 ^


e4630643 ^

3473c63a ^
15936c91 ^
1ad3fe9e ^
9dcbec39 ^
46026f62 ^

3473c63a ^
15936c91 ^

9dcbec39 ^
991d76f3 ^

3473c63a ^
15936c91 ^
fb85b3b4 ^
3377364a ^
991d76f3 ^
9dcbec39 ^
fb85b3b4 ^

0d219477 ^



b8515e8a ^


991d76f3 ^
3473c63a ^
15936c91 ^
b24eb476 ^
18e626df ^
acc4792d ^
18e626df ^

3473c63a ^
15936c91 ^

15936c91 ^

551d155c ^

6e793202 ^



991d76f3 ^



6e793202 ^
991d76f3 ^




a55bbd06 ^
c8a58cdc ^
991d76f3 ^
5f98a10c ^
1ead3562 ^
c6520d96 ^
bc643692 ^





991d76f3 ^

551d155c ^
5f98a10c ^
551d155c ^
991d76f3 ^
5f98a10c ^
1ead3562 ^
c6520d96 ^
bc643692 ^





991d76f3 ^

551d155c ^
5f98a10c ^
551d155c ^
0d219477 ^









c8a58cdc ^


1ead3562 ^
c6520d96 ^
bc643692 ^


c6520d96 ^
c8a58cdc ^





795f5244 ^
b8515e8a ^
c8a58cdc ^
b8515e8a ^
acc4792d ^
e4630643 ^

3473c63a ^
15936c91 ^

9dcbec39 ^
c8a58cdc ^

b8515e8a ^



3473c63a ^
15936c91 ^

acc4792d ^
18e626df ^

cfb142b9 ^
15936c91 ^
c8a58cdc ^

e74a2940 ^




991d76f3 ^
e74a2940 ^
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484