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