https://github.com/akkartik/mu/blob/main/apps/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 translate init.linux 0*.subx apps/subx-params.subx apps/hex.subx  -o apps/hex
   7 #   $ echo '80 81 82  # comment'  |./bootstrap run apps/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 (is-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 (is-hex-digit?(eax)) return eax
 503     # . save eax for now
 504     50/push-eax
 505     # . is-hex-digit?(eax)
 506     # . . push args
 507     50/push-eax
 508     # . . call
 509     e8/call  is-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/imm-7붩ܰM:Cr_@GuYi>3!hUV3㐹纵=W02}9AcsqvqZZvxKyߔZ% ̫-<.}A$:PZFJlY\WKC{(=d&:e0;{GіAr;5[Lm-)o1NɖӁ$RHxbLԒ~;NYBg-?~g4|
fQt
CQ
oq-	8xhmmhk
AyXóStx?r(
2mrV9f8R6cSUDZ=`q݌*(}	}ujee_kԹëow8̬X!`8x#7}fv
(k|c!#N[}2/S;K\"zUEg\^&S9]|鐬f~6^˖ybMIÞgOyVT*sqe袚HR޻>P(I_ݚ+V_E\'Q,Z[ةZgEHLH6CB|Tx^>%>%S>eQ§vg2OPh_ۅb`+2n@w`f54Ұ?5~'@vWnٱwܱ
Ɣ Ytү̝NH0|?y'iYCuڈ{yߧf5pՖx!Ytoxy3Z%K8眯&GῷƠ{'nZ
rWH1J\w|i4RfpgGt>)^S\PC(Ɯ ҁ}hF"
qMjb(UkͪuFUBTZr3ye,}Q՛\p4Y׀WFaW\Osu;gH vA{al!ik%Rmk`sp!gYrj`tΞkez/R̲dOgٞ!yK͘{f5s#tn(~#vBsݞ*]{kI~ZQ9T0=|muWڜ1a[/S93e+(Ȩc(d5SuoxF瞬-|Bh9ЖCh/݆fUBUNBhk#vꖒ~i$Xͪ:(d1wm֧hin5&{ZVq=}Ӄ˗ntӓИ-{>zZ*2%bO==|=]Ğ.v-@}%w9t=cO{i\`VSi+] 4l
\r,8C.Ûq\S];C.MuNe˶GAAזߥ1<Vhۑn6ryh3jÖ8\.Υ6mFrlsn|!˲2fd6s\&r9/_6m¥l0bS_v雷ee9ht6R,h2Wq]^%<^5xY.%ׯlZ#vjqwX6uc9dS
L1mٳsLYW]9a_:	VMk6}܀- l]ܷ lR
V1 H9ۙA*Fr6VlT_>[5fAAj%ۓ[3yb_KCX lCga{2˧aӧz lL.͘qi^C6})) lU~t lO]kas5#[U lUMW6x+ lU뎬\=nxa7%U1C1RI
E:;e<;as=Tn
+ƞ¦ lgJMQUjʌRRTA؆+[M
V- lUW¦s=u.*m?[>i6bzd{{I҂pfDۇӬZՃ7
UB]~ǾW1rN}>^v϶0⦲4LSRMJ^f4%dJӗTAReryLjM$ueYF;c"j2j'UI],9j=|k߃eodf>X@j+%^55L:eSS_b	8	\gAMe(b	j8SM]áQlvt,~-].t֤<f@#allj|Z֞6JeVc}^'4/h}h3j;9Z#i[^%r*zͶrh.hA]̤td֡[sW9Z.#qKnm~sxZꙭi,y
h銁%2̫[ԗ֭[)(5/h}88:+8f~
n$xcLrb;G/t5&>^IpL"
$+RLr	cC$f1+͞cU?XL1ɛI^W~bDXC9&yInZ䗋I^ytLu
tL򺅇mw:HLrx+ޘ
aCa;?&9=!1:pCjct4VcE:;v'nH1ɝsk}^%&9{Iޔ`/&FL|b*emV)w)bؘCq;gq1҅INj[6*^tz95
`ChO
izwAQvl_ptX>8q僨gQo7 uuA	^H rDBA T v<^h	D#z=+QpO]R uݕ&:k5YL'-*i}	(e|O+;;/'B񧸣׵kn	}G}z!?]1x=^%|^zgxw>~N#uea_潢u𞣏4>n7)x]7pO憖Rlq:78ukrEAKc>^wW>tu7_sӍ<8F;Qrq6r$}Mlj{<89xCoִ
]Sy"ͯ}a`hםhG=*FoBw>DCDo,}`v‚+xmG7E_-/} 98>8F񦪝W{>Td,a7uW>.79-N∷A'߻;]}|(~Kǔ#+LJ=6lC[VF}Po;E|#K},z8ctI	?@&*={l@`!ȵPTӚP#LHEF>^d\C}\_$NqvM̂x^ͽ1G6>VPyTxPB>ΒYA[J}QUNg7)~>t]r71=4po&Oz
^":o}CJ?- IOI쇤:IT'^|KE'IK%Ջ:$՛~(.^l#PzQr4|0I|QIҒT_~&mPEh[k˫cY?ٗWGL|Y"gԺK{My?
C_`{b]/|lz`Ʈ%Nlp@ooB#li;6Wԥ+(7]@"KIcjWXL4˱7U)e*K˱U{pBגccKre^1vr0#>U
O|R؛lK,!Nc/T-J[E	*[;N^;+NkgƩ=pJ`W7wQi+-OP7n^2:nDD|3#榺y.͗Nl^6n^8u"/O)9^-Ƃ2W7/Z
9P_(Ko^r
nyrBxf`"	p4	xi7:&nPLJHEKAG ^U72gӈ>Dyd2ic{i/۫io̭DKI
޲H{EڛyH8Dڍ@!nm4v͡lN̺u"^f:"-9z܆H{Y(#i'Tw("e9("e9:q=R#΁ZNi/KЕV̲C}s٩H{&/o&^9lxm6]eGD9TCi?Dvܥ]1މoEbIqd"pJA\"U"fWMi$98xHr7H>/K=U"MeݼFe.jOCe. tN*K0Y^=jiIlD+6V"sG*V)Ҟ"wo,^2չ7iOVi/,"et늴c"ˢRd6E`{P4UwߢĥHl=XPoT'$Z\{zZ!"bA#1h'rHmsǣ4j)I	}-ms8mcmH
kW{6m>QۼRX|tmJbWۼjWص((RFUbPk0d27~CV{Fԉ~w!jD4Fה?>e<]ӆ)fm˥U7҅Vj5z7]	X	qiAaxO|yӵ
Bs=c?7.ׂd] z{i)k&.j&ۃV#4[҂*<vZ0=U*8L)՟Wy$	kIXWpl\BN'5(^fZ؄P_YF!d+M*"P4Ì&7Ё0Xc#ijv5OqAWEB͓a]J)/dj&D,	
ϒ\$ehKj`u}}NTruhn][Vqm*rB*џ5ٿZU	m箪0ZEՍv{fSգ?e]G=aPsѪ#P:WQVzo!n`'͕4<N,rux}0֛(	s>7.&
:UVe._X{mqEi0>r(śNI!ҥ
pO?;z!wENsu	Q%Iaj
E("ו/V%!c\B^U<|USy9T׹@g1\bFpiSxw:8v0z+KGbCs4l	*lTTF㼝~ήqޞ[-yyy;X.3^'|v[4DD5~햧f!LCT|u.2NE.[hM{
띆TᏍ^Ginda{
Y+zה
p:Q k9y{]h
"r/q|ڽh{gвi]^Ȁl8`(:
jC^p+*, 	4jlQ99)t
3F>	pw4>}d\y(:/z)~YJNMGm9s+w"&#LHu>e5UQO͟@>vl8C`'z2m.Oʴ[mb6m+D9c%b82B]ɔRLtiFV".M9f3*UOQ^wL'*otNw45hHgF?qg_G6EKIP;mRpC2VM@u*ڏT﨣d]cH{|[84#hC@&Y5K^j$ՙJ$wB:+jvP]u*
|/֋"Q^{EXVNpx)ޣ.;3OZ}:ıC٦
6s;+{sڐO"42<=so76(Me縘H1<q\^7E>g\?ןDsԵ
F'%…;(h9jCi,%a)UB*#f3pJLJsx_cnט5KN}w\-7AoI5g\mjyvty;~+9~DF 1	$uIp+,"Rarkcr[mb.x]vV({eg)ߤ..{9wc!ݖNkn)º0q*\ªb?7ap]]vV!歂US&A6>
]rn`Ub[TX[x`X`ݚd^AU/03YJfWM}StY;ttΩ[Bw^T]a`[;`ad|ܓ|+3/>n$߮%0Td+C`ޟ,{iԱjMŅcoY6}euzyv%[yon79nnүؙ9{sMvؗ^S~ɱc?ϐcg9x9t˱+;n%ǎ38rvh9Pqd?'B]]ڟO^WeF&'#P9+D3^Zg>Ct7י?Sk6wtɬԔu[әBԙYEg6>ݖ
tԙ?_Qg.uy4>'c&7:=Ơم<`Gљo&83(/3yFŔtoљztNutC&yμέ=̟o3ϳ: uymti͚3^gę:<+&4Й_RgP::*Й/TF6uiIЙ&H><#יNo3:<גd*:$wՙ?í&̗ui81d.3IvuyE33Ǯ3/X=Й7{q<|Й,wSY"Oo3p4B8i7љoz}Nμb;_^g>Fj/Ig^631Й3"rd
C#ͬ=<M޼65JF
k;ch#
شEFWA66bii#~r_N7"B1T:`B:}&jn٢f4EgV3MWWNMnndb-*"u,"ť(=(fv-Eؗh}@$HTB
@k
Z{A
%h)s?v-Ŕ14BKӴ'CʄRz!eki)6يb-EbSZ1|-E>ƜlN򸢞bF_Qx9f|0a6JLk|LCQh#|YV4!F|CEyi\q>)t-	>K0Xe]&bǰ>\e{[&]Xdc	>:|d@őz!ëb#;Ed`8qfsMK]95-E\TQtVuE"6-]C-m|ɺq(+v|"6I*WQL7EtCErE)GBgQI:Bptm+
nUմ+YFV>Go^긅=H(m/WVU.ir.g\4OZ;wL;zDjNքb-iG*
E$R&`
ZSٻYY5f?/RX^	`lk(nA^VA6wiy
vNB_2`Խ%9y)DJmO;fmR'w'ul@w.`$5'Ig+],wr,
fiDRj=0VND4
gsUskLr8˼a0&'(gB2t+QjNs|=n pe6Ue]{aUQ/b%kO:K/sG/TSī~ī?OUP U˩:zwN媘bN;JU2>Hĩ\CSm&֑@}f4A%۝ħ|DBّ8m!ҲY	4}K@X;^
,l+fHxv{(wXYI>q ^x9^]uD3(_RD2Bo y5Y1,v4yn2Wo%;UZC2kV
/beVcRwבvK+U	)UQ;i:/Mq1j
Kjc$loPVrH/A-R*9R:|w@t"PNBAWÏ/
aW\xu8f
bknÒRB<.G6˙/~V*O5ci)d)Yk2}wWNOh/k݀Řm:JЂE+Fp%ZmIj+LJCL̴/ ͫo`ݴ ӹmN=/L}9EK/MSL$7YSRjY.Բ`EKtg=)3r]iQj׻T@\7tta1GʃV}Y64-iKIPk4&}?d:Or?ӝNjaϮ0`kO!33N
PI`0l:++ڕwեeߥDuLi+.26~!+[¾:]%WdiHg{XpSBzY#iȊhS/qOS",#'Y9vРM
mR/]/A8l@:^)jY}2.ы*aUAt˷6";R"Ul'oy5Au	-\
jWvz^
,t5۟HA(4TÔ03ĸ.wN?Nug.*[ۧ^4mO٩x>㓨z_R3VX<]jRx魦+xxScIOh4"ɳME~JȭOݯ{/lFyf[cWvĜ營?5;i7?^!a[1ˎ^|ڗ2uѰ)gk.jڕL">}>iQ"
[qi
|M_W|'f]dEj״-vEۢOd_.Y1lplx2#*v1Ւ_H/
guZE]FcNbz`uŲ.eHr!fN{PfL3bݭI6l85?)2}hhiAJB\Mx7Ugx^QrF[t).MhnlIzǏ&Drhz(nک[kK!Lj*ICRL??,ՕˀqUNxrOnn1T$
"uL{QB2u\`^]r*.aYR˒=oun_kIԕbK
V
0egTԙtVUXe7p5%*W5*|OXN-R[+/LUG,!5hRDsC@n6&K6flv ښR4cbϭݭ۪[z+.'uu<*k٭c5(v֥DtcwR[x9N9z.-1RN'~.uiNWx[6:"czv2})EG7`r-S;%0LJ?õHuEUx{Uʦ
֍dO3!=c(FwCBsA:+h继e>t${ޯo`è;YH-ŋj"-Ėo|	lasQ,f
G
.f*`Խp+X:*jKѺw|^CY~hLbl4UK|%z8@ȫÕ
>U*]Yz|>=޷/w0ZvWsXLTPκ!#Z.эkSr0UoH&+R'է/ʢ:dt)euš|=a/n^܄*7LwAXlb].de
~}==/ޟ_]X\±bafٺ}X buwP38sW*	g*؛UT+Lw[RQ1
Kfnv͆ܘgX,'P>)KW
(P7h0hx)S 
@[)f0H)X4izYޘ`
Dh0)ssS7
|oL~0UlS9@)@ÛЈL7?Q*L6)@JMhDSL(m |nba
4"S)@
S`
R>7h0hx)S 
@[)f0H)X4i{c
)`3Z,L4Fd
1Va
LRMm]boLq0b4
S`
R>7h0hx) S 
@[)g0H)X4i{c
)3Z,L4Fd
1Va
LR-
o@#2ޘ`
Dh0)ssS7
boLq0U|S9@)@ÛЈL78Q*L>)@JMhDS@L(m |nba
4"S@) @
S`
R>7h0hx) S 
@[) f0H)[4S7HH@3Z,L4Fd
{c
S 
@[) f0H)X4iHH@
S@`
R>7h0hx))L(m |nba
4"S S =Q*L1)@JMhD@7@z0UbS9@)@ÛЈLtoL`
Dh0)ssS7
ޘVa
LR-
o@#2ҽ1҃)3Z,L4Fd
{c
S 
@[)`
R>hi,L3"S S ;1Z
S  |nba
4"S S ;Q*LtS9@)@ÛЈLloL`
Dh0LR-
o@#21)Hg0H)X4i@
S  |nba
4"S S ;Q*LtS9@)@ÛЈLloL`
Dh0LR-
o@#21)Hg0H)X4i@
S  |nba
4"S S ;Q*LlS5@ba
𦶞ޘU)ssS7
ޘVa
d3Z,L4Fd
{c
S 
@[)`
R>7h0hx))L(m@6)@JMhD@7@~0U)ssS7
ޘVa
d3Z,L4Fd
{c
S 
@[)`
R>7h0hx))L(m@6)@JMhD@7@~0U)ssS7
ޘVa
3ϭZS7((@Vg0H)X4i((@
S  |nba
4"SS8Q*L|S9@)@ÛЈLboL`
Dh0LR-
o@#2ӗӿԿՃgzzvzz~˗?O_o/_k{r~G{9-{}kX’D05q~xbW/_~K9=_N[Ϭ.Inקۍ'ahӛ@O@ƄO`K2f(}UɡjT92Co:J7ͻl,m1%ehش=Ur
oF@VO-j`Br¸5/KUe޷\gk8>BUS%PcŀoVvͷTV:P Bcޮp0?}|KnGϘLEC0#ű苯{RUJ_|ƫ*cbZ[邎ئTɹHA
*k_Mkޯ)Rc=axf(2ćm@ٸ>}GKiEC`bQy
-CΩ]ԌZzP~Xp`IK&,`$ZfO^d}VUi\UXUp>Q3}f뺕m
,):T,8q
ڡ
;F3lvGS-~7`jP4.}W™dr3B$-Ԝ@'CP?帨:b
F-{y̅Vz^Q2&mXEE~4w*7WweR{|{m7Vu~tT>
7DXb)031TXglb虔:b.C1)߇.ʯz'%K]01mdP)ooC1'2:1|PV+'J=HeeOm[b(71"P$BDD
g7EDϙ~bhS%'RrK'bS
!ƖCyZF
ɼЩ%~TɘU{cImPut7ʹX;1jmFqKN\=9k}>)Zљs3Y6g1fsARFʪBbteWCV2}隗i1fLȘHcoϧS8r||~||?7zz|]ۨA۷FHYNO/xz-<9Jni$Ҵ1Rjh:K5]J~4>AKs.E5~o>n0|8MYT7>>W)|zn$ٰfqXf6
G]ڄ$zgS-#B3%гp5y
;4/Ps"ҏș}qף|[5/2U1D;f?/Rn
`l|7'Qejh'>jxF}-VMoɑlOxJuNGs׏?>kv3[puBt$t>8D;M:B2~dbLlveU׺}i5SFg)u]::5AGkeuvD|ٖֈ[F-h@8GX]\}@{)V)p0mp`.ռ2l`-^yr ylv5@j9^f^1ȾI$O뮘޲y^Ow|v3ng̸!ϘjZKsQOLl'ǰ/}K|zQK%m-Էygi:BGx
m[:!lEܥ園Zm`-ƹ6EG#r]6ЀĞtx>>~h䟆oَ[xKuneuz:MW;궇$M޺~sJBmVhȀaajQ&T@!`c>wsE	.õ[ 2	n_N	[7,pHQjd4X
zqGwu=kYd|Rk3t~
髗Pv[rRt	cb'f_}FMz
o7*ÕԚh1ѷDsTN^vz(W-^@pOϟ>`Ws0vF+Iñpꠍ+EǏKG'^q}2Ћ[uKea:PQ͍*ge-dfnnU}>U:AVViOD
TY޲׈ـ"
aYc
Pe/lao>%Ṫ`ݴ m
n[0u%۸k.ҡ6whuuW

))JݣK1:\;`֑zrʋþc<v}-t{!m Ԛ|^I1O92'ۮjaϮ0@c-G!3݉l#hd'b׀5OcUJMatu)ZGU}fnԥnjh	JPF2N3W?ums!sy1ce0-z՛Reok;c!Bx+37unE!;@h1v{8D48[=bjͨ7Bu)rs돚H,-[I
ė
ĕK
WL6jJw ̛<ܸMe'JLnډ߼Iv
ki]5mɤog
H?Wmtogdq_ZE
wFQewQOI'XD'&?zz:&O;z_y-
N#1H+D+F,d(g\M
Qq*JQQ"g0kxuu7fk]Hlhnoת;.VA}HzP4W`Hv(3ވ9cCXP?.h֋mR~A-[X7
D@|MZ~Zh@+hE,F›LFv(qVZ9=Zhϸ	@+@Uh՞HxZE4gUhV$XI,F›zdBZI[29-@+-鱛hlπ"444gb4h|πc444gb4
&h"@#Mhhϸ	@hb@Kg%ssh$i-%)swv0U)ssS7
ޘVa
3Z,L4Fd
{c
S 
@[)P`
R>7h0hx)P)PL(m@1)@JMhD@7@y0U)ssS7
ޘVa
3ϭZS7@V(g0H)X4i@
S |nba
4"SS:Q*LrS9@)@ÛЈLjoL`
Dh0LR-
o@#21)(g0H)X4i@
S |nba
4"SS:Q*LrS9@)@ÛЈLjoL`
Dh0LR-
o@#21)(g0H)X4i@
S |n
ЪX4H`aHkZt`|5@m[9P-@jD@ݡVT3(͡Z,"HT#@
o %nb
!G9P`wvp@U)tsy9ՈC@ f0HCXDȑF?,8PmA5F@B# BD5"Pājp	\RRP-.r$vj T[PP 2C7j
#QH);T;Hq*j9TU@jD^Aݡ,֠d:@m՚Fq-LRzP-n
r$Qlwvp@5"-͡Z4HTrājkpD2[ H顛Ch4ȑFq-d:@C7jph#Q-`[-tn nբ G[v-` T[[ AJE-AD5*[nA@$ӹ9T[@jTn܂8Pm
nHs)=ts
9ը;n;qLRzP-n
r$Qlwvp@Ul5TcphӠrDj|n- nբ G[w- T[[fpH顛Ch4ȑFq-VRzP-n
r$Q|w~p@Ul9T[@jTn܂8Pmn- nբ G[w- T[[fpH顛Ch4ȑFq-VRzP-n
r$Q|w~p@Ul9T[@jTn܂8Pmn- nբ G[w- T[[gpH[C5
9{QM[ nA&VRzP-n
r$Qbwqp@U|9T[@jTn@܂8Pmn- nբ G[ v- T[[gpH顛Ch4ȑFq-VRzP-n
r$Qbwqp@U|9T[@jTn@܂8Pmn- nբ G[ v- T[[gpH顛Ch4ȑFq-VRzP-n
r$Qbwqp@Ub5TphӠZJ 
TKWRzP-n
r$Q-VRzP-n
r$Q-VRzP-n
r$Q-VRzP-n
r$Q-VRzP-n
r$Q-VRzP-n
r$Q-VRzP-n
r$Q-VRzP-n
r$Q-VRzP-n
r$Q-V3ЭZ
9
eTnA;nAvp@lnA:[@JE-AD5*  ;q*܂t9T[@jTnA;nAvp@Un)=ts
9ը܂lw܂ājpRzP-n
r$Q-V3͡Z4HTrq[-HgpH顛Ch4ȑFdd T[[C7jph#Q-v-=~;}y>N[=qίwOﯗo׻z`ֿk=b~{;||vmB/͗c4n-cI+T~7\歶*./n῿9E|f뺩4zzVj`60)ZD.>s>7ٮ`ӈf+b=l1OՑ[:#djMZ8Js-\{}ԟ惦-|nvzz<~\ׇuwՠUpL6}Aγ{]#Tϡ1T7[}/Kzp+]`-u&O*Ӎ7a܏N*49KD&\MmC|@Q F˸}&t-sZ{1[0f21
޲eTȣ`zOgW==."7 rZi60qr1۪oWy=?İ	xc>{y2IitV1M1+LoMz^w]U8?~\P2)EW4ZrF>oY6ƓkBżå10@U/_~_Ek;z3мمJl;6:0t{hVAfFNL5kgLy_YpNBM-cc$1s0jXa~d*fV@y+RdvvN$5/v6Cd|ݧLu23nYq9Ω8WQƺpxgKOXh=!

'l uшɡ'DS_ 4k3UGf`Xr\95W!T_pU}u1>suq;͈:Ǫ;NS~{LIfrZެAuw bOߡ35D<6$ mzc#b@cB'bvQݬۍS-:h?x`N[MY%Et$].dlr *߷JNMC=U_1?4*Atc-j`BCܨRd~T)rUeBZ3 5P!/_q5rDQL@M8yNMh GD1>ǚH]4 3\ٕ38*3CpVk:]1=/uA>1(8Fٰq=X.y[hc.cC\(kXXQQa6J,F.[MڲlT1TBj+MLgv1-B 92BԞÿ\??./Ms46j=ﴃ|=dvVrig2OO/[ 12q_12C$9H44:dPu۳gn{n{:C$9TF9ըt۳C=T[E=Ne A۞N=?tۣ@|ln;Izwsn; r$Qun{n{6C$9TF9ըtC=T[E=NENjT|w۞m'InբmAD5n{;mVmf趓w7j GU=ߝn{~ǁjg3tIһChti#Q۞N=?t@Ut۳͡Z44ȑFmw۞~@RzP-n r$Q-Vd3͡Z4HTr q [-gp H[C<n rT+܂bw܂Dj*܂|9T[@jTnA;nAqp @U n)=ts 9ը܂bw܂ājp RzP-n r$Q-V3͡Z4HTr q [-gp H顛Ch4ȑF T[[C7jp h#Q-(v-(nA - nբ G[P[P܂8PmnA>[@JE-AD5*8q*܂|9T[@jTnA;nAqp @U n)=tkVD-ANj%[P[P܂(P\[PC7jp h#Q-(w-(nA - nբ G[P[P܂8PmnA1[@JE-AD5*<q*܂b9T[@jTnA;nAyp @U n)=ts 9ը܂rw܂ājp RzP-n r$Q-V3͡Z4HTr q ʃ[-(fp H顛Ch4ȑF T[[PC7jp h#Q-(w-(nA - n h4iPr q [Up RzP-n r$Q-V3͡Z4HTr q [-(gp H顛Ch4ȑFTT T[[PC7jp h#Q-v-nA - nբ G[P[P܂8PmnA9[@JE-AD5*:q*܂r9T[@jTnA;nAup @U n)=ts 9ը܂jw܂ājp RzP-n r$Q-VT3ЭZ 9zP6njMB .7E45ƥӏO|9,Gjd?czMWm.6J-@vT5:-PԞ-fjEt~ o/?R.orԎfAo}wO/^^Nз}~vZo_IQ t=N-\?߿-rr~9 p)o/i3x*ӗӿ~}@kr~UCҗxzq.筭gi=^C= neVcb*hČ7 x,gjB%Dfӗ<<+tT!Zš)TOMUx#Tm kei&΢An2]ɺ[l[`r[9z퓺ϯ_>ףᱞwj|o8{_~ GP]}@?+j+k{O뮘ISp{W4n˔q0)Gꩶ˱g,wBW\Ww|߿y@}fye{؋([~kʱJokjnfr`[#>=UzK~ut{'m,:{P9 ̵4O8n]$@wk8ٸ.te½%JLFf)7=|z}<)͠i0T`]6|o8M?w7†zŽCe1җ/wemu>5ڑUUا)/df`/_~_ڵk$w0VD(PFN}?֡v!w~=̮õى]UvUwJvZ-d`:헑AJ BopIjp_}_ =kYd|Rk>Naj8U঻ ӐgM.|~||?L;@- [ 2bE7yz~ofxk4j3G*lM3b7 VV􍺁m߰v1DQFDQ){aqHHi3$UDRؾfee|k3,Fgyp])4DD@&d53BxII\*3g0r 9İ/}}]_a7cZ}Eh[$&;#agpNE1Lw":5=~„=Lw@Iy:P æysͿ.M.&*K]'K!q6lDSB~zٴn O+fA{_0u~ձctw (Xh|c!Bx[;+1!!jhJPѐv{ɽ2- VpOv0AӦPRe˒ zׄ#kIMqrg]gcک?TT8pv#{|i~@mNI_'w;ks?0RV#g4AgQƸp^jv"5J9?穞67Vn'Tp<=)xt NݚjMiMήUid@|#$@0K^{scM11Yffem١~;-lc{xdNe:bzA(c= {1d[K I(Ԝ@'jŢj~ʵ~wc;}/q s!իWndp`|!)ܩԞwLmO~2i$B#]@gGG8́z:Ah8@v9bGxp1SF̄)DDm;=!>wG&;mq#=pnΐDB[@ֳ_7yhS5d [4f{мU/`:PbGR~) m z,&GD⾮Һo?8͛]Ͷ=/G 23'A9%n2.լq1kl#0j1 ~tPy]8%G UǮ=e?T'[-+._9u f3em:\;hY@K qOY >*R@RXR%ҹ4ی.}qD H.Bo9Z!%)oEܵI4ƴ[_&pIRS> Ô5%Wp̕G:# W#r=9iSҗõXSCWfU7tu\jYNƚH_-Ɠ0lߚ6my!ǭI}4ӂ".oMRS_֤֤H Ii֤fb֤(pܚdDp[qkء|6nMʒ˭ܚpܚZO [6M3[|BqIe[21\wܚ${=$ԒvIY ޸I&aluNoMXb^&ݚTj[mb&oMb(.s;ܚ$<[[[[\s%9Yl֤,)#5 N)֤_~[̮rkR 8}as(r?73׼5賌.Qj5oMjvBkDĭI6#P u[d߭IYU;nM$v[ 9ij,G{ WB A.&ɦu%ȱ>A +JVA=p֟5.%A(bX%9PoT'RѤʐ#d顁{6y3T&tx[5RW(h]uR[U߱zAÍgړz&ƇD]LCW]Yw)oUuSWzy]U¢깥3~?U}%ssu1u3z0Mg=CXc>-Uo]w7equ)ohnxW؞1gY>g9V{Zz&XVN Ϟ98iigeWV6;oN;D(*g+&WܫUB/^_dyPN>ͪ/N;*^w^-v1Ӟ!iwɨsE /p|`=g1^