From 6033844884f18c9a6e6e186c79c36fd1dd2c9bb0 Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Sun, 25 Aug 2019 15:53:24 -0700 Subject: 5582 --- html/apps/desugar.subx.html | 3790 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 3790 insertions(+) create mode 100644 html/apps/desugar.subx.html (limited to 'html/apps/desugar.subx.html') diff --git a/html/apps/desugar.subx.html b/html/apps/desugar.subx.html new file mode 100644 index 00000000..7fea0d16 --- /dev/null +++ b/html/apps/desugar.subx.html @@ -0,0 +1,3790 @@ + + + + +Mu - apps/desugar.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/master/apps/desugar.subx +
+   1 # Experimental syntax sugar for SubX programs.
+   2 #
+   3 # We're experimenting with the following expressions:
+   4 #
+   5 # 1.
+   6 #   $ echo "ab %eax"  |  ./subx run apps/desugar
+   7 #   ab 3/mod 0/rm32
+   8 #
+   9 # 2.
+  10 #   $ echo "ab *eax"  |  ./subx run apps/desugar
+  11 #   ab 0/mod 0/rm32
+  12 #
+  13 # 3.
+  14 #   $ echo "ab *(eax+4)"  |  ./subx run apps/desugar
+  15 #   ab 2/mod 0/rm32 4/disp32
+  16 #
+  17 # 4.
+  18 #   $ echo "ab *(eax+ecx)"  |  ./subx run apps/desugar
+  19 #   ab 0/mod 4/rm32 0/base 1/index 0/scale
+  20 #
+  21 # 5.
+  22 #   $ echo "ab *(eax+ecx+4)"  |  ./subx run apps/desugar
+  23 #   ab 2/mod 4/rm32 0/base 1/index 0/scale 4/disp32
+  24 #
+  25 # 6.
+  26 #   $ echo "ab *(eax+ecx<<2+4)"  |  ./subx run apps/desugar
+  27 #   ab 2/mod 4/rm32 0/base 1/index 2/scale 4/disp32
+  28 #
+  29 # Addition isn't commutative here. Template must always be (base+index<<scale+disp),
+  30 # though some components are optional as described above.
+  31 #
+  32 # No metadata allowed inside '*(...)'.
+  33 # Whitespace inside '*(...)' is ok. But not immediately after the '*' or '%'.
+  34 
+  35 == code
+  36 #   instruction                     effective address                                                   register    displacement    immediate
+  37 # . op          subop               mod             rm32          base        index         scale       r32
+  38 # . 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
+  39 
+  40 Entry:  # run tests if necessary, convert stdin if not
+  41     # initialize heap
+  42     # . Heap = new-segment(Heap-size)
+  43     # . . push args
+  44     68/push  Heap/imm32
+  45     ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Heap-size/disp32                  # push *Heap-size
+  46     # . . call
+  47     e8/call  new-segment/disp32
+  48     # . . discard args
+  49     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+  50 
+  51     # run tests if necessary, convert stdin if not
+  52     # . prolog
+  53     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+  54     # - if argc > 1 and argv[1] == "test", then return run_tests()
+  55     # . argc > 1
+  56     81          7/subop/compare     1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0/disp8         1/imm32           # compare *EBP
+  57     7e/jump-if-lesser-or-equal  $run-main/disp8
+  58     # . argv[1] == "test"
+  59     # . . push args
+  60     68/push  "test"/imm32
+  61     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
+  62     # . . call
+  63     e8/call  kernel-string-equal?/disp32
+  64     # . . discard args
+  65     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+  66     # . check result
+  67     3d/compare-EAX-and  1/imm32
+  68     75/jump-if-not-equal  $run-main/disp8
+  69     # . run-tests()
+  70     e8/call  run-tests/disp32
+  71     8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           3/r32/EBX   Num-test-failures/disp32          # copy *Num-test-failures to EBX
+  72     eb/jump  $main:end/disp8
+  73 $run-main:
+  74     # - otherwise convert stdin
+  75     # convert(Stdin, Stdout)
+  76     # . . push args
+  77     68/push  Stdout/imm32
+  78     68/push  Stdin/imm32
+  79     # . . call
+  80     e8/call  convert/disp32
+  81     # . . discard args
+  82     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x8/imm32         # add to ESP
+  83     # . syscall(exit, 0)
+  84     bb/copy-to-EBX  0/imm32
+  85 $main:end:
+  86     b8/copy-to-EAX  1/imm32/exit
+  87     cd/syscall  0x80/imm8
+  88 
+  89 # error messages considered:
+  90 #   *x + 34                 -> error: base+disp addressing must be within '()'
+  91 convert:  # in : (address buffered-file), out : (address buffered-file) -> <void>
+  92     # pseudocode:
+  93     #   var line = new-stream(512, 1)
+  94     #   while true
+  95     #     clear-stream(line)
+  96     #     read-line-buffered(in, line)
+  97     #     if (line->write == 0) break                     # end of file
+  98     #     while true
+  99     #       var word-slice = next-word-or-expression(line)
+ 100     #       if slice-empty?(word-slice)                   # end of line
+ 101     #         break
+ 102     #       if slice-starts-with?(word-slice, "#")        # comment
+ 103     #         continue
+ 104     #       if slice-starts-with?(word-slice, '%')        # direct mode
+ 105     #         emit-direct-mode(word-slice, out)
+ 106     #       else if slice-starts-with?(word-slice, '*')   # indirect mode
+ 107     #         base, index, scale, disp = parse-effective-address(word-slice)
+ 108     #         emit-indirect-mode(out, base, index, scale, disp)
+ 109     #       else if slice-starts-with?(word-slice, '+')
+ 110     #         abort("'+' only permitted within '*(...)'")
+ 111     #       else
+ 112     #         write-slice-buffered(out, word-slice)
+ 113     #       write(out, " ")
+ 114     #     write(out, "\n")
+ 115     #   flush(out)
+ 116     #
+ 117     # . prolog
+ 118     55/push-EBP
+ 119     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+ 120     # . save registers
+ 121     50/push-EAX
+ 122     51/push-ECX
+ 123     52/push-EDX
+ 124     53/push-EBX
+ 125     # var line/ECX : (address stream byte) = stream(512)
+ 126     81          5/subop/subtract    3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x200/imm32       # subtract from ESP
+ 127     68/push  0x200/imm32/length
+ 128     68/push  0/imm32/read
+ 129     68/push  0/imm32/write
+ 130     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+ 131     # var word-slice/EDX = {0, 0}
+ 132     68/push  0/imm32/end
+ 133     68/push  0/imm32/start
+ 134     89/copy                         3/mod/direct    2/rm32/EDX    .           .             .           4/r32/ESP   .               .                 # copy ESP to EDX
+ 135 $convert:line-loop:
+ 136     # clear-stream(line)
+ 137     # . . push args
+ 138     51/push-ECX
+ 139     # . . call
+ 140     e8/call  clear-stream/disp32
+ 141     # . . discard args
+ 142     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 143     # read-line-buffered(in, line)
+ 144     # . . push args
+ 145     51/push-ECX
+ 146     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
+ 147     # . . call
+ 148     e8/call  read-line-buffered/disp32
+ 149     # . . discard args
+ 150     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 151 $convert:check0:
+ 152     # if (line->write == 0) break
+ 153     81          7/subop/compare     0/mod/indirect  1/rm32/ECX    .           .             .           .           .               0/imm32           # compare *ECX
+ 154     0f 84/jump-if-equal  $convert:break/disp32
+ 155 $convert:word-loop:
+ 156     # next-word-or-expression(line, word-slice)
+ 157     # . . push args
+ 158     52/push-EDX
+ 159     51/push-ECX
+ 160     # . . call
+ 161     e8/call  next-word-or-expression/disp32
+ 162     # . . discard args
+ 163     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 164 $convert:check1:
+ 165     # if (slice-empty?(word-slice)) break
+ 166     # . EAX = slice-empty?(word-slice)
+ 167     # . . push args
+ 168     52/push-EDX
+ 169     # . . call
+ 170     e8/call  slice-empty?/disp32
+ 171     # . . discard args
+ 172     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 173     # . if (EAX != 0) break
+ 174     3d/compare-EAX-and  0/imm32
+ 175     0f 85/jump-if-not-equal  $convert:next-line/disp32
+ 176 $convert:check-for-comment:
+ 177     # if (slice-starts-with?(word-slice, "#")) continue
+ 178     # . start/EBX = word-slice->start
+ 179     8b/copy                         0/mod/indirect  2/rm32/EDX    .           .             .           3/r32/EBX   .               .                 # copy *EDX to EBX
+ 180     # . c/EAX = *start
+ 181     31/xor                          3/mod/direct    0/rm32/EAX    .           .             .           0/r32/EAX   .               .                 # clear EAX
+ 182     8a/copy-byte                    0/mod/indirect  3/rm32/EBX    .           .             .           0/r32/AL    .               .                 # copy byte at *EBX to AL
+ 183     # . if (EAX == '#') continue
+ 184     3d/compare-EAX-and  0x23/imm32/hash
+ 185     74/jump-if-equal  $convert:word-loop/disp8
+ 186 $convert:check-for-direct-mode:
+ 187     # if (!slice-starts-with?(word-slice, "%")) goto next check
+ 188     3d/compare-EAX-and  0x25/imm32/percent
+ 189     75/jump-if-not-equal  $convert:check-for-indirect-mode/disp8
+ 190 $convert:direct-mode:
+ 191 +-- 46 lines: #?     # dump word-slice -----------------------------------------------------------------------------------------------------------------------
+ 237     # emit-direct-mode(word-slice, out)
+ 238     # . . push args
+ 239     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
+ 240     52/push-EDX
+ 241     # . . call
+ 242     e8/call  emit-direct-mode/disp32
+ 243     # . . discard args
+ 244     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 245     # continue
+ 246     e9/jump  $convert:next-word/disp32
+ 247 $convert:check-for-indirect-mode:
+ 248     # if (!slice-starts-with?(word-slice, "*")) goto next check
+ 249     3d/compare-EAX-and  0x2a/imm32/asterisk
+ 250     75/jump-if-not-equal  $convert:check-for-invalid-addition/disp8
+ 251 $convert:indirect-mode:
+ 252     # spill registers
+ 253     50/push-EAX
+ 254     51/push-ECX
+ 255     52/push-EDX
+ 256     53/push-EBX
+ 257     # base/EAX, index/ECX, scale/EDX, disp/EBX = parse-effective-address(word-slice)
+ 258     # . . push args
+ 259     52/push-EDX
+ 260     # . . call
+ 261     e8/call  parse-effective-address/disp32
+ 262     # . . discard args
+ 263     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 264     # emit-indirect-mode(out, base, index, scale, disp)
+ 265     # . . push args
+ 266     53/push-EBX
+ 267     52/push-EDX
+ 268     51/push-ECX
+ 269     50/push-EAX
+ 270     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
+ 271     # . . call
+ 272     e8/call  emit-indirect-mode/disp32
+ 273     # . . discard args
+ 274     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x14/imm32        # add to ESP
+ 275     # restore registers
+ 276     5b/pop-to-EBX
+ 277     5a/pop-to-EDX
+ 278     59/pop-to-ECX
+ 279     58/pop-to-EAX
+ 280     # continue
+ 281     e9/jump  $convert:next-word/disp32
+ 282 $convert:check-for-invalid-addition:
+ 283     # if (slice-starts-with?(word-slice, "+")) goto error1
+ 284     3d/compare-EAX-and  0x2b/imm32/plus
+ 285     74/jump-if-equal  $convert:error1/disp8
+ 286 $convert:check-for-invalid-left-shift:
+ 287     # if (slice-starts-with?(word-slice, "<")) goto error1
+ 288     3d/compare-EAX-and  0x3c/imm32/less-than
+ 289     74/jump-if-equal  $convert:error1/disp8
+ 290 $convert:regular-word:
+ 291     # write-slice-buffered(out, word-slice)
+ 292     # . . push args
+ 293     52/push-EDX
+ 294     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
+ 295     # . . call
+ 296     e8/call  write-slice-buffered/disp32
+ 297     # . . discard args
+ 298     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 299     # fall through
+ 300 $convert:next-word:
+ 301     # write-buffered(out, " ")
+ 302     # . . push args
+ 303     68/push  " "/imm32
+ 304     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
+ 305     # . . call
+ 306     e8/call  write-buffered/disp32
+ 307     # . . discard args
+ 308     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 309     # loop
+ 310     e9/jump  $convert:word-loop/disp32
+ 311 $convert:next-line:
+ 312     # write-buffered(out, "\n")
+ 313     # . . push args
+ 314     68/push  Newline/imm32
+ 315     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
+ 316     # . . call
+ 317     e8/call  write-buffered/disp32
+ 318     # . . discard args
+ 319     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 320     # loop
+ 321     e9/jump  $convert:line-loop/disp32
+ 322 $convert:break:
+ 323     # flush(out)
+ 324     # . . push args
+ 325     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
+ 326     # . . call
+ 327     e8/call  flush/disp32
+ 328     # . . discard args
+ 329     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 330 $convert:end:
+ 331     # . reclaim locals
+ 332     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x214/imm32       # add to ESP
+ 333     # . restore registers
+ 334     5b/pop-to-EBX
+ 335     5a/pop-to-EDX
+ 336     59/pop-to-ECX
+ 337     58/pop-to-EAX
+ 338     # . epilog
+ 339     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+ 340     5d/pop-to-EBP
+ 341     c3/return
+ 342 
+ 343 $convert:error1:
+ 344     # print(stderr, "error: '" EAX "' only permitted within '*(...)' in '" line "'")
+ 345     # . write-buffered(Stderr, "error: '")
+ 346     # . . push args
+ 347     68/push  "error: '"/imm32
+ 348     68/push  Stderr/imm32
+ 349     # . . call
+ 350     e8/call  write-buffered/disp32
+ 351     # . . discard args
+ 352     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 353     # . write-byte-buffered(Stderr, EAX)
+ 354     # . . push args
+ 355     50/push-EAX
+ 356     68/push  Stderr/imm32
+ 357     # . . call
+ 358     e8/call  write-byte-buffered/disp32
+ 359     # . . discard args
+ 360     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 361     # . write-buffered(Stderr, "' only permitted within '*(...)' in '")
+ 362     # . . push args
+ 363     68/push  "' only permitted within '*(...)' in '"/imm32
+ 364     68/push  Stderr/imm32
+ 365     # . . call
+ 366     e8/call  write-buffered/disp32
+ 367     # . . discard args
+ 368     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 369     # . write-stream-data(Stderr, line)
+ 370     # . . push args
+ 371     51/push-ECX
+ 372     68/push  Stderr/imm32
+ 373     # . . call
+ 374     e8/call  write-stream-data/disp32
+ 375     # . . discard args
+ 376     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 377     # . write-buffered(Stderr, "'")
+ 378     # . . push args
+ 379     68/push  "'"/imm32
+ 380     68/push  Stderr/imm32
+ 381     # . . call
+ 382     e8/call  write-buffered/disp32
+ 383     # . . discard args
+ 384     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 385     # . flush(Stderr)
+ 386     # . . push args
+ 387     68/push  Stderr/imm32
+ 388     # . . call
+ 389     e8/call  flush/disp32
+ 390     # . . discard args
+ 391     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 392     # . syscall(exit, 1)
+ 393     bb/copy-to-EBX  1/imm32
+ 394     b8/copy-to-EAX  1/imm32/exit
+ 395     cd/syscall  0x80/imm8
+ 396     # never gets here
+ 397 
+ 398 test-convert-passes-most-words-through:
+ 399     # . prolog
+ 400     55/push-EBP
+ 401     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+ 402     # setup
+ 403     # . clear-stream(_test-input-stream)
+ 404     # . . push args
+ 405     68/push  _test-input-stream/imm32
+ 406     # . . call
+ 407     e8/call  clear-stream/disp32
+ 408     # . . discard args
+ 409     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 410     # . clear-stream(_test-input-buffered-file+4)
+ 411     # . . push args
+ 412     b8/copy-to-EAX  _test-input-buffered-file/imm32
+ 413     05/add-to-EAX  4/imm32
+ 414     50/push-EAX
+ 415     # . . call
+ 416     e8/call  clear-stream/disp32
+ 417     # . . discard args
+ 418     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 419     # . clear-stream(_test-output-stream)
+ 420     # . . push args
+ 421     68/push  _test-output-stream/imm32
+ 422     # . . call
+ 423     e8/call  clear-stream/disp32
+ 424     # . . discard args
+ 425     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 426     # . clear-stream(_test-output-buffered-file+4)
+ 427     # . . push args
+ 428     b8/copy-to-EAX  _test-output-buffered-file/imm32
+ 429     05/add-to-EAX  4/imm32
+ 430     50/push-EAX
+ 431     # . . call
+ 432     e8/call  clear-stream/disp32
+ 433     # . . discard args
+ 434     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 435     # initialize input
+ 436     # . write(_test-input-stream, "== abcd 0x1")
+ 437     # . . push args
+ 438     68/push  "== abcd 0x1"/imm32
+ 439     68/push  _test-input-stream/imm32
+ 440     # . . call
+ 441     e8/call  write/disp32
+ 442     # . . discard args
+ 443     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 444     # convert(_test-input-buffered-file, _test-output-buffered-file)
+ 445     # . . push args
+ 446     68/push  _test-output-buffered-file/imm32
+ 447     68/push  _test-input-buffered-file/imm32
+ 448     # . . call
+ 449     e8/call  convert/disp32
+ 450     # . . discard args
+ 451     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 452     # check that the line just passed through
+ 453     # . flush(_test-output-buffered-file)
+ 454     # . . push args
+ 455     68/push  _test-output-buffered-file/imm32
+ 456     # . . call
+ 457     e8/call  flush/disp32
+ 458     # . . discard args
+ 459     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 460 +-- 26 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------
+ 486     # . check-stream-equal(_test-output-stream, "== abcd 0x1 \n", msg)
+ 487     # . . push args
+ 488     68/push  "F - test-convert-passes-most-words-through"/imm32
+ 489     68/push  "== abcd 0x1 \n"/imm32
+ 490     68/push  _test-output-stream/imm32
+ 491     # . . call
+ 492     e8/call  check-stream-equal/disp32
+ 493     # . . discard args
+ 494     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 495     # . epilog
+ 496     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+ 497     5d/pop-to-EBP
+ 498     c3/return
+ 499 
+ 500 test-convert-direct-mode:
+ 501     # . prolog
+ 502     55/push-EBP
+ 503     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+ 504     # setup
+ 505     # . clear-stream(_test-input-stream)
+ 506     # . . push args
+ 507     68/push  _test-input-stream/imm32
+ 508     # . . call
+ 509     e8/call  clear-stream/disp32
+ 510     # . . discard args
+ 511     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 512     # . clear-stream(_test-input-buffered-file+4)
+ 513     # . . push args
+ 514     b8/copy-to-EAX  _test-input-buffered-file/imm32
+ 515     05/add-to-EAX  4/imm32
+ 516     50/push-EAX
+ 517     # . . call
+ 518     e8/call  clear-stream/disp32
+ 519     # . . discard args
+ 520     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 521     # . clear-stream(_test-output-stream)
+ 522     # . . push args
+ 523     68/push  _test-output-stream/imm32
+ 524     # . . call
+ 525     e8/call  clear-stream/disp32
+ 526     # . . discard args
+ 527     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 528     # . clear-stream(_test-output-buffered-file+4)
+ 529     # . . push args
+ 530     b8/copy-to-EAX  _test-output-buffered-file/imm32
+ 531     05/add-to-EAX  4/imm32
+ 532     50/push-EAX
+ 533     # . . call
+ 534     e8/call  clear-stream/disp32
+ 535     # . . discard args
+ 536     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 537     # initialize input
+ 538     # . write(_test-input-stream, "ab %ecx")
+ 539     # . . push args
+ 540     68/push  "ab %ecx"/imm32
+ 541     68/push  _test-input-stream/imm32
+ 542     # . . call
+ 543     e8/call  write/disp32
+ 544     # . . discard args
+ 545     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 546     # convert(_test-input-buffered-file, _test-output-buffered-file)
+ 547     # . . push args
+ 548     68/push  _test-output-buffered-file/imm32
+ 549     68/push  _test-input-buffered-file/imm32
+ 550     # . . call
+ 551     e8/call  convert/disp32
+ 552     # . . discard args
+ 553     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 554     # check that the line just passed through
+ 555     # . flush(_test-output-buffered-file)
+ 556     # . . push args
+ 557     68/push  _test-output-buffered-file/imm32
+ 558     # . . call
+ 559     e8/call  flush/disp32
+ 560     # . . discard args
+ 561     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 562 +-- 26 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------
+ 588     # . check-stream-equal(_test-output-stream, "ab 3/mod/direct 0x00000001/rm32 \n", msg)
+ 589     # . . push args
+ 590     68/push  "F - test-convert-direct-mode"/imm32
+ 591     68/push  "ab 3/mod/direct 0x00000001/rm32 \n"/imm32
+ 592     68/push  _test-output-stream/imm32
+ 593     # . . call
+ 594     e8/call  check-stream-equal/disp32
+ 595     # . . discard args
+ 596     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 597     # . epilog
+ 598     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+ 599     5d/pop-to-EBP
+ 600     c3/return
+ 601 
+ 602 test-convert-register-indirect-mode:
+ 603     # . prolog
+ 604     55/push-EBP
+ 605     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+ 606     # setup
+ 607     # . clear-stream(_test-input-stream)
+ 608     # . . push args
+ 609     68/push  _test-input-stream/imm32
+ 610     # . . call
+ 611     e8/call  clear-stream/disp32
+ 612     # . . discard args
+ 613     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 614     # . clear-stream(_test-input-buffered-file+4)
+ 615     # . . push args
+ 616     b8/copy-to-EAX  _test-input-buffered-file/imm32
+ 617     05/add-to-EAX  4/imm32
+ 618     50/push-EAX
+ 619     # . . call
+ 620     e8/call  clear-stream/disp32
+ 621     # . . discard args
+ 622     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 623     # . clear-stream(_test-output-stream)
+ 624     # . . push args
+ 625     68/push  _test-output-stream/imm32
+ 626     # . . call
+ 627     e8/call  clear-stream/disp32
+ 628     # . . discard args
+ 629     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 630     # . clear-stream(_test-output-buffered-file+4)
+ 631     # . . push args
+ 632     b8/copy-to-EAX  _test-output-buffered-file/imm32
+ 633     05/add-to-EAX  4/imm32
+ 634     50/push-EAX
+ 635     # . . call
+ 636     e8/call  clear-stream/disp32
+ 637     # . . discard args
+ 638     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 639     # initialize input
+ 640     # . write(_test-input-stream, "ab *ecx")
+ 641     # . . push args
+ 642     68/push  "ab *ecx"/imm32
+ 643     68/push  _test-input-stream/imm32
+ 644     # . . call
+ 645     e8/call  write/disp32
+ 646     # . . discard args
+ 647     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 648     # convert(_test-input-buffered-file, _test-output-buffered-file)
+ 649     # . . push args
+ 650     68/push  _test-output-buffered-file/imm32
+ 651     68/push  _test-input-buffered-file/imm32
+ 652     # . . call
+ 653     e8/call  convert/disp32
+ 654     # . . discard args
+ 655     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 656     # check that the line just passed through
+ 657     # . flush(_test-output-buffered-file)
+ 658     # . . push args
+ 659     68/push  _test-output-buffered-file/imm32
+ 660     # . . call
+ 661     e8/call  flush/disp32
+ 662     # . . discard args
+ 663     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 664 +-- 26 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------
+ 690     # . check-stream-equal(_test-output-stream, "ab 0/mod/indirect 0x00000001/rm32 \n", msg)
+ 691     # . . push args
+ 692     68/push  "F - test-convert-indirect-mode"/imm32
+ 693     68/push  "ab 0/mod/indirect 0x00000001/rm32 \n"/imm32
+ 694     68/push  _test-output-stream/imm32
+ 695     # . . call
+ 696     e8/call  check-stream-equal/disp32
+ 697     # . . discard args
+ 698     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 699     # . epilog
+ 700     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+ 701     5d/pop-to-EBP
+ 702     c3/return
+ 703 
+ 704 test-convert-register-indirect-mode-without-displacement:
+ 705     # . prolog
+ 706     55/push-EBP
+ 707     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+ 708     # setup
+ 709     # . clear-stream(_test-input-stream)
+ 710     # . . push args
+ 711     68/push  _test-input-stream/imm32
+ 712     # . . call
+ 713     e8/call  clear-stream/disp32
+ 714     # . . discard args
+ 715     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 716     # . clear-stream(_test-input-buffered-file+4)
+ 717     # . . push args
+ 718     b8/copy-to-EAX  _test-input-buffered-file/imm32
+ 719     05/add-to-EAX  4/imm32
+ 720     50/push-EAX
+ 721     # . . call
+ 722     e8/call  clear-stream/disp32
+ 723     # . . discard args
+ 724     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 725     # . clear-stream(_test-output-stream)
+ 726     # . . push args
+ 727     68/push  _test-output-stream/imm32
+ 728     # . . call
+ 729     e8/call  clear-stream/disp32
+ 730     # . . discard args
+ 731     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 732     # . clear-stream(_test-output-buffered-file+4)
+ 733     # . . push args
+ 734     b8/copy-to-EAX  _test-output-buffered-file/imm32
+ 735     05/add-to-EAX  4/imm32
+ 736     50/push-EAX
+ 737     # . . call
+ 738     e8/call  clear-stream/disp32
+ 739     # . . discard args
+ 740     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 741     # initialize input
+ 742     # . write(_test-input-stream, "ab *(ecx)")
+ 743     # . . push args
+ 744     68/push  "ab *(ecx)"/imm32
+ 745     68/push  _test-input-stream/imm32
+ 746     # . . call
+ 747     e8/call  write/disp32
+ 748     # . . discard args
+ 749     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 750     # convert(_test-input-buffered-file, _test-output-buffered-file)
+ 751     # . . push args
+ 752     68/push  _test-output-buffered-file/imm32
+ 753     68/push  _test-input-buffered-file/imm32
+ 754     # . . call
+ 755     e8/call  convert/disp32
+ 756     # . . discard args
+ 757     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 758     # check that the line just passed through
+ 759     # . flush(_test-output-buffered-file)
+ 760     # . . push args
+ 761     68/push  _test-output-buffered-file/imm32
+ 762     # . . call
+ 763     e8/call  flush/disp32
+ 764     # . . discard args
+ 765     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 766 +-- 26 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------
+ 792     # . check-stream-equal(_test-output-stream, "ab 0/mod/indirect 1/rm32 \n", msg)
+ 793     # . . push args
+ 794     68/push  "F - test-convert-indirect-mode-without-displacement"/imm32
+ 795     68/push  "ab 0/mod/indirect 0x00000001/rm32 \n"/imm32
+ 796     68/push  _test-output-stream/imm32
+ 797     # . . call
+ 798     e8/call  check-stream-equal/disp32
+ 799     # . . discard args
+ 800     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 801     # . epilog
+ 802     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+ 803     5d/pop-to-EBP
+ 804     c3/return
+ 805 
+ 806 test-convert-register-indirect-mode-with-displacement:
+ 807     # . prolog
+ 808     55/push-EBP
+ 809     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+ 810     # setup
+ 811     # . clear-stream(_test-input-stream)
+ 812     # . . push args
+ 813     68/push  _test-input-stream/imm32
+ 814     # . . call
+ 815     e8/call  clear-stream/disp32
+ 816     # . . discard args
+ 817     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 818     # . clear-stream(_test-input-buffered-file+4)
+ 819     # . . push args
+ 820     b8/copy-to-EAX  _test-input-buffered-file/imm32
+ 821     05/add-to-EAX  4/imm32
+ 822     50/push-EAX
+ 823     # . . call
+ 824     e8/call  clear-stream/disp32
+ 825     # . . discard args
+ 826     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 827     # . clear-stream(_test-output-stream)
+ 828     # . . push args
+ 829     68/push  _test-output-stream/imm32
+ 830     # . . call
+ 831     e8/call  clear-stream/disp32
+ 832     # . . discard args
+ 833     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 834     # . clear-stream(_test-output-buffered-file+4)
+ 835     # . . push args
+ 836     b8/copy-to-EAX  _test-output-buffered-file/imm32
+ 837     05/add-to-EAX  4/imm32
+ 838     50/push-EAX
+ 839     # . . call
+ 840     e8/call  clear-stream/disp32
+ 841     # . . discard args
+ 842     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 843     # initialize input
+ 844     # . write(_test-input-stream, "ab *(ecx+4)")
+ 845     # . . push args
+ 846     68/push  "ab *(ecx+4)"/imm32
+ 847     68/push  _test-input-stream/imm32
+ 848     # . . call
+ 849     e8/call  write/disp32
+ 850     # . . discard args
+ 851     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 852     # convert(_test-input-buffered-file, _test-output-buffered-file)
+ 853     # . . push args
+ 854     68/push  _test-output-buffered-file/imm32
+ 855     68/push  _test-input-buffered-file/imm32
+ 856     # . . call
+ 857     e8/call  convert/disp32
+ 858     # . . discard args
+ 859     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 860     # check that the line just passed through
+ 861     # . flush(_test-output-buffered-file)
+ 862     # . . push args
+ 863     68/push  _test-output-buffered-file/imm32
+ 864     # . . call
+ 865     e8/call  flush/disp32
+ 866     # . . discard args
+ 867     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 868 +-- 26 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------
+ 894     # . check-stream-equal(_test-output-stream, "ab 2/mod/*+disp32 1/rm32 4/disp32 \n", msg)
+ 895     # . . push args
+ 896     68/push  "F - test-convert-indirect-mode-with-displacement"/imm32
+ 897     68/push  "ab 2/mod/*+disp32 0x00000001/rm32 0x00000004/disp32 \n"/imm32
+ 898     68/push  _test-output-stream/imm32
+ 899     # . . call
+ 900     e8/call  check-stream-equal/disp32
+ 901     # . . discard args
+ 902     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+ 903     # . epilog
+ 904     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+ 905     5d/pop-to-EBP
+ 906     c3/return
+ 907 
+ 908 # boss level
+ 909 test-convert-register-indirect-mode-with-sib-byte:
+ 910     # . prolog
+ 911     55/push-EBP
+ 912     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+ 913     # setup
+ 914     # . clear-stream(_test-input-stream)
+ 915     # . . push args
+ 916     68/push  _test-input-stream/imm32
+ 917     # . . call
+ 918     e8/call  clear-stream/disp32
+ 919     # . . discard args
+ 920     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 921     # . clear-stream(_test-input-buffered-file+4)
+ 922     # . . push args
+ 923     b8/copy-to-EAX  _test-input-buffered-file/imm32
+ 924     05/add-to-EAX  4/imm32
+ 925     50/push-EAX
+ 926     # . . call
+ 927     e8/call  clear-stream/disp32
+ 928     # . . discard args
+ 929     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 930     # . clear-stream(_test-output-stream)
+ 931     # . . push args
+ 932     68/push  _test-output-stream/imm32
+ 933     # . . call
+ 934     e8/call  clear-stream/disp32
+ 935     # . . discard args
+ 936     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 937     # . clear-stream(_test-output-buffered-file+4)
+ 938     # . . push args
+ 939     b8/copy-to-EAX  _test-output-buffered-file/imm32
+ 940     05/add-to-EAX  4/imm32
+ 941     50/push-EAX
+ 942     # . . call
+ 943     e8/call  clear-stream/disp32
+ 944     # . . discard args
+ 945     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 946     # initialize input
+ 947     # . write(_test-input-stream, "ab *(ecx + edx<<3 + 4)")
+ 948     # . . push args
+ 949     68/push  "ab *(ecx + edx<<3 + 4)"/imm32
+ 950     68/push  _test-input-stream/imm32
+ 951     # . . call
+ 952     e8/call  write/disp32
+ 953     # . . discard args
+ 954     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 955     # convert(_test-input-buffered-file, _test-output-buffered-file)
+ 956     # . . push args
+ 957     68/push  _test-output-buffered-file/imm32
+ 958     68/push  _test-input-buffered-file/imm32
+ 959     # . . call
+ 960     e8/call  convert/disp32
+ 961     # . . discard args
+ 962     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+ 963     # check that the line just passed through
+ 964     # . flush(_test-output-buffered-file)
+ 965     # . . push args
+ 966     68/push  _test-output-buffered-file/imm32
+ 967     # . . call
+ 968     e8/call  flush/disp32
+ 969     # . . discard args
+ 970     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+ 971 +-- 26 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------
+ 997     # . check-stream-equal(_test-output-stream, "ab 2/mod/*+disp32 4/rm32/sib 1/base 2/index 3/scale 4/disp32 \n", msg)
+ 998     # . . push args
+ 999     68/push  "F - test-convert-indirect-mode-with-sib-byte"/imm32
+1000     68/push  "ab 2/mod/*+disp32 4/rm32/sib 0x00000001/base 0x00000002/index 0x00000003/scale 0x00000004/disp32 \n"/imm32
+1001     68/push  _test-output-stream/imm32
+1002     # . . call
+1003     e8/call  check-stream-equal/disp32
+1004     # . . discard args
+1005     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+1006     # . epilog
+1007     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+1008     5d/pop-to-EBP
+1009     c3/return
+1010 
+1011 test-convert-register-indirect-mode-with-sib-byte-negative-displacement:
+1012     # . prolog
+1013     55/push-EBP
+1014     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+1015     # setup
+1016     # . clear-stream(_test-input-stream)
+1017     # . . push args
+1018     68/push  _test-input-stream/imm32
+1019     # . . call
+1020     e8/call  clear-stream/disp32
+1021     # . . discard args
+1022     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+1023     # . clear-stream(_test-input-buffered-file+4)
+1024     # . . push args
+1025     b8/copy-to-EAX  _test-input-buffered-file/imm32
+1026     05/add-to-EAX  4/imm32
+1027     50/push-EAX
+1028     # . . call
+1029     e8/call  clear-stream/disp32
+1030     # . . discard args
+1031     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+1032     # . clear-stream(_test-output-stream)
+1033     # . . push args
+1034     68/push  _test-output-stream/imm32
+1035     # . . call
+1036     e8/call  clear-stream/disp32
+1037     # . . discard args
+1038     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+1039     # . clear-stream(_test-output-buffered-file+4)
+1040     # . . push args
+1041     b8/copy-to-EAX  _test-output-buffered-file/imm32
+1042     05/add-to-EAX  4/imm32
+1043     50/push-EAX
+1044     # . . call
+1045     e8/call  clear-stream/disp32
+1046     # . . discard args
+1047     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+1048     # initialize input
+1049     # . write(_test-input-stream, "ab *(ecx + edx<<3 - 4)")
+1050     # . . push args
+1051     68/push  "ab *(ecx + edx<<3 - 4)"/imm32
+1052     68/push  _test-input-stream/imm32
+1053     # . . call
+1054     e8/call  write/disp32
+1055     # . . discard args
+1056     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1057     # convert(_test-input-buffered-file, _test-output-buffered-file)
+1058     # . . push args
+1059     68/push  _test-output-buffered-file/imm32
+1060     68/push  _test-input-buffered-file/imm32
+1061     # . . call
+1062     e8/call  convert/disp32
+1063     # . . discard args
+1064     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1065     # check that the line just passed through
+1066     # . flush(_test-output-buffered-file)
+1067     # . . push args
+1068     68/push  _test-output-buffered-file/imm32
+1069     # . . call
+1070     e8/call  flush/disp32
+1071     # . . discard args
+1072     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+1073 +-- 26 lines: #?     # dump _test-output-stream --------------------------------------------------------------------------------------------------------------
+1099     # . check-stream-equal(_test-output-stream, "ab 2/mod/*+disp32 4/rm32/sib 1/base 2/index 3/scale -4/disp32 \n", msg)
+1100     # . . push args
+1101     68/push  "F - test-convert-indirect-mode-with-sib-byte-negative-displacement"/imm32
+1102     68/push  "ab 2/mod/*+disp32 4/rm32/sib 0x00000001/base 0x00000002/index 0x00000003/scale 0xfffffffc/disp32 \n"/imm32
+1103     68/push  _test-output-stream/imm32
+1104     # . . call
+1105     e8/call  check-stream-equal/disp32
+1106     # . . discard args
+1107     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+1108     # . epilog
+1109     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+1110     5d/pop-to-EBP
+1111     c3/return
+1112 
+1113 # beware: modifies 'word'
+1114 emit-direct-mode:  # word : (address slice), out : (address buffered-file)
+1115     # . prolog
+1116     55/push-EBP
+1117     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+1118     # . save registers
+1119     50/push-EAX
+1120     # ++word->start
+1121     # . EAX = word
+1122     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           0/r32/EAX   8/disp8         .                 # copy *(EBP+8) to EAX
+1123     # . ++(*EAX)
+1124     ff          0/subop/increment   0/mod/indirect  0/rm32/EAX    .           .             .           .           .               .                 # increment *EAX
+1125     # reg-num/EAX = get-slice(Registers, word, row-size=8)
+1126     # . . push args
+1127     68/push  "Registers"/imm32
+1128     68/push  8/imm32/row-size
+1129     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
+1130     68/push  Registers/imm32
+1131     # . . call
+1132     e8/call  get-slice/disp32
+1133     # . . discard args
+1134     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x10/imm32        # add to ESP
+1135     # write-buffered(out, "3/mod/direct ")
+1136     # . . push args
+1137     68/push  "3/mod/direct "/imm32
+1138     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
+1139     # . . call
+1140     e8/call  write-buffered/disp32
+1141     # . . discard args
+1142     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1143     # print-int32-buffered(out, *EAX)
+1144     # . . push args
+1145     ff          6/subop/push        0/mod/indirect  0/rm32/EAX    .           .             .           .           .               .                 # push *EAX
+1146     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
+1147     # . . call
+1148     e8/call  print-int32-buffered/disp32
+1149     # . . discard args
+1150     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1151     # write-buffered(out, "/rm32")
+1152     # . . push args
+1153     68/push  "/rm32"/imm32
+1154     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
+1155     # . . call
+1156     e8/call  write-buffered/disp32
+1157     # . . discard args
+1158     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1159 $emit-direct-mode:end:
+1160     # . restore registers
+1161     58/pop-to-EAX
+1162     # . epilog
+1163     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+1164     5d/pop-to-EBP
+1165     c3/return
+1166 
+1167 test-emit-direct-mode:
+1168     # . prolog
+1169     55/push-EBP
+1170     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+1171     # setup
+1172     # . clear-stream(_test-output-stream)
+1173     # . . push args
+1174     68/push  _test-output-stream/imm32
+1175     # . . call
+1176     e8/call  clear-stream/disp32
+1177     # . . discard args
+1178     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+1179     # . clear-stream(_test-output-buffered-file+4)
+1180     # . . push args
+1181     b8/copy-to-EAX  _test-output-buffered-file/imm32
+1182     05/add-to-EAX  4/imm32
+1183     50/push-EAX
+1184     # . . call
+1185     e8/call  clear-stream/disp32
+1186     # . . discard args
+1187     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+1188     # var slice/ECX = "%eax"
+1189     b8/copy-to-EAX  "%eax"/imm32
+1190     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
+1191     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
+1192     05/add-to-EAX  4/imm32
+1193     # . ECX = {EAX, ECX}
+1194     51/push-ECX
+1195     50/push-EAX
+1196     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+1197     # emit-direct-mode(str, _test-output-buffered-file)
+1198     # . . push args
+1199     68/push  _test-output-buffered-file/imm32
+1200     51/push-ECX
+1201     # . . call
+1202     e8/call  emit-direct-mode/disp32
+1203     # . . discard args
+1204     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32         # add to ESP
+1205     # . flush(_test-output-buffered-file)
+1206     # . . push args
+1207     68/push  _test-output-buffered-file/imm32
+1208     # . . call
+1209     e8/call  flush/disp32
+1210     # . . discard args
+1211     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+1212 +-- 26 lines: #?     # dump output ---------------------------------------------------------------------------------------------------------------------------
+1238     # check-stream-equal(_test-output-stream, "3/mod/direct 0/rm32", msg)
+1239     # . . push args
+1240     68/push  "F - test-emit-direct-mode/0"/imm32
+1241     68/push  "3/mod/direct 0x00000000/rm32"/imm32
+1242     68/push  _test-output-stream/imm32
+1243     # . . call
+1244     e8/call  check-stream-equal/disp32
+1245     # . . discard args
+1246     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+1247     # . epilog
+1248     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+1249     5d/pop-to-EBP
+1250     c3/return
+1251 
+1252 test-emit-direct-mode-2:
+1253     # . prolog
+1254     55/push-EBP
+1255     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+1256     # setup
+1257     # . clear-stream(_test-output-stream)
+1258     # . . push args
+1259     68/push  _test-output-stream/imm32
+1260     # . . call
+1261     e8/call  clear-stream/disp32
+1262     # . . discard args
+1263     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+1264     # . clear-stream(_test-output-buffered-file+4)
+1265     # . . push args
+1266     b8/copy-to-EAX  _test-output-buffered-file/imm32
+1267     05/add-to-EAX  4/imm32
+1268     50/push-EAX
+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     # var slice/ECX = "%edi"
+1274     b8/copy-to-EAX  "%edi"/imm32
+1275     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
+1276     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
+1277     05/add-to-EAX  4/imm32
+1278     # . ECX = {EAX, ECX}
+1279     51/push-ECX
+1280     50/push-EAX
+1281     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+1282     # emit-direct-mode(str/ECX, _test-output-buffered-file)
+1283     # . . push args
+1284     68/push  _test-output-buffered-file/imm32
+1285     51/push-ECX
+1286     # . . call
+1287     e8/call  emit-direct-mode/disp32
+1288     # . . discard args
+1289     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32         # add to ESP
+1290     # . flush(_test-output-buffered-file)
+1291     # . . push args
+1292     68/push  _test-output-buffered-file/imm32
+1293     # . . call
+1294     e8/call  flush/disp32
+1295     # . . discard args
+1296     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+1297 +-- 26 lines: #?     # dump output ---------------------------------------------------------------------------------------------------------------------------
+1323     # check-stream-equal(_test-output-stream, "3/mod/direct 7/rm32", msg)
+1324     # . . push args
+1325     68/push  "F - test-emit-direct-mode/1"/imm32
+1326     68/push  "3/mod/direct 0x00000007/rm32"/imm32
+1327     68/push  _test-output-stream/imm32
+1328     # . . call
+1329     e8/call  check-stream-equal/disp32
+1330     # . . discard args
+1331     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+1332     # . epilog
+1333     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+1334     5d/pop-to-EBP
+1335     c3/return
+1336 
+1337 # (re)compute the bounds of the next word or parenthetical expression in the line
+1338 # return empty string on reaching end of file
+1339 #
+1340 # error messages considered:
+1341 #   * ...                   -> error: no space after '*'
+1342 #   *(...                   -> error: *(...) expression must be all on a single line
+1343 next-word-or-expression:  # line : (address stream byte), out : (address slice)
+1344     # . prolog
+1345     55/push-EBP
+1346     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+1347     # . save registers
+1348     50/push-EAX
+1349     51/push-ECX
+1350     56/push-ESI
+1351     57/push-EDI
+1352     # ESI = line
+1353     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           6/r32/ESI   8/disp8         .                 # copy *(EBP+8) to ESI
+1354     # EDI = out
+1355     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           7/r32/EDI   0xc/disp8       .                 # copy *(EBP+12) to EDI
+1356     # skip-chars-matching(line, ' ')
+1357     # . . push args
+1358     68/push  0x20/imm32/space
+1359     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
+1360     # . . call
+1361     e8/call  skip-chars-matching/disp32
+1362     # . . discard args
+1363     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1364 $next-word-or-expression:check0:
+1365     # if (line->read >= line->write) clear out and return
+1366     # . EAX = line->read
+1367     8b/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           0/r32/EAX   4/disp8         .                 # copy *(ESI+4) to EAX
+1368     # . if (EAX < line->write) goto next check
+1369     3b/compare                      0/mod/indirect  6/rm32/ESI    .           .             .           0/r32/EAX   .               .                 # compare EAX with *ESI
+1370     7c/jump-if-lesser  $next-word-or-expression:check-for-comment/disp8
+1371     # . return out = {0, 0}
+1372     c7          0/subop/copy        0/mod/direct    7/rm32/EDI    .           .             .           .           .               0/imm32           # copy to *EDI
+1373     c7          0/subop/copy        1/mod/*+disp8   7/rm32/EDI    .           .             .           .           4/disp8         0/imm32           # copy to *(EDI+4)
+1374     eb/jump  $next-word-or-expression:end/disp8
+1375 $next-word-or-expression:check-for-comment:
+1376     # out->start = &line->data[line->read]
+1377     8b/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           1/r32/ECX   4/disp8         .                 # copy *(ESI+4) to ECX
+1378     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    6/base/ESI  1/index/ECX   .           0/r32/EAX   0xc/disp8       .                 # copy ESI+ECX+12 to EAX
+1379     89/copy                         0/mod/indirect  7/rm32/EDI    .           .             .           0/r32/EAX   .               .                 # copy EAX to *EDI
+1380     # if (line->data[line->read] != '#') goto next check
+1381     # . EAX = line->data[line->read]
+1382     31/xor                          3/mod/direct    0/rm32/EAX    .           .             .           0/r32/EAX   .               .                 # clear EAX
+1383     8a/copy-byte                    1/mod/*+disp8   4/rm32/sib    6/base/ESI  1/index/ECX   .           0/r32/AL    0xc/disp8       .                 # copy byte at *(ESI+ECX+12) to AL
+1384     # . compare
+1385     3d/compare-EAX-and  0x23/imm32/pound
+1386     75/jump-if-not-equal  $next-word-or-expression:check-for-paren/disp8
+1387 $next-word-or-expression:comment:
+1388     # out->end = &line->data[line->write]
+1389     8b/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           0/r32/EAX   .               .                 # copy *ESI to EAX
+1390     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    6/base/ESI  0/index/EAX   .           0/r32/EAX   0xc/disp8       .                 # copy ESI+EAX+12 to EAX
+1391     89/copy                         1/mod/*+disp8   7/rm32/EDI    .           .             .           0/r32/EAX   4/disp8         .                 # copy EAX to *(EDI+4)
+1392     # line->read = line->write  # skip rest of line
+1393     8b/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           0/r32/EAX   .               .                 # copy *ESI to EAX
+1394     89/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           0/r32/EAX   4/disp8         .                 # copy EAX to *(ESI+4)
+1395     # return
+1396     eb/jump  $next-word-or-expression:end/disp8
+1397 $next-word-or-expression:check-for-paren:
+1398     # if (line->data[line->read] != '*') goto next check
+1399     # . EAX = line->data[line->read]
+1400     31/xor                          3/mod/direct    0/rm32/EAX    .           .             .           0/r32/EAX   .               .                 # clear EAX
+1401     8a/copy-byte                    1/mod/*+disp8   4/rm32/sib    6/base/ESI  1/index/ECX   .           0/r32/AL    0xc/disp8       .                 # copy byte at *(ESI+ECX+12) to AL
+1402     # . compare
+1403     3d/compare-EAX-and  0x2a/imm32/asterisk
+1404     75/jump-if-not-equal  $next-word-or-expression:regular-word/disp8
+1405     # if (line->data[line->read] == ' ') goto error1
+1406     8a/copy-byte                    1/mod/*+disp8   4/rm32/sib    6/base/ESI  1/index/ECX   .           0/r32/AL    0xd/disp8       .                 # copy byte at *(ESI+ECX+12+1) to AL
+1407     # . compare
+1408     3d/compare-EAX-and  0x20/imm32/space
+1409     74/jump-if-equal  $next-word-or-expression:error1/disp8
+1410     # if (line->data[line->read] != '(') goto regular word
+1411     8a/copy-byte                    1/mod/*+disp8   4/rm32/sib    6/base/ESI  1/index/ECX   .           0/r32/AL    0xd/disp8       .                 # copy byte at *(ESI+ECX+12+1) to AL
+1412     # . compare
+1413     3d/compare-EAX-and  0x28/imm32/open-paren
+1414     75/jump-if-not-equal  $next-word-or-expression:regular-word/disp8
+1415 $next-word-or-expression:paren:
+1416     # skip-until-close-paren(line)
+1417     # . . push args
+1418     56/push-ESI
+1419     # . . call
+1420     e8/call  skip-until-close-paren/disp32
+1421     # . . discard args
+1422     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+1423     # if (line->data[line->read] != ')') goto error2
+1424     8b/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           1/r32/ECX   4/disp8         .                 # copy *(ESI+4) to ECX
+1425     8a/copy-byte                    1/mod/*+disp8   4/rm32/sib    6/base/ESI  1/index/ECX   .           0/r32/AL    0xc/disp8       .                 # copy byte at *(ESI+ECX+12) to AL
+1426     # . compare
+1427     3d/compare-EAX-and  0x29/imm32/close-paren
+1428     75/jump-if-not-equal  $next-word-or-expression:error2/disp8
+1429     # skip ')'
+1430     ff          0/subop/increment   1/mod/*+disp8   6/rm32/ESI    .           .             .           .           4/disp8         .                 # increment *(ESI+4)
+1431     # fall through
+1432 $next-word-or-expression:regular-word:
+1433     # skip-chars-not-matching-whitespace(line)  # including trailing newline
+1434     # . . push args
+1435     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
+1436     # . . call
+1437     e8/call  skip-chars-not-matching-whitespace/disp32
+1438     # . . discard args
+1439     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+1440     # out->end = &line->data[line->read]
+1441     8b/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           1/r32/ECX   4/disp8         .                 # copy *(ESI+4) to ECX
+1442     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    6/base/ESI  1/index/ECX   .           0/r32/EAX   0xc/disp8       .                 # copy ESI+ECX+12 to EAX
+1443     89/copy                         1/mod/*+disp8   7/rm32/EDI    .           .             .           0/r32/EAX   4/disp8         .                 # copy EAX to *(EDI+4)
+1444 $next-word-or-expression:end:
+1445     # . restore registers
+1446     5f/pop-to-EDI
+1447     5e/pop-to-ESI
+1448     59/pop-to-ECX
+1449     58/pop-to-EAX
+1450     # . epilog
+1451     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+1452     5d/pop-to-EBP
+1453     c3/return
+1454 
+1455 $next-word-or-expression:error1:
+1456     # print(stderr, "error: no space allowed after '*' in '" line "'")
+1457     # . write-buffered(Stderr, "error: no space allowed after '*' in '")
+1458     # . . push args
+1459     68/push  "error: no space allowed after '*' in '"/imm32
+1460     68/push  Stderr/imm32
+1461     # . . call
+1462     e8/call  write-buffered/disp32
+1463     # . . discard args
+1464     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1465     # . write-stream-data(Stderr, line)
+1466     # . . push args
+1467     56/push-ESI
+1468     68/push  Stderr/imm32
+1469     # . . call
+1470     e8/call  write-stream-data/disp32
+1471     # . . discard args
+1472     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1473     # . write-buffered(Stderr, "'")
+1474     # . . push args
+1475     68/push  "'"/imm32
+1476     68/push  Stderr/imm32
+1477     # . . call
+1478     e8/call  write-buffered/disp32
+1479     # . . discard args
+1480     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1481     # . flush(Stderr)
+1482     # . . push args
+1483     68/push  Stderr/imm32
+1484     # . . call
+1485     e8/call  flush/disp32
+1486     # . . discard args
+1487     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+1488     # . syscall(exit, 1)
+1489     bb/copy-to-EBX  1/imm32
+1490     b8/copy-to-EAX  1/imm32/exit
+1491     cd/syscall  0x80/imm8
+1492     # never gets here
+1493 
+1494 $next-word-or-expression:error2:
+1495     # print(stderr, "error: no space allowed after '*' in '" line "'")
+1496     # . write-buffered(Stderr, "error: *(...) expression must be all on a single line in '")
+1497     # . . push args
+1498     68/push  "error: *(...) expression must be all on a single line in '"/imm32
+1499     68/push  Stderr/imm32
+1500     # . . call
+1501     e8/call  write-buffered/disp32
+1502     # . . discard args
+1503     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1504     # . write-stream-data(Stderr, line)
+1505     # . . push args
+1506     56/push-ESI
+1507     68/push  Stderr/imm32
+1508     # . . call
+1509     e8/call  write-stream-data/disp32
+1510     # . . discard args
+1511     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1512     # . write-buffered(Stderr, "'")
+1513     # . . push args
+1514     68/push  "'"/imm32
+1515     68/push  Stderr/imm32
+1516     # . . call
+1517     e8/call  write-buffered/disp32
+1518     # . . discard args
+1519     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1520     # . flush(Stderr)
+1521     # . . push args
+1522     68/push  Stderr/imm32
+1523     # . . call
+1524     e8/call  flush/disp32
+1525     # . . discard args
+1526     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+1527     # . syscall(exit, 1)
+1528     bb/copy-to-EBX  1/imm32
+1529     b8/copy-to-EAX  1/imm32/exit
+1530     cd/syscall  0x80/imm8
+1531     # never gets here
+1532 
+1533 test-next-word-or-expression:
+1534     # . prolog
+1535     55/push-EBP
+1536     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+1537     # setup
+1538     # . clear-stream(_test-input-stream)
+1539     # . . push args
+1540     68/push  _test-input-stream/imm32
+1541     # . . call
+1542     e8/call  clear-stream/disp32
+1543     # . . discard args
+1544     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+1545     # var slice/ECX = {0, 0}
+1546     68/push  0/imm32/end
+1547     68/push  0/imm32/start
+1548     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+1549     # write(_test-input-stream, "  ab")
+1550     # . . push args
+1551     68/push  "  ab"/imm32
+1552     68/push  _test-input-stream/imm32
+1553     # . . call
+1554     e8/call  write/disp32
+1555     # . . discard args
+1556     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1557     # next-word-or-expression(_test-input-stream, slice)
+1558     # . . push args
+1559     51/push-ECX
+1560     68/push  _test-input-stream/imm32
+1561     # . . call
+1562     e8/call  next-word-or-expression/disp32
+1563     # . . discard args
+1564     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1565     # check-ints-equal(_test-input-stream->read, 4, msg)
+1566     # . . push args
+1567     68/push  "F - test-next-word-or-expression/updates-stream-read-correctly"/imm32
+1568     68/push  4/imm32
+1569     b8/copy-to-EAX  _test-input-stream/imm32
+1570     ff          6/subop/push        1/mod/*+disp8   0/rm32/EAX    .           .             .           .           4/disp8         .                 # push *(EAX+4)
+1571     # . . call
+1572     e8/call  check-ints-equal/disp32
+1573     # . . discard args
+1574     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+1575     # check-ints-equal(slice->start - _test-input-stream->data, 2, msg)
+1576     # . check-ints-equal(slice->start - _test-input-stream, 14, msg)
+1577     # . . push args
+1578     68/push  "F - test-next-word-or-expression: start"/imm32
+1579     68/push  0xe/imm32
+1580     # . . push slice->start - _test-input-stream
+1581     8b/copy                         0/mod/indirect  1/rm32/ECX    .           .             .           0/r32/EAX   .               .                 # copy *ECX to EAX
+1582     81          5/subop/subtract    3/mod/direct    0/rm32/EAX    .           .             .           .           .               _test-input-stream/imm32 # subtract from EAX
+1583     50/push-EAX
+1584     # . . call
+1585     e8/call  check-ints-equal/disp32
+1586     # . . discard args
+1587     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+1588     # check-ints-equal(slice->end - _test-input-stream->data, 4, msg)
+1589     # . check-ints-equal(slice->end - _test-input-stream, 16, msg)
+1590     # . . push args
+1591     68/push  "F - test-next-word-or-expression: end"/imm32
+1592     68/push  0x10/imm32
+1593     # . . push slice->end - _test-input-stream
+1594     8b/copy                         1/mod/*+disp8   1/rm32/ECX    .           .             .           0/r32/EAX   4/disp8         .                 # copy *(ECX+4) to EAX
+1595     81          5/subop/subtract    3/mod/direct    0/rm32/EAX    .           .             .           .           .               _test-input-stream/imm32 # subtract from EAX
+1596     50/push-EAX
+1597     # . . call
+1598     e8/call  check-ints-equal/disp32
+1599     # . . discard args
+1600     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+1601     # . epilog
+1602     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+1603     5d/pop-to-EBP
+1604     c3/return
+1605 
+1606 test-next-word-or-expression-returns-whole-comment:
+1607     # . prolog
+1608     55/push-EBP
+1609     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+1610     # setup
+1611     # . clear-stream(_test-input-stream)
+1612     # . . push args
+1613     68/push  _test-input-stream/imm32
+1614     # . . call
+1615     e8/call  clear-stream/disp32
+1616     # . . discard args
+1617     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+1618     # var slice/ECX = {0, 0}
+1619     68/push  0/imm32/end
+1620     68/push  0/imm32/start
+1621     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+1622     # write(_test-input-stream, "  # a")
+1623     # . . push args
+1624     68/push  "  # a"/imm32
+1625     68/push  _test-input-stream/imm32
+1626     # . . call
+1627     e8/call  write/disp32
+1628     # . . discard args
+1629     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1630     # next-word-or-expression(_test-input-stream, slice)
+1631     # . . push args
+1632     51/push-ECX
+1633     68/push  _test-input-stream/imm32
+1634     # . . call
+1635     e8/call  next-word-or-expression/disp32
+1636     # . . discard args
+1637     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1638     # check-ints-equal(_test-input-stream->read, 5, msg)
+1639     # . . push args
+1640     68/push  "F - test-next-word-or-expression-returns-whole-comment/updates-stream-read-correctly"/imm32
+1641     68/push  5/imm32
+1642     b8/copy-to-EAX  _test-input-stream/imm32
+1643     ff          6/subop/push        1/mod/*+disp8   0/rm32/EAX    .           .             .           .           4/disp8         .                 # push *(EAX+4)
+1644     # . . call
+1645     e8/call  check-ints-equal/disp32
+1646     # . . discard args
+1647     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+1648     # check-ints-equal(slice->start - _test-input-stream->data, 2, msg)
+1649     # . check-ints-equal(slice->start - _test-input-stream, 14, msg)
+1650     # . . push args
+1651     68/push  "F - test-next-word-or-expression-returns-whole-comment: start"/imm32
+1652     68/push  0xe/imm32
+1653     # . . push slice->start - _test-input-stream
+1654     8b/copy                         0/mod/indirect  1/rm32/ECX    .           .             .           0/r32/EAX   .               .                 # copy *ECX to EAX
+1655     81          5/subop/subtract    3/mod/direct    0/rm32/EAX    .           .             .           .           .               _test-input-stream/imm32 # subtract from EAX
+1656     50/push-EAX
+1657     # . . call
+1658     e8/call  check-ints-equal/disp32
+1659     # . . discard args
+1660     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+1661     # check-ints-equal(slice->end - _test-input-stream->data, 5, msg)
+1662     # . check-ints-equal(slice->end - _test-input-stream, 17, msg)
+1663     # . . push args
+1664     68/push  "F - test-next-word-or-expression-returns-whole-comment: end"/imm32
+1665     68/push  0x11/imm32
+1666     # . . push slice->end - _test-input-stream
+1667     8b/copy                         1/mod/*+disp8   1/rm32/ECX    .           .             .           0/r32/EAX   4/disp8         .                 # copy *(ECX+4) to EAX
+1668     81          5/subop/subtract    3/mod/direct    0/rm32/EAX    .           .             .           .           .               _test-input-stream/imm32 # subtract from EAX
+1669     50/push-EAX
+1670     # . . call
+1671     e8/call  check-ints-equal/disp32
+1672     # . . discard args
+1673     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+1674     # . epilog
+1675     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+1676     5d/pop-to-EBP
+1677     c3/return
+1678 
+1679 test-next-word-or-expression-returns-empty-expression-on-eof:
+1680     # . prolog
+1681     55/push-EBP
+1682     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+1683     # setup
+1684     # . clear-stream(_test-input-stream)
+1685     # . . push args
+1686     68/push  _test-input-stream/imm32
+1687     # . . call
+1688     e8/call  clear-stream/disp32
+1689     # . . discard args
+1690     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+1691     # var slice/ECX = {0, 0}
+1692     68/push  0/imm32/end
+1693     68/push  0/imm32/start
+1694     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+1695     # write nothing to _test-input-stream
+1696     # next-word-or-expression(_test-input-stream, slice)
+1697     # . . push args
+1698     51/push-ECX
+1699     68/push  _test-input-stream/imm32
+1700     # . . call
+1701     e8/call  next-word-or-expression/disp32
+1702     # . . discard args
+1703     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1704     # check-ints-equal(slice->end - slice->start, 0, msg)
+1705     # . . push args
+1706     68/push  "F - test-next-word-or-expression-returns-empty-expression-on-eof"/imm32
+1707     68/push  0/imm32
+1708     # . . push slice->end - slice->start
+1709     8b/copy                         1/mod/*+disp8   1/rm32/ECX    .           .             .           0/r32/EAX   4/disp8         .                 # copy *(ECX+4) to EAX
+1710     2b/subtract                     0/mod/indirect  1/rm32/ECX    .           .             .           0/r32/EAX   .               .                 # subtract *ECX from EAX
+1711     50/push-EAX
+1712     # . . call
+1713     e8/call  check-ints-equal/disp32
+1714     # . . discard args
+1715     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+1716     # . epilog
+1717     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+1718     5d/pop-to-EBP
+1719     c3/return
+1720 
+1721 test-next-word-or-expression-returns-whole-expression:
+1722     # . prolog
+1723     55/push-EBP
+1724     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+1725     # setup
+1726     # . clear-stream(_test-input-stream)
+1727     # . . push args
+1728     68/push  _test-input-stream/imm32
+1729     # . . call
+1730     e8/call  clear-stream/disp32
+1731     # . . discard args
+1732     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+1733     # var slice/ECX = {0, 0}
+1734     68/push  0/imm32/end
+1735     68/push  0/imm32/start
+1736     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+1737     # write(_test-input-stream, " *(a b)/imm32 ")
+1738     # . . push args
+1739     68/push  " *(a b)/imm32 "/imm32
+1740     68/push  _test-input-stream/imm32
+1741     # . . call
+1742     e8/call  write/disp32
+1743     # . . discard args
+1744     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1745     # next-word-or-expression(_test-input-stream, slice)
+1746     # . . push args
+1747     51/push-ECX
+1748     68/push  _test-input-stream/imm32
+1749     # . . call
+1750     e8/call  next-word-or-expression/disp32
+1751     # . . discard args
+1752     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1753     # check-ints-equal(slice->start - _test-input-stream->data, 1, msg)
+1754     # . check-ints-equal(slice->start - _test-input-stream, 13, msg)
+1755     # . . push args
+1756     68/push  "F - test-next-word-or-expression-returns-whole-expression: start"/imm32
+1757     68/push  0xd/imm32
+1758     # . . push slice->start - _test-input-stream
+1759     8b/copy                         0/mod/indirect  1/rm32/ECX    .           .             .           0/r32/EAX   .               .                 # copy *ECX to EAX
+1760     81          5/subop/subtract    3/mod/direct    0/rm32/EAX    .           .             .           .           .               _test-input-stream/imm32 # subtract from EAX
+1761     50/push-EAX
+1762     # . . call
+1763     e8/call  check-ints-equal/disp32
+1764     # . . discard args
+1765     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+1766     # check-ints-equal(slice->end - _test-input-stream->data, 13, msg)
+1767     # . check-ints-equal(slice->end - _test-input-stream, 25, msg)
+1768     # . . push args
+1769     68/push  "F - test-next-word-or-expression-returns-whole-expression: end"/imm32
+1770     68/push  0x19/imm32
+1771     # . . push slice->end - _test-input-stream
+1772     8b/copy                         1/mod/*+disp8   1/rm32/ECX    .           .             .           0/r32/EAX   4/disp8         .                 # copy *(ECX+4) to EAX
+1773     81          5/subop/subtract    3/mod/direct    0/rm32/EAX    .           .             .           .           .               _test-input-stream/imm32 # subtract from EAX
+1774     50/push-EAX
+1775     # . . call
+1776     e8/call  check-ints-equal/disp32
+1777     # . . discard args
+1778     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+1779     # . epilog
+1780     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+1781     5d/pop-to-EBP
+1782     c3/return
+1783 
+1784 # Grammar:
+1785 #   *reg                    -> 0/mod reg/rm32
+1786 #   *(reg)                  -> 0/mod reg/rm32
+1787 #   *(reg+disp)             -> 2/mod reg/rm32 disp/disp32
+1788 #   *(reg1+reg2<<s)         -> 2/mod 4/rm32 reg1/base reg2/index s/scale 0/disp32
+1789 #   *(reg1+reg2<<s+disp)    -> 2/mod 4/rm32 reg1/base reg2/index s/scale disp/disp32
+1790 # Intermediate structure: base, index, scale, disp
+1791 # Default values: base: 0, index: 4 (none), scale: 0, disp: 0
+1792 # beware: modifies 'word'
+1793 parse-effective-address:  # word : (address slice) -> base/EAX, index/ECX, scale/EDX, disp/EBX
+1794     # pseudocode:
+1795     #   ++word->start to skip '*'
+1796     #   initialize defaults: base=0, index=4, scale=0, disp=0
+1797     #   if (*word->start != '(') {
+1798     #     base = get-slice(Registers, word, row-size=8)
+1799     #     return
+1800     #   }
+1801     #   # compound expressions
+1802     #   skip whitespace
+1803     #   read register into base
+1804     #   skip whitespace
+1805     #   if (*word->start == ')') goto end
+1806     #   if (*word->start == '-') goto displacement
+1807     #   if (*word->start != '+') goto error2
+1808     #   ++word->start to skip '+'
+1809     #   skip whitespace
+1810     #   if next 3 characters don't make a register, goto displacement
+1811     #   read register into index
+1812     #   skip whitespace
+1813     #   if (*word->start == ')') goto end
+1814     #   if (*word->start == '<') {
+1815     #     ++word->start to skip '<'
+1816     #     if (*word->start != '<') goto error3
+1817     #     ++word->start to skip '<'
+1818     #     skip whitespace
+1819     #     read integer into scale
+1820     #     skip whitespace
+1821     #     if (*word->start == ')') goto end
+1822     #   }
+1823     #   if (*word->start not in '+' '-') goto error4
+1824     # displacement:
+1825     #   read integer into disp
+1826     #   skip whitespace
+1827     #   if (*word->start != ')') goto error5
+1828     # . prolog
+1829     55/push-EBP
+1830     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+1831     # . save registers
+1832     56/push-ESI
+1833     57/push-EDI
+1834     # ESI = word
+1835     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           6/r32/ESI   8/disp8         .                 # copy *(EBP+8) to ESI
+1836     # ++word->start to skip '*'
+1837     ff          0/subop/increment   0/mod/indirect  6/rm32/ESI    .           .             .           .           .               .                 # increment *ESI
+1838     # initialize defaults
+1839     # base is in EDI; we'll move it to EAX just before we return
+1840     bf/copy-to-EDI  0/imm32
+1841     b9/copy-to-ECX  4/imm32/no-index
+1842     ba/copy-to-EDX  0/imm32/.scale
+1843     bb/copy-to-EBX  0/imm32/disp
+1844 $parse-effective-address:check-for-simple-register:
+1845     # if (*word->start == '(') goto compound expression
+1846     8b/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           0/r32/EAX   .               .                 # copy *ESI to EAX
+1847     8a/copy-byte                    0/mod/indirect  0/rm32/EAX    .           .             .           0/r32/AL    .               .                 # copy byte at *EAX to AL
+1848     81          4/subop/and         3/mod/direct    0/rm32/EAX    .           .             .           .           .               0xff/imm32        # bitwise and of EAX
+1849     3d/compare-EAX-and  0x28/imm32/open-paren
+1850     74/jump-if-equal  $parse-effective-address:compound-expression/disp8
+1851 $parse-effective-address:simple-register:
+1852     # base = get-slice(Registers, word, row-size=8)
+1853     # . EAX = get-slice(Registers, word, row-size=8)
+1854     # . . push args
+1855     68/push  "Registers"/imm32
+1856     68/push  8/imm32/row-size
+1857     56/push-ESI
+1858     68/push  Registers/imm32
+1859     # . . call
+1860     e8/call  get-slice/disp32
+1861     # . . discard args
+1862     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x10/imm32        # add to ESP
+1863     # . base = *EAX
+1864     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           7/r32/EDI   .               .                 # copy *EAX to EDI
+1865     # return
+1866     e9/jump  $parse-effective-address:end/disp32
+1867 $parse-effective-address:compound-expression:
+1868     # ++word->start to skip '('
+1869     ff          0/subop/increment   0/mod/indirect  6/rm32/ESI    .           .             .           .           .               .                 # increment *ESI
+1870     # skip whitespace
+1871     # . EAX = skip-chars-matching-whitespace-in-slice(word->start, word->end)
+1872     # . . push args
+1873     ff          6/subop/push        1/mod/*+disp8   6/rm32/ESI    .           .             .           .           4/disp8         .                 # push *(ESI+4)
+1874     ff          6/subop/push        0/mod/indirect  6/rm32/ESI    .           .             .           .           .               .                 # push *ESI
+1875     # . . call
+1876     e8/call  skip-chars-matching-whitespace-in-slice/disp32
+1877     # . . discard args
+1878     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1879     # . word->start = EAX
+1880     89/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           0/r32/EAX   .               .                 # copy EAX to *ESI
+1881     # read register into base
+1882     # . EAX = next-register(word)
+1883     # . . push args
+1884     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
+1885     # . . call
+1886     e8/call  next-register/disp32
+1887     # . . discard args
+1888     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+1889     # . EDI = *EAX
+1890     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           7/r32/EDI   .               .                 # copy *EAX to EDI
+1891     # skip whitespace
+1892     # . EAX = skip-chars-matching-whitespace-in-slice(word->start, word->end)
+1893     # . . push args
+1894     ff          6/subop/push        1/mod/*+disp8   6/rm32/ESI    .           .             .           .           4/disp8         .                 # push *(ESI+4)
+1895     ff          6/subop/push        0/mod/indirect  6/rm32/ESI    .           .             .           .           .               .                 # push *ESI
+1896     # . . call
+1897     e8/call  skip-chars-matching-whitespace-in-slice/disp32
+1898     # . . discard args
+1899     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1900     # . word->start = EAX
+1901     89/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           0/r32/EAX   .               .                 # copy EAX to *ESI
+1902     # if (*word->start == ')') goto end
+1903     8a/copy-byte                    0/mod/indirect  0/rm32/EAX    .           .             .           0/r32/AL    .               .                 # copy byte at *EAX to AL
+1904     81          4/subop/and         3/mod/direct    0/rm32/EAX    .           .             .           .           .               0xff/imm32        # bitwise and of EAX
+1905     3d/compare-EAX-and  0x29/imm32/close-paren
+1906     0f 84/jump-if-equal  $parse-effective-address:end/disp32
+1907     # if (*word->start == '-') goto displacement
+1908     3d/compare-EAX-and  0x2d/imm32/minus
+1909     0f 84/jump-if-equal  $parse-effective-address:displacement/disp32
+1910     # if (*word->start != '+') goto error2
+1911 $parse-effective-address:check-for-index:
+1912     # ++word->start to skip '+'
+1913     ff          0/subop/increment   0/mod/indirect  6/rm32/ESI    .           .             .           .           .               .                 # increment *ESI
+1914     # skip whitespace
+1915     # . EAX = skip-chars-matching-whitespace-in-slice(word->start, word->end)
+1916     # . . push args
+1917     ff          6/subop/push        1/mod/*+disp8   6/rm32/ESI    .           .             .           .           4/disp8         .                 # push *(ESI+4)
+1918     ff          6/subop/push        0/mod/indirect  6/rm32/ESI    .           .             .           .           .               .                 # push *ESI
+1919     # . . call
+1920     e8/call  skip-chars-matching-whitespace-in-slice/disp32
+1921     # . . discard args
+1922     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1923     # . word->start = EAX
+1924     89/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           0/r32/EAX   .               .                 # copy EAX to *ESI
+1925 $parse-effective-address:resolve-ambiguity:
+1926     # if next 3 characters don't make a register, goto displacement
+1927     # . spill ECX
+1928     51/push-ECX
+1929     # . var tmp/ECX = {word->start, word->start+3}
+1930     # . . ECX = word->start
+1931     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           0/r32/EAX   .               .                 # copy EAX to ECX
+1932     # . . EAX = word->start+3
+1933     05/add-to-EAX  3/imm32
+1934     # . . push
+1935     50/push-EAX
+1936     51/push-ECX
+1937     # . . copy ESP to ECX
+1938     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+1939     # . EAX = maybe-get-slice(Register, tmp, row-size=8)
+1940     # . . push args
+1941     68/push  8/imm32/row-size
+1942     51/push-ECX
+1943     68/push  Registers/imm32
+1944     # . . call
+1945     e8/call  maybe-get-slice/disp32
+1946     # . . discard args
+1947     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+1948     # . reclaim tmp
+1949     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1950     # . restore ECX
+1951     59/pop-to-ECX
+1952     # . if (EAX == 0) goto displacement
+1953     3d/compare-EAX-and  0/imm32
+1954     0f 84/jump-if-equal  $parse-effective-address:displacement/disp32
+1955 $parse-effective-address:index:
+1956     # read register into index
+1957     # . EAX = next-register(word)
+1958     # . . push args
+1959     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
+1960     # . . call
+1961     e8/call  next-register/disp32
+1962     # . . discard args
+1963     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+1964     # . ECX = *EAX
+1965     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
+1966     # skip whitespace
+1967     # . EAX = skip-chars-matching-whitespace-in-slice(word->start, word->end)
+1968     # . . push args
+1969     ff          6/subop/push        1/mod/*+disp8   6/rm32/ESI    .           .             .           .           4/disp8         .                 # push *(ESI+4)
+1970     ff          6/subop/push        0/mod/indirect  6/rm32/ESI    .           .             .           .           .               .                 # push *ESI
+1971     # . . call
+1972     e8/call  skip-chars-matching-whitespace-in-slice/disp32
+1973     # . . discard args
+1974     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+1975     # . word->start = EAX
+1976     89/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           0/r32/EAX   .               .                 # copy EAX to *ESI
+1977     # if (*word->start == ')') goto end
+1978     8a/copy-byte                    0/mod/indirect  0/rm32/EAX    .           .             .           0/r32/AL    .               .                 # copy byte at *EAX to AL
+1979     81          4/subop/and         3/mod/direct    0/rm32/EAX    .           .             .           .           .               0xff/imm32        # bitwise and of EAX
+1980     3d/compare-EAX-and  0x29/imm32/close-paren
+1981     74/jump-if-equal  $parse-effective-address:end/disp8
+1982 $parse-effective-address:check-for-scale:
+1983     # if (*word->start != '<') goto next check
+1984     3d/compare-EAX-and  0x3c/imm32/less-than
+1985     75/jump-if-not-equal  $parse-effective-address:check-for-displacement/disp8
+1986     # ++word->start to skip '<'
+1987     ff          0/subop/increment   0/mod/indirect  6/rm32/ESI    .           .             .           .           .               .                 # increment *ESI
+1988     # if (*word->start != '<') goto error3
+1989     # ++word->start to skip '<'
+1990     ff          0/subop/increment   0/mod/indirect  6/rm32/ESI    .           .             .           .           .               .                 # increment *ESI
+1991     # skip whitespace
+1992     # . EAX = skip-chars-matching-whitespace-in-slice(word->start, word->end)
+1993     # . . push args
+1994     ff          6/subop/push        1/mod/*+disp8   6/rm32/ESI    .           .             .           .           4/disp8         .                 # push *(ESI+4)
+1995     ff          6/subop/push        0/mod/indirect  6/rm32/ESI    .           .             .           .           .               .                 # push *ESI
+1996     # . . call
+1997     e8/call  skip-chars-matching-whitespace-in-slice/disp32
+1998     # . . discard args
+1999     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+2000     # . word->start = EAX
+2001     89/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           0/r32/EAX   .               .                 # copy EAX to *ESI
+2002 $parse-effective-address:scale:
+2003     # read positive integer into scale
+2004     # . EAX = next-positive-hex-int(word)
+2005     # . . push args
+2006     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
+2007     # . . call
+2008     e8/call  next-positive-hex-int/disp32
+2009     # . . discard args
+2010     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+2011     # . EDX = EAX
+2012     89/copy                         3/mod/direct    2/rm32/EDX    .           .             .           0/r32/EAX   .               .                 # copy EAX to EDX
+2013     # skip whitespace
+2014     # . EAX = skip-chars-matching-whitespace-in-slice(word->start, word->end)
+2015     # . . push args
+2016     ff          6/subop/push        1/mod/*+disp8   6/rm32/ESI    .           .             .           .           4/disp8         .                 # push *(ESI+4)
+2017     ff          6/subop/push        0/mod/indirect  6/rm32/ESI    .           .             .           .           .               .                 # push *ESI
+2018     # . . call
+2019     e8/call  skip-chars-matching-whitespace-in-slice/disp32
+2020     # . . discard args
+2021     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+2022     # . word->start = EAX
+2023     89/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           0/r32/EAX   .               .                 # copy EAX to *ESI
+2024     # if (*word->start == ')') goto end
+2025     8a/copy-byte                    0/mod/indirect  0/rm32/EAX    .           .             .           0/r32/AL    .               .                 # copy byte at *EAX to AL
+2026     81          4/subop/and         3/mod/direct    0/rm32/EAX    .           .             .           .           .               0xff/imm32        # bitwise and of EAX
+2027     3d/compare-EAX-and  0x29/imm32/close-paren
+2028     74/jump-if-equal  $parse-effective-address:end/disp8
+2029 $parse-effective-address:check-for-displacement:
+2030     # if (*word->start not in '+' '-') goto error4
+2031 $parse-effective-address:displacement:
+2032     # read integer into disp
+2033     # . EAX = next-hex-int(word)
+2034     # . . push args
+2035     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
+2036     # . . call
+2037     e8/call  next-hex-int/disp32
+2038     # . . discard args
+2039     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+2040     # . EBX = EAX
+2041     89/copy                         3/mod/direct    3/rm32/EBX    .           .             .           0/r32/EAX   .               .                 # copy EAX to EBX
+2042     # skip whitespace
+2043     # . EAX = skip-chars-matching-whitespace-in-slice(word->start, word->end)
+2044     # . . push args
+2045     ff          6/subop/push        1/mod/*+disp8   6/rm32/ESI    .           .             .           .           4/disp8         .                 # push *(ESI+4)
+2046     ff          6/subop/push        0/mod/indirect  6/rm32/ESI    .           .             .           .           .               .                 # push *ESI
+2047     # . . call
+2048     e8/call  skip-chars-matching-whitespace-in-slice/disp32
+2049     # . . discard args
+2050     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+2051     # . word->start = EAX
+2052     89/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           0/r32/EAX   .               .                 # copy EAX to *ESI
+2053     # if (*word->start != ')') goto error5
+2054 $parse-effective-address:end:
+2055     # return base in EAX
+2056     89/copy                         3/mod/direct    0/rm32/EAX    .           .             .           7/r32/EDI   .               .                 # copy EDI to EAX
+2057     # . restore registers
+2058     5f/pop-to-EDI
+2059     5e/pop-to-ESI
+2060     # . epilog
+2061     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+2062     5d/pop-to-EBP
+2063     c3/return
+2064 
+2065 # assumes 'in' starts with a register name, and returns pointer to its code
+2066 # side-effect: modifies 'in' to scan past the initial register name
+2067 next-register:  # in : (address slice) -> reg/EAX : int
+2068     # . prolog
+2069     55/push-EBP
+2070     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+2071     # . save registers
+2072     51/push-ECX
+2073     56/push-ESI
+2074     # ESI = in
+2075     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           6/r32/ESI   8/disp8         .                 # copy *(EBP+8) to ESI
+2076     # var reg-slice/ECX : (address slice) = {in->start, in->start + 3}
+2077     8b/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           0/r32/EAX   .               .                 # copy *ESI to EAX
+2078     05/add-to-EAX  3/imm32
+2079     50/push-EAX
+2080     ff          6/subop/push        0/mod/indirect  6/rm32/ESI    .           .             .           .           .               .                 # push *ESI
+2081     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+2082     # in->start += 3
+2083     81          0/subop/add         0/mod/indirect  6/rm32/ESI    .           .             .           .           .               3/imm32           # add to *ESI
+2084     # EAX = get-slice(Registers, word, row-size=8)
+2085     # . . push args
+2086     68/push  "next-register"/imm32
+2087     68/push  8/imm32/row-size
+2088     51/push-ECX
+2089     68/push  Registers/imm32
+2090     # . . call
+2091     e8/call  get-slice/disp32
+2092     # . . discard args
+2093     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x10/imm32        # add to ESP
+2094 $next-register:end:
+2095     # reclaim locals
+2096     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+2097     # . restore registers
+2098     5e/pop-to-ESI
+2099     59/pop-to-ECX
+2100     # . epilog
+2101     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+2102     5d/pop-to-EBP
+2103     c3/return
+2104 
+2105 test-parse-effective-address-simple:
+2106     # . prolog
+2107     55/push-EBP
+2108     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+2109     # var slice/ECX = "*esi"
+2110     b8/copy-to-EAX  "*esi"/imm32
+2111     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
+2112     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
+2113     05/add-to-EAX  4/imm32
+2114     # . ECX = {EAX, ECX}
+2115     51/push-ECX
+2116     50/push-EAX
+2117     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+2118     # EAX, ECX, EDX, EBX = parse-effective-address(slice)
+2119     # . . push args
+2120     51/push-ECX
+2121     # . . call
+2122     e8/call  parse-effective-address/disp32
+2123     # . . discard args
+2124     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+2125     # slice clobbered beyond this point
+2126     # check-ints-equal(EAX, 6, msg)
+2127     # . . push args
+2128     68/push  "F - test-parse-effective-address-simple/base"/imm32
+2129     68/push  6/imm32/ESI
+2130     50/push-EAX
+2131     # . . call
+2132     e8/call  check-ints-equal/disp32
+2133     # . . discard args
+2134     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2135     # check-ints-equal(ECX, 4, msg)
+2136     # . . push args
+2137     68/push  "F - test-parse-effective-address-simple/index"/imm32
+2138     68/push  4/imm32/none
+2139     51/push-ECX
+2140     # . . call
+2141     e8/call  check-ints-equal/disp32
+2142     # . . discard args
+2143     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2144     # check-ints-equal(EDX, 0, msg)
+2145     # . . push args
+2146     68/push  "F - test-parse-effective-address-simple/scale"/imm32
+2147     68/push  0/imm32/none
+2148     52/push-EDX
+2149     # . . call
+2150     e8/call  check-ints-equal/disp32
+2151     # . . discard args
+2152     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2153     # check-ints-equal(EBX, 0, msg)
+2154     # . . push args
+2155     68/push  "F - test-parse-effective-address-simple/displacement"/imm32
+2156     68/push  0/imm32/none
+2157     53/push-EBX
+2158     # . . call
+2159     e8/call  check-ints-equal/disp32
+2160     # . . discard args
+2161     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2162     # . epilog
+2163     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+2164     5d/pop-to-EBP
+2165     c3/return
+2166 
+2167 test-parse-effective-address-base:
+2168     # . prolog
+2169     55/push-EBP
+2170     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+2171     # var slice/ECX = "*(esi  )"
+2172     b8/copy-to-EAX  "*(esi  )"/imm32
+2173     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
+2174     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
+2175     05/add-to-EAX  4/imm32
+2176     # . ECX = {EAX, ECX}
+2177     51/push-ECX
+2178     50/push-EAX
+2179     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+2180     # EAX, ECX, EDX, EBX = parse-effective-address(slice)
+2181     # . . push args
+2182     51/push-ECX
+2183     # . . call
+2184     e8/call  parse-effective-address/disp32
+2185     # . . discard args
+2186     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+2187     # slice clobbered beyond this point
+2188     # check-ints-equal(EAX, 6, msg)
+2189     # . . push args
+2190     68/push  "F - test-parse-effective-address-base/base"/imm32
+2191     68/push  6/imm32/ESI
+2192     50/push-EAX
+2193     # . . call
+2194     e8/call  check-ints-equal/disp32
+2195     # . . discard args
+2196     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2197     # check-ints-equal(ECX, 4, msg)
+2198     # . . push args
+2199     68/push  "F - test-parse-effective-address-base/index"/imm32
+2200     68/push  4/imm32/none
+2201     51/push-ECX
+2202     # . . call
+2203     e8/call  check-ints-equal/disp32
+2204     # . . discard args
+2205     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2206     # check-ints-equal(EDX, 0, msg)
+2207     # . . push args
+2208     68/push  "F - test-parse-effective-address-base/scale"/imm32
+2209     68/push  0/imm32/none
+2210     52/push-EDX
+2211     # . . call
+2212     e8/call  check-ints-equal/disp32
+2213     # . . discard args
+2214     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2215     # check-ints-equal(EBX, 0, msg)
+2216     # . . push args
+2217     68/push  "F - test-parse-effective-address-base/displacement"/imm32
+2218     68/push  0/imm32/none
+2219     53/push-EBX
+2220     # . . call
+2221     e8/call  check-ints-equal/disp32
+2222     # . . discard args
+2223     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2224     # . epilog
+2225     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+2226     5d/pop-to-EBP
+2227     c3/return
+2228 
+2229 test-parse-effective-address-base-displacement:
+2230     # . prolog
+2231     55/push-EBP
+2232     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+2233     # var slice/ECX = "*(esi+3)"
+2234     b8/copy-to-EAX  "*(esi+3)"/imm32
+2235     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
+2236     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
+2237     05/add-to-EAX  4/imm32
+2238     # . ECX = {EAX, ECX}
+2239     51/push-ECX
+2240     50/push-EAX
+2241     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+2242     # EAX, ECX, EDX, EBX = parse-effective-address(slice)
+2243     # . . push args
+2244     51/push-ECX
+2245     # . . call
+2246     e8/call  parse-effective-address/disp32
+2247     # . . discard args
+2248     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+2249     # slice clobbered beyond this point
+2250     # check-ints-equal(EAX, 6, msg)
+2251     # . . push args
+2252     68/push  "F - test-parse-effective-address-base-displacement/base"/imm32
+2253     68/push  6/imm32/ESI
+2254     50/push-EAX
+2255     # . . call
+2256     e8/call  check-ints-equal/disp32
+2257     # . . discard args
+2258     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2259     # check-ints-equal(ECX, 4, msg)
+2260     # . . push args
+2261     68/push  "F - test-parse-effective-address-base-displacement/index"/imm32
+2262     68/push  4/imm32/none
+2263     51/push-ECX
+2264     # . . call
+2265     e8/call  check-ints-equal/disp32
+2266     # . . discard args
+2267     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2268     # check-ints-equal(EDX, 0, msg)
+2269     # . . push args
+2270     68/push  "F - test-parse-effective-address-base-displacement/scale"/imm32
+2271     68/push  0/imm32/none
+2272     52/push-EDX
+2273     # . . call
+2274     e8/call  check-ints-equal/disp32
+2275     # . . discard args
+2276     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2277     # check-ints-equal(EBX, 3, msg)
+2278     # . . push args
+2279     68/push  "F - test-parse-effective-address-base-displacement/displacement"/imm32
+2280     68/push  3/imm32
+2281     53/push-EBX
+2282     # . . call
+2283     e8/call  check-ints-equal/disp32
+2284     # . . discard args
+2285     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2286     # . epilog
+2287     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+2288     5d/pop-to-EBP
+2289     c3/return
+2290 
+2291 test-parse-effective-address-base-negative-displacement:
+2292     # . prolog
+2293     55/push-EBP
+2294     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+2295     # var slice/ECX = "*(esi-3)"
+2296     b8/copy-to-EAX  "*(esi-3)"/imm32
+2297     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
+2298     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
+2299     05/add-to-EAX  4/imm32
+2300     # . ECX = {EAX, ECX}
+2301     51/push-ECX
+2302     50/push-EAX
+2303     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+2304     # EAX, ECX, EDX, EBX = parse-effective-address(slice)
+2305     # . . push args
+2306     51/push-ECX
+2307     # . . call
+2308     e8/call  parse-effective-address/disp32
+2309     # . . discard args
+2310     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+2311     # slice clobbered beyond this point
+2312     # check-ints-equal(EAX, 6, msg)
+2313     # . . push args
+2314     68/push  "F - test-parse-effective-address-base-negative-displacement/base"/imm32
+2315     68/push  6/imm32/ESI
+2316     50/push-EAX
+2317     # . . call
+2318     e8/call  check-ints-equal/disp32
+2319     # . . discard args
+2320     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2321     # check-ints-equal(ECX, 4, msg)
+2322     # . . push args
+2323     68/push  "F - test-parse-effective-address-base-negative-displacement/index"/imm32
+2324     68/push  4/imm32/none
+2325     51/push-ECX
+2326     # . . call
+2327     e8/call  check-ints-equal/disp32
+2328     # . . discard args
+2329     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2330     # check-ints-equal(EDX, 0, msg)
+2331     # . . push args
+2332     68/push  "F - test-parse-effective-address-base-negative-displacement/scale"/imm32
+2333     68/push  0/imm32/none
+2334     52/push-EDX
+2335     # . . call
+2336     e8/call  check-ints-equal/disp32
+2337     # . . discard args
+2338     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2339     # check-ints-equal(EBX, -3, msg)
+2340     # . . push args
+2341     68/push  "F - test-parse-effective-address-base-negative-displacement/displacement"/imm32
+2342     68/push  -3/imm32
+2343     53/push-EBX
+2344     # . . call
+2345     e8/call  check-ints-equal/disp32
+2346     # . . discard args
+2347     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2348     # . epilog
+2349     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+2350     5d/pop-to-EBP
+2351     c3/return
+2352 
+2353 test-parse-effective-address-base-index:
+2354     # . prolog
+2355     55/push-EBP
+2356     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+2357     # var slice/ECX = "*(esi+ecx)"
+2358     b8/copy-to-EAX  "*(esi+ecx)"/imm32
+2359     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
+2360     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
+2361     05/add-to-EAX  4/imm32
+2362     # . ECX = {EAX, ECX}
+2363     51/push-ECX
+2364     50/push-EAX
+2365     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+2366     # EAX, ECX, EDX, EBX = parse-effective-address(slice)
+2367     # . . push args
+2368     51/push-ECX
+2369     # . . call
+2370     e8/call  parse-effective-address/disp32
+2371     # . . discard args
+2372     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+2373     # slice clobbered beyond this point
+2374     # check-ints-equal(EAX, 6, msg)
+2375     # . . push args
+2376     68/push  "F - test-parse-effective-address-base-index/base"/imm32
+2377     68/push  6/imm32/ESI
+2378     50/push-EAX
+2379     # . . call
+2380     e8/call  check-ints-equal/disp32
+2381     # . . discard args
+2382     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2383     # check-ints-equal(ECX, 1, msg)
+2384     # . . push args
+2385     68/push  "F - test-parse-effective-address-base-index/index"/imm32
+2386     68/push  1/imm32/none
+2387     51/push-ECX
+2388     # . . call
+2389     e8/call  check-ints-equal/disp32
+2390     # . . discard args
+2391     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2392     # check-ints-equal(EDX, 0, msg)
+2393     # . . push args
+2394     68/push  "F - test-parse-effective-address-base-index/scale"/imm32
+2395     68/push  0/imm32/none
+2396     52/push-EDX
+2397     # . . call
+2398     e8/call  check-ints-equal/disp32
+2399     # . . discard args
+2400     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2401     # check-ints-equal(EBX, 0, msg)
+2402     # . . push args
+2403     68/push  "F - test-parse-effective-address-base-index/displacement"/imm32
+2404     68/push  0/imm32
+2405     53/push-EBX
+2406     # . . call
+2407     e8/call  check-ints-equal/disp32
+2408     # . . discard args
+2409     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2410     # . epilog
+2411     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+2412     5d/pop-to-EBP
+2413     c3/return
+2414 
+2415 test-parse-effective-address-base-index-scale:
+2416     # . prolog
+2417     55/push-EBP
+2418     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+2419     # var slice/ECX = "*(esi+ecx<<2)"
+2420     b8/copy-to-EAX  "*(esi+ecx<<2)"/imm32
+2421     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
+2422     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
+2423     05/add-to-EAX  4/imm32
+2424     # . ECX = {EAX, ECX}
+2425     51/push-ECX
+2426     50/push-EAX
+2427     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+2428     # EAX, ECX, EDX, EBX = parse-effective-address(slice)
+2429     # . . push args
+2430     51/push-ECX
+2431     # . . call
+2432     e8/call  parse-effective-address/disp32
+2433     # . . discard args
+2434     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+2435     # slice clobbered beyond this point
+2436     # check-ints-equal(EAX, 6, msg)
+2437     # . . push args
+2438     68/push  "F - test-parse-effective-address-base-index-scale/base"/imm32
+2439     68/push  6/imm32/ESI
+2440     50/push-EAX
+2441     # . . call
+2442     e8/call  check-ints-equal/disp32
+2443     # . . discard args
+2444     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2445     # check-ints-equal(ECX, 1, msg)
+2446     # . . push args
+2447     68/push  "F - test-parse-effective-address-base-index-scale/index"/imm32
+2448     68/push  1/imm32/none
+2449     51/push-ECX
+2450     # . . call
+2451     e8/call  check-ints-equal/disp32
+2452     # . . discard args
+2453     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2454     # check-ints-equal(EDX, 2, msg)
+2455     # . . push args
+2456     68/push  "F - test-parse-effective-address-base-index-scale/scale"/imm32
+2457     68/push  2/imm32
+2458     52/push-EDX
+2459     # . . call
+2460     e8/call  check-ints-equal/disp32
+2461     # . . discard args
+2462     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2463     # check-ints-equal(EBX, 0, msg)
+2464     # . . push args
+2465     68/push  "F - test-parse-effective-address-base-index-scale/displacement"/imm32
+2466     68/push  0/imm32
+2467     53/push-EBX
+2468     # . . call
+2469     e8/call  check-ints-equal/disp32
+2470     # . . discard args
+2471     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2472     # . epilog
+2473     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+2474     5d/pop-to-EBP
+2475     c3/return
+2476 
+2477 test-parse-effective-address-base-index-scale-displacement:
+2478     # . prolog
+2479     55/push-EBP
+2480     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+2481     # var slice/ECX = "*(esi + ecx<<2 - 0x34)"
+2482     b8/copy-to-EAX  "*(esi + ecx<<2 - 0x34)"/imm32
+2483     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
+2484     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
+2485     05/add-to-EAX  4/imm32
+2486     # . ECX = {EAX, ECX}
+2487     51/push-ECX
+2488     50/push-EAX
+2489     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+2490     # EAX, ECX, EDX, EBX = parse-effective-address(slice)
+2491     # . . push args
+2492     51/push-ECX
+2493     # . . call
+2494     e8/call  parse-effective-address/disp32
+2495     # . . discard args
+2496     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+2497     # slice clobbered beyond this point
+2498     # check-ints-equal(EAX, 6, msg)
+2499     # . . push args
+2500     68/push  "F - test-parse-effective-address-base-index-scale/base"/imm32
+2501     68/push  6/imm32/ESI
+2502     50/push-EAX
+2503     # . . call
+2504     e8/call  check-ints-equal/disp32
+2505     # . . discard args
+2506     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2507     # check-ints-equal(ECX, 1, msg)
+2508     # . . push args
+2509     68/push  "F - test-parse-effective-address-base-index-scale/index"/imm32
+2510     68/push  1/imm32/none
+2511     51/push-ECX
+2512     # . . call
+2513     e8/call  check-ints-equal/disp32
+2514     # . . discard args
+2515     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2516     # check-ints-equal(EDX, 2, msg)
+2517     # . . push args
+2518     68/push  "F - test-parse-effective-address-base-index-scale/scale"/imm32
+2519     68/push  2/imm32
+2520     52/push-EDX
+2521     # . . call
+2522     e8/call  check-ints-equal/disp32
+2523     # . . discard args
+2524     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2525     # check-ints-equal(EBX, -0x34, msg)
+2526     # . . push args
+2527     68/push  "F - test-parse-effective-address-base-index-scale/displacement"/imm32
+2528     68/push  -0x34/imm32
+2529     53/push-EBX
+2530     # . . call
+2531     e8/call  check-ints-equal/disp32
+2532     # . . discard args
+2533     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2534     # . epilog
+2535     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+2536     5d/pop-to-EBP
+2537     c3/return
+2538 
+2539 # Code generation:
+2540 #   if index is none and disp is 0, then mod = 0 and rm32 = base
+2541 #   if index is none, then mod = 2 and rm32 = base and disp32 = disp
+2542 #   if index is not none, then mod = 2 and rm32 = 4 and base = base and index = index and disp32 = disp
+2543 emit-indirect-mode:  # out : (address buffered-file), base : int, index : int, scale : int, disp : int
+2544     # . prolog
+2545     55/push-EBP
+2546     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+2547 $emit-indirect-mode:check-for-sib:
+2548     # if (index == 4/none) goto next check
+2549     81          7/subop/compare     1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0x10/disp8      4/imm32           # compare *(EBP+16)
+2550     0f 84/jump-if-equal  $emit-indirect-mode:check-for-disp/disp32
+2551 $emit-indirect-mode:emit-sib:
+2552     # emit(out, "2/mod/indirect 4/rm32/sib " base "/base " index "/index " scale "/scale " disp "/disp32")
+2553     # . write-buffered(out, "2/mod/*+disp32 4/rm32/sib ")
+2554     # . . push args
+2555     68/push  "2/mod/*+disp32 4/rm32/sib "/imm32
+2556     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
+2557     # . . call
+2558     e8/call  write-buffered/disp32
+2559     # . . discard args
+2560     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+2561     # . print-int32-buffered(out, base)
+2562     # . . push args
+2563     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
+2564     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
+2565     # . . call
+2566     e8/call  print-int32-buffered/disp32
+2567     # . . discard args
+2568     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+2569     # . write-buffered(out, "/base ")
+2570     # . . push args
+2571     68/push  "/base "/imm32
+2572     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
+2573     # . . call
+2574     e8/call  write-buffered/disp32
+2575     # . . discard args
+2576     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+2577     # . print-int32-buffered(out, index)
+2578     # . . push args
+2579     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0x10/disp8      .                 # push *(EBP+16)
+2580     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
+2581     # . . call
+2582     e8/call  print-int32-buffered/disp32
+2583     # . . discard args
+2584     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+2585     # . write-buffered(out, "/index ")
+2586     # . . push args
+2587     68/push  "/index "/imm32
+2588     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
+2589     # . . call
+2590     e8/call  write-buffered/disp32
+2591     # . . discard args
+2592     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+2593     # . print-int32-buffered(out, scale)
+2594     # . . push args
+2595     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0x14/disp8      .                 # push *(EBP+20)
+2596     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
+2597     # . . call
+2598     e8/call  print-int32-buffered/disp32
+2599     # . . discard args
+2600     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+2601     # . write-buffered(out, "/scale ")
+2602     # . . push args
+2603     68/push  "/scale "/imm32
+2604     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
+2605     # . . call
+2606     e8/call  write-buffered/disp32
+2607     # . . discard args
+2608     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+2609     # . print-int32-buffered(out, disp)
+2610     # . . push args
+2611     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0x18/disp8      .                 # push *(EBP+24)
+2612     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
+2613     # . . call
+2614     e8/call  print-int32-buffered/disp32
+2615     # . . discard args
+2616     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+2617     # . write-buffered(out, "/disp32")
+2618     # . . push args
+2619     68/push  "/disp32"/imm32
+2620     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
+2621     # . . call
+2622     e8/call  write-buffered/disp32
+2623     # . . discard args
+2624     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+2625     e9/jump  $emit-indirect-mode:end/disp32
+2626 $emit-indirect-mode:check-for-disp:
+2627     # if (disp == 0) goto next check
+2628     81          7/subop/compare     1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0x18/disp8      0/imm32           # compare *(EBP+24)
+2629     74/jump-if-equal  $emit-indirect-mode:emit-indirect/disp8
+2630 $emit-indirect-mode:emit-disp:
+2631     # emit(out, "2/mod/*+disp32 " base "/rm32 " disp "/disp32")
+2632     # . write-buffered(out, "2/mod/*+disp32 ")
+2633     # . . push args
+2634     68/push  "2/mod/*+disp32 "/imm32
+2635     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
+2636     # . . call
+2637     e8/call  write-buffered/disp32
+2638     # . . discard args
+2639     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+2640     # . print-int32-buffered(out, base)
+2641     # . . push args
+2642     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
+2643     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
+2644     # . . call
+2645     e8/call  print-int32-buffered/disp32
+2646     # . . discard args
+2647     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+2648     # . write-buffered(out, "/rm32 ")
+2649     # . . push args
+2650     68/push  "/rm32 "/imm32
+2651     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
+2652     # . . call
+2653     e8/call  write-buffered/disp32
+2654     # . . discard args
+2655     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+2656     # . print-int32-buffered(out, disp)
+2657     # . . push args
+2658     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0x18/disp8      .                 # push *(EBP+24)
+2659     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
+2660     # . . call
+2661     e8/call  print-int32-buffered/disp32
+2662     # . . discard args
+2663     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+2664     # . write-buffered(out, "/disp32")
+2665     # . . push args
+2666     68/push  "/disp32"/imm32
+2667     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
+2668     # . . call
+2669     e8/call  write-buffered/disp32
+2670     # . . discard args
+2671     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+2672     eb/jump  $emit-indirect-mode:end/disp8
+2673 $emit-indirect-mode:emit-indirect:
+2674     # emit(out, "0/mod/indirect " base "/rm32")
+2675     # . write-buffered(out, "0/mod/indirect ")
+2676     # . . push args
+2677     68/push  "0/mod/indirect "/imm32
+2678     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
+2679     # . . call
+2680     e8/call  write-buffered/disp32
+2681     # . . discard args
+2682     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+2683     # . print-int32-buffered(out, base)
+2684     # . . push args
+2685     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
+2686     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
+2687     # . . call
+2688     e8/call  print-int32-buffered/disp32
+2689     # . . discard args
+2690     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+2691     # . write-buffered(out, "/rm32")
+2692     # . . push args
+2693     68/push  "/rm32"/imm32
+2694     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
+2695     # . . call
+2696     e8/call  write-buffered/disp32
+2697     # . . discard args
+2698     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+2699 $emit-indirect-mode:end:
+2700     # . epilog
+2701     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+2702     5d/pop-to-EBP
+2703     c3/return
+2704 
+2705 test-emit-indirect-mode:
+2706     # . prolog
+2707     55/push-EBP
+2708     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+2709     # setup
+2710     # . clear-stream(_test-output-stream)
+2711     # . . push args
+2712     68/push  _test-output-stream/imm32
+2713     # . . call
+2714     e8/call  clear-stream/disp32
+2715     # . . discard args
+2716     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+2717     # . clear-stream(_test-output-buffered-file+4)
+2718     # . . push args
+2719     b8/copy-to-EAX  _test-output-buffered-file/imm32
+2720     05/add-to-EAX  4/imm32
+2721     50/push-EAX
+2722     # . . call
+2723     e8/call  clear-stream/disp32
+2724     # . . discard args
+2725     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+2726     # emit-indirect-mode(_test-output-buffered-file, 0, 4/none, 0, 0)
+2727     # . . write args
+2728     68/push  0/imm32/.disp
+2729     68/push  0/imm32/.scale
+2730     68/push  4/imm32/.index/none
+2731     68/push  0/imm32/.base
+2732     68/push  _test-output-buffered-file/imm32
+2733     # . . call
+2734     e8/call  emit-indirect-mode/disp32
+2735     # . . discard args
+2736     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x14/imm32        # add to ESP
+2737     # . flush(_test-output-buffered-file)
+2738     # . . push args
+2739     68/push  _test-output-buffered-file/imm32
+2740     # . . call
+2741     e8/call  flush/disp32
+2742     # . . discard args
+2743     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+2744 +-- 26 lines: #?     # dump output ---------------------------------------------------------------------------------------------------------------------------
+2770     # check-stream-equal(_test-output-stream, "0/mod/indirect 0/rm32", msg)
+2771     # . . push args
+2772     68/push  "F - test-emit-indirect-mode"/imm32
+2773     68/push  "0/mod/indirect 0x00000000/rm32"/imm32
+2774     68/push  _test-output-stream/imm32
+2775     # . . call
+2776     e8/call  check-stream-equal/disp32
+2777     # . . discard args
+2778     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2779     # . epilog
+2780     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+2781     5d/pop-to-EBP
+2782     c3/return
+2783 
+2784 test-emit-indirect-mode-2:
+2785     # . prolog
+2786     55/push-EBP
+2787     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+2788     # setup
+2789     # . clear-stream(_test-output-stream)
+2790     # . . push args
+2791     68/push  _test-output-stream/imm32
+2792     # . . call
+2793     e8/call  clear-stream/disp32
+2794     # . . discard args
+2795     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+2796     # . clear-stream(_test-output-buffered-file+4)
+2797     # . . push args
+2798     b8/copy-to-EAX  _test-output-buffered-file/imm32
+2799     05/add-to-EAX  4/imm32
+2800     50/push-EAX
+2801     # . . call
+2802     e8/call  clear-stream/disp32
+2803     # . . discard args
+2804     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+2805     # emit-indirect-mode(_test-output-buffered-file, 6, 4/none, 0, 0)
+2806     # . . write args
+2807     68/push  0/imm32/.disp
+2808     68/push  0/imm32/.scale
+2809     68/push  4/imm32/.index/none
+2810     68/push  7/imm32/.base
+2811     68/push  _test-output-buffered-file/imm32
+2812     # . . call
+2813     e8/call  emit-indirect-mode/disp32
+2814     # . . discard args
+2815     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x14/imm32        # add to ESP
+2816     # . flush(_test-output-buffered-file)
+2817     # . . push args
+2818     68/push  _test-output-buffered-file/imm32
+2819     # . . call
+2820     e8/call  flush/disp32
+2821     # . . discard args
+2822     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+2823 +-- 26 lines: #?     # dump output ---------------------------------------------------------------------------------------------------------------------------
+2849     # check-stream-equal(_test-output-stream, "0/mod/indirect 7/rm32", msg)
+2850     # . . push args
+2851     68/push  "F - test-emit-indirect-mode-2"/imm32
+2852     68/push  "0/mod/indirect 0x00000007/rm32"/imm32
+2853     68/push  _test-output-stream/imm32
+2854     # . . call
+2855     e8/call  check-stream-equal/disp32
+2856     # . . discard args
+2857     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2858     # . epilog
+2859     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+2860     5d/pop-to-EBP
+2861     c3/return
+2862 
+2863 test-emit-indirect-mode-with-disp:
+2864     # . prolog
+2865     55/push-EBP
+2866     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+2867     # setup
+2868     # . clear-stream(_test-output-stream)
+2869     # . . push args
+2870     68/push  _test-output-stream/imm32
+2871     # . . call
+2872     e8/call  clear-stream/disp32
+2873     # . . discard args
+2874     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+2875     # . clear-stream(_test-output-buffered-file+4)
+2876     # . . push args
+2877     b8/copy-to-EAX  _test-output-buffered-file/imm32
+2878     05/add-to-EAX  4/imm32
+2879     50/push-EAX
+2880     # . . call
+2881     e8/call  clear-stream/disp32
+2882     # . . discard args
+2883     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+2884     # emit-indirect-mode(_test-output-buffered-file, 6, 4/none, 0, 4)
+2885     # . . write args
+2886     68/push  4/imm32/.disp
+2887     68/push  0/imm32/.scale
+2888     68/push  4/imm32/.index/none
+2889     68/push  6/imm32/.base
+2890     68/push  _test-output-buffered-file/imm32
+2891     # . . call
+2892     e8/call  emit-indirect-mode/disp32
+2893     # . . discard args
+2894     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x14/imm32        # add to ESP
+2895     # . flush(_test-output-buffered-file)
+2896     # . . push args
+2897     68/push  _test-output-buffered-file/imm32
+2898     # . . call
+2899     e8/call  flush/disp32
+2900     # . . discard args
+2901     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+2902 +-- 26 lines: #?     # dump output ---------------------------------------------------------------------------------------------------------------------------
+2928     # check-stream-equal(_test-output-stream, "2/mod/*+disp32 6/rm32 4/disp32", msg)
+2929     # . . push args
+2930     68/push  "F - test-emit-indirect-mode-with-disp"/imm32
+2931     68/push  "2/mod/*+disp32 0x00000006/rm32 0x00000004/disp32"/imm32
+2932     68/push  _test-output-stream/imm32
+2933     # . . call
+2934     e8/call  check-stream-equal/disp32
+2935     # . . discard args
+2936     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+2937     # . epilog
+2938     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+2939     5d/pop-to-EBP
+2940     c3/return
+2941 
+2942 test-emit-indirect-mode-with-disp-negative:
+2943     # . prolog
+2944     55/push-EBP
+2945     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+2946     # setup
+2947     # . clear-stream(_test-output-stream)
+2948     # . . push args
+2949     68/push  _test-output-stream/imm32
+2950     # . . call
+2951     e8/call  clear-stream/disp32
+2952     # . . discard args
+2953     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+2954     # . clear-stream(_test-output-buffered-file+4)
+2955     # . . push args
+2956     b8/copy-to-EAX  _test-output-buffered-file/imm32
+2957     05/add-to-EAX  4/imm32
+2958     50/push-EAX
+2959     # . . call
+2960     e8/call  clear-stream/disp32
+2961     # . . discard args
+2962     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+2963     # emit-indirect-mode(_test-output-buffered-file, 6, 4/none, 0, -4)
+2964     # . . write args
+2965     68/push  -4/imm32/.disp
+2966     68/push  0/imm32/.scale
+2967     68/push  4/imm32/.index/none
+2968     68/push  6/imm32/.base
+2969     68/push  _test-output-buffered-file/imm32
+2970     # . . call
+2971     e8/call  emit-indirect-mode/disp32
+2972     # . . discard args
+2973     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x14/imm32        # add to ESP
+2974     # . flush(_test-output-buffered-file)
+2975     # . . push args
+2976     68/push  _test-output-buffered-file/imm32
+2977     # . . call
+2978     e8/call  flush/disp32
+2979     # . . discard args
+2980     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+2981 +-- 26 lines: #?     # dump output ---------------------------------------------------------------------------------------------------------------------------
+3007     # check-stream-equal(_test-output-stream, "2/mod/*+disp32 6/rm32 -4/disp32", msg)
+3008     # . . push args
+3009     68/push  "F - test-emit-indirect-mode-with-disp"/imm32
+3010     68/push  "2/mod/*+disp32 0x00000006/rm32 0xfffffffc/disp32"/imm32
+3011     68/push  _test-output-stream/imm32
+3012     # . . call
+3013     e8/call  check-stream-equal/disp32
+3014     # . . discard args
+3015     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+3016     # . epilog
+3017     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+3018     5d/pop-to-EBP
+3019     c3/return
+3020 
+3021 test-emit-indirect-mode-with-sib:
+3022     # . prolog
+3023     55/push-EBP
+3024     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+3025     # setup
+3026     # . clear-stream(_test-output-stream)
+3027     # . . push args
+3028     68/push  _test-output-stream/imm32
+3029     # . . call
+3030     e8/call  clear-stream/disp32
+3031     # . . discard args
+3032     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+3033     # . clear-stream(_test-output-buffered-file+4)
+3034     # . . push args
+3035     b8/copy-to-EAX  _test-output-buffered-file/imm32
+3036     05/add-to-EAX  4/imm32
+3037     50/push-EAX
+3038     # . . call
+3039     e8/call  clear-stream/disp32
+3040     # . . discard args
+3041     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+3042     # emit-indirect-mode(_test-output-buffered-file, 6/base, 1/index, 2/scale, 4/disp)
+3043     # . . write args
+3044     68/push  4/imm32/.disp
+3045     68/push  2/imm32/.scale
+3046     68/push  1/imm32/.index
+3047     68/push  6/imm32/.base
+3048     68/push  _test-output-buffered-file/imm32
+3049     # . . call
+3050     e8/call  emit-indirect-mode/disp32
+3051     # . . discard args
+3052     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x14/imm32        # add to ESP
+3053     # . flush(_test-output-buffered-file)
+3054     # . . push args
+3055     68/push  _test-output-buffered-file/imm32
+3056     # . . call
+3057     e8/call  flush/disp32
+3058     # . . discard args
+3059     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+3060 +-- 26 lines: #?     # dump output ---------------------------------------------------------------------------------------------------------------------------
+3086     # check-stream-equal(_test-output-stream, "2/mod/indirect 4/rm32/sib 6/base 1/index 2/scale 4/disp", msg)
+3087     # . . push args
+3088     68/push  "F - test-emit-indirect-mode-with-sib"/imm32
+3089     68/push  "2/mod/*+disp32 4/rm32/sib 0x00000006/base 0x00000001/index 0x00000002/scale 0x00000004/disp32"/imm32
+3090     68/push  _test-output-stream/imm32
+3091     # . . call
+3092     e8/call  check-stream-equal/disp32
+3093     # . . discard args
+3094     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+3095     # . epilog
+3096     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+3097     5d/pop-to-EBP
+3098     c3/return
+3099 
+3100 # update line->read to ')'
+3101 # line->read ends at ')'
+3102 skip-until-close-paren:  # line : (address stream)
+3103     # . prolog
+3104     55/push-EBP
+3105     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+3106     # . save registers
+3107     50/push-EAX
+3108     51/push-ECX
+3109     52/push-EDX
+3110     # ECX = line
+3111     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .                         1/r32/ECX   8/disp8         .                 # copy *(EBP+8) to ECX
+3112     # EAX = skip-until-close-paren-in-slice(&line->data[line->read], &line->data[line->write])
+3113     # . . push &line->data[line->write]
+3114     8b/copy                         1/mod/*+disp8   1/rm32/ECX    .           .                         2/r32/EDX   8/disp8         .                 # copy *(ECX+8) to EDX
+3115     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    1/base/ECX  2/index/EDX   .           2/r32/EDX   0xc/disp8       .                 # copy ECX+EDX+12 to EDX
+3116     52/push-EDX
+3117     # . . push &line->data[line->read]
+3118     8b/copy                         1/mod/*+disp8   1/rm32/ECX    .           .                         2/r32/EDX   4/disp8         .                 # copy *(ECX+4) to EDX
+3119     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    1/base/ECX  2/index/EDX   .           2/r32/EDX   0xc/disp8       .                 # copy ECX+EDX+12 to EDX
+3120     52/push-EDX
+3121     # . . call
+3122     e8/call  skip-until-close-paren-in-slice/disp32
+3123     # . . discard args
+3124     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+3125     # line->read = EAX - line->data
+3126     29/subtract                     3/mod/direct    0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # subtract ECX from EAX
+3127     2d/subtract-from-EAX  0xc/imm32
+3128     89/copy                         1/mod/*+disp8   1/rm32/ECX    .           .                         0/r32/EAX   4/disp8         .                 # copy EAX to *(ECX+4)
+3129 $skip-until-close-paren:end:
+3130     # . restore registers
+3131     5a/pop-to-EDX
+3132     59/pop-to-ECX
+3133     58/pop-to-EAX
+3134     # . epilog
+3135     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+3136     5d/pop-to-EBP
+3137     c3/return
+3138 
+3139 test-skip-until-close-paren:
+3140     # . prolog
+3141     55/push-EBP
+3142     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+3143     # setup
+3144     # . clear-stream(_test-input-stream)
+3145     # . . push args
+3146     68/push  _test-input-stream/imm32
+3147     # . . call
+3148     e8/call  clear-stream/disp32
+3149     # . . discard args
+3150     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+3151     # . write(_test-input-stream, "*(abc) def")
+3152     # .                   indices:  0123 45
+3153     # . . push args
+3154     68/push  "*(abc) def"/imm32
+3155     68/push  _test-input-stream/imm32
+3156     # . . call
+3157     e8/call  write/disp32
+3158     # . . discard args
+3159     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+3160     # precondition: line->read == 0
+3161     # . . push args
+3162     68/push  "F - test-skip-until-close-paren/precondition"/imm32
+3163     68/push  0/imm32
+3164     b8/copy-to-EAX  _test-input-stream/imm32
+3165     ff          6/subop/push        1/mod/*+disp8   0/rm32/EAX    .           .             .           .           4/disp8         .                 # push *(EAX+4)
+3166     # . . call
+3167     e8/call  check-ints-equal/disp32
+3168     # . . discard args
+3169     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+3170     # skip-until-close-paren(_test-input-stream)
+3171     # . . push args
+3172     68/push  _test-input-stream/imm32
+3173     # . . call
+3174     e8/call  skip-until-close-paren/disp32
+3175     # . . discard args
+3176     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+3177     # check-ints-equal(line->read, 5, msg)
+3178     # . . push args
+3179     68/push  "F - test-skip-until-close-paren"/imm32
+3180     68/push  5/imm32
+3181     b8/copy-to-EAX  _test-input-stream/imm32
+3182     ff          6/subop/push        1/mod/*+disp8   0/rm32/EAX    .           .             .           .           4/disp8         .                 # push *(EAX+4)
+3183     # . . call
+3184     e8/call  check-ints-equal/disp32
+3185     # . . discard args
+3186     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+3187     # . epilog
+3188     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+3189     5d/pop-to-EBP
+3190     c3/return
+3191 
+3192 test-skip-until-close-paren-ignores-spaces:
+3193     # . prolog
+3194     55/push-EBP
+3195     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+3196     # setup
+3197     # . clear-stream(_test-input-stream)
+3198     # . . push args
+3199     68/push  _test-input-stream/imm32
+3200     # . . call
+3201     e8/call  clear-stream/disp32
+3202     # . . discard args
+3203     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+3204     # . write(_test-input-stream, "*(a b)/yz")
+3205     # . . push args
+3206     68/push  "*(a b)/yz"/imm32
+3207     68/push  _test-input-stream/imm32
+3208     # . . call
+3209     e8/call  write/disp32
+3210     # . . discard args
+3211     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+3212     # precondition: line->read == 0
+3213     # . . push args
+3214     68/push  "F - test-skip-until-close-paren-ignores-spaces/precondition"/imm32
+3215     68/push  0/imm32
+3216     b8/copy-to-EAX  _test-input-stream/imm32
+3217     ff          6/subop/push        1/mod/*+disp8   0/rm32/EAX    .           .             .           .           4/disp8         .                 # push *(EAX+4)
+3218     # . . call
+3219     e8/call  check-ints-equal/disp32
+3220     # . . discard args
+3221     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+3222     # skip-until-close-paren(_test-input-stream)
+3223     # . . push args
+3224     68/push  _test-input-stream/imm32
+3225     # . . call
+3226     e8/call  skip-until-close-paren/disp32
+3227     # . . discard args
+3228     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+3229     # check-ints-equal(line->read, 5, msg)
+3230     # . . push args
+3231     68/push  "F - test-skip-until-close-paren-ignores-spaces"/imm32
+3232     68/push  5/imm32
+3233     b8/copy-to-EAX  _test-input-stream/imm32
+3234     ff          6/subop/push        1/mod/*+disp8   0/rm32/EAX    .           .             .           .           4/disp8         .                 # push *(EAX+4)
+3235     # . . call
+3236     e8/call  check-ints-equal/disp32
+3237     # . . discard args
+3238     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+3239     # . epilog
+3240     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+3241     5d/pop-to-EBP
+3242     c3/return
+3243 
+3244 test-skip-until-close-paren-works-from-mid-stream:
+3245     # . prolog
+3246     55/push-EBP
+3247     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+3248     # setup
+3249     # . clear-stream(_test-input-stream)
+3250     # . . push args
+3251     68/push  _test-input-stream/imm32
+3252     # . . call
+3253     e8/call  clear-stream/disp32
+3254     # . . discard args
+3255     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+3256     # . write(_test-input-stream, "0 *(a b)/yz")
+3257     # . . push args
+3258     68/push  "0 *(a b)/yz"/imm32
+3259     68/push  _test-input-stream/imm32
+3260     # . . call
+3261     e8/call  write/disp32
+3262     # . . discard args
+3263     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+3264     # precondition: _test-input-stream->read == 2
+3265     c7          0/subop/copy        1/mod/*+disp8   0/rm32/EAX    .           .             .           .           4/disp8         2/imm32           # copy to *(EAX+4)
+3266     # skip-until-close-paren(_test-input-stream)
+3267     # . . push args
+3268     68/push  _test-input-stream/imm32
+3269     # . . call
+3270     e8/call  skip-until-close-paren/disp32
+3271     # . . discard args
+3272     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+3273     # check-ints-equal(_test-input-stream->read, 7, msg)
+3274     # . . push args
+3275     68/push  "F - test-skip-until-close-paren-works-from-mid-stream"/imm32
+3276     68/push  7/imm32
+3277     b8/copy-to-EAX  _test-input-stream/imm32
+3278     ff          6/subop/push        1/mod/*+disp8   0/rm32/EAX    .           .             .           .           4/disp8         .                 # push *(EAX+4)
+3279     # . . call
+3280     e8/call  check-ints-equal/disp32
+3281     # . . discard args
+3282     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+3283     # . epilog
+3284     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+3285     5d/pop-to-EBP
+3286     c3/return
+3287 
+3288 skip-until-close-paren-in-slice:  # curr : (address byte), end : (address byte) -> new_curr/EAX
+3289     # . prolog
+3290     55/push-EBP
+3291     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+3292     # . save registers
+3293     51/push-ECX
+3294     52/push-EDX
+3295     # ECX = curr
+3296     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .                         1/r32/ECX   8/disp8         .                 # copy *(EBP+8) to ECX
+3297     # EDX = end
+3298     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .                         2/r32/EDX   0xc/disp8         .               # copy *(EBP+12) to EDX
+3299     # EAX = 0
+3300     31/xor                          3/mod/direct    0/rm32/EAX    .           .             .           0/r32/EAX   .               .                 # clear EAX
+3301     # skip initial dquote
+3302     41/increment-ECX
+3303 $skip-until-close-paren-in-slice:loop:
+3304     # if (curr >= end) break
+3305     39/compare                      3/mod/direct    1/rm32/ECX    .           .             .           2/r32/EDX   .               .                 # compare ECX with EDX
+3306     73/jump-if-greater-unsigned-or-equal  $skip-until-close-paren-in-slice:break/disp8
+3307     # AL = *curr
+3308     8a/copy-byte                    0/mod/indirect  1/rm32/ECX    .           .             .           0/r32/AL    .               .                 # copy byte at *ECX to AL
+3309 $skip-until-close-paren-in-slice:check-close:
+3310     # if (EAX == ')') break
+3311     3d/compare-EAX-and  0x29/imm32/close-paren
+3312     74/jump-if-equal  $skip-until-close-paren-in-slice:break/disp8
+3313     # ++curr
+3314     41/increment-ECX
+3315     eb/jump  $skip-until-close-paren-in-slice:loop/disp8
+3316 $skip-until-close-paren-in-slice:break:
+3317     # return curr
+3318     89/copy                         3/mod/direct    0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy ECX to EAX
+3319 $skip-until-close-paren-in-slice:end:
+3320     # . restore registers
+3321     5a/pop-to-EDX
+3322     59/pop-to-ECX
+3323     # . epilog
+3324     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+3325     5d/pop-to-EBP
+3326     c3/return
+3327 
+3328 test-skip-until-close-paren-in-slice:
+3329     # . prolog
+3330     55/push-EBP
+3331     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+3332     # setup: (EAX..ECX) = "*(abc) def"
+3333     b8/copy-to-EAX  "*(abc) def"/imm32
+3334     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
+3335     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
+3336     05/add-to-EAX  4/imm32
+3337     # EAX = skip-until-close-paren-in-slice(EAX, ECX)
+3338     # . . push args
+3339     51/push-ECX
+3340     50/push-EAX
+3341     # . . call
+3342     e8/call  skip-until-close-paren-in-slice/disp32
+3343     # . . discard args
+3344     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+3345     # check-ints-equal(ECX-EAX, 5, msg)  # EAX is at the ')'
+3346     # . . push args
+3347     68/push  "F - test-skip-until-close-paren-in-slice"/imm32
+3348     68/push  5/imm32
+3349     # . . push ECX-EAX
+3350     29/subtract                     3/mod/direct    1/rm32/ECX    .           .             .           0/r32/EAX   .               .                 # subtract EAX from ECX
+3351     51/push-ECX
+3352     # . . call
+3353     e8/call  check-ints-equal/disp32
+3354     # . . discard args
+3355     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+3356     # . epilog
+3357     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+3358     5d/pop-to-EBP
+3359     c3/return
+3360 
+3361 test-skip-until-close-paren-in-slice-ignores-spaces:
+3362     # . prolog
+3363     55/push-EBP
+3364     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+3365     # setup: (EAX..ECX) = "*(a b)/yz"
+3366     b8/copy-to-EAX  "*(a b)/yz"/imm32
+3367     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
+3368     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
+3369     05/add-to-EAX  4/imm32
+3370     # EAX = skip-until-close-paren-in-slice(EAX, ECX)
+3371     # . . push args
+3372     51/push-ECX
+3373     50/push-EAX
+3374     # . . call
+3375     e8/call  skip-until-close-paren-in-slice/disp32
+3376     # . . discard args
+3377     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+3378     # check-ints-equal(ECX-EAX, 4, msg)  # EAX is at the ')'
+3379     # . . push args
+3380     68/push  "F - test-skip-until-close-paren-in-slice-ignores-spaces"/imm32
+3381     68/push  4/imm32
+3382     # . . push ECX-EAX
+3383     29/subtract                     3/mod/direct    1/rm32/ECX    .           .             .           0/r32/EAX   .               .                 # subtract EAX from ECX
+3384     51/push-ECX
+3385     # . . call
+3386     e8/call  check-ints-equal/disp32
+3387     # . . discard args
+3388     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+3389     # . epilog
+3390     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+3391     5d/pop-to-EBP
+3392     c3/return
+3393 
+3394 test-skip-until-close-paren-in-slice-stops-at-end:
+3395     # . prolog
+3396     55/push-EBP
+3397     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+3398     # setup: (EAX..ECX) = "*(abc"  # unbalanced dquote
+3399     b8/copy-to-EAX  "*(abc"/imm32
+3400     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
+3401     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
+3402     05/add-to-EAX  4/imm32
+3403     # EAX = skip-until-close-paren-in-slice(EAX, ECX)
+3404     # . . push args
+3405     51/push-ECX
+3406     50/push-EAX
+3407     # . . call
+3408     e8/call  skip-until-close-paren-in-slice/disp32
+3409     # . . discard args
+3410     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+3411     # check-ints-equal(ECX-EAX, 0, msg)  # skipped to end of slice
+3412     # . . push args
+3413     68/push  "F - test-skip-until-close-paren-in-slice-stops-at-end"/imm32
+3414     68/push  0/imm32
+3415     # . . push ECX-EAX
+3416     29/subtract                     3/mod/direct    1/rm32/ECX    .           .             .           0/r32/EAX   .               .                 # subtract EAX from ECX
+3417     51/push-ECX
+3418     # . . call
+3419     e8/call  check-ints-equal/disp32
+3420     # . . discard args
+3421     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+3422     # . epilog
+3423     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+3424     5d/pop-to-EBP
+3425     c3/return
+3426 
+3427 # assumes 'in' starts with optional '+' or '-', optional whitespace, and an unsigned integer
+3428 # returns the value of the integer
+3429 # side-effect: modifies 'in' to skip past the integer
+3430 next-hex-int:  # in : (address slice) -> result/EAX
+3431     # . prolog
+3432     55/push-EBP
+3433     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+3434     # . save registers
+3435     51/push-ECX
+3436     52/push-EDX
+3437     53/push-EBX
+3438     56/push-ESI
+3439     57/push-EDI
+3440     # result/EDI = 0
+3441     31/xor                          3/mod/direct    7/rm32/EDI    .           .             .           7/r32/EDI   .               .                 # clear EDI
+3442     # ESI = in
+3443     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           6/r32/ESI   8/disp8         .                 # copy *(EBP+8) to ESI
+3444     # EDX = in->end
+3445     8b/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           2/r32/EDX   4/disp8         .                 # copy *(ESI+4) to EDX
+3446     # curr/ECX = in->start
+3447     8b/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           1/r32/ECX   .               .                 # copy *ESI to ECX
+3448     # negate?/EBX = false
+3449     31/xor                          3/mod/direct    3/rm32/EBX    .           .             .           3/r32/EBX   .               .                 # clear EBX
+3450     # EAX = *curr
+3451     31/xor                          3/mod/direct    0/rm32/EAX    .           .             .           0/r32/EAX   .               .                 # clear EAX
+3452     8a/copy-byte                    0/mod/indirect  1/rm32/ECX    .           .             .           0/r32/AL    .               .                 # copy byte at *ECX to AL
+3453 $next-hex-int:positive:
+3454     # if (*curr == '+') ++curr
+3455     3d/compare-EAX-and  0x2b/imm32/+
+3456     75/jump-if-not-equal  $next-hex-int:negative/disp8
+3457     # . ++curr
+3458     41/increment-ECX
+3459     eb/jump  $next-hex-int:skip-whitespace/disp8
+3460 $next-hex-int:negative:
+3461     # else if (*curr == '-') ++curr, negate = true
+3462     3d/compare-EAX-and  0x2d/imm32/-
+3463     75/jump-if-not-equal  $next-hex-int:skip-whitespace/disp8
+3464 $next-hex-int:need-to-negate:
+3465     # . ++curr
+3466     41/increment-ECX
+3467     # . negate = true
+3468     bb/copy-to-EBX  1/imm32/true
+3469     # fall through
+3470 $next-hex-int:skip-whitespace:
+3471     # spill EAX
+3472     50/push-EAX
+3473     # EAX = skip-chars-matching-whitespace-in-slice(word->start, word->end)
+3474     # . . push args
+3475     52/push-EDX
+3476     51/push-ECX
+3477     # . . call
+3478     e8/call  skip-chars-matching-whitespace-in-slice/disp32
+3479     # . . discard args
+3480     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+3481     # ECX = EAX
+3482     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           0/r32/EAX   .               .                 # copy EAX to ECX
+3483     # restore EAX
+3484     58/pop-to-EAX
+3485 $next-hex-int:initial-0:
+3486     # skip past leading '0x'
+3487     # . if (*curr != '0') jump to loop
+3488     8a/copy-byte                    0/mod/indirect  1/rm32/ECX    .           .             .           0/r32/AL    .               .                 # copy byte at *ECX to AL
+3489     3d/compare-EAX-and  0x30/imm32/0
+3490     75/jump-if-not-equal  $next-hex-int:loop/disp8
+3491     # . ++curr
+3492     41/increment-ECX
+3493 $next-hex-int:initial-0x:
+3494     # . if (curr >= in->end) return result
+3495     39/compare                      3/mod/direct    1/rm32/ECX    .           .             .           2/r32/EDX   .               .                 # compare ECX with EDX
+3496     73/jump-if-greater-or-equal-unsigned  $next-hex-int:end/disp8
+3497     # . if (*curr != 'x') jump to loop  # the previous '0' is still valid so doesn't need to be checked again
+3498     31/xor                          3/mod/direct    0/rm32/EAX    .           .             .           0/r32/EAX   .               .                 # clear EAX
+3499     8a/copy-byte                    0/mod/indirect  1/rm32/ECX    .           .             .           0/r32/AL    .               .                 # copy byte at *ECX to AL
+3500     3d/compare-EAX-and  0x78/imm32/x
+3501     75/jump-if-not-equal  $next-hex-int:loop/disp8
+3502     # . ++curr
+3503     41/increment-ECX
+3504 $next-hex-int:loop:
+3505     # if (curr >= in->end) break
+3506     39/compare                      3/mod/direct    1/rm32/ECX    .           .             .           2/r32/EDX   .               .                 # compare ECX with EDX
+3507     73/jump-if-greater-or-equal-unsigned  $next-hex-int:break/disp8
+3508     # if (!is-hex-digit?(*curr)) break
+3509     # . EAX = *curr
+3510     8a/copy-byte                    0/mod/indirect  1/rm32/ECX    .           .             .           0/r32/AL    .               .                 # copy byte at *ECX to AL
+3511     # . EAX = is-hex-digit?(*curr)
+3512     # . . push args
+3513     50/push-EAX
+3514     # . . call
+3515     e8/call  is-hex-digit?/disp32
+3516     # . . discard args
+3517     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+3518     # . if (EAX == 0) break
+3519     3d/compare-EAX-and  0/imm32
+3520     74/jump-if-equal  $next-hex-int:break/disp8
+3521     # EAX = from-hex-char(*curr)
+3522     # . . copy arg to EAX
+3523     8a/copy-byte                    0/mod/indirect  1/rm32/ECX    .           .             .           0/r32/AL    .               .                 # copy byte at *ECX to AL
+3524     # . . call
+3525     e8/call  from-hex-char/disp32
+3526     # result = result * 16 + EAX
+3527     c1/shift    4/subop/left        3/mod/direct    7/rm32/EDI    .           .             .           .           .               4/imm8            # shift EDI left by 4 bits
+3528     01/add                          3/mod/direct    7/rm32/EDI    .           .             .           0/r32/EAX   .               .                 # add EAX to EDI
+3529     # ++curr
+3530     41/increment-ECX
+3531     # loop
+3532     eb/jump  $next-hex-int:loop/disp8
+3533 $next-hex-int:break:
+3534     81          7/subop/compare     3/mod/direct    3/rm32/EBX    .           .             .           .           .               0/imm32           # compare EBX
+3535     74/jump-if-equal  $next-hex-int:end/disp8
+3536 $next-hex-int:negate:
+3537     f7          3/subop/negate      3/mod/direct    7/rm32/EDI    .           .             .           .           .               .                 # negate EDI
+3538 $next-hex-int:end:
+3539     # word->start = curr
+3540     89/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           1/r32/ECX   .               .                 # copy ECX to *ESI
+3541     # return EDI
+3542     89/copy                         3/mod/direct    0/rm32/EAX    .           .             .           7/r32/EDI   .               .                 # copy EDI to EAX
+3543     # . restore registers
+3544     5f/pop-to-EDI
+3545     5e/pop-to-ESI
+3546     5b/pop-to-EBX
+3547     5a/pop-to-EDX
+3548     59/pop-to-ECX
+3549     # . epilog
+3550     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+3551     5d/pop-to-EBP
+3552     c3/return
+3553 
+3554 $next-hex-int:abort:
+3555     # . _write(2/stderr, error)
+3556     # . . push args
+3557     68/push  "next-hex-int: invalid hex char: "/imm32
+3558     68/push  2/imm32/stderr
+3559     # . . call
+3560     e8/call  _write/disp32
+3561     # . . discard args
+3562     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+3563     # . clear-stream(Stderr+4)
+3564     # . . save EAX
+3565     50/push-EAX
+3566     # . . push args
+3567     b8/copy-to-EAX  Stderr/imm32
+3568     05/add-to-EAX  4/imm32
+3569     50/push-EAX
+3570     # . . call
+3571     e8/call  clear-stream/disp32
+3572     # . . discard args
+3573     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+3574     # . . restore EAX
+3575     58/pop-to-EAX
+3576     # . print-int32-buffered(Stderr, EAX)
+3577     # . . push args
+3578     50/push-EAX
+3579     68/push  Stderr/imm32
+3580     # . . call
+3581     e8/call  print-int32-buffered/disp32
+3582     # . . discard args
+3583     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+3584     # . flush(Stderr)
+3585     # . . push args
+3586     68/push  Stderr/imm32
+3587     # . . call
+3588     e8/call  flush/disp32
+3589     # . . discard args
+3590     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+3591     # . _write(2/stderr, "\n")
+3592     # . . push args
+3593     68/push  "\n"/imm32
+3594     68/push  2/imm32/stderr
+3595     # . . call
+3596     e8/call  _write/disp32
+3597     # . . discard args
+3598     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
+3599     # . syscall(exit, 1)
+3600     bb/copy-to-EBX  1/imm32
+3601     b8/copy-to-EAX  1/imm32/exit
+3602     cd/syscall  0x80/imm8
+3603     # never gets here
+3604 
+3605 test-next-hex-int-single-digit:
+3606     # . prolog
+3607     55/push-EBP
+3608     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+3609     # (EAX..ECX) = "+a)"
+3610     b8/copy-to-EAX  "+a)"/imm32
+3611     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
+3612     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
+3613     05/add-to-EAX  4/imm32
+3614     # var slice/ECX = {EAX, ECX}
+3615     51/push-ECX
+3616     50/push-EAX
+3617     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+3618     # EAX = next-hex-int(slice)
+3619     # . . push args
+3620     51/push-ECX
+3621     # . . call
+3622     e8/call  next-hex-int/disp32
+3623     # . . discard args
+3624     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+3625     # check-ints-equal(EAX, 0xa, msg)
+3626     # . . push args
+3627     68/push  "F - test-next-hex-int-single-digit"/imm32
+3628     68/push  0xa/imm32
+3629     50/push-EAX
+3630     # . . call
+3631     e8/call  check-ints-equal/disp32
+3632     # . . discard args
+3633     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+3634     # . epilog
+3635     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+3636     5d/pop-to-EBP
+3637     c3/return
+3638 
+3639 test-next-hex-int-multi-digit:
+3640     # . prolog
+3641     55/push-EBP
+3642     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+3643     # (EAX..ECX) = "+ 34a)"
+3644     b8/copy-to-EAX  "+ 34a)"/imm32
+3645     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
+3646     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
+3647     05/add-to-EAX  4/imm32
+3648     # var slice/ECX = {EAX, ECX}
+3649     51/push-ECX
+3650     50/push-EAX
+3651     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+3652     # EAX = next-hex-int(slice)
+3653     # . . push args
+3654     51/push-ECX
+3655     # . . call
+3656     e8/call  next-hex-int/disp32
+3657     # . . discard args
+3658     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+3659     # check-ints-equal(EAX, 0x34a, msg)
+3660     # . . push args
+3661     68/push  "F - test-next-hex-int-multi-digit"/imm32
+3662     68/push  0x34a/imm32
+3663     50/push-EAX
+3664     # . . call
+3665     e8/call  check-ints-equal/disp32
+3666     # . . discard args
+3667     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+3668     # . epilog
+3669     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+3670     5d/pop-to-EBP
+3671     c3/return
+3672 
+3673 test-next-hex-int-0x-prefix:
+3674     # . prolog
+3675     55/push-EBP
+3676     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+3677     # (EAX..ECX) = "+0x34)"
+3678     b8/copy-to-EAX  "+0x34)"/imm32
+3679     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
+3680     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
+3681     05/add-to-EAX  4/imm32
+3682     # var slice/ECX = {EAX, ECX}
+3683     51/push-ECX
+3684     50/push-EAX
+3685     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+3686     # EAX = next-hex-int(slice)
+3687     # . . push args
+3688     51/push-ECX
+3689     # . . call
+3690     e8/call  next-hex-int/disp32
+3691     # . . discard args
+3692     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+3693     # check-ints-equal(EAX, 0x34, msg)
+3694     # . . push args
+3695     68/push  "F - test-next-hex-int-0x-prefix"/imm32
+3696     68/push  0x34/imm32
+3697     50/push-EAX
+3698     # . . call
+3699     e8/call  check-ints-equal/disp32
+3700     # . . discard args
+3701     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+3702     # . epilog
+3703     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+3704     5d/pop-to-EBP
+3705     c3/return
+3706 
+3707 test-next-hex-int-zero:
+3708     # . prolog
+3709     55/push-EBP
+3710     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+3711     # (EAX..ECX) = "+0)"
+3712     b8/copy-to-EAX  "+0)"/imm32
+3713     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
+3714     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
+3715     05/add-to-EAX  4/imm32
+3716     # var slice/ECX = {EAX, ECX}
+3717     51/push-ECX
+3718     50/push-EAX
+3719     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+3720     # EAX = next-hex-int(slice)
+3721     # . . push args
+3722     51/push-ECX
+3723     # . . call
+3724     e8/call  next-hex-int/disp32
+3725     # . . discard args
+3726     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+3727     # check-ints-equal(EAX, 0, msg)
+3728     # . . push args
+3729     68/push  "F - test-next-hex-int-zero"/imm32
+3730     68/push  0/imm32
+3731     50/push-EAX
+3732     # . . call
+3733     e8/call  check-ints-equal/disp32
+3734     # . . discard args
+3735     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+3736     # . epilog
+3737     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+3738     5d/pop-to-EBP
+3739     c3/return
+3740 
+3741 test-next-hex-int-0-prefix:
+3742     # . prolog
+3743     55/push-EBP
+3744     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+3745     # (EAX..ECX) = "+ 03)"
+3746     b8/copy-to-EAX  "+ 03)"/imm32
+3747     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
+3748     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
+3749     05/add-to-EAX  4/imm32
+3750     # var slice/ECX = {EAX, ECX}
+3751     51/push-ECX
+3752     50/push-EAX
+3753     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+3754     # EAX = next-hex-int(slice)
+3755     # . . push args
+3756     51/push-ECX
+3757     # . . call
+3758     e8/call  next-hex-int/disp32
+3759     # . . discard args
+3760     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+3761     # check-ints-equal(EAX, 3, msg)
+3762     # . . push args
+3763     68/push  "F - test-next-hex-int-0-prefix"/imm32
+3764     68/push  3/imm32
+3765     50/push-EAX
+3766     # . . call
+3767     e8/call  check-ints-equal/disp32
+3768     # . . discard args
+3769     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+3770     # . epilog
+3771     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+3772     5d/pop-to-EBP
+3773     c3/return
+3774 
+3775 test-next-hex-int-negative:
+3776     # . prolog
+3777     55/push-EBP
+3778     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+3779     # (EAX..ECX) = "-03)"
+3780     b8/copy-to-EAX  "-03)"/imm32
+3781     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
+3782     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
+3783     05/add-to-EAX  4/imm32
+3784     # var slice/ECX = {EAX, ECX}
+3785     51/push-ECX
+3786     50/push-EAX
+3787     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+3788     # EAX = next-hex-int(slice)
+3789     # . . push args
+3790     51/push-ECX
+3791     # . . call
+3792     e8/call  next-hex-int/disp32
+3793     # . . discard args
+3794     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+3795     # check-ints-equal(EAX, -3, msg)
+3796     # . . push args
+3797     68/push  "F - test-next-hex-int-negative"/imm32
+3798     68/push  -3/imm32
+3799     50/push-EAX
+3800     # . . call
+3801     e8/call  check-ints-equal/disp32
+3802     # . . discard args
+3803     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+3804     # . epilog
+3805     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+3806     5d/pop-to-EBP
+3807     c3/return
+3808 
+3809 test-next-hex-int-negative-with-space:
+3810     # . prolog
+3811     55/push-EBP
+3812     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+3813     # (EAX..ECX) = "- 03)"
+3814     b8/copy-to-EAX  "- 03)"/imm32
+3815     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
+3816     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
+3817     05/add-to-EAX  4/imm32
+3818     # var slice/ECX = {EAX, ECX}
+3819     51/push-ECX
+3820     50/push-EAX
+3821     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+3822     # EAX = next-hex-int(slice)
+3823     # . . push args
+3824     51/push-ECX
+3825     # . . call
+3826     e8/call  next-hex-int/disp32
+3827     # . . discard args
+3828     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+3829     # check-ints-equal(EAX, -3, msg)
+3830     # . . push args
+3831     68/push  "F - test-next-hex-int-negative-with-space"/imm32
+3832     68/push  -3/imm32
+3833     50/push-EAX
+3834     # . . call
+3835     e8/call  check-ints-equal/disp32
+3836     # . . discard args
+3837     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+3838     # . epilog
+3839     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+3840     5d/pop-to-EBP
+3841     c3/return
+3842 
+3843 # assumes 'in' starts a positive unsigned integer
+3844 # returns the value of the integer
+3845 # side-effect: modifies 'in' to skip past the integer
+3846 next-positive-hex-int:  # in : (address slice) -> result/EAX
+3847     # . prolog
+3848     55/push-EBP
+3849     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+3850     # . save registers
+3851     51/push-ECX
+3852     52/push-EDX
+3853     53/push-EBX
+3854     56/push-ESI
+3855     57/push-EDI
+3856     # result/EDI = 0
+3857     31/xor                          3/mod/direct    7/rm32/EDI    .           .             .           7/r32/EDI   .               .                 # clear EDI
+3858     # ESI = in
+3859     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           6/r32/ESI   8/disp8         .                 # copy *(EBP+8) to ESI
+3860     # EDX = in->end
+3861     8b/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           2/r32/EDX   4/disp8         .                 # copy *(ESI+4) to EDX
+3862     # curr/ECX = in->start
+3863     8b/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           1/r32/ECX   .               .                 # copy *ESI to ECX
+3864     # negate?/EBX = false
+3865     31/xor                          3/mod/direct    3/rm32/EBX    .           .             .           3/r32/EBX   .               .                 # clear EBX
+3866     # EAX = *curr
+3867     31/xor                          3/mod/direct    0/rm32/EAX    .           .             .           0/r32/EAX   .               .                 # clear EAX
+3868     8a/copy-byte                    0/mod/indirect  1/rm32/ECX    .           .             .           0/r32/AL    .               .                 # copy byte at *ECX to AL
+3869 $next-positive-hex-int:initial-0:
+3870     # skip past leading '0x'
+3871     # . if (*curr != '0') jump to loop
+3872     8a/copy-byte                    0/mod/indirect  1/rm32/ECX    .           .             .           0/r32/AL    .               .                 # copy byte at *ECX to AL
+3873     3d/compare-EAX-and  0x30/imm32/0
+3874     75/jump-if-not-equal  $next-positive-hex-int:loop/disp8
+3875     # . ++curr
+3876     41/increment-ECX
+3877 $next-positive-hex-int:initial-0x:
+3878     # . if (curr >= in->end) return result
+3879     39/compare                      3/mod/direct    1/rm32/ECX    .           .             .           2/r32/EDX   .               .                 # compare ECX with EDX
+3880     73/jump-if-greater-or-equal-unsigned  $next-positive-hex-int:end/disp8
+3881     # . if (*curr != 'x') jump to loop  # the previous '0' is still valid so doesn't need to be checked again
+3882     31/xor                          3/mod/direct    0/rm32/EAX    .           .             .           0/r32/EAX   .               .                 # clear EAX
+3883     8a/copy-byte                    0/mod/indirect  1/rm32/ECX    .           .             .           0/r32/AL    .               .                 # copy byte at *ECX to AL
+3884     3d/compare-EAX-and  0x78/imm32/x
+3885     75/jump-if-not-equal  $next-positive-hex-int:loop/disp8
+3886     # . ++curr
+3887     41/increment-ECX
+3888 $next-positive-hex-int:loop:
+3889     # if (curr >= in->end) break
+3890     39/compare                      3/mod/direct    1/rm32/ECX    .           .             .           2/r32/EDX   .               .                 # compare ECX with EDX
+3891     73/jump-if-greater-or-equal-unsigned  $next-positive-hex-int:end/disp8
+3892     # if (!is-hex-digit?(*curr)) break
+3893     # . EAX = *curr
+3894     8a/copy-byte                    0/mod/indirect  1/rm32/ECX    .           .             .           0/r32/AL    .               .                 # copy byte at *ECX to AL
+3895     # . EAX = is-hex-digit?(*curr)
+3896     # . . push args
+3897     50/push-EAX
+3898     # . . call
+3899     e8/call  is-hex-digit?/disp32
+3900     # . . discard args
+3901     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+3902     # . if (EAX == 0) break
+3903     3d/compare-EAX-and  0/imm32
+3904     74/jump-if-equal  $next-positive-hex-int:end/disp8
+3905     # EAX = from-hex-char(*curr)
+3906     # . . copy arg to EAX
+3907     8a/copy-byte                    0/mod/indirect  1/rm32/ECX    .           .             .           0/r32/AL    .               .                 # copy byte at *ECX to AL
+3908     # . . call
+3909     e8/call  from-hex-char/disp32
+3910     # result = result * 16 + EAX
+3911     c1/shift    4/subop/left        3/mod/direct    7/rm32/EDI    .           .             .           .           .               4/imm8            # shift EDI left by 4 bits
+3912     01/add                          3/mod/direct    7/rm32/EDI    .           .             .           0/r32/EAX   .               .                 # add EAX to EDI
+3913     # ++curr
+3914     41/increment-ECX
+3915     # loop
+3916     eb/jump  $next-positive-hex-int:loop/disp8
+3917 $next-positive-hex-int:end:
+3918     # word->start = curr
+3919     89/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           1/r32/ECX   .               .                 # copy ECX to *ESI
+3920     # return EDI
+3921     89/copy                         3/mod/direct    0/rm32/EAX    .           .             .           7/r32/EDI   .               .                 # copy EDI to EAX
+3922     # . restore registers
+3923     5f/pop-to-EDI
+3924     5e/pop-to-ESI
+3925     5b/pop-to-EBX
+3926     5a/pop-to-EDX
+3927     59/pop-to-ECX
+3928     # . epilog
+3929     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+3930     5d/pop-to-EBP
+3931     c3/return
+3932 
+3933 test-next-positive-hex-int-single-digit:
+3934     # . prolog
+3935     55/push-EBP
+3936     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+3937     # (EAX..ECX) = "a)"
+3938     b8/copy-to-EAX  "a)"/imm32
+3939     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
+3940     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
+3941     05/add-to-EAX  4/imm32
+3942     # var slice/ECX = {EAX, ECX}
+3943     51/push-ECX
+3944     50/push-EAX
+3945     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+3946     # EAX = next-positive-hex-int(slice)
+3947     # . . push args
+3948     51/push-ECX
+3949     # . . call
+3950     e8/call  next-positive-hex-int/disp32
+3951     # . . discard args
+3952     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+3953     # check-ints-equal(EAX, 0xa, msg)
+3954     # . . push args
+3955     68/push  "F - test-next-positive-hex-int-single-digit"/imm32
+3956     68/push  0xa/imm32
+3957     50/push-EAX
+3958     # . . call
+3959     e8/call  check-ints-equal/disp32
+3960     # . . discard args
+3961     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+3962     # . epilog
+3963     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+3964     5d/pop-to-EBP
+3965     c3/return
+3966 
+3967 test-next-positive-hex-int-multi-digit:
+3968     # . prolog
+3969     55/push-EBP
+3970     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+3971     # (EAX..ECX) = "34a)"
+3972     b8/copy-to-EAX  "34a)"/imm32
+3973     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
+3974     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
+3975     05/add-to-EAX  4/imm32
+3976     # var slice/ECX = {EAX, ECX}
+3977     51/push-ECX
+3978     50/push-EAX
+3979     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+3980     # EAX = next-positive-hex-int(slice)
+3981     # . . push args
+3982     51/push-ECX
+3983     # . . call
+3984     e8/call  next-positive-hex-int/disp32
+3985     # . . discard args
+3986     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+3987     # check-ints-equal(EAX, 0x34a, msg)
+3988     # . . push args
+3989     68/push  "F - test-next-positive-hex-int-multi-digit"/imm32
+3990     68/push  0x34a/imm32
+3991     50/push-EAX
+3992     # . . call
+3993     e8/call  check-ints-equal/disp32
+3994     # . . discard args
+3995     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+3996     # . epilog
+3997     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+3998     5d/pop-to-EBP
+3999     c3/return
+4000 
+4001 test-next-positive-hex-int-0x-prefix:
+4002     # . prolog
+4003     55/push-EBP
+4004     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+4005     # (EAX..ECX) = "0x34)"
+4006     b8/copy-to-EAX  "0x34)"/imm32
+4007     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
+4008     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
+4009     05/add-to-EAX  4/imm32
+4010     # var slice/ECX = {EAX, ECX}
+4011     51/push-ECX
+4012     50/push-EAX
+4013     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+4014     # EAX = next-positive-hex-int(slice)
+4015     # . . push args
+4016     51/push-ECX
+4017     # . . call
+4018     e8/call  next-positive-hex-int/disp32
+4019     # . . discard args
+4020     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+4021     # check-ints-equal(EAX, 0x34, msg)
+4022     # . . push args
+4023     68/push  "F - test-next-positive-hex-int-0x-prefix"/imm32
+4024     68/push  0x34/imm32
+4025     50/push-EAX
+4026     # . . call
+4027     e8/call  check-ints-equal/disp32
+4028     # . . discard args
+4029     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+4030     # . epilog
+4031     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+4032     5d/pop-to-EBP
+4033     c3/return
+4034 
+4035 test-next-positive-hex-int-zero:
+4036     # . prolog
+4037     55/push-EBP
+4038     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+4039     # (EAX..ECX) = "0"
+4040     b8/copy-to-EAX  "0"/imm32
+4041     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
+4042     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
+4043     05/add-to-EAX  4/imm32
+4044     # var slice/ECX = {EAX, ECX}
+4045     51/push-ECX
+4046     50/push-EAX
+4047     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+4048     # EAX = next-positive-hex-int(slice)
+4049     # . . push args
+4050     51/push-ECX
+4051     # . . call
+4052     e8/call  next-positive-hex-int/disp32
+4053     # . . discard args
+4054     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+4055     # check-ints-equal(EAX, 0, msg)
+4056     # . . push args
+4057     68/push  "F - test-next-positive-hex-int-zero"/imm32
+4058     68/push  0/imm32
+4059     50/push-EAX
+4060     # . . call
+4061     e8/call  check-ints-equal/disp32
+4062     # . . discard args
+4063     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+4064     # . epilog
+4065     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+4066     5d/pop-to-EBP
+4067     c3/return
+4068 
+4069 test-next-positive-hex-int-0-prefix:
+4070     # . prolog
+4071     55/push-EBP
+4072     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
+4073     # (EAX..ECX) = "03)"
+4074     b8/copy-to-EAX  "03)"/imm32
+4075     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
+4076     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    0/base/EAX  1/index/ECX   .           1/r32/ECX   4/disp8         .                 # copy EAX+ECX+4 to ECX
+4077     05/add-to-EAX  4/imm32
+4078     # var slice/ECX = {EAX, ECX}
+4079     51/push-ECX
+4080     50/push-EAX
+4081     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
+4082     # EAX = next-positive-hex-int(slice)
+4083     # . . push args
+4084     51/push-ECX
+4085     # . . call
+4086     e8/call  next-positive-hex-int/disp32
+4087     # . . discard args
+4088     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
+4089     # check-ints-equal(EAX, 3, msg)
+4090     # . . push args
+4091     68/push  "F - test-next-positive-hex-int-0-prefix"/imm32
+4092     68/push  3/imm32
+4093     50/push-EAX
+4094     # . . call
+4095     e8/call  check-ints-equal/disp32
+4096     # . . discard args
+4097     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
+4098     # . epilog
+4099     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
+4100     5d/pop-to-EBP
+4101     c3/return
+4102 
+4103 == data
+4104 Registers:  # (table string int)
+4105   # a table is a stream
+4106   0x40/imm32/write
+4107   0/imm32/read
+4108   0x40/imm32/length
+4109   # data
+4110   "eax"/imm32  0/imm32
+4111   "ecx"/imm32  1/imm32
+4112   "edx"/imm32  2/imm32
+4113   "ebx"/imm32  3/imm32
+4114   "esp"/imm32  4/imm32
+4115   "ebp"/imm32  5/imm32
+4116   "esi"/imm32  6/imm32
+4117   "edi"/imm32  7/imm32
+4118 
+4119 # . . vim:nowrap:textwidth=0
+
+ + + -- cgit 1.4.1-2-gfad0