https://github.com/akkartik/mu/blob/master/subx/073next-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 : (address stream), delimiter : byte, out : (address slice)
 11     # . prolog
 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     # . epilog
 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     # . prolog
 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 = {0, 0}
 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     # . epilog
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     # . prolog
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 = {0, 0}
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     # . epilog
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 : (address byte), end : (address byte), delimiter : byte, out : (address slice) -> <void>
164     # . prolog
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     # . epilog
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     # . prolog
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 : (address slice) = {0, 0}
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     # . epilog
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     # . prolog
266     55/push-EBP
267     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
268     # var out/EDI : (address slice) = {0, 0}
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     # . epilog
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     # . prolog
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 : (address slice) = {0, 0}
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     # . epilog
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 : (address stream), delimiter : byte
342     # . prolog
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-greater-or-equal  $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-not-equal  $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     # . epilog
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 # minor fork of 'skip-chars-matching'
465 skip-chars-not-matching:  # in : (address stream), delimiter : byte
466     # . prolog
467     55/push-EBP
468     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
469     # . save registers
470     50/push-EAX
471     51/push-ECX
472     52/push-EDX
473     53/push-EBX
474     56/push-ESI
475     # ESI = in
476     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           6/r32/ESI   8/disp8         .                 # copy *(EBP+8) to ESI
477     # ECX = in->read
478     8b/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           1/r32/ECX   4/disp8         .                 # copy *(ESI+4) to ECX
479     # EBX = in->write
480     8b/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           3/r32/EBX   .               .                 # copy *ESI to EBX
481     # EDX = delimiter
482     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           2/r32/EDX   0xc/disp8       .                 # copy *(EBP+12) to EDX
483 $skip-chars-not-matching:loop:
484     # if (in->read >= in->write) break
485     39/compare                      3/mod/direct    1/rm32/ECX    .           .             .           3/r32/EBX   .               .                 # compare ECX with EBX
486     7d/jump-if-greater-or-equal  $skip-chars-not-matching:end/disp8
487     # EAX = in->data[in->read]
488     31/xor                          3/mod/direct    0/rm32/EAX    .           .             .           0/r32/EAX   .               .                 # clear EAX
489     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
490     # if (EAX == delimiter) break
491     39/compare                      3/mod/direct    0/rm32/EAX    .           .             .           2/r32/EDX   .               .                 # compare EAX and EDX
492     74/jump-if-equal  $skip-chars-not-matching:end/disp8
493     # ++in->read
494     41/increment-ECX
495     eb/jump  $skip-chars-not-matching:loop/disp8
496 $skip-chars-not-matching:end:
497     # persist in->read
498     89/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           1/r32/ECX   4/disp8         .                 # copy ECX to *(ESI+4)
499     # . restore registers
500     5e/pop-to-ESI
501     5b/pop-to-EBX
502     5a/pop-to-EDX
503     59/pop-to-ECX
504     58/pop-to-EAX
505     # . epilog
506     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
507     5d/pop-to-EBP
508     c3/return
509 
510 test-skip-chars-not-matching:
511     # setup
512     # . clear-stream(_test-stream)
513     # . . push args
514     68/push  _test-stream/imm32
515     # . . call
516     e8/call  clear-stream/disp32
517     # . . discard args
518     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
519     # write(_test-stream, "ab ")
520     # . . push args
521     68/push  "ab "/imm32
522     68/push  _test-stream/imm32
523     # . . call
524     e8/call  write/disp32
525     # . . discard args
526     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
527     # skip-chars-not-matching(_test-stream, 0x20/space)
528     # . . push args
529     68/push  0x20/imm32
530     68/push  _test-stream/imm32
531     # . . call
532     e8/call  skip-chars-not-matching/disp32
533     # . . discard args
534     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
535     # check-ints-equal(_test-stream->read, 2, msg)
536     # . . push args
537     68/push  "F - test-skip-chars-not-matching"/imm32
538     68/push  2/imm32
539     # . . push *_test-stream->read
540     b8/copy-to-EAX  _test-stream/imm32
541     ff          6/subop/push        1/mod/*+disp8   0/rm32/EAX    .           .             .           .           4/disp8         .                 # push *(EAX+4)
542     # . . call
543     e8/call  check-ints-equal/disp32
544     # . . discard args
545     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
546     # end
547     c3/return
548 
549 test-skip-chars-not-matching-none:
550     # setup
551     # . clear-stream(_test-stream)
552     # . . push args
553     68/push  _test-stream/imm32
554     # . . call
555     e8/call  clear-stream/disp32
556     # . . discard args
557     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
558     # write(_test-stream, " ab")
559     # . . push args
560     68/push  " ab"/imm32
561     68/push  _test-stream/imm32
562     # . . call
563     e8/call  write/disp32
564     # . . discard args
565     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
566     # skip-chars-not-matching(_test-stream, 0x20/space)
567     # . . push args
568     68/push  0x20/imm32
569     68/push  _test-stream/imm32
570     # . . call
571     e8/call  skip-chars-not-matching/disp32
572     # . . discard args
573     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
574     # check-ints-equal(_test-stream->read, 0, msg)
575     # . . push args
576     68/push  "F - test-skip-chars-not-matching-none"/imm32
577     68/push  0/imm32
578     # . . push *_test-stream->read
579     b8/copy-to-EAX  _test-stream/imm32
580     ff          6/subop/push        1/mod/*+disp8   0/rm32/EAX    .           .             .           .           4/disp8         .                 # push *(EAX+4)
581     # . . call
582     e8/call  check-ints-equal/disp32
583     # . . discard args
584     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
585     # end
586     c3/return
587 
588 test-skip-chars-not-matching-all:
589     # setup
590     # . clear-stream(_test-stream)
591     # . . push args
592     68/push  _test-stream/imm32
593     # . . call
594     e8/call  clear-stream/disp32
595     # . . discard args
596     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
597     # write(_test-stream, "ab")
598     # . . push args
599     68/push  "ab"/imm32
600     68/push  _test-stream/imm32
601     # . . call
602     e8/call  write/disp32
603     # . . discard args
604     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
605     # skip-chars-not-matching(_test-stream, 0x20/space)
606     # . . push args
607     68/push  0x20/imm32
608     68/push  _test-stream/imm32
609     # . . call
610     e8/call  skip-chars-not-matching/disp32
611     # . . discard args
612     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
613     # check-ints-equal(_test-stream->read, 2, msg)
614     # . . push args
615     68/push  "F - test-skip-chars-not-matching-all"/imm32
616     68/push  2/imm32
617     # . . push *_test-stream->read
618     b8/copy-to-EAX  _test-stream/imm32
619     ff          6/subop/push        1/mod/*+disp8   0/rm32/EAX    .           .             .           .           4/disp8         .                 # push *(EAX+4)
620     # . . call
621     e8/call  check-ints-equal/disp32
622     # . . discard args
623     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
624     # end
625     c3/return
626 
627 skip-chars-not-matching-whitespace:  # in : (address stream)
628     # . prolog
629     55/push-EBP
630     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
631     # . save registers
632     50/push-EAX
633     51/push-ECX
634     53/push-EBX
635     56/push-ESI
636     # ESI = in
637     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           6/r32/ESI   8/disp8         .                 # copy *(EBP+8) to ESI
638     # ECX = in->read
639     8b/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           1/r32/ECX   4/disp8         .                 # copy *(ESI+4) to ECX
640     # EBX = in->write
641     8b/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           3/r32/EBX   .               .                 # copy *ESI to EBX
642 $skip-chars-not-matching-whitespace:loop:
643     # if (in->read >= in->write) break
644     39/compare                      3/mod/direct    1/rm32/ECX    .           .             .           3/r32/EBX   .               .                 # compare ECX with EBX
645     7d/jump-if-greater-or-equal  $skip-chars-not-matching-whitespace:end/disp8
646     # EAX = in->data[in->read]
647     31/xor                          3/mod/direct    0/rm32/EAX    .           .             .           0/r32/EAX   .               .                 # clear EAX
648     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
649     # if (EAX == ' ') break
650     3d/compare-EAX-and  0x20/imm32/space
651     74/jump-if-equal  $skip-chars-not-matching-whitespace:end/disp8
652     # if (EAX == '\n') break
653     3d/compare-EAX-and  0x0a/imm32/newline
654     74/jump-if-equal  $skip-chars-not-matching-whitespace:end/disp8
655     # if (EAX == '\t') break
656     3d/compare-EAX-and  0x09/imm32/tab
657     74/jump-if-equal  $skip-chars-not-matching-whitespace:end/disp8
658     # if (EAX == '\r') break
659     3d/compare-EAX-and  0x0d/imm32/cr
660     74/jump-if-equal  $skip-chars-not-matching-whitespace:end/disp8
661     # ++in->read
662     41/increment-ECX
663     eb/jump  $skip-chars-not-matching-whitespace:loop/disp8
664 $skip-chars-not-matching-whitespace:end:
665     # persist in->read
666     89/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           1/r32/ECX   4/disp8         .                 # copy ECX to *(ESI+4)
667     # . restore registers
668     5e/pop-to-ESI
669     5b/pop-to-EBX
670     59/pop-to-ECX
671     58/pop-to-EAX
672     # . epilog
673     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
674     5d/pop-to-EBP
675     c3/return
676 
677 skip-chars-matching-in-slice:  # curr : (address byte), end : (address byte), delimiter : byte -> curr/EAX
678     # . prolog
679     55/push-EBP
680     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
681     # . save registers
682     51/push-ECX
683     52/push-EDX
684     53/push-EBX
685     # EAX = curr
686     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           0/r32/EAX   8/disp8         .                 # copy *(EBP+8) to EAX
687     # ECX = end
688     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           1/r32/ECX   0xc/disp8       .                 # copy *(EBP+12) to ECX
689     # EDX = delimiter
690     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           2/r32/EDX   0x10/disp8       .                 # copy *(EBP+16) to EDX
691     # EBX = 0
692     31/xor                          3/mod/direct    3/rm32/EBX    .           .             .           3/r32/EBX   .               .                 # clear EBX
693 $skip-chars-matching-in-slice:loop:
694     # if (curr >= end) break
695     39/compare                      3/mod/direct    0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # compare EAX with ECX
696     73/jump-if-greater-or-equal-unsigned  $skip-chars-matching-in-slice:end/disp8
697     # if (*curr != delimiter) break
698     8a/copy-byte                    0/mod/indirect  0/rm32/EAX    .           .             .           3/r32/BL    .               .                 # copy byte at *EAX to BL
699     39/compare                      3/mod/direct    3/rm32/EBX    .           .             .           2/r32/EDX   .               .                 # compare EBX and EDX
700     75/jump-if-not-equal  $skip-chars-matching-in-slice:end/disp8
701     # ++curr
702     40/increment-EAX
703     eb/jump  $skip-chars-matching-in-slice:loop/disp8
704 $skip-chars-matching-in-slice:end:
705     # . restore registers
706     5b/pop-to-EBX
707     5a/pop-to-EDX
708     59/pop-to-ECX
709     # . epilog
710     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
711     5d/pop-to-EBP
712     c3/return
713 
714 test-skip-chars-matching-in-slice:
715     # (EAX..ECX) = "  ab"
716     b8/copy-to-EAX  "  ab"/imm32
717     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
718     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
719     05/add-to-EAX  4/imm32
720     # EAX = skip-chars-matching-in-slice(EAX, ECX, 0x20/space)
721     # . . push args
722     68/push  0x20/imm32/space
723     51/push-ECX
724     50/push-EAX
725     # . . call
726     e8/call  skip-chars-matching-in-slice/disp32
727     # . . discard args
728     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
729     # check-ints-equal(ECX-EAX, 2, msg)
730     # . . push args
731     68/push  "F - test-skip-chars-matching-in-slice"/imm32
732     68/push  2/imm32
733     # . . push ECX-EAX
734     29/subtract                     3/mod/direct    1/rm32/ECX    .           .             .           0/r32/EAX   .               .                 # subtract EAX from ECX
735     51/push-ECX
736     # . . call
737     e8/call  check-ints-equal/disp32
738     # . . discard args
739     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
740     # end
741     c3/return
742 
743 test-skip-chars-matching-in-slice-none:
744     # (EAX..ECX) = "ab"
745     b8/copy-to-EAX  "ab"/imm32
746     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
747     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
748     05/add-to-EAX  4/imm32
749     # EAX = skip-chars-matching-in-slice(EAX, ECX, 0x20/space)
750     # . . push args
751     68/push  0x20/imm32/space
752     51/push-ECX
753     50/push-EAX
754     # . . call
755     e8/call  skip-chars-matching-in-slice/disp32
756     # . . discard args
757     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
758     # check-ints-equal(ECX-EAX, 2, msg)
759     # . . push args
760     68/push  "F - test-skip-chars-matching-in-slice-none"/imm32
761     68/push  2/imm32
762     # . . push ECX-EAX
763     29/subtract                     3/mod/direct    1/rm32/ECX    .           .             .           0/r32/EAX   .               .                 # subtract EAX from ECX
764     51/push-ECX
765     # . . call
766     e8/call  check-ints-equal/disp32
767     # . . discard args
768     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
769     # end
770     c3/return
771 
772 # minor fork of 'skip-chars-matching-in-slice'
773 skip-chars-not-matching-in-slice:  # curr : (address byte), end : (address byte), delimiter : byte -> curr/EAX
774     # . prolog
775     55/push-EBP
776     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
777     # . save registers
778     51/push-ECX
779     52/push-EDX
780     53/push-EBX
781     # EAX = curr
782     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           0/r32/EAX   8/disp8         .                 # copy *(EBP+8) to EAX
783     # ECX = end
784     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           1/r32/ECX   0xc/disp8       .                 # copy *(EBP+12) to ECX
785     # EDX = delimiter
786     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           2/r32/EDX   0x10/disp8       .                 # copy *(EBP+16) to EDX
787     # EBX = 0
788     31/xor                          3/mod/direct    3/rm32/EBX    .           .             .           3/r32/EBX   .               .                 # clear EBX
789 $skip-chars-not-matching-in-slice:loop:
790     # if (curr >= end) break
791     39/compare                      3/mod/direct    0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # compare EAX with ECX
792     73/jump-if-greater-or-equal-unsigned  $skip-chars-not-matching-in-slice:end/disp8
793     # if (*curr == delimiter) break
794     8a/copy-byte                    0/mod/indirect  0/rm32/EAX    .           .             .           3/r32/BL    .               .                 # copy byte at *EAX to BL
795     39/compare                      3/mod/direct    3/rm32/EBX    .           .             .           2/r32/EDX   .               .                 # compare EBX and EDX
796     74/jump-if-equal  $skip-chars-not-matching-in-slice:end/disp8
797     # ++curr
798     40/increment-EAX
799     eb/jump  $skip-chars-not-matching-in-slice:loop/disp8
800 $skip-chars-not-matching-in-slice:end:
801     # . restore registers
802     5b/pop-to-EBX
803     5a/pop-to-EDX
804     59/pop-to-ECX
805     # . epilog
806     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
807     5d/pop-to-EBP
808     c3/return
809 
810 test-skip-chars-not-matching-in-slice:
811     # (EAX..ECX) = "ab "
812     b8/copy-to-EAX  "ab "/imm32
813     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
814     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
815     05/add-to-EAX  4/imm32
816     # EAX = skip-chars-not-matching-in-slice(EAX, ECX, 0x20/space)
817     # . . push args
818     68/push  0x20/imm32/space
819     51/push-ECX
820     50/push-EAX
821     # . . call
822     e8/call  skip-chars-not-matching-in-slice/disp32
823     # . . discard args
824     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
825     # check-ints-equal(ECX-EAX, 1, msg)
826     # . . push args
827     68/push  "F - test-skip-chars-not-matching-in-slice"/imm32
828     68/push  1/imm32
829     # . . push ECX-EAX
830     29/subtract                     3/mod/direct    1/rm32/ECX    .           .             .           0/r32/EAX   .               .                 # subtract EAX from ECX
831     51/push-ECX
832     # . . call
833     e8/call  check-ints-equal/disp32
834     # . . discard args
835     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
836     # end
837     c3/return
838 
839 test-skip-chars-not-matching-in-slice-none:
840     # (EAX..ECX) = " ab"
841     b8/copy-to-EAX  " ab"/imm32
842     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
843     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
844     05/add-to-EAX  4/imm32
845     # EAX = skip-chars-not-matching-in-slice(EAX, ECX, 0x20/space)
846     # . . push args
847     68/push  0x20/imm32/space
848     51/push-ECX
849     50/push-EAX
850     # . . call
851     e8/call  skip-chars-not-matching-in-slice/disp32
852     # . . discard args
853     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
854     # check-ints-equal(ECX-EAX, 3, msg)
855     # . . push args
856     68/push  "F - test-skip-chars-not-matching-in-slice-none"/imm32
857     68/push  3/imm32
858     # . . push ECX-EAX
859     29/subtract                     3/mod/direct    1/rm32/ECX    .           .             .           0/r32/EAX   .               .                 # subtract EAX from ECX
860     51/push-ECX
861     # . . call
862     e8/call  check-ints-equal/disp32
863     # . . discard args
864     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
865     # end
866     c3/return
867 
868 test-skip-chars-not-matching-in-slice-all:
869     # (EAX..ECX) = "ab"
870     b8/copy-to-EAX  "ab"/imm32
871     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
872     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
873     05/add-to-EAX  4/imm32
874     # EAX = skip-chars-not-matching-in-slice(EAX, ECX, 0x20/space)
875     # . . push args
876     68/push  0x20/imm32/space
877     51/push-ECX
878     50/push-EAX
879     # . . call
880     e8/call  skip-chars-not-matching-in-slice/disp32
881     # . . discard args
882     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
883     # check-ints-equal(ECX-EAX, 0, msg)
884     # . . push args
885     68/push  "F - test-skip-chars-not-matching-in-slice-all"/imm32
886     68/push  0/imm32
887     # . . push ECX-EAX
888     29/subtract                     3/mod/direct    1/rm32/ECX    .           .             .           0/r32/EAX   .               .                 # subtract EAX from ECX
889     51/push-ECX
890     # . . call
891     e8/call  check-ints-equal/disp32
892     # . . discard args
893     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
894     # end
895     c3/return
896 
897 # . . vim:nowrap:textwidth=0