From ec73ed1230d75deb0f913a32617c9f1e0a5ca640 Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Fri, 10 Jul 2020 23:44:10 -0700 Subject: 6631 --- html/124next-token.subx.html | 1988 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1988 insertions(+) create mode 100644 html/124next-token.subx.html (limited to 'html/124next-token.subx.html') diff --git a/html/124next-token.subx.html b/html/124next-token.subx.html new file mode 100644 index 00000000..a14c0fb8 --- /dev/null +++ b/html/124next-token.subx.html @@ -0,0 +1,1988 @@ + + + + +Mu - 124next-token.subx + + + + + + + + + + +https://github.com/akkartik/mu/blob/master/124next-token.subx +
+   1 # Some tokenization primitives.
+   2 
+   3 == code
+   4 #   instruction                     effective address                                                   register    displacement    immediate
+   5 # . op          subop               mod             rm32          base        index         scale       r32
+   6 # . 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
+   7 
+   8 # extract the next run of characters that are different from a given 'delimiter' (skipping multiple delimiters if necessary)
+   9 # on reaching end of file, return an empty interval
+  10 next-token:  # in: (addr stream byte), delimiter: byte, out: (addr slice)
+  11     # . prologue
+  12     55/push-ebp
+  13     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+  14     # . save registers
+  15     50/push-eax
+  16     51/push-ecx
+  17     56/push-esi
+  18     57/push-edi
+  19     # esi = in
+  20     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
+  21     # edi = out
+  22     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           7/r32/edi   0x10/disp8      .                 # copy *(ebp+16) to edi
+  23     # skip-chars-matching(in, delimiter)
+  24     # . . push args
+  25     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+  26     56/push-esi
+  27     # . . call
+  28     e8/call  skip-chars-matching/disp32
+  29     # . . discard args
+  30     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+  31     # out->start = &in->data[in->read]
+  32     8b/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   4/disp8         .                 # copy *(esi+4) to ecx
+  33     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
+  34     89/copy                         0/mod/indirect  7/rm32/edi    .           .             .           0/r32/eax   .               .                 # copy eax to *edi
+  35     # skip-chars-not-matching(in, delimiter)
+  36     # . . push args
+  37     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
+  38     56/push-esi
+  39     # . . call
+  40     e8/call  skip-chars-not-matching/disp32
+  41     # . . discard args
+  42     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+  43     # out->end = &in->data[in->read]
+  44     8b/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   4/disp8         .                 # copy *(esi+4) to ecx
+  45     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
+  46     89/copy                         1/mod/*+disp8   7/rm32/edi    .           .             .           0/r32/eax   4/disp8         .                 # copy eax to *(edi+4)
+  47     # . restore registers
+  48     5f/pop-to-edi
+  49     5e/pop-to-esi
+  50     59/pop-to-ecx
+  51     58/pop-to-eax
+  52     # . epilogue
+  53     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+  54     5d/pop-to-ebp
+  55     c3/return
+  56 
+  57 test-next-token:
+  58     # . prologue
+  59     55/push-ebp
+  60     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+  61     # setup
+  62     # . clear-stream(_test-stream)
+  63     # . . push args
+  64     68/push  _test-stream/imm32
+  65     # . . call
+  66     e8/call  clear-stream/disp32
+  67     # . . discard args
+  68     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+  69     # var slice/ecx: slice
+  70     68/push  0/imm32/end
+  71     68/push  0/imm32/start
+  72     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+  73     # write(_test-stream, "  ab")
+  74     # . . push args
+  75     68/push  "  ab"/imm32
+  76     68/push  _test-stream/imm32
+  77     # . . call
+  78     e8/call  write/disp32
+  79     # . . discard args
+  80     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+  81     # next-token(_test-stream, 0x20/space, slice)
+  82     # . . push args
+  83     51/push-ecx
+  84     68/push  0x20/imm32
+  85     68/push  _test-stream/imm32
+  86     # . . call
+  87     e8/call  next-token/disp32
+  88     # . . discard args
+  89     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+  90     # check-ints-equal(slice->start - _test-stream->data, 2, msg)
+  91     # . check-ints-equal(slice->start - _test-stream, 14, msg)
+  92     # . . push args
+  93     68/push  "F - test-next-token: start"/imm32
+  94     68/push  0xe/imm32
+  95     # . . push slice->start - _test-stream
+  96     8b/copy                         0/mod/indirect  1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # copy *ecx to eax
+  97     81          5/subop/subtract    3/mod/direct    0/rm32/eax    .           .             .           .           .               _test-stream/imm32 # subtract from eax
+  98     50/push-eax
+  99     # . . call
+ 100     e8/call  check-ints-equal/disp32
+ 101     # . . discard args
+ 102     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 103     # check-ints-equal(slice->end - _test-stream->data, 4, msg)
+ 104     # . check-ints-equal(slice->end - _test-stream, 16, msg)
+ 105     # . . push args
+ 106     68/push  "F - test-next-token: end"/imm32
+ 107     68/push  0x10/imm32
+ 108     # . . push slice->end - _test-stream
+ 109     8b/copy                         1/mod/*+disp8   1/rm32/ecx    .           .             .           0/r32/eax   4/disp8         .                 # copy *(ecx+4) to eax
+ 110     81          5/subop/subtract    3/mod/direct    0/rm32/eax    .           .             .           .           .               _test-stream/imm32 # subtract from eax
+ 111     50/push-eax
+ 112     # . . call
+ 113     e8/call  check-ints-equal/disp32
+ 114     # . . discard args
+ 115     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 116     # . epilogue
+ 117     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+ 118     5d/pop-to-ebp
+ 119     c3/return
+ 120 
+ 121 test-next-token-Eof:
+ 122     # . prologue
+ 123     55/push-ebp
+ 124     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 125     # setup
+ 126     # . clear-stream(_test-stream)
+ 127     # . . push args
+ 128     68/push  _test-stream/imm32
+ 129     # . . call
+ 130     e8/call  clear-stream/disp32
+ 131     # . . discard args
+ 132     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+ 133     # var slice/ecx: slice
+ 134     68/push  0/imm32/end
+ 135     68/push  0/imm32/start
+ 136     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
+ 137     # write nothing to _test-stream
+ 138     # next-token(_test-stream, 0x20/space, slice)
+ 139     # . . push args
+ 140     51/push-ecx
+ 141     68/push  0x20/imm32
+ 142     68/push  _test-stream/imm32
+ 143     # . . call
+ 144     e8/call  next-token/disp32
+ 145     # . . discard args
+ 146     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 147     # check-ints-equal(slice->end, slice->start, msg)
+ 148     # . . push args
+ 149     68/push  "F - test-next-token-Eof"/imm32
+ 150     ff          6/subop/push        1/mod/*+disp8   1/rm32/ecx    .           .             .           .           4/disp8         .                 # push *(ecx+4)
+ 151     ff          6/subop/push        0/mod/indirect  1/rm32/ecx    .           .             .           .           .               .                 # push *ecx
+ 152     # . . call
+ 153     e8/call  check-ints-equal/disp32
+ 154     # . . discard args
+ 155     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 156     # . epilogue
+ 157     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+ 158     5d/pop-to-ebp
+ 159     c3/return
+ 160 
+ 161 # extract the next run of characters that are different from a given 'delimiter' (skipping multiple delimiters if necessary)
+ 162 # on reaching end of file, return an empty interval
+ 163 next-token-from-slice:  # start: (addr byte), end: (addr byte), delimiter: byte, out: (addr slice)
+ 164     # . prologue
+ 165     55/push-ebp
+ 166     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 167     # . save registers
+ 168     50/push-eax
+ 169     51/push-ecx
+ 170     52/push-edx
+ 171     57/push-edi
+ 172     # ecx = end
+ 173     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           1/r32/ecx   0xc/disp8       .                 # copy *(ebp+12) to ecx
+ 174     # edx = delimiter
+ 175     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           2/r32/edx   0x10/disp8      .                 # copy *(ebp+16) to edx
+ 176     # edi = out
+ 177     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           7/r32/edi   0x14/disp8      .                 # copy *(ebp+20) to edi
+ 178     # eax = skip-chars-matching-in-slice(start, end, delimiter)
+ 179     # . . push args
+ 180     52/push-edx
+ 181     51/push-ecx
+ 182     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
+ 183     # . . call
+ 184     e8/call  skip-chars-matching-in-slice/disp32
+ 185     # . . discard args
+ 186     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 187     # out->start = eax
+ 188     89/copy                         0/mod/indirect  7/rm32/edi    .           .             .           0/r32/eax   .               .                 # copy eax to *edi
+ 189     # eax = skip-chars-not-matching-in-slice(eax, end, delimiter)
+ 190     # . . push args
+ 191     52/push-edx
+ 192     51/push-ecx
+ 193     50/push-eax
+ 194     # . . call
+ 195     e8/call  skip-chars-not-matching-in-slice/disp32
+ 196     # . . discard args
+ 197     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 198     # out->end = eax
+ 199     89/copy                         1/mod/*+disp8   7/rm32/edi    .           .             .           0/r32/eax   4/disp8         .                 # copy eax to *(edi+4)
+ 200     # . restore registers
+ 201     5f/pop-to-edi
+ 202     5a/pop-to-edx
+ 203     59/pop-to-ecx
+ 204     58/pop-to-eax
+ 205     # . epilogue
+ 206     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+ 207     5d/pop-to-ebp
+ 208     c3/return
+ 209 
+ 210 test-next-token-from-slice:
+ 211     # . prologue
+ 212     55/push-ebp
+ 213     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 214     # (eax..ecx) = "  ab"
+ 215     b8/copy-to-eax  "  ab"/imm32
+ 216     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
+ 217     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
+ 218     05/add-to-eax  4/imm32
+ 219     # var out/edi: slice
+ 220     68/push  0/imm32/end
+ 221     68/push  0/imm32/start
+ 222     89/copy                         3/mod/direct    7/rm32/edi    .           .             .           4/r32/esp   .               .                 # copy esp to edi
+ 223     # next-token-from-slice(eax, ecx, 0x20/space, out)
+ 224     # . . push args
+ 225     57/push-edi
+ 226     68/push  0x20/imm32
+ 227     51/push-ecx
+ 228     50/push-eax
+ 229     # . . call
+ 230     e8/call  next-token-from-slice/disp32
+ 231     # . . discard args
+ 232     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
+ 233     # out->start should be at the 'a'
+ 234     # . check-ints-equal(out->start - in->start, 2, msg)
+ 235     # . . push args
+ 236     68/push  "F - test-next-token-from-slice: start"/imm32
+ 237     68/push  2/imm32
+ 238     # . . push out->start - in->start
+ 239     8b/copy                         0/mod/indirect  7/rm32/edi    .           .             .           1/r32/ecx   .               .                 # copy *edi to ecx
+ 240     2b/subtract                     3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # subtract eax from ecx
+ 241     51/push-ecx
+ 242     # . . call
+ 243     e8/call  check-ints-equal/disp32
+ 244     # . . discard args
+ 245     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 246     # out->end should be after the 'b'
+ 247     # check-ints-equal(out->end - in->start, 4, msg)
+ 248     # . . push args
+ 249     68/push  "F - test-next-token-from-slice: end"/imm32
+ 250     68/push  4/imm32
+ 251     # . . push out->end - in->start
+ 252     8b/copy                         1/mod/*+disp8   7/rm32/edi    .           .             .           1/r32/ecx   4/disp8         .                 # copy *(edi+4) to ecx
+ 253     2b/subtract                     3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # subtract eax from ecx
+ 254     51/push-ecx
+ 255     # . . call
+ 256     e8/call  check-ints-equal/disp32
+ 257     # . . discard args
+ 258     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 259     # . epilogue
+ 260     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+ 261     5d/pop-to-ebp
+ 262     c3/return
+ 263 
+ 264 test-next-token-from-slice-Eof:
+ 265     # . prologue
+ 266     55/push-ebp
+ 267     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 268     # var out/edi: slice
+ 269     68/push  0/imm32/end
+ 270     68/push  0/imm32/start
+ 271     89/copy                         3/mod/direct    7/rm32/edi    .           .             .           4/r32/esp   .               .                 # copy esp to edi
+ 272     # next-token-from-slice(0, 0, 0x20/space, out)
+ 273     # . . push args
+ 274     57/push-edi
+ 275     68/push  0x20/imm32
+ 276     68/push  0/imm32
+ 277     68/push  0/imm32
+ 278     # . . call
+ 279     e8/call  next-token-from-slice/disp32
+ 280     # . . discard args
+ 281     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
+ 282     # out should be empty
+ 283     # . check-ints-equal(out->end - out->start, 0, msg)
+ 284     # . . push args
+ 285     68/push  "F - test-next-token-from-slice-Eof"/imm32
+ 286     68/push  0/imm32
+ 287     # . . push out->start - in->start
+ 288     8b/copy                         1/mod/*+disp8   7/rm32/edi    .           .             .           1/r32/ecx   4/disp8         .                 # copy *(edi+4) to ecx
+ 289     2b/subtract                     0/mod/indirect  7/rm32/edi    .           .             .           1/r32/ecx   .               .                 # subtract *edi from ecx
+ 290     51/push-ecx
+ 291     # . . call
+ 292     e8/call  check-ints-equal/disp32
+ 293     # . . discard args
+ 294     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 295     # . epilogue
+ 296     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+ 297     5d/pop-to-ebp
+ 298     c3/return
+ 299 
+ 300 test-next-token-from-slice-nothing:
+ 301     # . prologue
+ 302     55/push-ebp
+ 303     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 304     # (eax..ecx) = "    "
+ 305     b8/copy-to-eax  "    "/imm32
+ 306     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
+ 307     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
+ 308     05/add-to-eax  4/imm32
+ 309     # var out/edi: slice
+ 310     68/push  0/imm32/end
+ 311     68/push  0/imm32/start
+ 312     89/copy                         3/mod/direct    7/rm32/edi    .           .             .           4/r32/esp   .               .                 # copy esp to edi
+ 313     # next-token-from-slice(in, 0x20/space, out)
+ 314     # . . push args
+ 315     57/push-edi
+ 316     68/push  0x20/imm32
+ 317     51/push-ecx
+ 318     50/push-eax
+ 319     # . . call
+ 320     e8/call  next-token-from-slice/disp32
+ 321     # . . discard args
+ 322     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0x10/imm32        # add to esp
+ 323     # out should be empty
+ 324     # . check-ints-equal(out->end - out->start, 0, msg)
+ 325     # . . push args
+ 326     68/push  "F - test-next-token-from-slice-Eof"/imm32
+ 327     68/push  0/imm32
+ 328     # . . push out->start - in->start
+ 329     8b/copy                         1/mod/*+disp8   7/rm32/edi    .           .             .           1/r32/ecx   4/disp8         .                 # copy *(edi+4) to ecx
+ 330     2b/subtract                     0/mod/indirect  7/rm32/edi    .           .             .           1/r32/ecx   .               .                 # subtract *edi from ecx
+ 331     51/push-ecx
+ 332     # . . call
+ 333     e8/call  check-ints-equal/disp32
+ 334     # . . discard args
+ 335     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 336     # . epilogue
+ 337     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+ 338     5d/pop-to-ebp
+ 339     c3/return
+ 340 
+ 341 skip-chars-matching:  # in: (addr stream byte), delimiter: byte
+ 342     # . prologue
+ 343     55/push-ebp
+ 344     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 345     # . save registers
+ 346     50/push-eax
+ 347     51/push-ecx
+ 348     52/push-edx
+ 349     53/push-ebx
+ 350     56/push-esi
+ 351     # esi = in
+ 352     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
+ 353     # ecx = in->read
+ 354     8b/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   4/disp8         .                 # copy *(esi+4) to ecx
+ 355     # ebx = in->write
+ 356     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           3/r32/ebx   .               .                 # copy *esi to ebx
+ 357     # edx = delimiter
+ 358     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           2/r32/edx   0xc/disp8       .                 # copy *(ebp+12) to edx
+ 359 $skip-chars-matching:loop:
+ 360     # if (in->read >= in->write) break
+ 361     39/compare                      3/mod/direct    1/rm32/ecx    .           .             .           3/r32/ebx   .               .                 # compare ecx with ebx
+ 362     7d/jump-if->=  $skip-chars-matching:end/disp8
+ 363     # eax = in->data[in->read]
+ 364     31/xor                          3/mod/direct    0/rm32/eax    .           .             .           0/r32/eax   .               .                 # clear eax
+ 365     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
+ 366     # if (eax != delimiter) break
+ 367     39/compare                      3/mod/direct    0/rm32/eax    .           .             .           2/r32/edx   .               .                 # compare eax and edx
+ 368     75/jump-if-!=  $skip-chars-matching:end/disp8
+ 369     # ++in->read
+ 370     41/increment-ecx
+ 371     eb/jump  $skip-chars-matching:loop/disp8
+ 372 $skip-chars-matching:end:
+ 373     # persist in->read
+ 374     89/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   4/disp8         .                 # copy ecx to *(esi+4)
+ 375     # . restore registers
+ 376     5e/pop-to-esi
+ 377     5b/pop-to-ebx
+ 378     5a/pop-to-edx
+ 379     59/pop-to-ecx
+ 380     58/pop-to-eax
+ 381     # . epilogue
+ 382     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+ 383     5d/pop-to-ebp
+ 384     c3/return
+ 385 
+ 386 test-skip-chars-matching:
+ 387     # setup
+ 388     # . clear-stream(_test-stream)
+ 389     # . . push args
+ 390     68/push  _test-stream/imm32
+ 391     # . . call
+ 392     e8/call  clear-stream/disp32
+ 393     # . . discard args
+ 394     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+ 395     # write(_test-stream, "  ab")
+ 396     # . . push args
+ 397     68/push  "  ab"/imm32
+ 398     68/push  _test-stream/imm32
+ 399     # . . call
+ 400     e8/call  write/disp32
+ 401     # . . discard args
+ 402     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 403     # skip-chars-matching(_test-stream, 0x20/space)
+ 404     # . . push args
+ 405     68/push  0x20/imm32
+ 406     68/push  _test-stream/imm32
+ 407     # . . call
+ 408     e8/call  skip-chars-matching/disp32
+ 409     # . . discard args
+ 410     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 411     # check-ints-equal(_test-stream->read, 2, msg)
+ 412     # . . push args
+ 413     68/push  "F - test-skip-chars-matching"/imm32
+ 414     68/push  2/imm32
+ 415     # . . push *_test-stream->read
+ 416     b8/copy-to-eax  _test-stream/imm32
+ 417     ff          6/subop/push        1/mod/*+disp8   0/rm32/eax    .           .             .           .           4/disp8         .                 # push *(eax+4)
+ 418     # . . call
+ 419     e8/call  check-ints-equal/disp32
+ 420     # . . discard args
+ 421     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 422     # end
+ 423     c3/return
+ 424 
+ 425 test-skip-chars-matching-none:
+ 426     # setup
+ 427     # . clear-stream(_test-stream)
+ 428     # . . push args
+ 429     68/push  _test-stream/imm32
+ 430     # . . call
+ 431     e8/call  clear-stream/disp32
+ 432     # . . discard args
+ 433     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+ 434     # write(_test-stream, "ab")
+ 435     # . . push args
+ 436     68/push  "ab"/imm32
+ 437     68/push  _test-stream/imm32
+ 438     # . . call
+ 439     e8/call  write/disp32
+ 440     # . . discard args
+ 441     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 442     # skip-chars-matching(_test-stream, 0x20/space)
+ 443     # . . push args
+ 444     68/push  0x20/imm32
+ 445     68/push  _test-stream/imm32
+ 446     # . . call
+ 447     e8/call  skip-chars-matching/disp32
+ 448     # . . discard args
+ 449     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 450     # check-ints-equal(_test-stream->read, 0, msg)
+ 451     # . . push args
+ 452     68/push  "F - test-skip-chars-matching-none"/imm32
+ 453     68/push  0/imm32
+ 454     # . . push *_test-stream->read
+ 455     b8/copy-to-eax  _test-stream/imm32
+ 456     ff          6/subop/push        1/mod/*+disp8   0/rm32/eax    .           .             .           .           4/disp8         .                 # push *(eax+4)
+ 457     # . . call
+ 458     e8/call  check-ints-equal/disp32
+ 459     # . . discard args
+ 460     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 461     # end
+ 462     c3/return
+ 463 
+ 464 skip-chars-matching-whitespace:  # in: (addr stream byte)
+ 465     # . prologue
+ 466     55/push-ebp
+ 467     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 468     # . save registers
+ 469     50/push-eax
+ 470     51/push-ecx
+ 471     53/push-ebx
+ 472     56/push-esi
+ 473     # esi = in
+ 474     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
+ 475     # ecx = in->read
+ 476     8b/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   4/disp8         .                 # copy *(esi+4) to ecx
+ 477     # ebx = in->write
+ 478     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           3/r32/ebx   .               .                 # copy *esi to ebx
+ 479 $skip-chars-matching-whitespace:loop:
+ 480     # if (in->read >= in->write) break
+ 481     39/compare                      3/mod/direct    1/rm32/ecx    .           .             .           3/r32/ebx   .               .                 # compare ecx with ebx
+ 482     7d/jump-if->=  $skip-chars-matching-whitespace:end/disp8
+ 483     # eax = in->data[in->read]
+ 484     31/xor                          3/mod/direct    0/rm32/eax    .           .             .           0/r32/eax   .               .                 # clear eax
+ 485     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
+ 486     # if (eax == ' ') goto body
+ 487     3d/compare-eax-and  0x20/imm32/space
+ 488     74/jump-if-=  $skip-chars-matching-whitespace:body/disp8
+ 489     # if (eax == '\n') goto body
+ 490     3d/compare-eax-and  0x0a/imm32/newline
+ 491     74/jump-if-=  $skip-chars-matching-whitespace:body/disp8
+ 492     # if (eax == '\t') goto body
+ 493     3d/compare-eax-and  0x09/imm32/tab
+ 494     74/jump-if-=  $skip-chars-matching-whitespace:body/disp8
+ 495     # if (eax != '\r') break
+ 496     3d/compare-eax-and  0x0d/imm32/cr
+ 497     75/jump-if-!=  $skip-chars-matching-whitespace:end/disp8
+ 498 $skip-chars-matching-whitespace:body:
+ 499     # ++in->read
+ 500     41/increment-ecx
+ 501     eb/jump  $skip-chars-matching-whitespace:loop/disp8
+ 502 $skip-chars-matching-whitespace:end:
+ 503     # persist in->read
+ 504     89/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   4/disp8         .                 # copy ecx to *(esi+4)
+ 505     # . restore registers
+ 506     5e/pop-to-esi
+ 507     5b/pop-to-ebx
+ 508     59/pop-to-ecx
+ 509     58/pop-to-eax
+ 510     # . epilogue
+ 511     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+ 512     5d/pop-to-ebp
+ 513     c3/return
+ 514 
+ 515 test-skip-chars-matching-whitespace:
+ 516     # setup
+ 517     # . clear-stream(_test-stream)
+ 518     # . . push args
+ 519     68/push  _test-stream/imm32
+ 520     # . . call
+ 521     e8/call  clear-stream/disp32
+ 522     # . . discard args
+ 523     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+ 524     # write(_test-stream, " \nab")
+ 525     # . . push args
+ 526     68/push  " \nab"/imm32
+ 527     68/push  _test-stream/imm32
+ 528     # . . call
+ 529     e8/call  write/disp32
+ 530     # . . discard args
+ 531     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 532     # skip-chars-matching-whitespace(_test-stream)
+ 533     # . . push args
+ 534     68/push  _test-stream/imm32
+ 535     # . . call
+ 536     e8/call  skip-chars-matching-whitespace/disp32
+ 537     # . . discard args
+ 538     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+ 539     # check-ints-equal(_test-stream->read, 2, msg)
+ 540     # . . push args
+ 541     68/push  "F - test-skip-chars-matching-whitespace"/imm32
+ 542     68/push  2/imm32
+ 543     # . . push *_test-stream->read
+ 544     b8/copy-to-eax  _test-stream/imm32
+ 545     ff          6/subop/push        1/mod/*+disp8   0/rm32/eax    .           .             .           .           4/disp8         .                 # push *(eax+4)
+ 546     # . . call
+ 547     e8/call  check-ints-equal/disp32
+ 548     # . . discard args
+ 549     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 550     # end
+ 551     c3/return
+ 552 
+ 553 # minor fork of 'skip-chars-matching'
+ 554 skip-chars-not-matching:  # in: (addr stream byte), delimiter: byte
+ 555     # . prologue
+ 556     55/push-ebp
+ 557     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 558     # . save registers
+ 559     50/push-eax
+ 560     51/push-ecx
+ 561     52/push-edx
+ 562     53/push-ebx
+ 563     56/push-esi
+ 564     # esi = in
+ 565     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
+ 566     # ecx = in->read
+ 567     8b/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   4/disp8         .                 # copy *(esi+4) to ecx
+ 568     # ebx = in->write
+ 569     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           3/r32/ebx   .               .                 # copy *esi to ebx
+ 570     # edx = delimiter
+ 571     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           2/r32/edx   0xc/disp8       .                 # copy *(ebp+12) to edx
+ 572 $skip-chars-not-matching:loop:
+ 573     # if (in->read >= in->write) break
+ 574     39/compare                      3/mod/direct    1/rm32/ecx    .           .             .           3/r32/ebx   .               .                 # compare ecx with ebx
+ 575     7d/jump-if->=  $skip-chars-not-matching:end/disp8
+ 576     # eax = in->data[in->read]
+ 577     31/xor                          3/mod/direct    0/rm32/eax    .           .             .           0/r32/eax   .               .                 # clear eax
+ 578     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
+ 579     # if (eax == delimiter) break
+ 580     39/compare                      3/mod/direct    0/rm32/eax    .           .             .           2/r32/edx   .               .                 # compare eax and edx
+ 581     74/jump-if-=  $skip-chars-not-matching:end/disp8
+ 582     # ++in->read
+ 583     41/increment-ecx
+ 584     eb/jump  $skip-chars-not-matching:loop/disp8
+ 585 $skip-chars-not-matching:end:
+ 586     # persist in->read
+ 587     89/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   4/disp8         .                 # copy ecx to *(esi+4)
+ 588     # . restore registers
+ 589     5e/pop-to-esi
+ 590     5b/pop-to-ebx
+ 591     5a/pop-to-edx
+ 592     59/pop-to-ecx
+ 593     58/pop-to-eax
+ 594     # . epilogue
+ 595     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+ 596     5d/pop-to-ebp
+ 597     c3/return
+ 598 
+ 599 test-skip-chars-not-matching:
+ 600     # setup
+ 601     # . clear-stream(_test-stream)
+ 602     # . . push args
+ 603     68/push  _test-stream/imm32
+ 604     # . . call
+ 605     e8/call  clear-stream/disp32
+ 606     # . . discard args
+ 607     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+ 608     # write(_test-stream, "ab ")
+ 609     # . . push args
+ 610     68/push  "ab "/imm32
+ 611     68/push  _test-stream/imm32
+ 612     # . . call
+ 613     e8/call  write/disp32
+ 614     # . . discard args
+ 615     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 616     # skip-chars-not-matching(_test-stream, 0x20/space)
+ 617     # . . push args
+ 618     68/push  0x20/imm32
+ 619     68/push  _test-stream/imm32
+ 620     # . . call
+ 621     e8/call  skip-chars-not-matching/disp32
+ 622     # . . discard args
+ 623     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 624     # check-ints-equal(_test-stream->read, 2, msg)
+ 625     # . . push args
+ 626     68/push  "F - test-skip-chars-not-matching"/imm32
+ 627     68/push  2/imm32
+ 628     # . . push *_test-stream->read
+ 629     b8/copy-to-eax  _test-stream/imm32
+ 630     ff          6/subop/push        1/mod/*+disp8   0/rm32/eax    .           .             .           .           4/disp8         .                 # push *(eax+4)
+ 631     # . . call
+ 632     e8/call  check-ints-equal/disp32
+ 633     # . . discard args
+ 634     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 635     # end
+ 636     c3/return
+ 637 
+ 638 test-skip-chars-not-matching-none:
+ 639     # setup
+ 640     # . clear-stream(_test-stream)
+ 641     # . . push args
+ 642     68/push  _test-stream/imm32
+ 643     # . . call
+ 644     e8/call  clear-stream/disp32
+ 645     # . . discard args
+ 646     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+ 647     # write(_test-stream, " ab")
+ 648     # . . push args
+ 649     68/push  " ab"/imm32
+ 650     68/push  _test-stream/imm32
+ 651     # . . call
+ 652     e8/call  write/disp32
+ 653     # . . discard args
+ 654     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 655     # skip-chars-not-matching(_test-stream, 0x20/space)
+ 656     # . . push args
+ 657     68/push  0x20/imm32
+ 658     68/push  _test-stream/imm32
+ 659     # . . call
+ 660     e8/call  skip-chars-not-matching/disp32
+ 661     # . . discard args
+ 662     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 663     # check-ints-equal(_test-stream->read, 0, msg)
+ 664     # . . push args
+ 665     68/push  "F - test-skip-chars-not-matching-none"/imm32
+ 666     68/push  0/imm32
+ 667     # . . push *_test-stream->read
+ 668     b8/copy-to-eax  _test-stream/imm32
+ 669     ff          6/subop/push        1/mod/*+disp8   0/rm32/eax    .           .             .           .           4/disp8         .                 # push *(eax+4)
+ 670     # . . call
+ 671     e8/call  check-ints-equal/disp32
+ 672     # . . discard args
+ 673     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 674     # end
+ 675     c3/return
+ 676 
+ 677 test-skip-chars-not-matching-all:
+ 678     # setup
+ 679     # . clear-stream(_test-stream)
+ 680     # . . push args
+ 681     68/push  _test-stream/imm32
+ 682     # . . call
+ 683     e8/call  clear-stream/disp32
+ 684     # . . discard args
+ 685     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+ 686     # write(_test-stream, "ab")
+ 687     # . . push args
+ 688     68/push  "ab"/imm32
+ 689     68/push  _test-stream/imm32
+ 690     # . . call
+ 691     e8/call  write/disp32
+ 692     # . . discard args
+ 693     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 694     # skip-chars-not-matching(_test-stream, 0x20/space)
+ 695     # . . push args
+ 696     68/push  0x20/imm32
+ 697     68/push  _test-stream/imm32
+ 698     # . . call
+ 699     e8/call  skip-chars-not-matching/disp32
+ 700     # . . discard args
+ 701     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 702     # check-ints-equal(_test-stream->read, 2, msg)
+ 703     # . . push args
+ 704     68/push  "F - test-skip-chars-not-matching-all"/imm32
+ 705     68/push  2/imm32
+ 706     # . . push *_test-stream->read
+ 707     b8/copy-to-eax  _test-stream/imm32
+ 708     ff          6/subop/push        1/mod/*+disp8   0/rm32/eax    .           .             .           .           4/disp8         .                 # push *(eax+4)
+ 709     # . . call
+ 710     e8/call  check-ints-equal/disp32
+ 711     # . . discard args
+ 712     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 713     # end
+ 714     c3/return
+ 715 
+ 716 skip-chars-not-matching-whitespace:  # in: (addr stream byte)
+ 717     # . prologue
+ 718     55/push-ebp
+ 719     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 720     # . save registers
+ 721     50/push-eax
+ 722     51/push-ecx
+ 723     53/push-ebx
+ 724     56/push-esi
+ 725     # esi = in
+ 726     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
+ 727     # ecx = in->read
+ 728     8b/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   4/disp8         .                 # copy *(esi+4) to ecx
+ 729     # ebx = in->write
+ 730     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           3/r32/ebx   .               .                 # copy *esi to ebx
+ 731 $skip-chars-not-matching-whitespace:loop:
+ 732     # if (in->read >= in->write) break
+ 733     39/compare                      3/mod/direct    1/rm32/ecx    .           .             .           3/r32/ebx   .               .                 # compare ecx with ebx
+ 734     7d/jump-if->=  $skip-chars-not-matching-whitespace:end/disp8
+ 735     # eax = in->data[in->read]
+ 736     31/xor                          3/mod/direct    0/rm32/eax    .           .             .           0/r32/eax   .               .                 # clear eax
+ 737     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
+ 738     # if (eax == ' ') break
+ 739     3d/compare-eax-and  0x20/imm32/space
+ 740     74/jump-if-=  $skip-chars-not-matching-whitespace:end/disp8
+ 741     # if (eax == '\n') break
+ 742     3d/compare-eax-and  0x0a/imm32/newline
+ 743     74/jump-if-=  $skip-chars-not-matching-whitespace:end/disp8
+ 744     # if (eax == '\t') break
+ 745     3d/compare-eax-and  0x09/imm32/tab
+ 746     74/jump-if-=  $skip-chars-not-matching-whitespace:end/disp8
+ 747     # if (eax == '\r') break
+ 748     3d/compare-eax-and  0x0d/imm32/cr
+ 749     74/jump-if-=  $skip-chars-not-matching-whitespace:end/disp8
+ 750     # ++in->read
+ 751     41/increment-ecx
+ 752     eb/jump  $skip-chars-not-matching-whitespace:loop/disp8
+ 753 $skip-chars-not-matching-whitespace:end:
+ 754     # persist in->read
+ 755     89/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   4/disp8         .                 # copy ecx to *(esi+4)
+ 756     # . restore registers
+ 757     5e/pop-to-esi
+ 758     5b/pop-to-ebx
+ 759     59/pop-to-ecx
+ 760     58/pop-to-eax
+ 761     # . epilogue
+ 762     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+ 763     5d/pop-to-ebp
+ 764     c3/return
+ 765 
+ 766 test-skip-chars-not-matching-whitespace:
+ 767     # setup
+ 768     # . clear-stream(_test-stream)
+ 769     # . . push args
+ 770     68/push  _test-stream/imm32
+ 771     # . . call
+ 772     e8/call  clear-stream/disp32
+ 773     # . . discard args
+ 774     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+ 775     # write(_test-stream, "ab\n")
+ 776     # . . push args
+ 777     68/push  "ab\n"/imm32
+ 778     68/push  _test-stream/imm32
+ 779     # . . call
+ 780     e8/call  write/disp32
+ 781     # . . discard args
+ 782     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 783     # skip-chars-not-matching-whitespace(_test-stream)
+ 784     # . . push args
+ 785     68/push  _test-stream/imm32
+ 786     # . . call
+ 787     e8/call  skip-chars-not-matching-whitespace/disp32
+ 788     # . . discard args
+ 789     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+ 790     # check-ints-equal(_test-stream->read, 2, msg)
+ 791     # . . push args
+ 792     68/push  "F - test-skip-chars-not-matching-whitespace"/imm32
+ 793     68/push  2/imm32
+ 794     # . . push *_test-stream->read
+ 795     b8/copy-to-eax  _test-stream/imm32
+ 796     ff          6/subop/push        1/mod/*+disp8   0/rm32/eax    .           .             .           .           4/disp8         .                 # push *(eax+4)
+ 797     # . . call
+ 798     e8/call  check-ints-equal/disp32
+ 799     # . . discard args
+ 800     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 801     # end
+ 802     c3/return
+ 803 
+ 804 skip-chars-matching-in-slice:  # curr: (addr byte), end: (addr byte), delimiter: byte -> curr/eax
+ 805     # . prologue
+ 806     55/push-ebp
+ 807     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 808     # . save registers
+ 809     51/push-ecx
+ 810     52/push-edx
+ 811     53/push-ebx
+ 812     # eax = curr
+ 813     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           0/r32/eax   8/disp8         .                 # copy *(ebp+8) to eax
+ 814     # ecx = end
+ 815     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           1/r32/ecx   0xc/disp8       .                 # copy *(ebp+12) to ecx
+ 816     # edx = delimiter
+ 817     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           2/r32/edx   0x10/disp8       .                 # copy *(ebp+16) to edx
+ 818     # var c/ebx: byte = 0
+ 819     31/xor                          3/mod/direct    3/rm32/ebx    .           .             .           3/r32/ebx   .               .                 # clear ebx
+ 820 $skip-chars-matching-in-slice:loop:
+ 821     # if (curr >= end) break
+ 822     39/compare                      3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # compare eax with ecx
+ 823     73/jump-if-addr>=  $skip-chars-matching-in-slice:end/disp8
+ 824     # c = *curr
+ 825     8a/copy-byte                    0/mod/indirect  0/rm32/eax    .           .             .           3/r32/BL    .               .                 # copy byte at *eax to BL
+ 826     # if (c != delimiter) break
+ 827     39/compare                      3/mod/direct    3/rm32/ebx    .           .             .           2/r32/edx   .               .                 # compare ebx and edx
+ 828     75/jump-if-!=  $skip-chars-matching-in-slice:end/disp8
+ 829     # ++curr
+ 830     40/increment-eax
+ 831     eb/jump  $skip-chars-matching-in-slice:loop/disp8
+ 832 $skip-chars-matching-in-slice:end:
+ 833     # . restore registers
+ 834     5b/pop-to-ebx
+ 835     5a/pop-to-edx
+ 836     59/pop-to-ecx
+ 837     # . epilogue
+ 838     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+ 839     5d/pop-to-ebp
+ 840     c3/return
+ 841 
+ 842 test-skip-chars-matching-in-slice:
+ 843     # (eax..ecx) = "  ab"
+ 844     b8/copy-to-eax  "  ab"/imm32
+ 845     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
+ 846     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
+ 847     05/add-to-eax  4/imm32
+ 848     # eax = skip-chars-matching-in-slice(eax, ecx, 0x20/space)
+ 849     # . . push args
+ 850     68/push  0x20/imm32/space
+ 851     51/push-ecx
+ 852     50/push-eax
+ 853     # . . call
+ 854     e8/call  skip-chars-matching-in-slice/disp32
+ 855     # . . discard args
+ 856     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 857     # check-ints-equal(ecx-eax, 2, msg)
+ 858     # . . push args
+ 859     68/push  "F - test-skip-chars-matching-in-slice"/imm32
+ 860     68/push  2/imm32
+ 861     # . . push ecx-eax
+ 862     29/subtract                     3/mod/direct    1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # subtract eax from ecx
+ 863     51/push-ecx
+ 864     # . . call
+ 865     e8/call  check-ints-equal/disp32
+ 866     # . . discard args
+ 867     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 868     # end
+ 869     c3/return
+ 870 
+ 871 test-skip-chars-matching-in-slice-none:
+ 872     # (eax..ecx) = "ab"
+ 873     b8/copy-to-eax  "ab"/imm32
+ 874     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
+ 875     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
+ 876     05/add-to-eax  4/imm32
+ 877     # eax = skip-chars-matching-in-slice(eax, ecx, 0x20/space)
+ 878     # . . push args
+ 879     68/push  0x20/imm32/space
+ 880     51/push-ecx
+ 881     50/push-eax
+ 882     # . . call
+ 883     e8/call  skip-chars-matching-in-slice/disp32
+ 884     # . . discard args
+ 885     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 886     # check-ints-equal(ecx-eax, 2, msg)
+ 887     # . . push args
+ 888     68/push  "F - test-skip-chars-matching-in-slice-none"/imm32
+ 889     68/push  2/imm32
+ 890     # . . push ecx-eax
+ 891     29/subtract                     3/mod/direct    1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # subtract eax from ecx
+ 892     51/push-ecx
+ 893     # . . call
+ 894     e8/call  check-ints-equal/disp32
+ 895     # . . discard args
+ 896     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 897     # end
+ 898     c3/return
+ 899 
+ 900 skip-chars-matching-whitespace-in-slice:  # curr: (addr byte), end: (addr byte) -> curr/eax
+ 901     # . prologue
+ 902     55/push-ebp
+ 903     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 904     # . save registers
+ 905     51/push-ecx
+ 906     53/push-ebx
+ 907     # eax = curr
+ 908     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           0/r32/eax   8/disp8         .                 # copy *(ebp+8) to eax
+ 909     # ecx = end
+ 910     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           1/r32/ecx   0xc/disp8       .                 # copy *(ebp+12) to ecx
+ 911     # var c/ebx: byte = 0
+ 912     31/xor                          3/mod/direct    3/rm32/ebx    .           .             .           3/r32/ebx   .               .                 # clear ebx
+ 913 $skip-chars-matching-whitespace-in-slice:loop:
+ 914     # if (curr >= end) break
+ 915     39/compare                      3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # compare eax with ecx
+ 916     0f 83/jump-if-addr>=  $skip-chars-matching-in-slice:end/disp32
+ 917     # c = *curr
+ 918     8a/copy-byte                    0/mod/indirect  0/rm32/eax    .           .             .           3/r32/BL    .               .                 # copy byte at *eax to BL
+ 919     # if (c == ' ') goto body
+ 920     81          7/subop/compare     3/mod/direct    3/rm32/ebx    .           .             .           .           .               0x20/imm32/space  # compare ebx
+ 921     74/jump-if-=  $skip-chars-matching-whitespace-in-slice:body/disp8
+ 922     # if (c == '\n') goto body
+ 923     81          7/subop/compare     3/mod/direct    3/rm32/ebx    .           .             .           .           .               0x0a/imm32/newline  # compare ebx
+ 924     74/jump-if-=  $skip-chars-matching-whitespace-in-slice:body/disp8
+ 925     # if (c == '\t') goto body
+ 926     81          7/subop/compare     3/mod/direct    3/rm32/ebx    .           .             .           .           .               0x09/imm32/tab    # compare ebx
+ 927     74/jump-if-=  $skip-chars-matching-whitespace-in-slice:body/disp8
+ 928     # if (c != '\r') break
+ 929     81          7/subop/compare     3/mod/direct    3/rm32/ebx    .           .             .           .           .               0x0d/imm32/cr     # compare ebx
+ 930     75/jump-if-!=  $skip-chars-matching-whitespace-in-slice:end/disp8
+ 931 $skip-chars-matching-whitespace-in-slice:body:
+ 932     # ++curr
+ 933     40/increment-eax
+ 934     eb/jump  $skip-chars-matching-whitespace-in-slice:loop/disp8
+ 935 $skip-chars-matching-whitespace-in-slice:end:
+ 936     # . restore registers
+ 937     5b/pop-to-ebx
+ 938     59/pop-to-ecx
+ 939     # . epilogue
+ 940     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+ 941     5d/pop-to-ebp
+ 942     c3/return
+ 943 
+ 944 test-skip-chars-matching-whitespace-in-slice:
+ 945     # (eax..ecx) = " \nab"
+ 946     b8/copy-to-eax  " \nab"/imm32
+ 947     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
+ 948     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
+ 949     05/add-to-eax  4/imm32
+ 950     # eax = skip-chars-matching-whitespace-in-slice(eax, ecx)
+ 951     # . . push args
+ 952     51/push-ecx
+ 953     50/push-eax
+ 954     # . . call
+ 955     e8/call  skip-chars-matching-whitespace-in-slice/disp32
+ 956     # . . discard args
+ 957     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+ 958     # check-ints-equal(ecx-eax, 2, msg)
+ 959     # . . push args
+ 960     68/push  "F - test-skip-chars-matching-whitespace-in-slice"/imm32
+ 961     68/push  2/imm32
+ 962     # . . push ecx-eax
+ 963     29/subtract                     3/mod/direct    1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # subtract eax from ecx
+ 964     51/push-ecx
+ 965     # . . call
+ 966     e8/call  check-ints-equal/disp32
+ 967     # . . discard args
+ 968     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+ 969     # end
+ 970     c3/return
+ 971 
+ 972 # minor fork of 'skip-chars-matching-in-slice'
+ 973 skip-chars-not-matching-in-slice:  # curr: (addr byte), end: (addr byte), delimiter: byte -> curr/eax
+ 974     # . prologue
+ 975     55/push-ebp
+ 976     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+ 977     # . save registers
+ 978     51/push-ecx
+ 979     52/push-edx
+ 980     53/push-ebx
+ 981     # eax = curr
+ 982     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           0/r32/eax   8/disp8         .                 # copy *(ebp+8) to eax
+ 983     # ecx = end
+ 984     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           1/r32/ecx   0xc/disp8       .                 # copy *(ebp+12) to ecx
+ 985     # edx = delimiter
+ 986     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           2/r32/edx   0x10/disp8       .                 # copy *(ebp+16) to edx
+ 987     # var c/ebx: byte = 0
+ 988     31/xor                          3/mod/direct    3/rm32/ebx    .           .             .           3/r32/ebx   .               .                 # clear ebx
+ 989 $skip-chars-not-matching-in-slice:loop:
+ 990     # if (curr >= end) break
+ 991     39/compare                      3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # compare eax with ecx
+ 992     73/jump-if-addr>=  $skip-chars-not-matching-in-slice:end/disp8
+ 993     # c = *curr
+ 994     8a/copy-byte                    0/mod/indirect  0/rm32/eax    .           .             .           3/r32/BL    .               .                 # copy byte at *eax to BL
+ 995     # if (c == delimiter) break
+ 996     39/compare                      3/mod/direct    3/rm32/ebx    .           .             .           2/r32/edx   .               .                 # compare ebx and edx
+ 997     74/jump-if-=  $skip-chars-not-matching-in-slice:end/disp8
+ 998     # ++curr
+ 999     40/increment-eax
+1000     eb/jump  $skip-chars-not-matching-in-slice:loop/disp8
+1001 $skip-chars-not-matching-in-slice:end:
+1002     # . restore registers
+1003     5b/pop-to-ebx
+1004     5a/pop-to-edx
+1005     59/pop-to-ecx
+1006     # . epilogue
+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-skip-chars-not-matching-in-slice:
+1012     # (eax..ecx) = "ab "
+1013     b8/copy-to-eax  "ab "/imm32
+1014     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
+1015     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
+1016     05/add-to-eax  4/imm32
+1017     # eax = skip-chars-not-matching-in-slice(eax, ecx, 0x20/space)
+1018     # . . push args
+1019     68/push  0x20/imm32/space
+1020     51/push-ecx
+1021     50/push-eax
+1022     # . . call
+1023     e8/call  skip-chars-not-matching-in-slice/disp32
+1024     # . . discard args
+1025     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1026     # check-ints-equal(ecx-eax, 1, msg)
+1027     # . . push args
+1028     68/push  "F - test-skip-chars-not-matching-in-slice"/imm32
+1029     68/push  1/imm32
+1030     # . . push ecx-eax
+1031     29/subtract                     3/mod/direct    1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # subtract eax from ecx
+1032     51/push-ecx
+1033     # . . call
+1034     e8/call  check-ints-equal/disp32
+1035     # . . discard args
+1036     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1037     # end
+1038     c3/return
+1039 
+1040 test-skip-chars-not-matching-in-slice-none:
+1041     # (eax..ecx) = " ab"
+1042     b8/copy-to-eax  " ab"/imm32
+1043     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
+1044     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
+1045     05/add-to-eax  4/imm32
+1046     # eax = skip-chars-not-matching-in-slice(eax, ecx, 0x20/space)
+1047     # . . push args
+1048     68/push  0x20/imm32/space
+1049     51/push-ecx
+1050     50/push-eax
+1051     # . . call
+1052     e8/call  skip-chars-not-matching-in-slice/disp32
+1053     # . . discard args
+1054     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1055     # check-ints-equal(ecx-eax, 3, msg)
+1056     # . . push args
+1057     68/push  "F - test-skip-chars-not-matching-in-slice-none"/imm32
+1058     68/push  3/imm32
+1059     # . . push ecx-eax
+1060     29/subtract                     3/mod/direct    1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # subtract eax from ecx
+1061     51/push-ecx
+1062     # . . call
+1063     e8/call  check-ints-equal/disp32
+1064     # . . discard args
+1065     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1066     # end
+1067     c3/return
+1068 
+1069 test-skip-chars-not-matching-in-slice-all:
+1070     # (eax..ecx) = "ab"
+1071     b8/copy-to-eax  "ab"/imm32
+1072     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
+1073     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
+1074     05/add-to-eax  4/imm32
+1075     # eax = skip-chars-not-matching-in-slice(eax, ecx, 0x20/space)
+1076     # . . push args
+1077     68/push  0x20/imm32/space
+1078     51/push-ecx
+1079     50/push-eax
+1080     # . . call
+1081     e8/call  skip-chars-not-matching-in-slice/disp32
+1082     # . . discard args
+1083     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1084     # check-ints-equal(ecx-eax, 0, msg)
+1085     # . . push args
+1086     68/push  "F - test-skip-chars-not-matching-in-slice-all"/imm32
+1087     68/push  0/imm32
+1088     # . . push ecx-eax
+1089     29/subtract                     3/mod/direct    1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # subtract eax from ecx
+1090     51/push-ecx
+1091     # . . call
+1092     e8/call  check-ints-equal/disp32
+1093     # . . discard args
+1094     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1095     # end
+1096     c3/return
+1097 
+1098 skip-chars-not-matching-whitespace-in-slice:  # curr: (addr byte), end: (addr byte) -> curr/eax
+1099     # . prologue
+1100     55/push-ebp
+1101     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+1102     # . save registers
+1103     51/push-ecx
+1104     53/push-ebx
+1105     # eax = curr
+1106     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           0/r32/eax   8/disp8         .                 # copy *(ebp+8) to eax
+1107     # ecx = end
+1108     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           1/r32/ecx   0xc/disp8       .                 # copy *(ebp+12) to ecx
+1109     # var c/ebx: byte = 0
+1110     31/xor                          3/mod/direct    3/rm32/ebx    .           .             .           3/r32/ebx   .               .                 # clear ebx
+1111 $skip-chars-not-matching-whitespace-in-slice:loop:
+1112     # if (curr >= end) break
+1113     39/compare                      3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # compare eax with ecx
+1114     0f 83/jump-if-addr>=  $skip-chars-not-matching-in-slice:end/disp32
+1115     # c = *curr
+1116     8a/copy-byte                    0/mod/indirect  0/rm32/eax    .           .             .           3/r32/BL    .               .                 # copy byte at *eax to BL
+1117     # if (c == ' ') break
+1118     81          7/subop/compare     3/mod/direct    3/rm32/ebx    .           .             .           .           .               0x20/imm32/space  # compare ebx
+1119     74/jump-if-=  $skip-chars-not-matching-whitespace-in-slice:end/disp8
+1120     # if (c == '\n') break
+1121     81          7/subop/compare     3/mod/direct    3/rm32/ebx    .           .             .           .           .               0x0a/imm32/newline  # compare ebx
+1122     74/jump-if-=  $skip-chars-not-matching-whitespace-in-slice:end/disp8
+1123     # if (c == '\t') break
+1124     81          7/subop/compare     3/mod/direct    3/rm32/ebx    .           .             .           .           .               0x09/imm32/tab    # compare ebx
+1125     74/jump-if-=  $skip-chars-not-matching-whitespace-in-slice:end/disp8
+1126     # if (c == '\r') break
+1127     81          7/subop/compare     3/mod/direct    3/rm32/ebx    .           .             .           .           .               0x0d/imm32/cr     # compare ebx
+1128     74/jump-if-=  $skip-chars-not-matching-whitespace-in-slice:end/disp8
+1129     # ++curr
+1130     40/increment-eax
+1131     eb/jump  $skip-chars-not-matching-whitespace-in-slice:loop/disp8
+1132 $skip-chars-not-matching-whitespace-in-slice:end:
+1133     # . restore registers
+1134     5b/pop-to-ebx
+1135     59/pop-to-ecx
+1136     # . epilogue
+1137     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+1138     5d/pop-to-ebp
+1139     c3/return
+1140 
+1141 test-skip-chars-not-matching-whitespace-in-slice:
+1142     # (eax..ecx) = "ab\n"
+1143     b8/copy-to-eax  "ab\n"/imm32
+1144     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
+1145     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
+1146     05/add-to-eax  4/imm32
+1147     # eax = skip-chars-not-matching-whitespace-in-slice(eax, ecx)
+1148     # . . push args
+1149     51/push-ecx
+1150     50/push-eax
+1151     # . . call
+1152     e8/call  skip-chars-not-matching-whitespace-in-slice/disp32
+1153     # . . discard args
+1154     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1155     # check-ints-equal(ecx-eax, 1, msg)
+1156     # . . push args
+1157     68/push  "F - test-skip-chars-not-matching-whitespace-in-slice"/imm32
+1158     68/push  1/imm32
+1159     # . . push ecx-eax
+1160     29/subtract                     3/mod/direct    1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # subtract eax from ecx
+1161     51/push-ecx
+1162     # . . call
+1163     e8/call  check-ints-equal/disp32
+1164     # . . discard args
+1165     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1166     # end
+1167     c3/return
+1168 
+1169 # update line->read to end of string literal surrounded by double quotes
+1170 # line->read must start out at a double-quote
+1171 skip-string:  # line: (addr stream byte)
+1172     # . prologue
+1173     55/push-ebp
+1174     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+1175     # . save registers
+1176     50/push-eax
+1177     51/push-ecx
+1178     52/push-edx
+1179     # ecx = line
+1180     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .                         1/r32/ecx   8/disp8         .                 # copy *(ebp+8) to ecx
+1181     # eax = skip-string-in-slice(&line->data[line->read], &line->data[line->write])
+1182     # . . push &line->data[line->write]
+1183     8b/copy                         1/mod/*+disp8   1/rm32/ecx    .           .                         2/r32/edx   8/disp8         .                 # copy *(ecx+8) to edx
+1184     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
+1185     52/push-edx
+1186     # . . push &line->data[line->read]
+1187     8b/copy                         1/mod/*+disp8   1/rm32/ecx    .           .                         2/r32/edx   4/disp8         .                 # copy *(ecx+4) to edx
+1188     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
+1189     52/push-edx
+1190     # . . call
+1191     e8/call  skip-string-in-slice/disp32
+1192     # . . discard args
+1193     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1194     # line->read = eax - line->data
+1195     29/subtract                     3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # subtract ecx from eax
+1196     2d/subtract-from-eax  0xc/imm32
+1197     89/copy                         1/mod/*+disp8   1/rm32/ecx    .           .                         0/r32/eax   4/disp8         .                 # copy eax to *(ecx+4)
+1198 $skip-string:end:
+1199     # . restore registers
+1200     5a/pop-to-edx
+1201     59/pop-to-ecx
+1202     58/pop-to-eax
+1203     # . epilogue
+1204     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+1205     5d/pop-to-ebp
+1206     c3/return
+1207 
+1208 test-skip-string:
+1209     # . prologue
+1210     55/push-ebp
+1211     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+1212     # setup
+1213     # . clear-stream(_test-input-stream)
+1214     # . . push args
+1215     68/push  _test-input-stream/imm32
+1216     # . . call
+1217     e8/call  clear-stream/disp32
+1218     # . . discard args
+1219     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+1220     # . write(_test-input-stream, "\"abc\" def")
+1221     # .                   indices:  0123 45
+1222     # . . push args
+1223     68/push  "\"abc\" def"/imm32
+1224     68/push  _test-input-stream/imm32
+1225     # . . call
+1226     e8/call  write/disp32
+1227     # . . discard args
+1228     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1229     # precondition: line->read == 0
+1230     # . . push args
+1231     68/push  "F - test-skip-string/precondition"/imm32
+1232     68/push  0/imm32
+1233     b8/copy-to-eax  _test-input-stream/imm32
+1234     ff          6/subop/push        1/mod/*+disp8   0/rm32/eax    .           .             .           .           4/disp8         .                 # push *(eax+4)
+1235     # . . call
+1236     e8/call  check-ints-equal/disp32
+1237     # . . discard args
+1238     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1239     # skip-string(_test-input-stream)
+1240     # . . push args
+1241     68/push  _test-input-stream/imm32
+1242     # . . call
+1243     e8/call  skip-string/disp32
+1244     # . . discard args
+1245     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+1246     # check-ints-equal(line->read, 5, msg)
+1247     # . . push args
+1248     68/push  "F - test-skip-string"/imm32
+1249     68/push  5/imm32
+1250     b8/copy-to-eax  _test-input-stream/imm32
+1251     ff          6/subop/push        1/mod/*+disp8   0/rm32/eax    .           .             .           .           4/disp8         .                 # push *(eax+4)
+1252     # . . call
+1253     e8/call  check-ints-equal/disp32
+1254     # . . discard args
+1255     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1256     # . epilogue
+1257     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+1258     5d/pop-to-ebp
+1259     c3/return
+1260 
+1261 test-skip-string-ignores-spaces:
+1262     # . prologue
+1263     55/push-ebp
+1264     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+1265     # setup
+1266     # . clear-stream(_test-input-stream)
+1267     # . . push args
+1268     68/push  _test-input-stream/imm32
+1269     # . . call
+1270     e8/call  clear-stream/disp32
+1271     # . . discard args
+1272     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+1273     # . write(_test-input-stream, "\"a b\"/yz")
+1274     # .                   indices:  0123 45
+1275     # . . push args
+1276     68/push  "\"a b\"/yz"/imm32
+1277     68/push  _test-input-stream/imm32
+1278     # . . call
+1279     e8/call  write/disp32
+1280     # . . discard args
+1281     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1282     # precondition: line->read == 0
+1283     # . . push args
+1284     68/push  "F - test-skip-string-ignores-spaces/precondition"/imm32
+1285     68/push  0/imm32
+1286     b8/copy-to-eax  _test-input-stream/imm32
+1287     ff          6/subop/push        1/mod/*+disp8   0/rm32/eax    .           .             .           .           4/disp8         .                 # push *(eax+4)
+1288     # . . call
+1289     e8/call  check-ints-equal/disp32
+1290     # . . discard args
+1291     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1292     # skip-string(_test-input-stream)
+1293     # . . push args
+1294     68/push  _test-input-stream/imm32
+1295     # . . call
+1296     e8/call  skip-string/disp32
+1297     # . . discard args
+1298     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+1299     # check-ints-equal(line->read, 5, msg)
+1300     # . . push args
+1301     68/push  "F - test-skip-string-ignores-spaces"/imm32
+1302     68/push  5/imm32
+1303     b8/copy-to-eax  _test-input-stream/imm32
+1304     ff          6/subop/push        1/mod/*+disp8   0/rm32/eax    .           .             .           .           4/disp8         .                 # push *(eax+4)
+1305     # . . call
+1306     e8/call  check-ints-equal/disp32
+1307     # . . discard args
+1308     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1309     # . epilogue
+1310     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+1311     5d/pop-to-ebp
+1312     c3/return
+1313 
+1314 test-skip-string-ignores-escapes:
+1315     # . prologue
+1316     55/push-ebp
+1317     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+1318     # setup
+1319     # . clear-stream(_test-input-stream)
+1320     # . . push args
+1321     68/push  _test-input-stream/imm32
+1322     # . . call
+1323     e8/call  clear-stream/disp32
+1324     # . . discard args
+1325     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+1326     # . write(_test-input-stream, "\"a\\\"b\"/yz")
+1327     # .                   indices:  01 2 34 56
+1328     # . . push args
+1329     68/push  "\"a\\\"b\"/yz"/imm32
+1330     68/push  _test-input-stream/imm32
+1331     # . . call
+1332     e8/call  write/disp32
+1333     # . . discard args
+1334     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1335     # precondition: line->read == 0
+1336     # . . push args
+1337     68/push  "F - test-skip-string-ignores-escapes/precondition"/imm32
+1338     68/push  0/imm32
+1339     b8/copy-to-eax  _test-input-stream/imm32
+1340     ff          6/subop/push        1/mod/*+disp8   0/rm32/eax    .           .             .           .           4/disp8         .                 # push *(eax+4)
+1341     # . . call
+1342     e8/call  check-ints-equal/disp32
+1343     # . . discard args
+1344     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1345     # skip-string(_test-input-stream)
+1346     # . . push args
+1347     68/push  _test-input-stream/imm32
+1348     # . . call
+1349     e8/call  skip-string/disp32
+1350     # . . discard args
+1351     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+1352     # check-ints-equal(line->read, 6, msg)
+1353     # . . push args
+1354     68/push  "F - test-skip-string-ignores-escapes"/imm32
+1355     68/push  6/imm32
+1356     b8/copy-to-eax  _test-input-stream/imm32
+1357     ff          6/subop/push        1/mod/*+disp8   0/rm32/eax    .           .             .           .           4/disp8         .                 # push *(eax+4)
+1358     # . . call
+1359     e8/call  check-ints-equal/disp32
+1360     # . . discard args
+1361     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1362     # . epilogue
+1363     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+1364     5d/pop-to-ebp
+1365     c3/return
+1366 
+1367 test-skip-string-works-from-mid-stream:
+1368     # . prologue
+1369     55/push-ebp
+1370     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+1371     # setup
+1372     # . clear-stream(_test-input-stream)
+1373     # . . push args
+1374     68/push  _test-input-stream/imm32
+1375     # . . call
+1376     e8/call  clear-stream/disp32
+1377     # . . discard args
+1378     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+1379     # . write(_test-input-stream, "0 \"a\\\"b\"/yz")
+1380     # .                   indices:  01 2 34 56
+1381     # . . push args
+1382     68/push  "0 \"a\\\"b\"/yz"/imm32
+1383     68/push  _test-input-stream/imm32
+1384     # . . call
+1385     e8/call  write/disp32
+1386     # . . discard args
+1387     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1388     # precondition: line->read == 2
+1389     b8/copy-to-eax  _test-input-stream/imm32
+1390     c7          0/subop/copy        1/mod/*+disp8   0/rm32/eax    .           .             .           .           4/disp8         2/imm32           # copy to *(eax+4)
+1391     # skip-string(_test-input-stream)
+1392     # . . push args
+1393     68/push  _test-input-stream/imm32
+1394     # . . call
+1395     e8/call  skip-string/disp32
+1396     # . . discard args
+1397     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+1398     # check-ints-equal(line->read, 8, msg)
+1399     # . . push args
+1400     68/push  "F - test-skip-string-works-from-mid-stream"/imm32
+1401     68/push  8/imm32
+1402     b8/copy-to-eax  _test-input-stream/imm32
+1403     ff          6/subop/push        1/mod/*+disp8   0/rm32/eax    .           .             .           .           4/disp8         .                 # push *(eax+4)
+1404     # . . call
+1405     e8/call  check-ints-equal/disp32
+1406     # . . discard args
+1407     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1408     # . epilogue
+1409     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+1410     5d/pop-to-ebp
+1411     c3/return
+1412 
+1413 skip-string-in-slice:  # curr: (addr byte), end: (addr byte) -> new_curr/eax
+1414     # . prologue
+1415     55/push-ebp
+1416     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+1417     # . save registers
+1418     51/push-ecx
+1419     52/push-edx
+1420     53/push-ebx
+1421     # ecx = curr
+1422     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .                         1/r32/ecx   8/disp8         .                 # copy *(ebp+8) to ecx
+1423     # edx = end
+1424     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .                         2/r32/edx   0xc/disp8         .               # copy *(ebp+12) to edx
+1425     # var c/eax: byte = 0
+1426     31/xor                          3/mod/direct    0/rm32/eax    .           .             .           0/r32/eax   .               .                 # clear eax
+1427     # skip initial dquote
+1428     41/increment-ecx
+1429 $skip-string-in-slice:loop:
+1430     # if (curr >= end) return curr
+1431     39/compare                      3/mod/direct    1/rm32/ecx    .           .             .           2/r32/edx   .               .                 # compare ecx with edx
+1432     73/jump-if-addr>=  $skip-string-in-slice:return-curr/disp8
+1433     # c = *curr
+1434     8a/copy-byte                    0/mod/indirect  1/rm32/ecx    .           .             .           0/r32/AL    .               .                 # copy byte at *ecx to AL
+1435 $skip-string-in-slice:dquote:
+1436     # if (c == '"') break
+1437     3d/compare-eax-and  0x22/imm32/double-quote
+1438     74/jump-if-=  $skip-string-in-slice:break/disp8
+1439 $skip-string-in-slice:check-for-escape:
+1440     # if (c == '\') escape next char
+1441     3d/compare-eax-and  0x5c/imm32/backslash
+1442     75/jump-if-!=  $skip-string-in-slice:continue/disp8
+1443 $skip-string-in-slice:escape:
+1444     41/increment-ecx
+1445 $skip-string-in-slice:continue:
+1446     # ++curr
+1447     41/increment-ecx
+1448     eb/jump  $skip-string-in-slice:loop/disp8
+1449 $skip-string-in-slice:break:
+1450     # skip final dquote
+1451     41/increment-ecx
+1452 $skip-string-in-slice:return-curr:
+1453     # return curr
+1454     89/copy                         3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy ecx to eax
+1455 $skip-string-in-slice:end:
+1456     # . restore registers
+1457     5b/pop-to-ebx
+1458     5a/pop-to-edx
+1459     59/pop-to-ecx
+1460     # . epilogue
+1461     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+1462     5d/pop-to-ebp
+1463     c3/return
+1464 
+1465 test-skip-string-in-slice:
+1466     # . prologue
+1467     55/push-ebp
+1468     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+1469     # setup: (eax..ecx) = "\"abc\" def"
+1470     b8/copy-to-eax  "\"abc\" def"/imm32
+1471     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
+1472     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
+1473     05/add-to-eax  4/imm32
+1474     # eax = skip-string-in-slice(eax, ecx)
+1475     # . . push args
+1476     51/push-ecx
+1477     50/push-eax
+1478     # . . call
+1479     e8/call  skip-string-in-slice/disp32
+1480     # . . discard args
+1481     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1482     # check-ints-equal(ecx-eax, 4, msg)  # number of chars remaining after the string literal
+1483     # . . push args
+1484     68/push  "F - test-skip-string-in-slice"/imm32
+1485     68/push  4/imm32
+1486     # . . push ecx-eax
+1487     29/subtract                     3/mod/direct    1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # subtract eax from ecx
+1488     51/push-ecx
+1489     # . . call
+1490     e8/call  check-ints-equal/disp32
+1491     # . . discard args
+1492     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1493     # . epilogue
+1494     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+1495     5d/pop-to-ebp
+1496     c3/return
+1497 
+1498 test-skip-string-in-slice-ignores-spaces:
+1499     # . prologue
+1500     55/push-ebp
+1501     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+1502     # setup: (eax..ecx) = "\"a b\"/yz"
+1503     b8/copy-to-eax  "\"a b\"/yz"/imm32
+1504     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
+1505     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
+1506     05/add-to-eax  4/imm32
+1507     # eax = skip-string-in-slice(eax, ecx)
+1508     # . . push args
+1509     51/push-ecx
+1510     50/push-eax
+1511     # . . call
+1512     e8/call  skip-string-in-slice/disp32
+1513     # . . discard args
+1514     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1515     # check-ints-equal(ecx-eax, 3, msg)  # number of chars remaining after the string literal
+1516     # . . push args
+1517     68/push  "F - test-skip-string-in-slice-ignores-spaces"/imm32
+1518     68/push  3/imm32
+1519     # . . push ecx-eax
+1520     29/subtract                     3/mod/direct    1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # subtract eax from ecx
+1521     51/push-ecx
+1522     # . . call
+1523     e8/call  check-ints-equal/disp32
+1524     # . . discard args
+1525     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1526     # . epilogue
+1527     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+1528     5d/pop-to-ebp
+1529     c3/return
+1530 
+1531 test-skip-string-in-slice-ignores-escapes:
+1532     # . prologue
+1533     55/push-ebp
+1534     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+1535     # setup: (eax..ecx) = "\"a\\\"b\"/yz"
+1536     b8/copy-to-eax  "\"a\\\"b\"/yz"/imm32
+1537     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
+1538     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
+1539     05/add-to-eax  4/imm32
+1540     # eax = skip-string-in-slice(eax, ecx)
+1541     # . . push args
+1542     51/push-ecx
+1543     50/push-eax
+1544     # . . call
+1545     e8/call  skip-string-in-slice/disp32
+1546     # . . discard args
+1547     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1548     # check-ints-equal(ecx-eax, 3, msg)  # number of chars remaining after the string literal
+1549     # . . push args
+1550     68/push  "F - test-skip-string-in-slice-ignores-escapes"/imm32
+1551     68/push  3/imm32
+1552     # . . push ecx-eax
+1553     29/subtract                     3/mod/direct    1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # subtract eax from ecx
+1554     51/push-ecx
+1555     # . . call
+1556     e8/call  check-ints-equal/disp32
+1557     # . . discard args
+1558     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1559     # . epilogue
+1560     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+1561     5d/pop-to-ebp
+1562     c3/return
+1563 
+1564 test-skip-string-in-slice-stops-at-end:
+1565     # . prologue
+1566     55/push-ebp
+1567     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+1568     # setup: (eax..ecx) = "\"abc"  # unbalanced dquote
+1569     b8/copy-to-eax  "\"abc"/imm32
+1570     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
+1571     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
+1572     05/add-to-eax  4/imm32
+1573     # eax = skip-string-in-slice(eax, ecx)
+1574     # . . push args
+1575     51/push-ecx
+1576     50/push-eax
+1577     # . . call
+1578     e8/call  skip-string-in-slice/disp32
+1579     # . . discard args
+1580     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1581     # check-ints-equal(ecx-eax, 0, msg)  # skipped to end of slice
+1582     # . . push args
+1583     68/push  "F - test-skip-string-in-slice-stops-at-end"/imm32
+1584     68/push  0/imm32
+1585     # . . push ecx-eax
+1586     29/subtract                     3/mod/direct    1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # subtract eax from ecx
+1587     51/push-ecx
+1588     # . . call
+1589     e8/call  check-ints-equal/disp32
+1590     # . . discard args
+1591     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1592     # . epilogue
+1593     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+1594     5d/pop-to-ebp
+1595     c3/return
+1596 
+1597 # update line->read to ')'
+1598 # line->read ends at ')'
+1599 skip-until-close-paren:  # line: (addr stream byte)
+1600     # . prologue
+1601     55/push-ebp
+1602     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+1603     # . save registers
+1604     50/push-eax
+1605     51/push-ecx
+1606     52/push-edx
+1607     # ecx = line
+1608     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .                         1/r32/ecx   8/disp8         .                 # copy *(ebp+8) to ecx
+1609     # eax = skip-until-close-paren-in-slice(&line->data[line->read], &line->data[line->write])
+1610     # . . push &line->data[line->write]
+1611     8b/copy                         1/mod/*+disp8   1/rm32/ecx    .           .                         2/r32/edx   8/disp8         .                 # copy *(ecx+8) to edx
+1612     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
+1613     52/push-edx
+1614     # . . push &line->data[line->read]
+1615     8b/copy                         1/mod/*+disp8   1/rm32/ecx    .           .                         2/r32/edx   4/disp8         .                 # copy *(ecx+4) to edx
+1616     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
+1617     52/push-edx
+1618     # . . call
+1619     e8/call  skip-until-close-paren-in-slice/disp32
+1620     # . . discard args
+1621     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1622     # line->read = eax - line->data
+1623     29/subtract                     3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # subtract ecx from eax
+1624     2d/subtract-from-eax  0xc/imm32
+1625     89/copy                         1/mod/*+disp8   1/rm32/ecx    .           .                         0/r32/eax   4/disp8         .                 # copy eax to *(ecx+4)
+1626 $skip-until-close-paren:end:
+1627     # . restore registers
+1628     5a/pop-to-edx
+1629     59/pop-to-ecx
+1630     58/pop-to-eax
+1631     # . epilogue
+1632     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+1633     5d/pop-to-ebp
+1634     c3/return
+1635 
+1636 test-skip-until-close-paren:
+1637     # . prologue
+1638     55/push-ebp
+1639     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+1640     # setup
+1641     # . clear-stream(_test-input-stream)
+1642     # . . push args
+1643     68/push  _test-input-stream/imm32
+1644     # . . call
+1645     e8/call  clear-stream/disp32
+1646     # . . discard args
+1647     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+1648     # . write(_test-input-stream, "*(abc) def")
+1649     # .                   indices:  0123 45
+1650     # . . push args
+1651     68/push  "*(abc) def"/imm32
+1652     68/push  _test-input-stream/imm32
+1653     # . . call
+1654     e8/call  write/disp32
+1655     # . . discard args
+1656     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1657     # precondition: line->read == 0
+1658     # . . push args
+1659     68/push  "F - test-skip-until-close-paren/precondition"/imm32
+1660     68/push  0/imm32
+1661     b8/copy-to-eax  _test-input-stream/imm32
+1662     ff          6/subop/push        1/mod/*+disp8   0/rm32/eax    .           .             .           .           4/disp8         .                 # push *(eax+4)
+1663     # . . call
+1664     e8/call  check-ints-equal/disp32
+1665     # . . discard args
+1666     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1667     # skip-until-close-paren(_test-input-stream)
+1668     # . . push args
+1669     68/push  _test-input-stream/imm32
+1670     # . . call
+1671     e8/call  skip-until-close-paren/disp32
+1672     # . . discard args
+1673     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+1674     # check-ints-equal(line->read, 5, msg)
+1675     # . . push args
+1676     68/push  "F - test-skip-until-close-paren"/imm32
+1677     68/push  5/imm32
+1678     b8/copy-to-eax  _test-input-stream/imm32
+1679     ff          6/subop/push        1/mod/*+disp8   0/rm32/eax    .           .             .           .           4/disp8         .                 # push *(eax+4)
+1680     # . . call
+1681     e8/call  check-ints-equal/disp32
+1682     # . . discard args
+1683     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1684     # . epilogue
+1685     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+1686     5d/pop-to-ebp
+1687     c3/return
+1688 
+1689 test-skip-until-close-paren-ignores-spaces:
+1690     # . prologue
+1691     55/push-ebp
+1692     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+1693     # setup
+1694     # . clear-stream(_test-input-stream)
+1695     # . . push args
+1696     68/push  _test-input-stream/imm32
+1697     # . . call
+1698     e8/call  clear-stream/disp32
+1699     # . . discard args
+1700     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+1701     # . write(_test-input-stream, "*(a b)/yz")
+1702     # . . push args
+1703     68/push  "*(a b)/yz"/imm32
+1704     68/push  _test-input-stream/imm32
+1705     # . . call
+1706     e8/call  write/disp32
+1707     # . . discard args
+1708     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1709     # precondition: line->read == 0
+1710     # . . push args
+1711     68/push  "F - test-skip-until-close-paren-ignores-spaces/precondition"/imm32
+1712     68/push  0/imm32
+1713     b8/copy-to-eax  _test-input-stream/imm32
+1714     ff          6/subop/push        1/mod/*+disp8   0/rm32/eax    .           .             .           .           4/disp8         .                 # push *(eax+4)
+1715     # . . call
+1716     e8/call  check-ints-equal/disp32
+1717     # . . discard args
+1718     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1719     # skip-until-close-paren(_test-input-stream)
+1720     # . . push args
+1721     68/push  _test-input-stream/imm32
+1722     # . . call
+1723     e8/call  skip-until-close-paren/disp32
+1724     # . . discard args
+1725     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+1726     # check-ints-equal(line->read, 5, msg)
+1727     # . . push args
+1728     68/push  "F - test-skip-until-close-paren-ignores-spaces"/imm32
+1729     68/push  5/imm32
+1730     b8/copy-to-eax  _test-input-stream/imm32
+1731     ff          6/subop/push        1/mod/*+disp8   0/rm32/eax    .           .             .           .           4/disp8         .                 # push *(eax+4)
+1732     # . . call
+1733     e8/call  check-ints-equal/disp32
+1734     # . . discard args
+1735     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1736     # . epilogue
+1737     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+1738     5d/pop-to-ebp
+1739     c3/return
+1740 
+1741 test-skip-until-close-paren-works-from-mid-stream:
+1742     # . prologue
+1743     55/push-ebp
+1744     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+1745     # setup
+1746     # . clear-stream(_test-input-stream)
+1747     # . . push args
+1748     68/push  _test-input-stream/imm32
+1749     # . . call
+1750     e8/call  clear-stream/disp32
+1751     # . . discard args
+1752     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+1753     # . write(_test-input-stream, "0 *(a b)/yz")
+1754     # . . push args
+1755     68/push  "0 *(a b)/yz"/imm32
+1756     68/push  _test-input-stream/imm32
+1757     # . . call
+1758     e8/call  write/disp32
+1759     # . . discard args
+1760     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1761     # precondition: _test-input-stream->read == 2
+1762     b8/copy-to-eax  _test-input-stream/imm32
+1763     c7          0/subop/copy        1/mod/*+disp8   0/rm32/eax    .           .             .           .           4/disp8         2/imm32           # copy to *(eax+4)
+1764     # skip-until-close-paren(_test-input-stream)
+1765     # . . push args
+1766     68/push  _test-input-stream/imm32
+1767     # . . call
+1768     e8/call  skip-until-close-paren/disp32
+1769     # . . discard args
+1770     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
+1771     # check-ints-equal(_test-input-stream->read, 7, msg)
+1772     # . . push args
+1773     68/push  "F - test-skip-until-close-paren-works-from-mid-stream"/imm32
+1774     68/push  7/imm32
+1775     b8/copy-to-eax  _test-input-stream/imm32
+1776     ff          6/subop/push        1/mod/*+disp8   0/rm32/eax    .           .             .           .           4/disp8         .                 # push *(eax+4)
+1777     # . . call
+1778     e8/call  check-ints-equal/disp32
+1779     # . . discard args
+1780     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1781     # . epilogue
+1782     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+1783     5d/pop-to-ebp
+1784     c3/return
+1785 
+1786 skip-until-close-paren-in-slice:  # curr: (addr byte), end: (addr byte) -> new_curr/eax: (addr byte)
+1787     # . prologue
+1788     55/push-ebp
+1789     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+1790     # . save registers
+1791     51/push-ecx
+1792     52/push-edx
+1793     # ecx = curr
+1794     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .                         1/r32/ecx   8/disp8         .                 # copy *(ebp+8) to ecx
+1795     # edx = end
+1796     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .                         2/r32/edx   0xc/disp8         .               # copy *(ebp+12) to edx
+1797     # var c/eax: byte = 0
+1798     31/xor                          3/mod/direct    0/rm32/eax    .           .             .           0/r32/eax   .               .                 # clear eax
+1799     # skip initial dquote
+1800     41/increment-ecx
+1801 $skip-until-close-paren-in-slice:loop:
+1802     # if (curr >= end) break
+1803     39/compare                      3/mod/direct    1/rm32/ecx    .           .             .           2/r32/edx   .               .                 # compare ecx with edx
+1804     73/jump-if-addr>=  $skip-until-close-paren-in-slice:break/disp8
+1805     # c = *curr
+1806     8a/copy-byte                    0/mod/indirect  1/rm32/ecx    .           .             .           0/r32/AL    .               .                 # copy byte at *ecx to AL
+1807 $skip-until-close-paren-in-slice:check-close:
+1808     # if (c == ')') break
+1809     3d/compare-eax-and  0x29/imm32/close-paren
+1810     74/jump-if-=  $skip-until-close-paren-in-slice:break/disp8
+1811     # ++curr
+1812     41/increment-ecx
+1813     eb/jump  $skip-until-close-paren-in-slice:loop/disp8
+1814 $skip-until-close-paren-in-slice:break:
+1815     # return curr
+1816     89/copy                         3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy ecx to eax
+1817 $skip-until-close-paren-in-slice:end:
+1818     # . restore registers
+1819     5a/pop-to-edx
+1820     59/pop-to-ecx
+1821     # . epilogue
+1822     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+1823     5d/pop-to-ebp
+1824     c3/return
+1825 
+1826 test-skip-until-close-paren-in-slice:
+1827     # . prologue
+1828     55/push-ebp
+1829     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+1830     # setup: (eax..ecx) = "*(abc) def"
+1831     b8/copy-to-eax  "*(abc) def"/imm32
+1832     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
+1833     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
+1834     05/add-to-eax  4/imm32
+1835     # eax = skip-until-close-paren-in-slice(eax, ecx)
+1836     # . . push args
+1837     51/push-ecx
+1838     50/push-eax
+1839     # . . call
+1840     e8/call  skip-until-close-paren-in-slice/disp32
+1841     # . . discard args
+1842     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1843     # check-ints-equal(ecx-eax, 5, msg)  # eax is at the ')'
+1844     # . . push args
+1845     68/push  "F - test-skip-until-close-paren-in-slice"/imm32
+1846     68/push  5/imm32
+1847     # . . push ecx-eax
+1848     29/subtract                     3/mod/direct    1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # subtract eax from ecx
+1849     51/push-ecx
+1850     # . . call
+1851     e8/call  check-ints-equal/disp32
+1852     # . . discard args
+1853     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1854     # . epilogue
+1855     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+1856     5d/pop-to-ebp
+1857     c3/return
+1858 
+1859 test-skip-until-close-paren-in-slice-ignores-spaces:
+1860     # . prologue
+1861     55/push-ebp
+1862     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+1863     # setup: (eax..ecx) = "*(a b)/yz"
+1864     b8/copy-to-eax  "*(a b)/yz"/imm32
+1865     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
+1866     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
+1867     05/add-to-eax  4/imm32
+1868     # eax = skip-until-close-paren-in-slice(eax, ecx)
+1869     # . . push args
+1870     51/push-ecx
+1871     50/push-eax
+1872     # . . call
+1873     e8/call  skip-until-close-paren-in-slice/disp32
+1874     # . . discard args
+1875     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1876     # check-ints-equal(ecx-eax, 4, msg)  # eax is at the ')'
+1877     # . . push args
+1878     68/push  "F - test-skip-until-close-paren-in-slice-ignores-spaces"/imm32
+1879     68/push  4/imm32
+1880     # . . push ecx-eax
+1881     29/subtract                     3/mod/direct    1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # subtract eax from ecx
+1882     51/push-ecx
+1883     # . . call
+1884     e8/call  check-ints-equal/disp32
+1885     # . . discard args
+1886     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1887     # . epilogue
+1888     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+1889     5d/pop-to-ebp
+1890     c3/return
+1891 
+1892 test-skip-until-close-paren-in-slice-stops-at-end:
+1893     # . prologue
+1894     55/push-ebp
+1895     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
+1896     # setup: (eax..ecx) = "*(abc"  # unbalanced dquote
+1897     b8/copy-to-eax  "*(abc"/imm32
+1898     8b/copy                         0/mod/indirect  0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # copy *eax to ecx
+1899     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
+1900     05/add-to-eax  4/imm32
+1901     # eax = skip-until-close-paren-in-slice(eax, ecx)
+1902     # . . push args
+1903     51/push-ecx
+1904     50/push-eax
+1905     # . . call
+1906     e8/call  skip-until-close-paren-in-slice/disp32
+1907     # . . discard args
+1908     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
+1909     # check-ints-equal(ecx-eax, 0, msg)  # skipped to end of slice
+1910     # . . push args
+1911     68/push  "F - test-skip-until-close-paren-in-slice-stops-at-end"/imm32
+1912     68/push  0/imm32
+1913     # . . push ecx-eax
+1914     29/subtract                     3/mod/direct    1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # subtract eax from ecx
+1915     51/push-ecx
+1916     # . . call
+1917     e8/call  check-ints-equal/disp32
+1918     # . . discard args
+1919     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
+1920     # . epilogue
+1921     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
+1922     5d/pop-to-ebp
+1923     c3/return
+1924 
+1925 # . . vim:nowrap:textwidth=0
+
+ + + -- cgit 1.4.1-2-gfad0