https://github.com/akkartik/mu/blob/master/subx/073next-token.subx
  1 == code
  2 #   instruction                     effective address                                                   register    displacement    immediate
  3 # . op          subop               mod             rm32          base        index         scale       r32
  4 # . 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
  5 
  6 # main:
  7 #? e8/call test-next-token-from-slice/disp32
  8     e8/call  run-tests/disp32  # 'run-tests' is a function created automatically by SubX. It calls all functions that start with 'test-'.
  9     # syscall(exit, Num-test-failures)
 10     8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           3/r32/EBX   Num-test-failures/disp32          # copy *Num-test-failures to EBX
 11     b8/copy-to-EAX  1/imm32/exit
 12     cd/syscall  0x80/imm8
 13 
 14 # extract the next run of characters that are different from a given 'delimiter' (skipping multiple delimiters if necessary)
 15 # on eof return an empty interval
 16 next-token:  # in : (address stream), delimiter : byte, out : (address slice)
 17     # . prolog
 18     55/push-EBP
 19     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
 20     # . save registers
 21     50/push-EAX
 22     51/push-ECX
 23     56/push-ESI
 24     57/push-EDI
 25     # ESI = in
 26     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           6/r32/ESI   8/disp8         .                 # copy *(EBP+8) to ESI
 27     # EDI = out
 28     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           7/r32/EDI   0x10/disp8      .                 # copy *(EBP+16) to EDI
 29     # skip-chars-matching(in, delimiter)
 30     # . . push args
 31     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
 32     56/push-ESI
 33     # . . call
 34     e8/call  skip-chars-matching/disp32
 35     # . . discard args
 36     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
 37     # out->start = &in->data[in->read]
 38     8b/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           1/r32/ECX   4/disp8         .                 # copy *(ESI+4) to ECX
 39     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
 40     89/copy                         0/mod/indirect  7/rm32/EDI    .           .             .           0/r32/EAX   .               .                 # copy EAX to *EDI
 41     # skip-chars-not-matching(in, delimiter)
 42     # . . push args
 43     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
 44     56/push-ESI
 45     # . . call
 46     e8/call  skip-chars-not-matching/disp32
 47     # . . discard args
 48     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
 49     # out->end = &in->data[in->read]
 50     8b/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           1/r32/ECX   4/disp8         .                 # copy *(ESI+4) to ECX
 51     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
 52     89/copy                         1/mod/*+disp8   7/rm32/EDI    .           .             .           0/r32/EAX   4/disp8         .                 # copy EAX to *(EDI+4)
 53     # . restore registers
 54     5f/pop-to-EDI
 55     5e/pop-to-ESI
 56     59/pop-to-ECX
 57     58/pop-to-EAX
 58     # . epilog
 59     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
 60     5d/pop-to-EBP
 61     c3/return
 62 
 63 test-next-token:
 64     # . prolog
 65     55/push-EBP
 66     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
 67     # setup
 68     # . clear-stream(_test-stream)
 69     # . . push args
 70     68/push  _test-stream/imm32
 71     # . . call
 72     e8/call  clear-stream/disp32
 73     # . . discard args
 74     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
 75     # var slice/ECX = {0, 0}
 76     68/push  0/imm32/end
 77     68/push  0/imm32/start
 78     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
 79     # write(_test-stream, "  ab")
 80     # . . push args
 81     68/push  "  ab"/imm32
 82     68/push  _test-stream/imm32
 83     # . . call
 84     e8/call  write/disp32
 85     # . . discard args
 86     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
 87     # next-token(_test-stream, 0x20/space, slice)
 88     # . . push args
 89     51/push-ECX
 90     68/push  0x20/imm32
 91     68/push  _test-stream/imm32
 92     # . . call
 93     e8/call  next-token/disp32
 94     # . . discard args
 95     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
 96     # check-ints-equal(slice->start - _test-stream->data, 2, msg)
 97     # . check-ints-equal(slice->start - _test-stream, 14, msg)
 98     # . . push args
 99     68/push  "F - test-next-token: start"/imm32
100     68/push  0xe/imm32
101     # . . push slice->start - _test-stream
102     8b/copy                         0/mod/indirect  1/rm32/ECX    .           .             .           0/r32/EAX   .               .                 # copy *ECX to EAX
103     81          5/subop/subtract    3/mod/direct    0/rm32/EAX    .           .             .           .           .               _test-stream/imm32 # subtract from EAX
104     50/push-EAX
105     # . . call
106     e8/call  check-ints-equal/disp32
107     # . . discard args
108     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
109     # check-ints-equal(slice->end - _test-stream->data, 4, msg)
110     # . check-ints-equal(slice->end - _test-stream, 16, msg)
111     # . . push args
112     68/push  "F - test-next-token: end"/imm32
113     68/push  0x10/imm32
114     # . . push slice->end - _test-stream
115     8b/copy                         1/mod/*+disp8   1/rm32/ECX    .           .             .           0/r32/EAX   4/disp8         .                 # copy *(ECX+4) to EAX
116     81          5/subop/subtract    3/mod/direct    0/rm32/EAX    .           .             .           .           .               _test-stream/imm32 # subtract from EAX
117     50/push-EAX
118     # . . call
119     e8/call  check-ints-equal/disp32
120     # . . discard args
121     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
122     # . epilog
123     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
124     5d/pop-to-EBP
125     c3/return
126 
127 test-next-token-eof:
128     # . prolog
129     55/push-EBP
130     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
131     # setup
132     # . clear-stream(_test-stream)
133     # . . push args
134     68/push  _test-stream/imm32
135     # . . call
136     e8/call  clear-stream/disp32
137     # . . discard args
138     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
139     # var slice/ECX = {0, 0}
140     68/push  0/imm32/end
141     68/push  0/imm32/start
142     89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
143     # write nothing to _test-stream
144     # next-token(_test-stream, 0x20/space, slice)
145     # . . push args
146     51/push-ECX
147     68/push  0x20/imm32
148     68/push  _test-stream/imm32
149     # . . call
150     e8/call  next-token/disp32
151     # . . discard args
152     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
153     # check-ints-equal(slice->end, slice->start, msg)
154     # . . push args
155     68/push  "F - test-next-token-eof"/imm32
156     ff          6/subop/push        1/mod/*+disp8   1/rm32/ECX    .           .             .           .           4/disp8         .                 # push *(ECX+4)
157     ff          6/subop/push        0/mod/indirect  1/rm32/ECX    .           .             .           .           .               .                 # push *ECX
158     # . . call
159     e8/call  check-ints-equal/disp32
160     # . . discard args
161     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
162     # . epilog
163     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
164     5d/pop-to-EBP
165     c3/return
166 
167 # extract the next run of characters that are different from a given 'delimiter' (skipping multiple delimiters if necessary)
168 # on eof return an empty interval
169 next-token-from-slice:  # start : (address byte), end : (address byte), delimiter : byte, out : (address slice) -> <void>
170     # . prolog
171     55/push-EBP
172     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
173     # . save registers
174     50/push-EAX
175     51/push-ECX
176     52/push-EDX
177     57/push-EDI
178     # ECX = end
179     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           1/r32/ECX   0xc/disp8       .                 # copy *(EBP+12) to ECX
180     # EDX = delimiter
181     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           2/r32/EDX   0x10/disp8      .                 # copy *(EBP+16) to EDX
182     # EDI = out
183     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           7/r32/EDI   0x14/disp8      .                 # copy *(EBP+20) to EDI
184     # EAX = skip-chars-matching-in-slice(start, end, delimiter)
185     # . . push args
186     52/push-EDX
187     51/push-ECX
188     ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
189     # . . call
190     e8/call  skip-chars-matching-in-slice/disp32
191     # . . discard args
192     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
193     # out->start = EAX
194     89/copy                         0/mod/indirect  7/rm32/EDI    .           .             .           0/r32/EAX   .               .                 # copy EAX to *EDI
195     # EAX = skip-chars-not-matching-in-slice(EAX, end, delimiter)
196     # . . push args
197     52/push-EDX
198     51/push-ECX
199     50/push-EAX
200     # . . call
201     e8/call  skip-chars-not-matching-in-slice/disp32
202     # . . discard args
203     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
204     # out->end = EAX
205     89/copy                         1/mod/*+disp8   7/rm32/EDI    .           .             .           0/r32/EAX   4/disp8         .                 # copy EAX to *(EDI+4)
206     # . restore registers
207     5f/pop-to-EDI
208     5a/pop-to-EDX
209     59/pop-to-ECX
210     58/pop-to-EAX
211     # . epilog
212     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
213     5d/pop-to-EBP
214     c3/return
215 
216 test-next-token-from-slice:
217     # . prolog
218     55/push-EBP
219     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
220     # (EAX..ECX) = "  ab"
221     b8/copy-to-EAX  "  ab"/imm32
222     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
223     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
224     05/add-to-EAX  4/imm32
225     # var out/EDI : (address slice) = {0, 0}
226     68/push  0/imm32/end
227     68/push  0/imm32/start
228     89/copy                         3/mod/direct    7/rm32/EDI    .           .             .           4/r32/ESP   .               .                 # copy ESP to EDI
229     # next-token-from-slice(EAX, ECX, 0x20/space, out)
230     # . . push args
231     57/push-EDI
232     68/push  0x20/imm32
233     51/push-ECX
234     50/push-EAX
235     # . . call
236     e8/call  next-token-from-slice/disp32
237     # . . discard args
238     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x10/imm32        # add to ESP
239     # out->start should be at the 'a'
240     # . check-ints-equal(out->start - in->start, 2, msg)
241     # . . push args
242     68/push  "F - test-next-token-from-slice: start"/imm32
243     68/push  2/imm32
244     # . . push out->start - in->start
245     8b/copy                         0/mod/indirect  7/rm32/EDI    .           .             .           1/r32/ECX   .               .                 # copy *EDI to ECX
246     2b/subtract                     3/mod/direct    0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # subtract EAX from ECX
247     51/push-ECX
248     # . . call
249     e8/call  check-ints-equal/disp32
250     # . . discard args
251     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
252     # out->end should be after the 'b'
253     # check-ints-equal(out->end - in->start, 4, msg)
254     # . . push args
255     68/push  "F - test-next-token-from-slice: end"/imm32
256     68/push  4/imm32
257     # . . push out->end - in->start
258     8b/copy                         1/mod/*+disp8   7/rm32/EDI    .           .             .           1/r32/ECX   4/disp8         .                 # copy *(EDI+4) to ECX
259     2b/subtract                     3/mod/direct    0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # subtract EAX from ECX
260     51/push-ECX
261     # . . call
262     e8/call  check-ints-equal/disp32
263     # . . discard args
264     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
265     # . epilog
266     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
267     5d/pop-to-EBP
268     c3/return
269 
270 test-next-token-from-slice-eof:
271     # . prolog
272     55/push-EBP
273     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
274     # var out/EDI : (address slice) = {0, 0}
275     68/push  0/imm32/end
276     68/push  0/imm32/start
277     89/copy                         3/mod/direct    7/rm32/EDI    .           .             .           4/r32/ESP   .               .                 # copy ESP to EDI
278     # next-token-from-slice(0, 0, 0x20/space, out)
279     # . . push args
280     57/push-EDI
281     68/push  0x20/imm32
282     68/push  0/imm32
283     68/push  0/imm32
284     # . . call
285     e8/call  next-token-from-slice/disp32
286     # . . discard args
287     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x10/imm32        # add to ESP
288     # out should be empty
289     # . check-ints-equal(out->end - out->start, 0, msg)
290     # . . push args
291     68/push  "F - test-next-token-from-slice-eof"/imm32
292     68/push  0/imm32
293     # . . push out->start - in->start
294     8b/copy                         1/mod/*+disp8   7/rm32/EDI    .           .             .           1/r32/ECX   4/disp8         .                 # copy *(EDI+4) to ECX
295     2b/subtract                     0/mod/indirect  7/rm32/EDI    .           .             .           1/r32/ECX   .               .                 # subtract *EDI from ECX
296     51/push-ECX
297     # . . call
298     e8/call  check-ints-equal/disp32
299     # . . discard args
300     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
301     # . epilog
302     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
303     5d/pop-to-EBP
304     c3/return
305 
306 test-next-token-from-slice-nothing:
307     # . prolog
308     55/push-EBP
309     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
310     # (EAX..ECX) = "    "
311     b8/copy-to-EAX  "    "/imm32
312     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
313     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
314     05/add-to-EAX  4/imm32
315     # var out/EDI : (address slice) = {0, 0}
316     68/push  0/imm32/end
317     68/push  0/imm32/start
318     89/copy                         3/mod/direct    7/rm32/EDI    .           .             .           4/r32/ESP   .               .                 # copy ESP to EDI
319     # next-token-from-slice(in, 0x20/space, out)
320     # . . push args
321     57/push-EDI
322     68/push  0x20/imm32
323     51/push-ECX
324     50/push-EAX
325     # . . call
326     e8/call  next-token-from-slice/disp32
327     # . . discard args
328     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x10/imm32        # add to ESP
329     # out should be empty
330     # . check-ints-equal(out->end - out->start, 0, msg)
331     # . . push args
332     68/push  "F - test-next-token-from-slice-eof"/imm32
333     68/push  0/imm32
334     # . . push out->start - in->start
335     8b/copy                         1/mod/*+disp8   7/rm32/EDI    .           .             .           1/r32/ECX   4/disp8         .                 # copy *(EDI+4) to ECX
336     2b/subtract                     0/mod/indirect  7/rm32/EDI    .           .             .           1/r32/ECX   .               .                 # subtract *EDI from ECX
337     51/push-ECX
338     # . . call
339     e8/call  check-ints-equal/disp32
340     # . . discard args
341     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
342     # . epilog
343     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
344     5d/pop-to-EBP
345     c3/return
346 
347 skip-chars-matching:  # in : (address stream), delimiter : byte
348     # . prolog
349     55/push-EBP
350     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
351     # . save registers
352     50/push-EAX
353     51/push-ECX
354     52/push-EDX
355     56/push-ESI
356     # ESI = in
357     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           6/r32/ESI   8/disp8         .                 # copy *(EBP+8) to ESI
358     # ECX = in->read
359     8b/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           1/r32/ECX   4/disp8         .                 # copy *(ESI+4) to ECX
360     # EBX = in->write
361     8b/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           3/r32/EBX   .               .                 # copy *ESI to EBX
362     # EDX = delimiter
363     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           2/r32/EDX   0xc/disp8       .                 # copy *(EBP+12) to EDX
364 $skip-chars-matching:loop:
365     # if (in->read >= in->write) break
366     39/compare                      3/mod/direct    1/rm32/ECX    .           .             .           3/r32/EBX   .               .                 # compare ECX with EBX
367     7d/jump-if-greater-or-equal  $skip-chars-matching:end/disp8
368     # EAX = in->data[in->read]
369     31/xor                          3/mod/direct    0/rm32/EAX    .           .             .           0/r32/EAX   .               .                 # clear EAX
370     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
371     # if (EAX != delimiter) break
372     39/compare                      3/mod/direct    0/rm32/EAX    .           .             .           2/r32/EDX   .               .                 # compare EAX and EDX
373     75/jump-if-not-equal  $skip-chars-matching:end/disp8
374     # ++in->read
375     41/inc-ECX
376     eb/jump  $skip-chars-matching:loop/disp8
377 $skip-chars-matching:end:
378     # persist in->read
379     89/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           1/r32/ECX   4/disp8         .                 # copy ECX to *(ESI+4)
380     # . restore registers
381     5e/pop-to-ESI
382     5a/pop-to-EDX
383     59/pop-to-ECX
384     58/pop-to-EAX
385     # . epilog
386     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
387     5d/pop-to-EBP
388     c3/return
389 
390 test-skip-chars-matching:
391     # setup
392     # . clear-stream(_test-stream)
393     # . . push args
394     68/push  _test-stream/imm32
395     # . . call
396     e8/call  clear-stream/disp32
397     # . . discard args
398     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
399     # write(_test-stream, "  ab")
400     # . . push args
401     68/push  "  ab"/imm32
402     68/push  _test-stream/imm32
403     # . . call
404     e8/call  write/disp32
405     # . . discard args
406     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
407     # skip-chars-matching(_test-stream, 0x20/space)
408     # . . push args
409     68/push  0x20/imm32
410     68/push  _test-stream/imm32
411     # . . call
412     e8/call  skip-chars-matching/disp32
413     # . . discard args
414     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
415     # check-ints-equal(_test-stream->read, 2, msg)
416     # . . push args
417     68/push  "F - test-skip-chars-matching"/imm32
418     68/push  2/imm32
419     # . . push *_test-stream->read
420     b8/copy-to-EAX  _test-stream/imm32
421     ff          6/subop/push        1/mod/*+disp8   0/rm32/EAX    .           .             .           .           4/disp8         .                 # push *(EAX+4)
422     # . . call
423     e8/call  check-ints-equal/disp32
424     # . . discard args
425     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
426     # end
427     c3/return
428 
429 test-skip-chars-matching-none:
430     # setup
431     # . clear-stream(_test-stream)
432     # . . push args
433     68/push  _test-stream/imm32
434     # . . call
435     e8/call  clear-stream/disp32
436     # . . discard args
437     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
438     # write(_test-stream, "ab")
439     # . . push args
440     68/push  "ab"/imm32
441     68/push  _test-stream/imm32
442     # . . call
443     e8/call  write/disp32
444     # . . discard args
445     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
446     # skip-chars-matching(_test-stream, 0x20/space)
447     # . . push args
448     68/push  0x20/imm32
449     68/push  _test-stream/imm32
450     # . . call
451     e8/call  skip-chars-matching/disp32
452     # . . discard args
453     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
454     # check-ints-equal(_test-stream->read, 0, msg)
455     # . . push args
456     68/push  "F - test-skip-chars-matching-none"/imm32
457     68/push  0/imm32
458     # . . push *_test-stream->read
459     b8/copy-to-EAX  _test-stream/imm32
460     ff          6/subop/push        1/mod/*+disp8   0/rm32/EAX    .           .             .           .           4/disp8         .                 # push *(EAX+4)
461     # . . call
462     e8/call  check-ints-equal/disp32
463     # . . discard args
464     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
465     # end
466     c3/return
467 
468 # minor fork of 'skip-chars-matching'
469 skip-chars-not-matching:  # in : (address stream), delimiter : byte
470     # . prolog
471     55/push-EBP
472     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
473     # . save registers
474     50/push-EAX
475     51/push-ECX
476     52/push-EDX
477     56/push-ESI
478     # ESI = in
479     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           6/r32/ESI   8/disp8         .                 # copy *(EBP+8) to ESI
480     # ECX = in->read
481     8b/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           1/r32/ECX   4/disp8         .                 # copy *(ESI+4) to ECX
482     # EBX = in->write
483     8b/copy                         0/mod/indirect  6/rm32/ESI    .           .             .           3/r32/EBX   .               .                 # copy *ESI to EBX
484     # EDX = delimiter
485     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           2/r32/EDX   0xc/disp8       .                 # copy *(EBP+12) to EDX
486 $skip-chars-not-matching:loop:
487     # if (in->read >= in->write) break
488     39/compare                      3/mod/direct    1/rm32/ECX    .           .             .           3/r32/EBX   .               .                 # compare ECX with EBX
489     7d/jump-if-greater-or-equal  $skip-chars-not-matching:end/disp8
490     # EAX = in->data[in->read]
491     31/xor                          3/mod/direct    0/rm32/EAX    .           .             .           0/r32/EAX   .               .                 # clear EAX
492     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
493     # if (EAX == delimiter) break
494     39/compare                      3/mod/direct    0/rm32/EAX    .           .             .           2/r32/EDX   .               .                 # compare EAX and EDX
495     74/jump-if-equal  $skip-chars-not-matching:end/disp8
496     # ++in->read
497     41/inc-ECX
498     eb/jump  $skip-chars-not-matching:loop/disp8
499 $skip-chars-not-matching:end:
500     # persist in->read
501     89/copy                         1/mod/*+disp8   6/rm32/ESI    .           .             .           1/r32/ECX   4/disp8         .                 # copy ECX to *(ESI+4)
502     # . restore registers
503     5e/pop-to-ESI
504     5a/pop-to-EDX
505     59/pop-to-ECX
506     58/pop-to-EAX
507     # . epilog
508     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
509     5d/pop-to-EBP
510     c3/return
511 
512 test-skip-chars-not-matching:
513     # setup
514     # . clear-stream(_test-stream)
515     # . . push args
516     68/push  _test-stream/imm32
517     # . . call
518     e8/call  clear-stream/disp32
519     # . . discard args
520     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
521     # write(_test-stream, "ab ")
522     # . . push args
523     68/push  "ab "/imm32
524     68/push  _test-stream/imm32
525     # . . call
526     e8/call  write/disp32
527     # . . discard args
528     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
529     # skip-chars-not-matching(_test-stream, 0x20/space)
530     # . . push args
531     68/push  0x20/imm32
532     68/push  _test-stream/imm32
533     # . . call
534     e8/call  skip-chars-not-matching/disp32
535     # . . discard args
536     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
537     # check-ints-equal(_test-stream->read, 2, msg)
538     # . . push args
539     68/push  "F - test-skip-chars-not-matching"/imm32
540     68/push  2/imm32
541     # . . push *_test-stream->read
542     b8/copy-to-EAX  _test-stream/imm32
543     ff          6/subop/push        1/mod/*+disp8   0/rm32/EAX    .           .             .           .           4/disp8         .                 # push *(EAX+4)
544     # . . call
545     e8/call  check-ints-equal/disp32
546     # . . discard args
547     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
548     # end
549     c3/return
550 
551 test-skip-chars-not-matching-none:
552     # setup
553     # . clear-stream(_test-stream)
554     # . . push args
555     68/push  _test-stream/imm32
556     # . . call
557     e8/call  clear-stream/disp32
558     # . . discard args
559     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
560     # write(_test-stream, " ab")
561     # . . push args
562     68/push  " ab"/imm32
563     68/push  _test-stream/imm32
564     # . . call
565     e8/call  write/disp32
566     # . . discard args
567     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
568     # skip-chars-not-matching(_test-stream, 0x20/space)
569     # . . push args
570     68/push  0x20/imm32
571     68/push  _test-stream/imm32
572     # . . call
573     e8/call  skip-chars-not-matching/disp32
574     # . . discard args
575     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
576     # check-ints-equal(_test-stream->read, 0, msg)
577     # . . push args
578     68/push  "F - test-skip-chars-not-matching-none"/imm32
579     68/push  0/imm32
580     # . . push *_test-stream->read
581     b8/copy-to-EAX  _test-stream/imm32
582     ff          6/subop/push        1/mod/*+disp8   0/rm32/EAX    .           .             .           .           4/disp8         .                 # push *(EAX+4)
583     # . . call
584     e8/call  check-ints-equal/disp32
585     # . . discard args
586     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
587     # end
588     c3/return
589 
590 test-skip-chars-not-matching-all:
591     # setup
592     # . clear-stream(_test-stream)
593     # . . push args
594     68/push  _test-stream/imm32
595     # . . call
596     e8/call  clear-stream/disp32
597     # . . discard args
598     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
599     # write(_test-stream, "ab")
600     # . . push args
601     68/push  "ab"/imm32
602     68/push  _test-stream/imm32
603     # . . call
604     e8/call  write/disp32
605     # . . discard args
606     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
607     # skip-chars-not-matching(_test-stream, 0x20/space)
608     # . . push args
609     68/push  0x20/imm32
610     68/push  _test-stream/imm32
611     # . . call
612     e8/call  skip-chars-not-matching/disp32
613     # . . discard args
614     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
615     # check-ints-equal(_test-stream->read, 2, msg)
616     # . . push args
617     68/push  "F - test-skip-chars-not-matching-all"/imm32
618     68/push  2/imm32
619     # . . push *_test-stream->read
620     b8/copy-to-EAX  _test-stream/imm32
621     ff          6/subop/push        1/mod/*+disp8   0/rm32/EAX    .           .             .           .           4/disp8         .                 # push *(EAX+4)
622     # . . call
623     e8/call  check-ints-equal/disp32
624     # . . discard args
625     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
626     # end
627     c3/return
628 
629 skip-chars-matching-in-slice:  # curr : (address byte), end : (address byte), delimiter : byte -> curr/EAX
630     # . prolog
631     55/push-EBP
632     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
633     # . save registers
634     51/push-ECX
635     52/push-EDX
636     53/push-EBX
637     # EAX = curr
638     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           0/r32/EAX   8/disp8         .                 # copy *(EBP+8) to EAX
639     # ECX = end
640     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           1/r32/ECX   0xc/disp8       .                 # copy *(EBP+12) to ECX
641     # EDX = delimiter
642     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           2/r32/EDX   0x10/disp8       .                 # copy *(EBP+16) to EDX
643     # EBX = 0
644     31/xor                          3/mod/direct    3/rm32/EBX    .           .             .           3/r32/EBX   .               .                 # clear EBX
645 $skip-chars-matching-in-slice:loop:
646     # if (curr >= end) break
647     39/compare                      3/mod/direct    0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # compare EAX with ECX
648     7d/jump-if-greater-or-equal  $skip-chars-matching-in-slice:end/disp8
649     # if (*curr != delimiter) break
650     8a/copy-byte                    0/mod/indirect  0/rm32/EAX    .           .             .           3/r32/BL    .               .                 # copy byte at *EAX to BL
651     39/compare                      3/mod/direct    3/rm32/EBX    .           .             .           2/r32/EDX   .               .                 # compare EBX and EDX
652     75/jump-if-not-equal  $skip-chars-matching-in-slice:end/disp8
653     # ++in->read
654     40/inc-EAX
655     eb/jump  $skip-chars-matching-in-slice:loop/disp8
656 $skip-chars-matching-in-slice:end:
657     # . restore registers
658     5b/pop-to-EBX
659     5a/pop-to-EDX
660     59/pop-to-ECX
661     # . epilog
662     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
663     5d/pop-to-EBP
664     c3/return
665 
666 test-skip-chars-matching-in-slice:
667     # (EAX..ECX) = "  ab"
668     b8/copy-to-EAX  "  ab"/imm32
669     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
670     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
671     05/add-to-EAX  4/imm32
672     # EAX = skip-chars-matching-in-slice(EAX, ECX, 0x20/space)
673     # . . push args
674     68/push  0x20/imm32
675     51/push-ECX
676     50/push-EAX
677     # . . call
678     e8/call  skip-chars-matching-in-slice/disp32
679     # . . discard args
680     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
681     # check-ints-equal(ECX-EAX, 2, msg)
682     # . . push args
683     68/push  "F - test-skip-chars-matching-in-slice"/imm32
684     68/push  2/imm32
685     # . . push ECX-EAX
686     29/subtract                     3/mod/direct    1/rm32/ECX    .           .             .           0/r32/EAX   .               .                 # subtract EAX from ECX
687     51/push-ECX
688     # . . call
689     e8/call  check-ints-equal/disp32
690     # . . discard args
691     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
692     # end
693     c3/return
694 
695 test-skip-chars-matching-in-slice-none:
696     # (EAX..ECX) = "ab"
697     b8/copy-to-EAX  "ab"/imm32
698     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
699     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
700     05/add-to-EAX  4/imm32
701     # EAX = skip-chars-matching-in-slice(EAX, ECX, 0x20/space)
702     # . . push args
703     68/push  0x20/imm32
704     51/push-ECX
705     50/push-EAX
706     # . . call
707     e8/call  skip-chars-matching-in-slice/disp32
708     # . . discard args
709     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
710     # check-ints-equal(ECX-EAX, 2, msg)
711     # . . push args
712     68/push  "F - test-skip-chars-matching-in-slice-none"/imm32
713     68/push  2/imm32
714     # . . push ECX-EAX
715     29/subtract                     3/mod/direct    1/rm32/ECX    .           .             .           0/r32/EAX   .               .                 # subtract EAX from ECX
716     51/push-ECX
717     # . . call
718     e8/call  check-ints-equal/disp32
719     # . . discard args
720     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
721     # end
722     c3/return
723 
724 # minor fork of 'skip-chars-matching-in-slice'
725 skip-chars-not-matching-in-slice:  # curr : (address byte), end : (address byte), delimiter : byte -> curr/EAX
726     # . prolog
727     55/push-EBP
728     89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
729     # . save registers
730     51/push-ECX
731     52/push-EDX
732     53/push-EBX
733     # EAX = curr
734     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           0/r32/EAX   8/disp8         .                 # copy *(EBP+8) to EAX
735     # ECX = end
736     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           1/r32/ECX   0xc/disp8       .                 # copy *(EBP+12) to ECX
737     # EDX = delimiter
738     8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           2/r32/EDX   0x10/disp8       .                 # copy *(EBP+16) to EDX
739     # EBX = 0
740     31/xor                          3/mod/direct    3/rm32/EBX    .           .             .           3/r32/EBX   .               .                 # clear EBX
741 $skip-chars-not-matching-in-slice:loop:
742     # if (curr >= end) break
743     39/compare                      3/mod/direct    0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # compare EAX with ECX
744     7d/jump-if-greater-or-equal  $skip-chars-not-matching-in-slice:end/disp8
745     # if (*curr == delimiter) break
746     8a/copy-byte                    0/mod/indirect  0/rm32/EAX    .           .             .           3/r32/BL    .               .                 # copy byte at *EAX to BL
747     39/compare                      3/mod/direct    3/rm32/EBX    .           .             .           2/r32/EDX   .               .                 # compare EBX and EDX
748     74/jump-if-equal  $skip-chars-not-matching-in-slice:end/disp8
749     # ++in->read
750     40/inc-EAX
751     eb/jump  $skip-chars-not-matching-in-slice:loop/disp8
752 $skip-chars-not-matching-in-slice:end:
753     # . restore registers
754     5b/pop-to-EBX
755     5a/pop-to-EDX
756     59/pop-to-ECX
757     # . epilog
758     89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
759     5d/pop-to-EBP
760     c3/return
761 
762 test-skip-chars-not-matching-in-slice:
763     # (EAX..ECX) = "ab "
764     b8/copy-to-EAX  "ab "/imm32
765     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
766     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
767     05/add-to-EAX  4/imm32
768     # EAX = skip-chars-not-matching-in-slice(EAX, ECX, 0x20/space)
769     # . . push args
770     68/push  0x20/imm32
771     51/push-ECX
772     50/push-EAX
773     # . . call
774     e8/call  skip-chars-not-matching-in-slice/disp32
775     # . . discard args
776     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
777     # check-ints-equal(ECX-EAX, 1, msg)
778     # . . push args
779     68/push  "F - test-skip-chars-not-matching-in-slice"/imm32
780     68/push  1/imm32
781     # . . push ECX-EAX
782     29/subtract                     3/mod/direct    1/rm32/ECX    .           .             .           0/r32/EAX   .               .                 # subtract EAX from ECX
783     51/push-ECX
784     # . . call
785     e8/call  check-ints-equal/disp32
786     # . . discard args
787     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
788     # end
789     c3/return
790 
791 test-skip-chars-not-matching-in-slice-none:
792     # (EAX..ECX) = " ab"
793     b8/copy-to-EAX  " ab"/imm32
794     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
795     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
796     05/add-to-EAX  4/imm32
797     # EAX = skip-chars-not-matching-in-slice(EAX, ECX, 0x20/space)
798     # . . push args
799     68/push  0x20/imm32
800     51/push-ECX
801     50/push-EAX
802     # . . call
803     e8/call  skip-chars-not-matching-in-slice/disp32
804     # . . discard args
805     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
806     # check-ints-equal(ECX-EAX, 3, msg)
807     # . . push args
808     68/push  "F - test-skip-chars-not-matching-in-slice-none"/imm32
809     68/push  3/imm32
810     # . . push ECX-EAX
811     29/subtract                     3/mod/direct    1/rm32/ECX    .           .             .           0/r32/EAX   .               .                 # subtract EAX from ECX
812     51/push-ECX
813     # . . call
814     e8/call  check-ints-equal/disp32
815     # . . discard args
816     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
817     # end
818     c3/return
819 
820 test-skip-chars-not-matching-in-slice-all:
821     # (EAX..ECX) = "ab"
822     b8/copy-to-EAX  "ab"/imm32
823     8b/copy                         0/mod/indirect  0/rm32/EAX    .           .             .           1/r32/ECX   .               .                 # copy *EAX to ECX
824     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
825     05/add-to-EAX  4/imm32
826     # EAX = skip-chars-not-matching-in-slice(EAX, ECX, 0x20/space)
827     # . . push args
828     68/push  0x20/imm32
829     51/push-ECX
830     50/push-EAX
831     # . . call
832     e8/call  skip-chars-not-matching-in-slice/disp32
833     # . . discard args
834     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
835     # check-ints-equal(ECX-EAX, 0, msg)
836     # . . push args
837     68/push  "F - test-skip-chars-not-matching-in-slice-all"/imm32
838     68/push  0/imm32
839     # . . push ECX-EAX
840     29/subtract                     3/mod/direct    1/rm32/ECX    .           .             .           0/r32/EAX   .               .                 # subtract EAX from ECX
841     51/push-ECX
842     # . . call
843     e8/call  check-ints-equal/disp32
844     # . . discard args
845     81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
846     # end
847     c3/return
848 
849 # . . vim:nowrap:textwidth=0