From 3350c34a74844e21ea69077e01efff3bae64bdcd Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Tue, 23 Mar 2021 17:31:08 -0700 Subject: . --- html/linux/hex.subx.html | 1500 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1500 insertions(+) create mode 100644 html/linux/hex.subx.html (limited to 'html/linux/hex.subx.html') diff --git a/html/linux/hex.subx.html b/html/linux/hex.subx.html new file mode 100644 index 00000000..b7f1bb3b --- /dev/null +++ b/html/linux/hex.subx.html @@ -0,0 +1,1500 @@ + + + + +Mu - linux/hex.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/main/linux/hex.subx +
+   1 # Read a text file containing whitespace-separated pairs of ascii hex bytes
+   2 # from stdin, and convert them into binary bytes (octets) on stdout. Ignore
+   3 # comments between '#' and newline.
+   4 #
+   5 # To run:
+   6 #   $ bootstrap/bootstrap translate [01]*.subx apps/subx-params.subx apps/hex.subx  -o apps/hex
+   7 #   $ echo '80 81 82  # comment'  |bootstrap/bootstrap run hex  |xxd -
+   8 # Expected output:
+   9 #   00000000: 8081 82
+  10 #
+  11 # Only hex bytes and comments are permitted. Outside of comments all words
+  12 # must be exactly 2 characters long and contain only characters [0-9a-f]. No
+  13 # uppercase hex.
+  14 
+  15 == code
+  16 #   instruction                     effective address                                                   register    displacement    immediate
+  17 # . op          subop               mod             rm32          base        index         scale       r32
+  18 # . 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
+  19 
+  20 Entry:  # run tests if necessary, convert stdin if not
+  21     # . prologue
+  22     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+  23 
+  24     # initialize heap
+  25     # . Heap = new-segment(Heap-size)
+  26     # . . push args
+  27     68/push  Heap/imm32
+  28     ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Heap-size/disp32                  # push *Heap-size
+  29     # . . call
+  30     e8/call  new-segment/disp32
+  31     # . . discard args
+  32     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+  33 
+  34     # - if argc > 1 and argv[1] == "test", then return run_tests()
+  35     # if (argc <= 1) goto interactive
+  36     81          7/subop/compare     1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0/disp8         1/imm32           # compare *ebp
+  37     7e/jump-if-<=  $subx-hex-main:interactive/disp8
+  38     # if (!kernel-string-equal?(argv[1], "test")) goto interactive
+  39     # . eax = kernel-string-equal?(argv[1], "test")
+  40     # . . push args
+  41     68/push  "test"/imm32
+  42     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
+  43     # . . call
+  44     e8/call  kernel-string-equal?/disp32
+  45     # . . discard args
+  46     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+  47     # . if (eax == false) goto interactive
+  48     3d/compare-eax-and  0/imm32/false
+  49     74/jump-if-=  $subx-hex-main:interactive/disp8
+  50     # run-tests()
+  51     e8/call  run-tests/disp32
+  52     # syscall(exit, *Num-test-failures)
+  53     8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           3/r32/ebx   Num-test-failures/disp32          # copy *Num-test-failures to ebx
+  54     eb/jump  $subx-hex-main:end/disp8
+  55 $subx-hex-main:interactive:
+  56     # - otherwise convert stdin
+  57     # . subx-hex(Stdin, Stdout, Stderr, 0)
+  58     # . . push args
+  59     68/push  0/imm32/exit-descriptor
+  60     68/push  Stderr/imm32
+  61     68/push  Stdout/imm32
+  62     68/push  Stdin/imm32
+  63     # . . call
+  64     e8/call  subx-hex/disp32
+  65     # . . discard args
+  66     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
+  67     # syscall(exit, 0)
+  68     bb/copy-to-ebx  0/imm32
+  69 $subx-hex-main:end:
+  70     e8/call  syscall_exit/disp32
+  71 
+  72 # the main entry point
+  73 subx-hex:  # in: (addr buffered-file), out: (addr buffered-file), err: (addr buffered-file), ed: (addr exit-descriptor)
+  74     # pseudocode:
+  75     #   while true
+  76     #     eax = convert-next-octet(in, err, ed)
+  77     #     if (eax == Eof) break
+  78     #     write-byte-buffered(out, AL)
+  79     #   flush(out)
+  80     #
+  81     # . prologue
+  82     55/push-ebp
+  83     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+  84     # . save registers
+  85     50/push-eax
+  86 $subx-hex:loop:
+  87     # eax = convert-next-octet(in, err, ed)
+  88     # . . push args
+  89     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x14/disp8      .                 # push *(ebp+20)
+  90     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x10/disp8      .                 # push *(ebp+16)
+  91     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
+  92     # . . call
+  93     e8/call  convert-next-octet/disp32
+  94     # . . discard first 2 args
+  95     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+  96     # if (eax == Eof) break
+  97     3d/compare-eax-and  0xffffffff/imm32/Eof
+  98     74/jump-if-=  $subx-hex:loop-end/disp8
+  99     # write-byte-buffered(out, AL)
+ 100     # . . push args
+ 101     50/push-eax
+ 102     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+ 103     # . . call
+ 104     e8/call  write-byte-buffered/disp32
+ 105     # . . discard args
+ 106     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 107     # loop
+ 108     eb/jump  $subx-hex:loop/disp8
+ 109 $subx-hex:loop-end:
+ 110     # flush(out)
+ 111     # . . push args
+ 112     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+ 113     # . . call
+ 114     e8/call  flush/disp32
+ 115     # . . discard args
+ 116     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+ 117 $subx-hex:end:
+ 118     # . restore registers
+ 119     58/pop-to-eax
+ 120     # . epilogue
+ 121     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+ 122     5d/pop-to-ebp
+ 123     c3/return
+ 124 
+ 125 # read bytes from 'in' until a sequence of two lowercase hex (0-9, a-f) bytes
+ 126 # skip spaces and newlines
+ 127 # on '#' skip bytes until newline
+ 128 # raise an error and abort on all other unexpected bytes
+ 129 # return in eax an _octet_ containing the binary value of the two hex characters
+ 130 # return Eof on reaching end of file
+ 131 convert-next-octet:  # in: (addr buffered-file), err: (addr buffered-file), ed: (addr exit-descriptor) -> byte-or-Eof/eax
+ 132     # pseudocode:
+ 133     #   eax = scan-next-byte(in, err, ed)
+ 134     #   if (eax == Eof) return
+ 135     #   ecx = from-hex-char(eax)
+ 136     #   eax = scan-next-byte(in, err, ed)
+ 137     #   if (eax == Eof) error("partial byte found.")
+ 138     #   eax = from-hex-char(eax)
+ 139     #   eax = (ecx << 4) | eax
+ 140     #   return
+ 141     #
+ 142     # . prologue
+ 143     55/push-ebp
+ 144     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 145     # . save registers
+ 146     51/push-ecx
+ 147     # eax = scan-next-byte(in, err, ed)
+ 148     # . . push args
+ 149     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x10/disp8      .                 # push *(ebp+16)
+ 150     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+ 151     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
+ 152     # . . call
+ 153     e8/call  scan-next-byte/disp32
+ 154     # . . discard args
+ 155     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 156     # if (eax == Eof) return
+ 157     3d/compare-eax-and  0xffffffff/imm32/Eof
+ 158     74/jump-if-=  $convert-next-octet:end/disp8
+ 159     # eax = from-hex-char(eax)
+ 160     e8/call from-hex-char/disp32
+ 161     # ecx = eax
+ 162     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # copy eax to ecx
+ 163     # eax = scan-next-byte(in, err, ed)
+ 164     # . . push args
+ 165     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x10/disp8      .                 # push *(ebp+16)
+ 166     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+ 167     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
+ 168     # . . call
+ 169     e8/call  scan-next-byte/disp32
+ 170     # . . discard args
+ 171     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 172     # if (eax == Eof) error(ed, err, "partial byte found.")
+ 173     3d/compare-eax-and  0xffffffff/imm32/Eof
+ 174     75/jump-if-!=  $convert-next-octet:convert/disp8
+ 175     # . error-byte(ed, err, msg, '.')  # reusing error-byte to avoid creating _yet_ another helper
+ 176     # . . push args
+ 177     68/push  0x2e/imm32/period/dummy
+ 178     68/push  "convert-next-octet: partial byte found"/imm32
+ 179     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+ 180     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x10/disp8      .                 # push *(ebp+16)
+ 181     # . . call
+ 182     e8/call  error-byte/disp32  # never returns
+ 183 $convert-next-octet:convert:
+ 184     # eax = from-hex-char(eax)
+ 185     e8/call from-hex-char/disp32
+ 186     # eax = (ecx << 4) | eax
+ 187     # . ecx <<= 4
+ 188     c1/shift    4/subop/left        3/mod/direct    1/rm32/ecx    .           .             .           .           .               4/imm8            # shift ecx left by 4 bits
+ 189     # . eax |= ecx
+ 190     09/or                           3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # eax = bitwise OR with ecx
+ 191 $convert-next-octet:end:
+ 192     # . restore registers
+ 193     59/pop-to-ecx
+ 194     # . epilogue
+ 195     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+ 196     5d/pop-to-ebp
+ 197     c3/return
+ 198 
+ 199 test-convert-next-octet:
+ 200     # - check that the first two bytes of the input are assembled into the resulting octet
+ 201     # This test uses exit-descriptors. Use ebp for setting up local variables.
+ 202     55/push-ebp
+ 203     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 204     # clear all streams
+ 205     # . clear-stream(_test-stream)
+ 206     # . . push args
+ 207     68/push  _test-stream/imm32
+ 208     # . . call
+ 209     e8/call  clear-stream/disp32
+ 210     # . . discard args
+ 211     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+ 212     # . clear-stream($_test-buffered-file->buffer)
+ 213     # . . push args
+ 214     68/push  $_test-buffered-file->buffer/imm32
+ 215     # . . call
+ 216     e8/call  clear-stream/disp32
+ 217     # . . discard args
+ 218     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+ 219     # . clear-stream(_test-error-stream)
+ 220     # . . push args
+ 221     68/push  _test-error-stream/imm32
+ 222     # . . call
+ 223     e8/call  clear-stream/disp32
+ 224     # . . discard args
+ 225     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+ 226     # . clear-stream($_test-error-buffered-file->buffer)
+ 227     # . . push args
+ 228     68/push  $_test-error-buffered-file->buffer/imm32
+ 229     # . . call
+ 230     e8/call  clear-stream/disp32
+ 231     # . . discard args
+ 232     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+ 233     # initialize '_test-stream' to "abc"
+ 234     # . write(_test-stream, "abc")
+ 235     # . . push args
+ 236     68/push  "abc"/imm32
+ 237     68/push  _test-stream/imm32
+ 238     # . . call
+ 239     e8/call  write/disp32
+ 240     # . . discard args
+ 241     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 242     # initialize exit-descriptor 'ed' for the call to 'convert-next-octet' below
+ 243     # . var ed/ecx: exit-descriptor
+ 244     81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # subtract from esp
+ 245     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+ 246     # . tailor-exit-descriptor(ed, 12)
+ 247     # . . push args
+ 248     68/push  0xc/imm32/nbytes-of-args-for-convert-next-octet
+ 249     51/push-ecx/ed
+ 250     # . . call
+ 251     e8/call  tailor-exit-descriptor/disp32
+ 252     # . . discard args
+ 253     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 254     # eax = convert-next-octet(_test-buffered-file, _test-error-buffered-file, ed)
+ 255     # . . push args
+ 256     51/push-ecx/ed
+ 257     68/push  _test-error-buffered-file/imm32
+ 258     68/push  _test-buffered-file/imm32
+ 259     # . . call
+ 260     e8/call  convert-next-octet/disp32
+ 261     # registers except esp may be clobbered at this point
+ 262     # pop args to convert-next-octet
+ 263     # . . discard first 2 args
+ 264     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 265     # . . restore ed
+ 266     59/pop-to-ecx
+ 267     # check that convert-next-octet didn't abort
+ 268     # . check-ints-equal(ed->value, 0, msg)
+ 269     # . . push args
+ 270     68/push  "F - test-convert-next-octet: unexpected abort"/imm32
+ 271     68/push  0/imm32
+ 272     # . . push ed->value
+ 273     ff          6/subop/push        1/mod/*+disp8   1/rm32/ecx    .           .             .           .           4/disp8         .                 # push *(ecx+4)
+ 274     # . . call
+ 275     e8/call  check-ints-equal/disp32
+ 276     # . . discard args
+ 277     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 278     # return if abort
+ 279     81          7/subop/compare     1/mod/*+disp8   1/rm32/ecx    .           .             .           .           4/disp8         0/imm32           # compare *(ecx+4)
+ 280     75/jump-if-!=  $test-convert-next-octet:end/disp8
+ 281     # check-ints-equal(eax, 0xab, msg)
+ 282     # . . push args
+ 283     68/push  "F - test-convert-next-octet"/imm32
+ 284     68/push  0xab/imm32/ab
+ 285     50/push-eax
+ 286     # . . call
+ 287     e8/call  check-ints-equal/disp32
+ 288     # . . discard args
+ 289     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 290 $test-convert-next-octet:end:
+ 291     # . epilogue
+ 292     # don't restore esp from ebp; manually reclaim locals
+ 293     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 294     5d/pop-to-ebp
+ 295     c3/return
+ 296 
+ 297 test-convert-next-octet-handles-Eof:
+ 298     # - check that reaching end of file returns Eof
+ 299     # This test uses exit-descriptors. Use ebp for setting up local variables.
+ 300     55/push-ebp
+ 301     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 302     # clear all streams
+ 303     # . clear-stream(_test-stream)
+ 304     # . . push args
+ 305     68/push  _test-stream/imm32
+ 306     # . . call
+ 307     e8/call  clear-stream/disp32
+ 308     # . . discard args
+ 309     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+ 310     # . clear-stream($_test-buffered-file->buffer)
+ 311     # . . push args
+ 312     68/push  $_test-buffered-file->buffer/imm32
+ 313     # . . call
+ 314     e8/call  clear-stream/disp32
+ 315     # . . discard args
+ 316     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+ 317     # . clear-stream(_test-error-stream)
+ 318     # . . push args
+ 319     68/push  _test-error-stream/imm32
+ 320     # . . call
+ 321     e8/call  clear-stream/disp32
+ 322     # . . discard args
+ 323     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+ 324     # . clear-stream($_test-error-buffered-file->buffer)
+ 325     # . . push args
+ 326     68/push  $_test-error-buffered-file->buffer/imm32
+ 327     # . . call
+ 328     e8/call  clear-stream/disp32
+ 329     # . . discard args
+ 330     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+ 331     # don't initialize '_test-stream'
+ 332     # initialize exit-descriptor 'ed' for the call to 'convert-next-octet' below
+ 333     # . var ed/ecx: exit-descriptor
+ 334     81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # subtract from esp
+ 335     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+ 336     # . tailor-exit-descriptor(ed, 12)
+ 337     # . . push args
+ 338     68/push  0xc/imm32/nbytes-of-args-for-convert-next-octet
+ 339     51/push-ecx/ed
+ 340     # . . call
+ 341     e8/call  tailor-exit-descriptor/disp32
+ 342     # . . discard args
+ 343     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 344     # eax = convert-next-octet(_test-buffered-file, _test-error-buffered-file, ed)
+ 345     # . . push args
+ 346     51/push-ecx/ed
+ 347     68/push  _test-error-buffered-file/imm32
+ 348     68/push  _test-buffered-file/imm32
+ 349     # . . call
+ 350     e8/call  convert-next-octet/disp32
+ 351     # registers except esp may be clobbered at this point
+ 352     # pop args to convert-next-octet
+ 353     # . . discard first 2 args
+ 354     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 355     # . . restore ed
+ 356     59/pop-to-ecx
+ 357     # check that convert-next-octet didn't abort
+ 358     # . check-ints-equal(ed->value, 0, msg)
+ 359     # . . push args
+ 360     68/push  "F - test-convert-next-octet: unexpected abort"/imm32
+ 361     68/push  0/imm32
+ 362     # . . push ed->value
+ 363     ff          6/subop/push        1/mod/*+disp8   1/rm32/ecx    .           .             .           .           4/disp8         .                 # push *(ecx+4)
+ 364     # . . call
+ 365     e8/call  check-ints-equal/disp32
+ 366     # . . discard args
+ 367     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 368     # return if abort
+ 369     81          7/subop/compare     1/mod/*+disp8   1/rm32/ecx    .           .             .           .           4/disp8         0/imm32           # compare *(ecx+4)
+ 370     75/jump-if-!=  $test-convert-next-octet-handles-Eof:end/disp8
+ 371     # check-ints-equal(eax, Eof, msg)
+ 372     # . . push args
+ 373     68/push  "F - test-convert-next-octet-handles-Eof"/imm32
+ 374     68/push  0xffffffff/imm32/Eof
+ 375     50/push-eax
+ 376     # . . call
+ 377     e8/call  check-ints-equal/disp32
+ 378     # . . discard args
+ 379     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 380 $test-convert-next-octet-handles-Eof:end:
+ 381     # . epilogue
+ 382     # don't restore esp from ebp; manually reclaim locals
+ 383     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 384     5d/pop-to-ebp
+ 385     c3/return
+ 386 
+ 387 test-convert-next-octet-aborts-on-single-hex-byte:
+ 388     # - check that a single unaccompanied hex byte aborts
+ 389     # This test uses exit-descriptors. Use ebp for setting up local variables.
+ 390     55/push-ebp
+ 391     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 392     # clear all streams
+ 393     # . clear-stream(_test-stream)
+ 394     # . . push args
+ 395     68/push  _test-stream/imm32
+ 396     # . . call
+ 397     e8/call  clear-stream/disp32
+ 398     # . . discard args
+ 399     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+ 400     # . clear-stream($_test-buffered-file->buffer)
+ 401     # . . push args
+ 402     68/push  $_test-buffered-file->buffer/imm32
+ 403     # . . call
+ 404     e8/call  clear-stream/disp32
+ 405     # . . discard args
+ 406     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+ 407     # . clear-stream(_test-error-stream)
+ 408     # . . push args
+ 409     68/push  _test-error-stream/imm32
+ 410     # . . call
+ 411     e8/call  clear-stream/disp32
+ 412     # . . discard args
+ 413     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+ 414     # . clear-stream($_test-error-buffered-file->buffer)
+ 415     # . . push args
+ 416     68/push  $_test-error-buffered-file->buffer/imm32
+ 417     # . . call
+ 418     e8/call  clear-stream/disp32
+ 419     # . . discard args
+ 420     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+ 421     # initialize '_test-stream' to "a"
+ 422     # . write(_test-stream, "a")
+ 423     # . . push args
+ 424     68/push  "a"/imm32
+ 425     68/push  _test-stream/imm32
+ 426     # . . call
+ 427     e8/call  write/disp32
+ 428     # . . discard args
+ 429     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 430     # initialize exit-descriptor 'ed' for the call to 'convert-next-octet' below
+ 431     # . var ed/ecx: exit-descriptor
+ 432     81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # subtract from esp
+ 433     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+ 434     # . tailor-exit-descriptor(ed, 12)
+ 435     # . . push args
+ 436     68/push  0xc/imm32/nbytes-of-args-for-convert-next-octet
+ 437     51/push-ecx/ed
+ 438     # . . call
+ 439     e8/call  tailor-exit-descriptor/disp32
+ 440     # . . discard args
+ 441     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 442     # eax = convert-next-octet(_test-buffered-file, _test-error-buffered-file, ed)
+ 443     # . . push args
+ 444     51/push-ecx/ed
+ 445     68/push  _test-error-buffered-file/imm32
+ 446     68/push  _test-buffered-file/imm32
+ 447     # . . call
+ 448     e8/call  convert-next-octet/disp32
+ 449     # registers except esp may be clobbered at this point
+ 450     # pop args to convert-next-octet
+ 451     # . . discard first 2 args
+ 452     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 453     # . . restore ed
+ 454     59/pop-to-ecx
+ 455     # check that convert-next-octet aborted
+ 456     # . check-ints-equal(ed->value, 2, msg)
+ 457     # . . push args
+ 458     68/push  "F - test-convert-next-octet-aborts-on-single-hex-byte: unexpected abort"/imm32
+ 459     68/push  2/imm32
+ 460     # . . push ed->value
+ 461     ff          6/subop/push        1/mod/*+disp8   1/rm32/ecx    .           .             .           .           4/disp8         .                 # push *(ecx+4)
+ 462     # . . call
+ 463     e8/call  check-ints-equal/disp32
+ 464     # . . discard args
+ 465     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 466 $test-convert-next-octet-aborts-on-single-hex-byte:end:
+ 467     # . epilogue
+ 468     # don't restore esp from ebp; manually reclaim locals
+ 469     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 470     5d/pop-to-ebp
+ 471     c3/return
+ 472 
+ 473 # read whitespace until a hex byte, and return it
+ 474 # return Eof if file ends without finding a hex byte
+ 475 # on '#' skip all bytes until newline
+ 476 # abort on any other byte
+ 477 scan-next-byte:  # in: (addr buffered-file), err: (addr buffered-file), ed: (addr exit-descriptor) -> byte-or-Eof/eax
+ 478     # pseudocode:
+ 479     #   while true
+ 480     #     eax = read-byte-buffered(in)
+ 481     #     if (eax == Eof) return eax
+ 482     #     if (hex-digit?(eax)) return eax
+ 483     #     if (eax == ' ' or '\t' or '\n') continue
+ 484     #     if (eax == '#') skip-until-newline(in)
+ 485     #     else error-byte(ed, err, "invalid byte: " eax)
+ 486     #
+ 487     # . prologue
+ 488     55/push-ebp
+ 489     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 490     # . save registers
+ 491 $scan-next-byte:loop:
+ 492     # eax = read-byte-buffered(in)
+ 493     # . . push args
+ 494     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
+ 495     # . . call
+ 496     e8/call  read-byte-buffered/disp32
+ 497     # . . discard args
+ 498     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+ 499     # if (eax == Eof) return eax
+ 500     3d/compare-with-eax  0xffffffff/imm32/Eof
+ 501     74/jump-if-=  $scan-next-byte:end/disp8
+ 502     # if (hex-digit?(eax)) return eax
+ 503     # . save eax for now
+ 504     50/push-eax
+ 505     # . hex-digit?(eax)
+ 506     # . . push args
+ 507     50/push-eax
+ 508     # . . call
+ 509     e8/call  hex-digit?/disp32
+ 510     # . . discard args
+ 511     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+ 512     # . compare with 'false'
+ 513     3d/compare-with-eax  0/imm32/false
+ 514     # . restore eax (does not affect flags)
+ 515     58/pop-to-eax
+ 516     # . check whether to return
+ 517     75/jump-if-!=  $scan-next-byte:end/disp8
+ 518 $scan-next-byte:check1:
+ 519     # if (eax == ' ') continue
+ 520     3d/compare-eax-and  0x20/imm32/space
+ 521     74/jump-if-=  $scan-next-byte:loop/disp8
+ 522     # if (eax == '\t') continue
+ 523     3d/compare-eax-and  9/imm32/tab
+ 524     74/jump-if-=  $scan-next-byte:loop/disp8
+ 525     # if (eax == '\n') continue
+ 526     3d/compare-eax-and  0xa/imm32/newline
+ 527     74/jump-if-=  $scan-next-byte:loop/disp8
+ 528 $scan-next-byte:check2:
+ 529     # if (eax == '#') skip-until-newline(in)
+ 530     3d/compare-with-eax  0x23/imm32/hash
+ 531     75/jump-if-!=  $scan-next-byte:check3/disp8
+ 532     # . skip-until-newline(in)
+ 533     # . . push args
+ 534     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
+ 535     # . . call
+ 536     e8/call  skip-until-newline/disp32
+ 537     # . . discard args
+ 538     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+ 539     eb/jump  $scan-next-byte:loop/disp8
+ 540 $scan-next-byte:check3:
+ 541     # otherwise error-byte(ed, err, msg, eax)
+ 542     # . . push args
+ 543     50/push-eax
+ 544     68/push  "scan-next-byte: invalid byte"/imm32
+ 545     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+ 546     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x10/disp8      .                 # push *(ebp+16)
+ 547     # . . call
+ 548     e8/call  error-byte/disp32  # never returns
+ 549 $scan-next-byte:end:
+ 550     # . restore registers
+ 551     # . epilogue
+ 552     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+ 553     5d/pop-to-ebp
+ 554     c3/return
+ 555 
+ 556 test-scan-next-byte:
+ 557     # - check that the first byte of the input is returned
+ 558     # This test uses exit-descriptors. Use ebp for setting up local variables.
+ 559     55/push-ebp
+ 560     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 561     # clear all streams
+ 562     # . clear-stream(_test-stream)
+ 563     # . . push args
+ 564     68/push  _test-stream/imm32
+ 565     # . . call
+ 566     e8/call  clear-stream/disp32
+ 567     # . . discard args
+ 568     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+ 569     # . clear-stream($_test-buffered-file->buffer)
+ 570     # . . push args
+ 571     68/push  $_test-buffered-file->buffer/imm32
+ 572     # . . call
+ 573     e8/call  clear-stream/disp32
+ 574     # . . discard args
+ 575     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+ 576     # . clear-stream(_test-error-stream)
+ 577     # . . push args
+ 578     68/push  _test-error-stream/imm32
+ 579     # . . call
+ 580     e8/call  clear-stream/disp32
+ 581     # . . discard args
+ 582     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+ 583     # . clear-stream($_test-error-buffered-file->buffer)
+ 584     # . . push args
+ 585     68/push  $_test-error-buffered-file->buffer/imm32
+ 586     # . . call
+ 587     e8/call  clear-stream/disp32
+ 588     # . . discard args
+ 589     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+ 590     # initialize '_test-stream' to "abc"
+ 591     # . write(_test-stream, "abc")
+ 592     # . . push args
+ 593     68/push  "abc"/imm32
+ 594     68/push  _test-stream/imm32
+ 595     # . . call
+ 596     e8/call  write/disp32
+ 597     # . . discard args
+ 598     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 599     # initialize exit-descriptor 'ed' for the call to 'scan-next-byte' below
+ 600     # . var ed/ecx: exit-descriptor
+ 601     81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # subtract from esp
+ 602     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+ 603     # . tailor-exit-descriptor(ed, 12)
+ 604     # . . push args
+ 605     68/push  0xc/imm32/nbytes-of-args-for-scan-next-byte
+ 606     51/push-ecx/ed
+ 607     # . . call
+ 608     e8/call  tailor-exit-descriptor/disp32
+ 609     # . . discard args
+ 610     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 611     # eax = scan-next-byte(_test-buffered-file, _test-error-buffered-file, ed)
+ 612     # . . push args
+ 613     51/push-ecx/ed
+ 614     68/push  _test-error-buffered-file/imm32
+ 615     68/push  _test-buffered-file/imm32
+ 616     # . . call
+ 617     e8/call  scan-next-byte/disp32
+ 618     # registers except esp may be clobbered at this point
+ 619     # pop args to scan-next-byte
+ 620     # . . discard first 2 args
+ 621     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 622     # . . restore ed
+ 623     59/pop-to-ecx
+ 624     # check that scan-next-byte didn't abort
+ 625     # . check-ints-equal(ed->value, 0, msg)
+ 626     # . . push args
+ 627     68/push  "F - test-scan-next-byte: unexpected abort"/imm32
+ 628     68/push  0/imm32
+ 629     # . . push ed->value
+ 630     ff          6/subop/push        1/mod/*+disp8   1/rm32/ecx    .           .             .           .           4/disp8         .                 # push *(ecx+4)
+ 631     # . . call
+ 632     e8/call  check-ints-equal/disp32
+ 633     # . . discard args
+ 634     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 635     # return if abort
+ 636     81          7/subop/compare     1/mod/*+disp8   1/rm32/ecx    .           .             .           .           4/disp8         0/imm32           # compare *(ecx+4)
+ 637     75/jump-if-!=  $test-scan-next-byte:end/disp8
+ 638     # check-ints-equal(eax, 0x61/a, msg)
+ 639     # . . push args
+ 640     68/push  "F - test-scan-next-byte"/imm32
+ 641     68/push  0x61/imm32/a
+ 642     50/push-eax
+ 643     # . . call
+ 644     e8/call  check-ints-equal/disp32
+ 645     # . . discard args
+ 646     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 647 $test-scan-next-byte:end:
+ 648     # . epilogue
+ 649     # don't restore esp from ebp; manually reclaim locals
+ 650     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 651     5d/pop-to-ebp
+ 652     c3/return
+ 653 
+ 654 test-scan-next-byte-skips-whitespace:
+ 655     # - check that the first byte after whitespace is returned
+ 656     # This test uses exit-descriptors. Use ebp for setting up local variables.
+ 657     55/push-ebp
+ 658     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 659     # clear all streams
+ 660     # . clear-stream(_test-stream)
+ 661     # . . push args
+ 662     68/push  _test-stream/imm32
+ 663     # . . call
+ 664     e8/call  clear-stream/disp32
+ 665     # . . discard args
+ 666     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+ 667     # . clear-stream($_test-buffered-file->buffer)
+ 668     # . . push args
+ 669     68/push  $_test-buffered-file->buffer/imm32
+ 670     # . . call
+ 671     e8/call  clear-stream/disp32
+ 672     # . . discard args
+ 673     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+ 674     # . clear-stream(_test-error-stream)
+ 675     # . . push args
+ 676     68/push  _test-error-stream/imm32
+ 677     # . . call
+ 678     e8/call  clear-stream/disp32
+ 679     # . . discard args
+ 680     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+ 681     # . clear-stream($_test-error-buffered-file->buffer)
+ 682     # . . push args
+ 683     68/push  $_test-error-buffered-file->buffer/imm32
+ 684     # . . call
+ 685     e8/call  clear-stream/disp32
+ 686     # . . discard args
+ 687     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+ 688     # initialize '_test-stream' to input with leading whitespace
+ 689     # . write(_test-stream, text)
+ 690     # . . push args
+ 691     68/push  "  abc"/imm32
+ 692     68/push  _test-stream/imm32
+ 693     # . . call
+ 694     e8/call  write/disp32
+ 695     # . . discard args
+ 696     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 697     # initialize exit-descriptor 'ed' for the call to 'scan-next-byte' below
+ 698     # . var ed/ecx: exit-descriptor
+ 699     81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # subtract from esp
+ 700     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+ 701     # . tailor-exit-descriptor(ed, 12)
+ 702     # . . push args
+ 703     68/push  0xc/imm32/nbytes-of-args-for-scan-next-byte
+ 704     51/push-ecx/ed
+ 705     # . . call
+ 706     e8/call  tailor-exit-descriptor/disp32
+ 707     # . . discard args
+ 708     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 709     # eax = scan-next-byte(_test-buffered-file, _test-error-buffered-file, ed)
+ 710     # . . push args
+ 711     51/push-ecx/ed
+ 712     68/push  _test-error-buffered-file/imm32
+ 713     68/push  _test-buffered-file/imm32
+ 714     # . . call
+ 715     e8/call  scan-next-byte/disp32
+ 716     # registers except esp may be clobbered at this point
+ 717     # pop args to scan-next-byte
+ 718     # . . discard first 2 args
+ 719     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 720     # . . restore ed
+ 721     59/pop-to-ecx
+ 722     # check that scan-next-byte didn't abort
+ 723     # . check-ints-equal(ed->value, 0, msg)
+ 724     # . . push args
+ 725     68/push  "F - test-scan-next-byte-skips-whitespace: unexpected abort"/imm32
+ 726     68/push  0/imm32
+ 727     # . . push ed->value
+ 728     ff          6/subop/push        1/mod/*+disp8   1/rm32/ecx    .           .             .           .           4/disp8         .                 # push *(ecx+4)
+ 729     # . . call
+ 730     e8/call  check-ints-equal/disp32
+ 731     # . . discard args
+ 732     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 733     # return if abort
+ 734     81          7/subop/compare     1/mod/*+disp8   1/rm32/ecx    .           .             .           .           4/disp8         0/imm32           # compare *(ecx+4)
+ 735     75/jump-if-!=  $test-scan-next-byte-skips-whitespace:end/disp8
+ 736     # check-ints-equal(eax, 0x61/a, msg)
+ 737     # . . push args
+ 738     68/push  "F - test-scan-next-byte-skips-whitespace"/imm32
+ 739     68/push  0x61/imm32/a
+ 740     50/push-eax
+ 741     # . . call
+ 742     e8/call  check-ints-equal/disp32
+ 743     # . . discard args
+ 744     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 745 $test-scan-next-byte-skips-whitespace:end:
+ 746     # . epilogue
+ 747     # don't restore esp from ebp; manually reclaim locals
+ 748     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 749     5d/pop-to-ebp
+ 750     c3/return
+ 751 
+ 752 test-scan-next-byte-skips-comment:
+ 753     # - check that the first byte after a comment (and newline) is returned
+ 754     # This test uses exit-descriptors. Use ebp for setting up local variables.
+ 755     55/push-ebp
+ 756     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 757     # clear all streams
+ 758     # . clear-stream(_test-stream)
+ 759     # . . push args
+ 760     68/push  _test-stream/imm32
+ 761     # . . call
+ 762     e8/call  clear-stream/disp32
+ 763     # . . discard args
+ 764     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+ 765     # . clear-stream($_test-buffered-file->buffer)
+ 766     # . . push args
+ 767     68/push  $_test-buffered-file->buffer/imm32
+ 768     # . . call
+ 769     e8/call  clear-stream/disp32
+ 770     # . . discard args
+ 771     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+ 772     # . clear-stream(_test-error-stream)
+ 773     # . . push args
+ 774     68/push  _test-error-stream/imm32
+ 775     # . . call
+ 776     e8/call  clear-stream/disp32
+ 777     # . . discard args
+ 778     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+ 779     # . clear-stream($_test-error-buffered-file->buffer)
+ 780     # . . push args
+ 781     68/push  $_test-error-buffered-file->buffer/imm32
+ 782     # . . call
+ 783     e8/call  clear-stream/disp32
+ 784     # . . discard args
+ 785     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+ 786     # initialize '_test-stream' to input with leading comment
+ 787     # . write(_test-stream, comment)
+ 788     # . . push args
+ 789     68/push  "#x\n"/imm32
+ 790     68/push  _test-stream/imm32
+ 791     # . . call
+ 792     e8/call  write/disp32
+ 793     # . . discard args
+ 794     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 795     # . write(_test-stream, real text)
+ 796     # . . push args
+ 797     68/push  "ab"/imm32
+ 798     68/push  _test-stream/imm32
+ 799     # . . call
+ 800     e8/call  write/disp32
+ 801     # . . discard args
+ 802     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 803     # initialize exit-descriptor 'ed' for the call to 'scan-next-byte' below
+ 804     # . var ed/ecx: exit-descriptor
+ 805     81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # subtract from esp
+ 806     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+ 807     # . tailor-exit-descriptor(ed, 12)
+ 808     # . . push args
+ 809     68/push  0xc/imm32/nbytes-of-args-for-scan-next-byte
+ 810     51/push-ecx/ed
+ 811     # . . call
+ 812     e8/call  tailor-exit-descriptor/disp32
+ 813     # . . discard args
+ 814     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 815     # eax = scan-next-byte(_test-buffered-file, _test-error-buffered-file, ed)
+ 816     # . . push args
+ 817     51/push-ecx/ed
+ 818     68/push  _test-error-buffered-file/imm32
+ 819     68/push  _test-buffered-file/imm32
+ 820     # . . call
+ 821     e8/call  scan-next-byte/disp32
+ 822     # registers except esp may be clobbered at this point
+ 823     # pop args to scan-next-byte
+ 824     # . . discard first 2 args
+ 825     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 826     # . . restore ed
+ 827     59/pop-to-ecx
+ 828     # check that scan-next-byte didn't abort
+ 829     # . check-ints-equal(ed->value, 0, msg)
+ 830     # . . push args
+ 831     68/push  "F - test-scan-next-byte-skips-comment: unexpected abort"/imm32
+ 832     68/push  0/imm32
+ 833     # . . push ed->value
+ 834     ff          6/subop/push        1/mod/*+disp8   1/rm32/ecx    .           .             .           .           4/disp8         .                 # push *(ecx+4)
+ 835     # . . call
+ 836     e8/call  check-ints-equal/disp32
+ 837     # . . discard args
+ 838     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 839     # return if abort
+ 840     81          7/subop/compare     1/mod/*+disp8   1/rm32/ecx    .           .             .           .           4/disp8         0/imm32           # compare *(ecx+4)
+ 841     75/jump-if-!=  $test-scan-next-byte-skips-comment:end/disp8
+ 842     # check-ints-equal(eax, 0x61/a, msg)
+ 843     # . . push args
+ 844     68/push  "F - test-scan-next-byte-skips-comment"/imm32
+ 845     68/push  0x61/imm32/a
+ 846     50/push-eax
+ 847     # . . call
+ 848     e8/call  check-ints-equal/disp32
+ 849     # . . discard args
+ 850     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 851 $test-scan-next-byte-skips-comment:end:
+ 852     # . epilogue
+ 853     # don't restore esp from ebp; manually reclaim locals
+ 854     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 855     5d/pop-to-ebp
+ 856     c3/return
+ 857 
+ 858 test-scan-next-byte-skips-comment-and-whitespace:
+ 859     # - check that the first byte after a comment and any further whitespace is returned
+ 860     # This test uses exit-descriptors. Use ebp for setting up local variables.
+ 861     55/push-ebp
+ 862     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 863     # clear all streams
+ 864     # . clear-stream(_test-stream)
+ 865     # . . push args
+ 866     68/push  _test-stream/imm32
+ 867     # . . call
+ 868     e8/call  clear-stream/disp32
+ 869     # . . discard args
+ 870     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+ 871     # . clear-stream($_test-buffered-file->buffer)
+ 872     # . . push args
+ 873     68/push  $_test-buffered-file->buffer/imm32
+ 874     # . . call
+ 875     e8/call  clear-stream/disp32
+ 876     # . . discard args
+ 877     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+ 878     # . clear-stream(_test-error-stream)
+ 879     # . . push args
+ 880     68/push  _test-error-stream/imm32
+ 881     # . . call
+ 882     e8/call  clear-stream/disp32
+ 883     # . . discard args
+ 884     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+ 885     # . clear-stream($_test-error-buffered-file->buffer)
+ 886     # . . push args
+ 887     68/push  $_test-error-buffered-file->buffer/imm32
+ 888     # . . call
+ 889     e8/call  clear-stream/disp32
+ 890     # . . discard args
+ 891     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+ 892     # initialize '_test-stream' to input with leading comment and more whitespace after newline
+ 893     # . write(_test-stream, comment)
+ 894     # . . push args
+ 895     68/push  "#x\n"/imm32
+ 896     68/push  _test-stream/imm32
+ 897     # . . call
+ 898     e8/call  write/disp32
+ 899     # . . discard args
+ 900     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 901     # . write(_test-stream, real text)
+ 902     # . . push args
+ 903     68/push  " ab"/imm32
+ 904     68/push  _test-stream/imm32
+ 905     # . . call
+ 906     e8/call  write/disp32
+ 907     # . . discard args
+ 908     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 909     # initialize exit-descriptor 'ed' for the call to 'scan-next-byte' below
+ 910     # . var ed/ecx: exit-descriptor
+ 911     81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # subtract from esp
+ 912     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+ 913     # . tailor-exit-descriptor(ed, 12)
+ 914     # . . push args
+ 915     68/push  0xc/imm32/nbytes-of-args-for-scan-next-byte
+ 916     51/push-ecx/ed
+ 917     # . . call
+ 918     e8/call  tailor-exit-descriptor/disp32
+ 919     # . . discard args
+ 920     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 921     # eax = scan-next-byte(_test-buffered-file, _test-error-buffered-file, ed)
+ 922     # . . push args
+ 923     51/push-ecx/ed
+ 924     68/push  _test-error-buffered-file/imm32
+ 925     68/push  _test-buffered-file/imm32
+ 926     # . . call
+ 927     e8/call  scan-next-byte/disp32
+ 928     # registers except esp may be clobbered at this point
+ 929     # pop args to scan-next-byte
+ 930     # . . discard first 2 args
+ 931     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 932     # . . restore ed
+ 933     59/pop-to-ecx
+ 934     # check that scan-next-byte didn't abort
+ 935     # . check-ints-equal(ed->value, 0, msg)
+ 936     # . . push args
+ 937     68/push  "F - test-scan-next-byte-skips-comment-and-whitespace: unexpected abort"/imm32
+ 938     68/push  0/imm32
+ 939     # . . push ed->value
+ 940     ff          6/subop/push        1/mod/*+disp8   1/rm32/ecx    .           .             .           .           4/disp8         .                 # push *(ecx+4)
+ 941     # . . call
+ 942     e8/call  check-ints-equal/disp32
+ 943     # . . discard args
+ 944     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 945     # return if abort
+ 946     81          7/subop/compare     1/mod/*+disp8   1/rm32/ecx    .           .             .           .           4/disp8         0/imm32           # compare *(ecx+4)
+ 947     75/jump-if-!=  $test-scan-next-byte-skips-comment-and-whitespace:end/disp8
+ 948     # check-ints-equal(eax, 0x61/a, msg)
+ 949     # . . push args
+ 950     68/push  "F - test-scan-next-byte-skips-comment-and-whitespace"/imm32
+ 951     68/push  0x61/imm32/a
+ 952     50/push-eax
+ 953     # . . call
+ 954     e8/call  check-ints-equal/disp32
+ 955     # . . discard args
+ 956     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 957 $test-scan-next-byte-skips-comment-and-whitespace:end:
+ 958     # . epilogue
+ 959     # don't restore esp from ebp; manually reclaim locals
+ 960     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 961     5d/pop-to-ebp
+ 962     c3/return
+ 963 
+ 964 test-scan-next-byte-skips-whitespace-and-comment:
+ 965     # - check that the first byte after any whitespace and comments is returned
+ 966     # This test uses exit-descriptors. Use ebp for setting up local variables.
+ 967     55/push-ebp
+ 968     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 969     # clear all streams
+ 970     # . clear-stream(_test-stream)
+ 971     # . . push args
+ 972     68/push  _test-stream/imm32
+ 973     # . . call
+ 974     e8/call  clear-stream/disp32
+ 975     # . . discard args
+ 976     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+ 977     # . clear-stream($_test-buffered-file->buffer)
+ 978     # . . push args
+ 979     b8/copy-to-eax  _test-buffered-file/imm32
+ 980     05/add-to-eax  4/imm32
+ 981     50/push-eax
+ 982     # . . call
+ 983     e8/call  clear-stream/disp32
+ 984     # . . discard args
+ 985     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+ 986     # . clear-stream(_test-error-stream)
+ 987     # . . push args
+ 988     68/push  _test-error-stream/imm32
+ 989     # . . call
+ 990     e8/call  clear-stream/disp32
+ 991     # . . discard args
+ 992     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+ 993     # . clear-stream($_test-error-buffered-file->buffer)
+ 994     # . . push args
+ 995     68/push  $_test-error-buffered-file->buffer/imm32
+ 996     # . . call
+ 997     e8/call  clear-stream/disp32
+ 998     # . . discard args
+ 999     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+1000     # initialize '_test-stream' to input with leading whitespace and comment
+1001     # . write(_test-stream, comment)
+1002     # . . push args
+1003     68/push  " #x\n"/imm32
+1004     68/push  _test-stream/imm32
+1005     # . . call
+1006     e8/call  write/disp32
+1007     # . . discard args
+1008     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1009     # . write(_test-stream, real text)
+1010     # . . push args
+1011     68/push  "ab"/imm32
+1012     68/push  _test-stream/imm32
+1013     # . . call
+1014     e8/call  write/disp32
+1015     # . . discard args
+1016     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1017     # initialize exit-descriptor 'ed' for the call to 'scan-next-byte' below
+1018     # . var ed/ecx: exit-descriptor
+1019     81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # subtract from esp
+1020     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+1021     # . tailor-exit-descriptor(ed, 12)
+1022     # . . push args
+1023     68/push  0xc/imm32/nbytes-of-args-for-scan-next-byte
+1024     51/push-ecx/ed
+1025     # . . call
+1026     e8/call  tailor-exit-descriptor/disp32
+1027     # . . discard args
+1028     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1029     # eax = scan-next-byte(_test-buffered-file, _test-error-buffered-file, ed)
+1030     # . . push args
+1031     51/push-ecx/ed
+1032     68/push  _test-error-buffered-file/imm32
+1033     68/push  _test-buffered-file/imm32
+1034     # . . call
+1035     e8/call  scan-next-byte/disp32
+1036     # registers except esp may be clobbered at this point
+1037     # pop args to scan-next-byte
+1038     # . . discard first 2 args
+1039     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1040     # . . restore ed
+1041     59/pop-to-ecx
+1042     # check that scan-next-byte didn't abort
+1043     # . check-ints-equal(ed->value, 0, msg)
+1044     # . . push args
+1045     68/push  "F - test-scan-next-byte-skips-whitespace-and-comment: unexpected abort"/imm32
+1046     68/push  0/imm32
+1047     # . . push ed->value
+1048     ff          6/subop/push        1/mod/*+disp8   1/rm32/ecx    .           .             .           .           4/disp8         .                 # push *(ecx+4)
+1049     # . . call
+1050     e8/call  check-ints-equal/disp32
+1051     # . . discard args
+1052     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1053     # return if abort
+1054     81          7/subop/compare     1/mod/*+disp8   1/rm32/ecx    .           .             .           .           4/disp8         0/imm32           # compare *(ecx+4)
+1055     75/jump-if-!=  $test-scan-next-byte-skips-whitespace-and-comment:end/disp8
+1056     # check-ints-equal(eax, 0x61/a, msg)
+1057     # . . push args
+1058     68/push  "F - test-scan-next-byte-skips-whitespace-and-comment"/imm32
+1059     68/push  0x61/imm32/a
+1060     50/push-eax
+1061     # . . call
+1062     e8/call  check-ints-equal/disp32
+1063     # . . discard args
+1064     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1065 $test-scan-next-byte-skips-whitespace-and-comment:end:
+1066     # . epilogue
+1067     # don't restore esp from ebp; manually reclaim locals
+1068     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1069     5d/pop-to-ebp
+1070     c3/return
+1071 
+1072 test-scan-next-byte-reads-final-byte:
+1073     # - check that the final byte in input is returned
+1074     # This test uses exit-descriptors. Use ebp for setting up local variables.
+1075     55/push-ebp
+1076     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+1077     # clear all streams
+1078     # . clear-stream(_test-stream)
+1079     # . . push args
+1080     68/push  _test-stream/imm32
+1081     # . . call
+1082     e8/call  clear-stream/disp32
+1083     # . . discard args
+1084     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+1085     # . clear-stream($_test-buffered-file->buffer)
+1086     # . . push args
+1087     68/push  $_test-buffered-file->buffer/imm32
+1088     # . . call
+1089     e8/call  clear-stream/disp32
+1090     # . . discard args
+1091     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+1092     # . clear-stream(_test-error-stream)
+1093     # . . push args
+1094     68/push  _test-error-stream/imm32
+1095     # . . call
+1096     e8/call  clear-stream/disp32
+1097     # . . discard args
+1098     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+1099     # . clear-stream($_test-error-buffered-file->buffer)
+1100     # . . push args
+1101     68/push  $_test-error-buffered-file->buffer/imm32
+1102     # . . call
+1103     e8/call  clear-stream/disp32
+1104     # . . discard args
+1105     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+1106     # initialize '_test-stream' to input with single character
+1107     # . write(_test-stream, character)
+1108     # . . push args
+1109     68/push  "a"/imm32
+1110     68/push  _test-stream/imm32
+1111     # . . call
+1112     e8/call  write/disp32
+1113     # . . discard args
+1114     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1115     # initialize exit-descriptor 'ed' for the call to 'scan-next-byte' below
+1116     # . var ed/ecx: exit-descriptor
+1117     81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # subtract from esp
+1118     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+1119     # . tailor-exit-descriptor(ed, 12)
+1120     # . . push args
+1121     68/push  0xc/imm32/nbytes-of-args-for-scan-next-byte
+1122     51/push-ecx/ed
+1123     # . . call
+1124     e8/call  tailor-exit-descriptor/disp32
+1125     # . . discard args
+1126     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1127     # eax = scan-next-byte(_test-buffered-file, _test-error-buffered-file, ed)
+1128     # . . push args
+1129     51/push-ecx/ed
+1130     68/push  _test-error-buffered-file/imm32
+1131     68/push  _test-buffered-file/imm32
+1132     # . . call
+1133     e8/call  scan-next-byte/disp32
+1134     # registers except esp may be clobbered at this point
+1135     # pop args to scan-next-byte
+1136     # . . discard first 2 args
+1137     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1138     # . . restore ed
+1139     59/pop-to-ecx
+1140     # check that scan-next-byte didn't abort
+1141     # . check-ints-equal(ed->value, 0, msg)
+1142     # . . push args
+1143     68/push  "F - test-scan-next-byte-reads-final-byte: unexpected abort"/imm32
+1144     68/push  0/imm32
+1145     # . . push ed->value
+1146     ff          6/subop/push        1/mod/*+disp8   1/rm32/ecx    .           .             .           .           4/disp8         .                 # push *(ecx+4)
+1147     # . . call
+1148     e8/call  check-ints-equal/disp32
+1149     # . . discard args
+1150     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1151     # return if abort
+1152     81          7/subop/compare     1/mod/*+disp8   1/rm32/ecx    .           .             .           .           4/disp8         0/imm32           # compare *(ecx+4)
+1153     75/jump-if-!=  $test-scan-next-byte-reads-final-byte:end/disp8
+1154     # check-ints-equal(eax, 0x61/a, msg)
+1155     # . . push args
+1156     68/push  "F - test-scan-next-byte-reads-final-byte"/imm32
+1157     68/push  0x61/imm32/a
+1158     50/push-eax
+1159     # . . call
+1160     e8/call  check-ints-equal/disp32
+1161     # . . discard args
+1162     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1163 $test-scan-next-byte-reads-final-byte:end:
+1164     # . epilogue
+1165     # don't restore esp from ebp; manually reclaim locals
+1166     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1167     5d/pop-to-ebp
+1168     c3/return
+1169 
+1170 test-scan-next-byte-handles-Eof:
+1171     # - check that the right sentinel value is returned when there's no data remaining to be read
+1172     # This test uses exit-descriptors. Use ebp for setting up local variables.
+1173     55/push-ebp
+1174     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+1175     # clear all streams
+1176     # . clear-stream(_test-stream)
+1177     # . . push args
+1178     68/push  _test-stream/imm32
+1179     # . . call
+1180     e8/call  clear-stream/disp32
+1181     # . . discard args
+1182     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+1183     # . clear-stream($_test-buffered-file->buffer)
+1184     # . . push args
+1185     68/push  $_test-buffered-file->buffer/imm32
+1186     # . . call
+1187     e8/call  clear-stream/disp32
+1188     # . . discard args
+1189     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+1190     # . clear-stream(_test-error-stream)
+1191     # . . push args
+1192     68/push  _test-error-stream/imm32
+1193     # . . call
+1194     e8/call  clear-stream/disp32
+1195     # . . discard args
+1196     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+1197     # . clear-stream($_test-error-buffered-file->buffer)
+1198     # . . push args
+1199     68/push  $_test-error-buffered-file->buffer/imm32
+1200     # . . call
+1201     e8/call  clear-stream/disp32
+1202     # . . discard args
+1203     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+1204     # leave '_test-stream' empty
+1205     # initialize exit-descriptor 'ed' for the call to 'scan-next-byte' below
+1206     # . var ed/ecx: exit-descriptor
+1207     81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # subtract from esp
+1208     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+1209     # . tailor-exit-descriptor(ed, 12)
+1210     # . . push args
+1211     68/push  0xc/imm32/nbytes-of-args-for-scan-next-byte
+1212     51/push-ecx/ed
+1213     # . . call
+1214     e8/call  tailor-exit-descriptor/disp32
+1215     # . . discard args
+1216     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1217     # eax = scan-next-byte(_test-buffered-file, _test-error-buffered-file, ed)
+1218     # . . push args
+1219     51/push-ecx/ed
+1220     68/push  _test-error-buffered-file/imm32
+1221     68/push  _test-buffered-file/imm32
+1222     # . . call
+1223     e8/call  scan-next-byte/disp32
+1224     # registers except esp may be clobbered at this point
+1225     # pop args to scan-next-byte
+1226     # . . discard first 2 args
+1227     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1228     # . . restore ed
+1229     59/pop-to-ecx
+1230     # check that scan-next-byte didn't abort
+1231     # . check-ints-equal(ed->value, 0, msg)
+1232     # . . push args
+1233     68/push  "F - test-scan-next-byte-handles-Eof: unexpected abort"/imm32
+1234     68/push  0/imm32
+1235     # . . push ed->value
+1236     ff          6/subop/push        1/mod/*+disp8   1/rm32/ecx    .           .             .           .           4/disp8         .                 # push *(ecx+4)
+1237     # . . call
+1238     e8/call  check-ints-equal/disp32
+1239     # . . discard args
+1240     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1241     # return if abort
+1242     81          7/subop/compare     1/mod/*+disp8   1/rm32/ecx    .           .             .           .           4/disp8         0/imm32           # compare *(ecx+4)
+1243     75/jump-if-!=  $test-scan-next-byte-handles-Eof:end/disp8
+1244     # check-ints-equal(eax, Eof, msg)
+1245     # . . push args
+1246     68/push  "F - test-scan-next-byte-handles-Eof"/imm32
+1247     68/push  0xffffffff/imm32/Eof
+1248     50/push-eax
+1249     # . . call
+1250     e8/call  check-ints-equal/disp32
+1251     # . . discard args
+1252     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1253 $test-scan-next-byte-handles-Eof:end:
+1254     # . epilogue
+1255     # don't restore esp from ebp; manually reclaim locals
+1256     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1257     5d/pop-to-ebp
+1258     c3/return
+1259 
+1260 test-scan-next-byte-aborts-on-invalid-byte:
+1261     # - check that the a bad byte immediately aborts
+1262     # This test uses exit-descriptors. Use ebp for setting up local variables.
+1263     55/push-ebp
+1264     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+1265     # clear all streams
+1266     # . clear-stream(_test-stream)
+1267     # . . push args
+1268     68/push  _test-stream/imm32
+1269     # . . call
+1270     e8/call  clear-stream/disp32
+1271     # . . discard args
+1272     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+1273     # . clear-stream($_test-buffered-file->buffer)
+1274     # . . push args
+1275     68/push  $_test-buffered-file->buffer/imm32
+1276     # . . call
+1277     e8/call  clear-stream/disp32
+1278     # . . discard args
+1279     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+1280     # . clear-stream(_test-error-stream)
+1281     # . . push args
+1282     68/push  _test-error-stream/imm32
+1283     # . . call
+1284     e8/call  clear-stream/disp32
+1285     # . . discard args
+1286     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+1287     # . clear-stream($_test-error-buffered-file->buffer)
+1288     # . . push args
+1289     68/push  $_test-error-buffered-file->buffer/imm32
+1290     # . . call
+1291     e8/call  clear-stream/disp32
+1292     # . . discard args
+1293     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+1294     # initialize '_test-stream' to "x"
+1295     # . write(_test-stream, "x")
+1296     # . . push args
+1297     68/push  "x"/imm32
+1298     68/push  _test-stream/imm32
+1299     # . . call
+1300     e8/call  write/disp32
+1301     # . . discard args
+1302     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1303     # initialize exit-descriptor 'ed' for the call to 'scan-next-byte' below
+1304     # . var ed/ecx: exit-descriptor
+1305     81          5/subop/subtract    3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # subtract from esp
+1306     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+1307     # . tailor-exit-descriptor(ed, 12)
+1308     # . . push args
+1309     68/push  0xc/imm32/nbytes-of-args-for-scan-next-byte
+1310     51/push-ecx/ed
+1311     # . . call
+1312     e8/call  tailor-exit-descriptor/disp32
+1313     # . . discard args
+1314     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1315     # eax = scan-next-byte(_test-buffered-file, _test-error-buffered-file, ed)
+1316     # . . push args
+1317     51/push-ecx/ed
+1318     68/push  _test-error-buffered-file/imm32
+1319     68/push  _test-buffered-file/imm32
+1320     # . . call
+1321     e8/call  scan-next-byte/disp32
+1322     # registers except esp may be clobbered at this point
+1323     # pop args to scan-next-byte
+1324     # . . discard first 2 args
+1325     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1326     # . . restore ed
+1327     59/pop-to-ecx
+1328     # check that scan-next-byte aborted
+1329     # . check-ints-equal(ed->value, 2, msg)
+1330     # . . push args
+1331     68/push  "F - test-scan-next-byte-aborts-on-invalid-byte"/imm32
+1332     68/push  2/imm32
+1333     # . . push ed->value
+1334     ff          6/subop/push        1/mod/*+disp8   1/rm32/ecx    .           .             .           .           4/disp8         .                 # push *(ecx+4)
+1335     # . . call
+1336     e8/call  check-ints-equal/disp32
+1337     # . . discard args
+1338     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1339 $test-scan-next-byte-aborts-on-invalid-byte:end:
+1340     # . epilogue
+1341     # don't restore esp from ebp; manually reclaim locals
+1342     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1343     5d/pop-to-ebp
+1344     c3/return
+1345 
+1346 skip-until-newline:  # in: (addr buffered-file)
+1347     # pseudocode:
+1348     #   push eax
+1349     #   while true
+1350     #     eax = read-byte-buffered(in)
+1351     #     if (eax == Eof) break
+1352     #     if (eax == 0x0a) break
+1353     #   pop eax
+1354     # . prologue
+1355     55/push-ebp
+1356     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+1357     # . save registers
+1358     50/push-eax
+1359 $skip-until-newline:loop:
+1360     # . eax = read-byte-buffered(in)
+1361     # . . push args
+1362     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
+1363     # . . call
+1364     e8/call  read-byte-buffered/disp32
+1365     # . . discard args
+1366     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+1367     # . if (eax == Eof) break
+1368     3d/compare-eax-and  0xffffffff/imm32/Eof
+1369     74/jump-if-=  $skip-until-newline:end/disp8
+1370     # . if (eax != 0xa/newline) loop
+1371     3d/compare-eax-and  0xa/imm32/newline
+1372     75/jump-if-!=  $skip-until-newline:loop/disp8
+1373 $skip-until-newline:end:
+1374     # . restore registers
+1375     58/pop-to-eax
+1376     # . epilogue
+1377     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+1378     5d/pop-to-ebp
+1379     c3/return
+1380 
+1381 test-skip-until-newline:
+1382     # - check that the read pointer points after the newline
+1383     # setup
+1384     # . clear-stream(_test-stream)
+1385     # . . push args
+1386     68/push  _test-stream/imm32
+1387     # . . call
+1388     e8/call  clear-stream/disp32
+1389     # . . discard args
+1390     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+1391     # . clear-stream($_test-buffered-file->buffer)
+1392     # . . push args
+1393     68/push  $_test-buffered-file->buffer/imm32
+1394     # . . call
+1395     e8/call  clear-stream/disp32
+1396     # . . discard args
+1397     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+1398     # initialize '_test-stream' to "abc\nde"
+1399     # . write(_test-stream, "abc")
+1400     # . . push args
+1401     68/push  "abc\n"/imm32
+1402     68/push  _test-stream/imm32
+1403     # . . call
+1404     e8/call  write/disp32
+1405     # . . discard args
+1406     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1407     # . write(_test-stream, "de")
+1408     # . . push args
+1409     68/push  "de"/imm32
+1410     68/push  _test-stream/imm32
+1411     # . . call
+1412     e8/call  write/disp32
+1413     # . . discard args
+1414     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1415     # skip-until-newline(_test-buffered-file)
+1416     # . . push args
+1417     68/push  _test-buffered-file/imm32
+1418     # . . call
+1419     e8/call  skip-until-newline/disp32
+1420     # . . discard args
+1421     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+1422     # check-ints-equal(_test-buffered-file->read, 4, msg)
+1423     # . . push args
+1424     68/push  "F - test-skip-until-newline"/imm32
+1425     68/push  4/imm32
+1426     b8/copy-to-eax  _test-buffered-file/imm32
+1427     ff          6/subop/push        1/mod/*+disp8   0/rm32/eax    .           .             .           .           8/disp8         .                 # push *(eax+8)
+1428     # . . call
+1429     e8/call  check-ints-equal/disp32
+1430     # . . discard args
+1431     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1432     # . end
+1433     c3/return
+1434 
+1435 # . . vim:nowrap:textwidth=0
+
+ + + -- cgit 1.4.1-2-gfad0