1 # Some tokenization primitives.
4 # instruction effective address register displacement immediate
5 # . op subop mod rm32 base index scale r32
6 # . 1-3 bytes 3 bits 2 bits 3 bits 3 bits 3 bits 2 bits 2 bits 0/1/2/4 bytes 0/1/2/4 bytes
8 # extract the next run of characters that are different from a given 'delimiter' (skipping multiple delimiters if necessary)
9 # on reaching end of file, return an empty interval
10 next-token-from-slice: # start: (addr byte), end: (addr byte), delimiter: byte, out: (addr slice)
13 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
20 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 0xc/disp8 . # copy *(ebp+12) to ecx
22 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 2/r32/edx 0x10/disp8 . # copy *(ebp+16) to edx
24 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 7/r32/edi 0x14/disp8 . # copy *(ebp+20) to edi
25 # eax = skip-chars-matching-in-slice(start, end, delimiter)
29 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
31 e8/call skip-chars-matching-in-slice/disp32
33 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
35 89/copy 0/mod/indirect 7/rm32/edi . . . 0/r32/eax . . # copy eax to *edi
36 # eax = skip-chars-not-matching-in-slice(eax, end, delimiter)
42 e8/call skip-chars-not-matching-in-slice/disp32
44 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
46 89/copy 1/mod/*+disp8 7/rm32/edi . . . 0/r32/eax 4/disp8 . # copy eax to *(edi+4)
53 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
57 test-next-token-from-slice:
60 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
62 b8/copy-to-eax " ab"/imm32
63 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
64 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
69 89/copy 3/mod/direct 7/rm32/edi . . . 4/r32/esp . . # copy esp to edi
70 # next-token-from-slice(eax, ecx, 0x20/space, out)
77 e8/call next-token-from-slice/disp32
79 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp
80 # out->start should be at the 'a'
81 # . check-ints-equal(out->start - in->start, 2, msg)
83 68/push "F - test-next-token-from-slice: start"/imm32
85 # . . push out->start - in->start
86 8b/copy 0/mod/indirect 7/rm32/edi . . . 1/r32/ecx . . # copy *edi to ecx
87 2b/subtract 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # subtract eax from ecx
90 e8/call check-ints-equal/disp32
92 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
93 # out->end should be after the 'b'
94 # check-ints-equal(out->end - in->start, 4, msg)
96 68/push "F - test-next-token-from-slice: end"/imm32
98 # . . push out->end - in->start
99 8b/copy 1/mod/*+disp8 7/rm32/edi . . . 1/r32/ecx 4/disp8 . # copy *(edi+4) to ecx
100 2b/subtract 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # subtract eax from ecx
103 e8/call check-ints-equal/disp32
105 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
107 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
111 test-next-token-from-slice-Eof:
114 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
117 68/push 0/imm32/start
118 89/copy 3/mod/direct 7/rm32/edi . . . 4/r32/esp . . # copy esp to edi
119 # next-token-from-slice(0, 0, 0x20/space, out)
126 e8/call next-token-from-slice/disp32
128 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp
129 # out should be empty
130 # . check-ints-equal(out->end - out->start, 0, msg)
132 68/push "F - test-next-token-from-slice-Eof"/imm32
134 # . . push out->start - in->start
135 8b/copy 1/mod/*+disp8 7/rm32/edi . . . 1/r32/ecx 4/disp8 . # copy *(edi+4) to ecx
136 2b/subtract 0/mod/indirect 7/rm32/edi . . . 1/r32/ecx . . # subtract *edi from ecx
139 e8/call check-ints-equal/disp32
141 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
143 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
147 test-next-token-from-slice-nothing:
150 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
152 b8/copy-to-eax " "/imm32
153 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
154 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
155 05/add-to-eax 4/imm32
158 68/push 0/imm32/start
159 89/copy 3/mod/direct 7/rm32/edi . . . 4/r32/esp . . # copy esp to edi
160 # next-token-from-slice(in, 0x20/space, out)
167 e8/call next-token-from-slice/disp32
169 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp
170 # out should be empty
171 # . check-ints-equal(out->end - out->start, 0, msg)
173 68/push "F - test-next-token-from-slice-Eof"/imm32
175 # . . push out->start - in->start
176 8b/copy 1/mod/*+disp8 7/rm32/edi . . . 1/r32/ecx 4/disp8 . # copy *(edi+4) to ecx
177 2b/subtract 0/mod/indirect 7/rm32/edi . . . 1/r32/ecx . . # subtract *edi from ecx
180 e8/call check-ints-equal/disp32
182 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
184 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
188 skip-chars-matching: # in: (addr stream byte), delimiter: byte
191 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
199 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi
201 8b/copy 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 4/disp8 . # copy *(esi+4) to ecx
203 8b/copy 0/mod/indirect 6/rm32/esi . . . 3/r32/ebx . . # copy *esi to ebx
205 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 2/r32/edx 0xc/disp8 . # copy *(ebp+12) to edx
206 $skip-chars-matching:loop:
207 # if (in->read >= in->write) break
208 39/compare 3/mod/direct 1/rm32/ecx . . . 3/r32/ebx . . # compare ecx with ebx
209 7d/jump-if->= $skip-chars-matching:end/disp8
210 # eax = in->data[in->read]
211 31/xor 3/mod/direct 0/rm32/eax . . . 0/r32/eax . . # clear eax
212 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
213 # if (eax != delimiter) break
214 39/compare 3/mod/direct 0/rm32/eax . . . 2/r32/edx . . # compare eax and edx
215 75/jump-if-!= $skip-chars-matching:end/disp8
218 eb/jump $skip-chars-matching:loop/disp8
219 $skip-chars-matching:end:
221 89/copy 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 4/disp8 . # copy ecx to *(esi+4)
222 # . restore registers
229 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
233 test-skip-chars-matching:
235 # . clear-stream(_test-stream)
237 68/push _test-stream/imm32
239 e8/call clear-stream/disp32
241 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
242 # write(_test-stream, " ab")
245 68/push _test-stream/imm32
249 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
250 # skip-chars-matching(_test-stream, 0x20/space)
253 68/push _test-stream/imm32
255 e8/call skip-chars-matching/disp32
257 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
258 # check-ints-equal(_test-stream->read, 2, msg)
260 68/push "F - test-skip-chars-matching"/imm32
262 # . . push *_test-stream->read
263 b8/copy-to-eax _test-stream/imm32
264 ff 6/subop/push 1/mod/*+disp8 0/rm32/eax . . . . 4/disp8 . # push *(eax+4)
266 e8/call check-ints-equal/disp32
268 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
272 test-skip-chars-matching-none:
274 # . clear-stream(_test-stream)
276 68/push _test-stream/imm32
278 e8/call clear-stream/disp32
280 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
281 # write(_test-stream, "ab")
284 68/push _test-stream/imm32
288 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
289 # skip-chars-matching(_test-stream, 0x20/space)
292 68/push _test-stream/imm32
294 e8/call skip-chars-matching/disp32
296 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
297 # check-ints-equal(_test-stream->read, 0, msg)
299 68/push "F - test-skip-chars-matching-none"/imm32
301 # . . push *_test-stream->read
302 b8/copy-to-eax _test-stream/imm32
303 ff 6/subop/push 1/mod/*+disp8 0/rm32/eax . . . . 4/disp8 . # push *(eax+4)
305 e8/call check-ints-equal/disp32
307 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
311 skip-chars-matching-whitespace: # in: (addr stream byte)
314 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
321 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi
323 8b/copy 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 4/disp8 . # copy *(esi+4) to ecx
325 8b/copy 0/mod/indirect 6/rm32/esi . . . 3/r32/ebx . . # copy *esi to ebx
326 $skip-chars-matching-whitespace:loop:
327 # if (in->read >= in->write) break
328 39/compare 3/mod/direct 1/rm32/ecx . . . 3/r32/ebx . . # compare ecx with ebx
329 7d/jump-if->= $skip-chars-matching-whitespace:end/disp8
330 # eax = in->data[in->read]
331 31/xor 3/mod/direct 0/rm32/eax . . . 0/r32/eax . . # clear eax
332 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
333 # if (eax == ' ') goto body
334 3d/compare-eax-and 0x20/imm32/space
335 74/jump-if-= $skip-chars-matching-whitespace:body/disp8
336 # if (eax == '\n') goto body
337 3d/compare-eax-and 0x0a/imm32/newline
338 74/jump-if-= $skip-chars-matching-whitespace:body/disp8
339 # if (eax == '\t') goto body
340 3d/compare-eax-and 0x09/imm32/tab
341 74/jump-if-= $skip-chars-matching-whitespace:body/disp8
342 # if (eax != '\r') break
343 3d/compare-eax-and 0x0d/imm32/cr
344 75/jump-if-!= $skip-chars-matching-whitespace:end/disp8
345 $skip-chars-matching-whitespace:body:
348 eb/jump $skip-chars-matching-whitespace:loop/disp8
349 $skip-chars-matching-whitespace:end:
351 89/copy 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 4/disp8 . # copy ecx to *(esi+4)
352 # . restore registers
358 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
362 test-skip-chars-matching-whitespace:
364 # . clear-stream(_test-stream)
366 68/push _test-stream/imm32
368 e8/call clear-stream/disp32
370 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
371 # write(_test-stream, " \nab")
373 68/push " \nab"/imm32
374 68/push _test-stream/imm32
378 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
379 # skip-chars-matching-whitespace(_test-stream)
381 68/push _test-stream/imm32
383 e8/call skip-chars-matching-whitespace/disp32
385 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
386 # check-ints-equal(_test-stream->read, 2, msg)
388 68/push "F - test-skip-chars-matching-whitespace"/imm32
390 # . . push *_test-stream->read
391 b8/copy-to-eax _test-stream/imm32
392 ff 6/subop/push 1/mod/*+disp8 0/rm32/eax . . . . 4/disp8 . # push *(eax+4)
394 e8/call check-ints-equal/disp32
396 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
400 # minor fork of 'skip-chars-matching'
401 skip-chars-not-matching: # in: (addr stream byte), delimiter: byte
404 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
412 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi
414 8b/copy 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 4/disp8 . # copy *(esi+4) to ecx
416 8b/copy 0/mod/indirect 6/rm32/esi . . . 3/r32/ebx . . # copy *esi to ebx
418 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 2/r32/edx 0xc/disp8 . # copy *(ebp+12) to edx
419 $skip-chars-not-matching:loop:
420 # if (in->read >= in->write) break
421 39/compare 3/mod/direct 1/rm32/ecx . . . 3/r32/ebx . . # compare ecx with ebx
422 7d/jump-if->= $skip-chars-not-matching:end/disp8
423 # eax = in->data[in->read]
424 31/xor 3/mod/direct 0/rm32/eax . . . 0/r32/eax . . # clear eax
425 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
426 # if (eax == delimiter) break
427 39/compare 3/mod/direct 0/rm32/eax . . . 2/r32/edx . . # compare eax and edx
428 74/jump-if-= $skip-chars-not-matching:end/disp8
431 eb/jump $skip-chars-not-matching:loop/disp8
432 $skip-chars-not-matching:end:
434 89/copy 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 4/disp8 . # copy ecx to *(esi+4)
435 # . restore registers
442 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
446 test-skip-chars-not-matching:
448 # . clear-stream(_test-stream)
450 68/push _test-stream/imm32
452 e8/call clear-stream/disp32
454 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
455 # write(_test-stream, "ab ")
458 68/push _test-stream/imm32
462 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
463 # skip-chars-not-matching(_test-stream, 0x20/space)
466 68/push _test-stream/imm32
468 e8/call skip-chars-not-matching/disp32
470 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
471 # check-ints-equal(_test-stream->read, 2, msg)
473 68/push "F - test-skip-chars-not-matching"/imm32
475 # . . push *_test-stream->read
476 b8/copy-to-eax _test-stream/imm32
477 ff 6/subop/push 1/mod/*+disp8 0/rm32/eax . . . . 4/disp8 . # push *(eax+4)
479 e8/call check-ints-equal/disp32
481 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
485 test-skip-chars-not-matching-none:
487 # . clear-stream(_test-stream)
489 68/push _test-stream/imm32
491 e8/call clear-stream/disp32
493 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
494 # write(_test-stream, " ab")
497 68/push _test-stream/imm32
501 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
502 # skip-chars-not-matching(_test-stream, 0x20/space)
505 68/push _test-stream/imm32
507 e8/call skip-chars-not-matching/disp32
509 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
510 # check-ints-equal(_test-stream->read, 0, msg)
512 68/push "F - test-skip-chars-not-matching-none"/imm32
514 # . . push *_test-stream->read
515 b8/copy-to-eax _test-stream/imm32
516 ff 6/subop/push 1/mod/*+disp8 0/rm32/eax . . . . 4/disp8 . # push *(eax+4)
518 e8/call check-ints-equal/disp32
520 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
524 test-skip-chars-not-matching-all:
526 # . clear-stream(_test-stream)
528 68/push _test-stream/imm32
530 e8/call clear-stream/disp32
532 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
533 # write(_test-stream, "ab")
536 68/push _test-stream/imm32
540 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
541 # skip-chars-not-matching(_test-stream, 0x20/space)
544 68/push _test-stream/imm32
546 e8/call skip-chars-not-matching/disp32
548 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
549 # check-ints-equal(_test-stream->read, 2, msg)
551 68/push "F - test-skip-chars-not-matching-all"/imm32
553 # . . push *_test-stream->read
554 b8/copy-to-eax _test-stream/imm32
555 ff 6/subop/push 1/mod/*+disp8 0/rm32/eax . . . . 4/disp8 . # push *(eax+4)
557 e8/call check-ints-equal/disp32
559 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
563 skip-chars-not-matching-whitespace: # in: (addr stream byte)
566 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
573 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi
575 8b/copy 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 4/disp8 . # copy *(esi+4) to ecx
577 8b/copy 0/mod/indirect 6/rm32/esi . . . 3/r32/ebx . . # copy *esi to ebx
578 $skip-chars-not-matching-whitespace:loop:
579 # if (in->read >= in->write) break
580 39/compare 3/mod/direct 1/rm32/ecx . . . 3/r32/ebx . . # compare ecx with ebx
581 7d/jump-if->= $skip-chars-not-matching-whitespace:end/disp8
582 # eax = in->data[in->read]
583 31/xor 3/mod/direct 0/rm32/eax . . . 0/r32/eax . . # clear eax
584 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
585 # if (eax == ' ') break
586 3d/compare-eax-and 0x20/imm32/space
587 74/jump-if-= $skip-chars-not-matching-whitespace:end/disp8
588 # if (eax == '\n') break
589 3d/compare-eax-and 0x0a/imm32/newline
590 74/jump-if-= $skip-chars-not-matching-whitespace:end/disp8
591 # if (eax == '\t') break
592 3d/compare-eax-and 0x09/imm32/tab
593 74/jump-if-= $skip-chars-not-matching-whitespace:end/disp8
594 # if (eax == '\r') break
595 3d/compare-eax-and 0x0d/imm32/cr
596 74/jump-if-= $skip-chars-not-matching-whitespace:end/disp8
599 eb/jump $skip-chars-not-matching-whitespace:loop/disp8
600 $skip-chars-not-matching-whitespace:end:
602 89/copy 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 4/disp8 . # copy ecx to *(esi+4)
603 # . restore registers
609 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
613 test-skip-chars-not-matching-whitespace:
615 # . clear-stream(_test-stream)
617 68/push _test-stream/imm32
619 e8/call clear-stream/disp32
621 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
622 # write(_test-stream, "ab\n")
625 68/push _test-stream/imm32
629 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
630 # skip-chars-not-matching-whitespace(_test-stream)
632 68/push _test-stream/imm32
634 e8/call skip-chars-not-matching-whitespace/disp32
636 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
637 # check-ints-equal(_test-stream->read, 2, msg)
639 68/push "F - test-skip-chars-not-matching-whitespace"/imm32
641 # . . push *_test-stream->read
642 b8/copy-to-eax _test-stream/imm32
643 ff 6/subop/push 1/mod/*+disp8 0/rm32/eax . . . . 4/disp8 . # push *(eax+4)
645 e8/call check-ints-equal/disp32
647 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
651 skip-chars-matching-in-slice: # curr: (addr byte), end: (addr byte), delimiter: byte -> curr/eax: (addr byte)
654 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
660 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 8/disp8 . # copy *(ebp+8) to eax
662 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 0xc/disp8 . # copy *(ebp+12) to ecx
664 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 2/r32/edx 0x10/disp8 . # copy *(ebp+16) to edx
665 # var c/ebx: byte = 0
666 31/xor 3/mod/direct 3/rm32/ebx . . . 3/r32/ebx . . # clear ebx
667 $skip-chars-matching-in-slice:loop:
668 # if (curr >= end) break
669 39/compare 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # compare eax with ecx
670 73/jump-if-addr>= $skip-chars-matching-in-slice:end/disp8
672 8a/copy-byte 0/mod/indirect 0/rm32/eax . . . 3/r32/BL . . # copy byte at *eax to BL
673 # if (c != delimiter) break
674 39/compare 3/mod/direct 3/rm32/ebx . . . 2/r32/edx . . # compare ebx and edx
675 75/jump-if-!= $skip-chars-matching-in-slice:end/disp8
678 eb/jump $skip-chars-matching-in-slice:loop/disp8
679 $skip-chars-matching-in-slice:end:
680 # . restore registers
685 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
689 test-skip-chars-matching-in-slice:
691 b8/copy-to-eax " ab"/imm32
692 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
693 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
694 05/add-to-eax 4/imm32
695 # eax = skip-chars-matching-in-slice(eax, ecx, 0x20/space)
697 68/push 0x20/imm32/space
701 e8/call skip-chars-matching-in-slice/disp32
703 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
704 # check-ints-equal(ecx-eax, 2, msg)
706 68/push "F - test-skip-chars-matching-in-slice"/imm32
709 29/subtract 3/mod/direct 1/rm32/ecx . . . 0/r32/eax . . # subtract eax from ecx
712 e8/call check-ints-equal/disp32
714 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
718 test-skip-chars-matching-in-slice-none:
720 b8/copy-to-eax "ab"/imm32
721 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
722 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
723 05/add-to-eax 4/imm32
724 # eax = skip-chars-matching-in-slice(eax, ecx, 0x20/space)
726 68/push 0x20/imm32/space
730 e8/call skip-chars-matching-in-slice/disp32
732 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
733 # check-ints-equal(ecx-eax, 2, msg)
735 68/push "F - test-skip-chars-matching-in-slice-none"/imm32
738 29/subtract 3/mod/direct 1/rm32/ecx . . . 0/r32/eax . . # subtract eax from ecx
741 e8/call check-ints-equal/disp32
743 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
747 skip-chars-matching-whitespace-in-slice: # curr: (addr byte), end: (addr byte) -> curr/eax: (addr byte)
750 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
755 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 8/disp8 . # copy *(ebp+8) to eax
757 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 0xc/disp8 . # copy *(ebp+12) to ecx
758 # var c/ebx: byte = 0
759 31/xor 3/mod/direct 3/rm32/ebx . . . 3/r32/ebx . . # clear ebx
760 $skip-chars-matching-whitespace-in-slice:loop:
761 # if (curr >= end) break
762 39/compare 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # compare eax with ecx
763 0f 83/jump-if-addr>= $skip-chars-matching-in-slice:end/disp32
765 8a/copy-byte 0/mod/indirect 0/rm32/eax . . . 3/r32/BL . . # copy byte at *eax to BL
766 # if (c == ' ') goto body
767 81 7/subop/compare 3/mod/direct 3/rm32/ebx . . . . . 0x20/imm32/space # compare ebx
768 74/jump-if-= $skip-chars-matching-whitespace-in-slice:body/disp8
769 # if (c == '\n') goto body
770 81 7/subop/compare 3/mod/direct 3/rm32/ebx . . . . . 0x0a/imm32/newline # compare ebx
771 74/jump-if-= $skip-chars-matching-whitespace-in-slice:body/disp8
772 # if (c == '\t') goto body
773 81 7/subop/compare 3/mod/direct 3/rm32/ebx . . . . . 0x09/imm32/tab # compare ebx
774 74/jump-if-= $skip-chars-matching-whitespace-in-slice:body/disp8
775 # if (c != '\r') break
776 81 7/subop/compare 3/mod/direct 3/rm32/ebx . . . . . 0x0d/imm32/cr # compare ebx
777 75/jump-if-!= $skip-chars-matching-whitespace-in-slice:end/disp8
778 $skip-chars-matching-whitespace-in-slice:body:
781 eb/jump $skip-chars-matching-whitespace-in-slice:loop/disp8
782 $skip-chars-matching-whitespace-in-slice:end:
783 # . restore registers
787 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
791 test-skip-chars-matching-whitespace-in-slice:
792 # (eax..ecx) = " \nab"
793 b8/copy-to-eax " \nab"/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-matching-whitespace-in-slice(eax, ecx)
802 e8/call skip-chars-matching-whitespace-in-slice/disp32
804 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
805 # check-ints-equal(ecx-eax, 2, msg)
807 68/push "F - test-skip-chars-matching-whitespace-in-slice"/imm32
810 29/subtract 3/mod/direct 1/rm32/ecx . . . 0/r32/eax . . # subtract eax from ecx
813 e8/call check-ints-equal/disp32
815 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
819 # minor fork of 'skip-chars-matching-in-slice'
820 skip-chars-not-matching-in-slice: # curr: (addr byte), end: (addr byte), delimiter: byte -> curr/eax: (addr byte)
823 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
829 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 8/disp8 . # copy *(ebp+8) to eax
831 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 0xc/disp8 . # copy *(ebp+12) to ecx
833 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 2/r32/edx 0x10/disp8 . # copy *(ebp+16) to edx
834 # var c/ebx: byte = 0
835 31/xor 3/mod/direct 3/rm32/ebx . . . 3/r32/ebx . . # clear ebx
836 $skip-chars-not-matching-in-slice:loop:
837 # if (curr >= end) break
838 39/compare 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # compare eax with ecx
839 73/jump-if-addr>= $skip-chars-not-matching-in-slice:end/disp8
841 8a/copy-byte 0/mod/indirect 0/rm32/eax . . . 3/r32/BL . . # copy byte at *eax to BL
842 # if (c == delimiter) break
843 39/compare 3/mod/direct 3/rm32/ebx . . . 2/r32/edx . . # compare ebx and edx
844 74/jump-if-= $skip-chars-not-matching-in-slice:end/disp8
847 eb/jump $skip-chars-not-matching-in-slice:loop/disp8
848 $skip-chars-not-matching-in-slice:end:
849 # . restore registers
854 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
858 test-skip-chars-not-matching-in-slice:
860 b8/copy-to-eax "ab "/imm32
861 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
862 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
863 05/add-to-eax 4/imm32
864 # eax = skip-chars-not-matching-in-slice(eax, ecx, 0x20/space)
866 68/push 0x20/imm32/space
870 e8/call skip-chars-not-matching-in-slice/disp32
872 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
873 # check-ints-equal(ecx-eax, 1, msg)
875 68/push "F - test-skip-chars-not-matching-in-slice"/imm32
878 29/subtract 3/mod/direct 1/rm32/ecx . . . 0/r32/eax . . # subtract eax from ecx
881 e8/call check-ints-equal/disp32
883 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
887 test-skip-chars-not-matching-in-slice-none:
889 b8/copy-to-eax " ab"/imm32
890 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
891 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
892 05/add-to-eax 4/imm32
893 # eax = skip-chars-not-matching-in-slice(eax, ecx, 0x20/space)
895 68/push 0x20/imm32/space
899 e8/call skip-chars-not-matching-in-slice/disp32
901 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
902 # check-ints-equal(ecx-eax, 3, msg)
904 68/push "F - test-skip-chars-not-matching-in-slice-none"/imm32
907 29/subtract 3/mod/direct 1/rm32/ecx . . . 0/r32/eax . . # subtract eax from ecx
910 e8/call check-ints-equal/disp32
912 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
916 test-skip-chars-not-matching-in-slice-all:
918 b8/copy-to-eax "ab"/imm32
919 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
920 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
921 05/add-to-eax 4/imm32
922 # eax = skip-chars-not-matching-in-slice(eax, ecx, 0x20/space)
924 68/push 0x20/imm32/space
928 e8/call skip-chars-not-matching-in-slice/disp32
930 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
931 # check-ints-equal(ecx-eax, 0, msg)
933 68/push "F - test-skip-chars-not-matching-in-slice-all"/imm32
936 29/subtract 3/mod/direct 1/rm32/ecx . . . 0/r32/eax . . # subtract eax from ecx
939 e8/call check-ints-equal/disp32
941 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
945 skip-chars-not-matching-whitespace-in-slice: # curr: (addr byte), end: (addr byte) -> curr/eax: (addr byte)
948 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
953 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 8/disp8 . # copy *(ebp+8) to eax
955 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 0xc/disp8 . # copy *(ebp+12) to ecx
956 # var c/ebx: byte = 0
957 31/xor 3/mod/direct 3/rm32/ebx . . . 3/r32/ebx . . # clear ebx
958 $skip-chars-not-matching-whitespace-in-slice:loop:
959 # if (curr >= end) break
960 39/compare 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # compare eax with ecx
961 0f 83/jump-if-addr>= $skip-chars-not-matching-in-slice:end/disp32
963 8a/copy-byte 0/mod/indirect 0/rm32/eax . . . 3/r32/BL . . # copy byte at *eax to BL
964 # if (c == ' ') break
965 81 7/subop/compare 3/mod/direct 3/rm32/ebx . . . . . 0x20/imm32/space # compare ebx
966 74/jump-if-= $skip-chars-not-matching-whitespace-in-slice:end/disp8
967 # if (c == '\n') break
968 81 7/subop/compare 3/mod/direct 3/rm32/ebx . . . . . 0x0a/imm32/newline # compare ebx
969 74/jump-if-= $skip-chars-not-matching-whitespace-in-slice:end/disp8
970 # if (c == '\t') break
971 81 7/subop/compare 3/mod/direct 3/rm32/ebx . . . . . 0x09/imm32/tab # compare ebx
972 74/jump-if-= $skip-chars-not-matching-whitespace-in-slice:end/disp8
973 # if (c == '\r') break
974 81 7/subop/compare 3/mod/direct 3/rm32/ebx . . . . . 0x0d/imm32/cr # compare ebx
975 74/jump-if-= $skip-chars-not-matching-whitespace-in-slice:end/disp8
978 eb/jump $skip-chars-not-matching-whitespace-in-slice:loop/disp8
979 $skip-chars-not-matching-whitespace-in-slice:end:
980 # . restore registers
984 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
988 test-skip-chars-not-matching-whitespace-in-slice:
989 # (eax..ecx) = "ab\n"
990 b8/copy-to-eax "ab\n"/imm32
991 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
992 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
993 05/add-to-eax 4/imm32
994 # eax = skip-chars-not-matching-whitespace-in-slice(eax, ecx)
999 e8/call skip-chars-not-matching-whitespace-in-slice/disp32
1001 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
1002 # check-ints-equal(ecx-eax, 1, msg)
1004 68/push "F - test-skip-chars-not-matching-whitespace-in-slice"/imm32
1007 29/subtract 3/mod/direct 1/rm32/ecx . . . 0/r32/eax . . # subtract eax from ecx
1010 e8/call check-ints-equal/disp32
1012 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
1016 # update line->read to end of string literal surrounded by double quotes
1017 # line->read must start out at a double-quote
1018 skip-string: # line: (addr stream byte)
1021 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
1027 8b/copy 1/mod/*+disp8 5/rm32/ebp . . 1/r32/ecx 8/disp8 . # copy *(ebp+8) to ecx
1028 # eax = skip-string-in-slice(&line->data[line->read], &line->data[line->write])
1029 # . . push &line->data[line->write]
1030 8b/copy 1/mod/*+disp8 1/rm32/ecx . . 2/r32/edx 8/disp8 . # copy *(ecx+8) to edx
1031 8d/copy-address 1/mod/*+disp8 4/rm32/sib 1/base/ecx 2/index/edx . 2/r32/edx 0xc/disp8 . # copy ecx+edx+12 to edx
1033 # . . push &line->data[line->read]
1034 8b/copy 1/mod/*+disp8 1/rm32/ecx . . 2/r32/edx 4/disp8 . # copy *(ecx+4) to edx
1035 8d/copy-address 1/mod/*+disp8 4/rm32/sib 1/base/ecx 2/index/edx . 2/r32/edx 0xc/disp8 . # copy ecx+edx+12 to edx
1038 e8/call skip-string-in-slice/disp32
1040 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
1041 # line->read = eax - line->data
1042 29/subtract 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # subtract ecx from eax
1043 2d/subtract-from-eax 0xc/imm32
1044 89/copy 1/mod/*+disp8 1/rm32/ecx . . 0/r32/eax 4/disp8 . # copy eax to *(ecx+4)
1046 # . restore registers
1051 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
1058 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
1060 # . clear-stream(_test-stream)
1062 68/push _test-stream/imm32
1064 e8/call clear-stream/disp32
1066 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
1067 # . write(_test-stream, "\"abc\" def")
1068 # . indices: 0123 45
1070 68/push "\"abc\" def"/imm32
1071 68/push _test-stream/imm32
1073 e8/call write/disp32
1075 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
1076 # precondition: line->read == 0
1078 68/push "F - test-skip-string/precondition"/imm32
1080 b8/copy-to-eax _test-stream/imm32
1081 ff 6/subop/push 1/mod/*+disp8 0/rm32/eax . . . . 4/disp8 . # push *(eax+4)
1083 e8/call check-ints-equal/disp32
1085 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
1086 # skip-string(_test-stream)
1088 68/push _test-stream/imm32
1090 e8/call skip-string/disp32
1092 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
1093 # check-ints-equal(line->read, 5, msg)
1095 68/push "F - test-skip-string"/imm32
1097 b8/copy-to-eax _test-stream/imm32
1098 ff 6/subop/push 1/mod/*+disp8 0/rm32/eax . . . . 4/disp8 . # push *(eax+4)
1100 e8/call check-ints-equal/disp32
1102 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
1104 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
1108 test-skip-string-ignores-spaces:
1111 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
1113 # . clear-stream(_test-stream)
1115 68/push _test-stream/imm32
1117 e8/call clear-stream/disp32
1119 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
1120 # . write(_test-stream, "\"a b\"/yz")
1121 # . indices: 0123 45
1123 68/push "\"a b\"/yz"/imm32
1124 68/push _test-stream/imm32
1126 e8/call write/disp32
1128 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
1129 # precondition: line->read == 0
1131 68/push "F - test-skip-string-ignores-spaces/precondition"/imm32
1133 b8/copy-to-eax _test-stream/imm32
1134 ff 6/subop/push 1/mod/*+disp8 0/rm32/eax . . . . 4/disp8 . # push *(eax+4)
1136 e8/call check-ints-equal/disp32
1138 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
1139 # skip-string(_test-stream)
1141 68/push _test-stream/imm32
1143 e8/call skip-string/disp32
1145 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
1146 # check-ints-equal(line->read, 5, msg)
1148 68/push "F - test-skip-string-ignores-spaces"/imm32
1150 b8/copy-to-eax _test-stream/imm32
1151 ff 6/subop/push 1/mod/*+disp8 0/rm32/eax . . . . 4/disp8 . # push *(eax+4)
1153 e8/call check-ints-equal/disp32
1155 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
1157 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
1161 test-skip-string-ignores-escapes:
1164 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
1166 # . clear-stream(_test-stream)
1168 68/push _test-stream/imm32
1170 e8/call clear-stream/disp32
1172 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
1173 # . write(_test-stream, "\"a\\\"b\"/yz")
1174 # . indices: 01 2 34 56
1176 68/push "\"a\\\"b\"/yz"/imm32
1177 68/push _test-stream/imm32
1179 e8/call write/disp32
1181 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
1182 # precondition: line->read == 0
1184 68/push "F - test-skip-string-ignores-escapes/precondition"/imm32
1186 b8/copy-to-eax _test-stream/imm32
1187 ff 6/subop/push 1/mod/*+disp8 0/rm32/eax . . . . 4/disp8 . # push *(eax+4)
1189 e8/call check-ints-equal/disp32
1191 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
1192 # skip-string(_test-stream)
1194 68/push _test-stream/imm32
1196 e8/call skip-string/disp32
1198 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
1199 # check-ints-equal(line->read, 6, msg)
1201 68/push "F - test-skip-string-ignores-escapes"/imm32
1203 b8/copy-to-eax _test-stream/imm32
1204 ff 6/subop/push 1/mod/*+disp8 0/rm32/eax . . . . 4/disp8 . # push *(eax+4)
1206 e8/call check-ints-equal/disp32
1208 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
1210 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
1214 test-skip-string-works-from-mid-stream:
1217 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
1219 # . clear-stream(_test-stream)
1221 68/push _test-stream/imm32
1223 e8/call clear-stream/disp32
1225 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
1226 # . write(_test-stream, "0 \"a\\\"b\"/yz")
1227 # . indices: 01 2 34 56
1229 68/push "0 \"a\\\"b\"/yz"/imm32
1230 68/push _test-stream/imm32
1232 e8/call write/disp32
1234 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
1235 # precondition: line->read == 2
1236 b8/copy-to-eax _test-stream/imm32
1237 c7 0/subop/copy 1/mod/*+disp8 0/rm32/eax . . . . 4/disp8 2/imm32 # copy to *(eax+4)
1238 # skip-string(_test-stream)
1240 68/push _test-stream/imm32
1242 e8/call skip-string/disp32
1244 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
1245 # check-ints-equal(line->read, 8, msg)
1247 68/push "F - test-skip-string-works-from-mid-stream"/imm32
1249 b8/copy-to-eax _test-stream/imm32
1250 ff 6/subop/push 1/mod/*+disp8 0/rm32/eax . . . . 4/disp8 . # push *(eax+4)
1252 e8/call check-ints-equal/disp32
1254 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
1256 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
1260 skip-string-in-slice: # curr: (addr byte), end: (addr byte) -> curr/eax: (addr byte)
1263 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
1269 8b/copy 1/mod/*+disp8 5/rm32/ebp . . 1/r32/ecx 8/disp8 . # copy *(ebp+8) to ecx
1271 8b/copy 1/mod/*+disp8 5/rm32/ebp . . 2/r32/edx 0xc/disp8 . # copy *(ebp+12) to edx
1272 # var c/eax: byte = 0
1273 31/xor 3/mod/direct 0/rm32/eax . . . 0/r32/eax . . # clear eax
1274 # skip initial dquote
1276 $skip-string-in-slice:loop:
1277 # if (curr >= end) return curr
1278 39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx
1279 73/jump-if-addr>= $skip-string-in-slice:return-curr/disp8
1281 8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 0/r32/AL . . # copy byte at *ecx to AL
1282 $skip-string-in-slice:dquote:
1283 # if (c == '"') break
1284 3d/compare-eax-and 0x22/imm32/double-quote
1285 74/jump-if-= $skip-string-in-slice:break/disp8
1286 $skip-string-in-slice:check-for-escape:
1287 # if (c == '\') escape next char
1288 3d/compare-eax-and 0x5c/imm32/backslash
1289 75/jump-if-!= $skip-string-in-slice:continue/disp8
1290 $skip-string-in-slice:escape:
1292 $skip-string-in-slice:continue:
1295 eb/jump $skip-string-in-slice:loop/disp8
1296 $skip-string-in-slice:break:
1299 $skip-string-in-slice:return-curr:
1301 89/copy 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # copy ecx to eax
1302 $skip-string-in-slice:end:
1303 # . restore registers
1308 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
1312 test-skip-string-in-slice:
1315 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
1316 # setup: (eax..ecx) = "\"abc\" def"
1317 b8/copy-to-eax "\"abc\" def"/imm32
1318 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
1319 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
1320 05/add-to-eax 4/imm32
1321 # eax = skip-string-in-slice(eax, ecx)
1326 e8/call skip-string-in-slice/disp32
1328 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
1329 # check-ints-equal(ecx-eax, 4, msg) # number of chars remaining after the string literal
1331 68/push "F - test-skip-string-in-slice"/imm32
1334 29/subtract 3/mod/direct 1/rm32/ecx . . . 0/r32/eax . . # subtract eax from ecx
1337 e8/call check-ints-equal/disp32
1339 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
1341 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
1345 test-skip-string-in-slice-ignores-spaces:
1348 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
1349 # setup: (eax..ecx) = "\"a b\"/yz"
1350 b8/copy-to-eax "\"a b\"/yz"/imm32
1351 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
1352 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
1353 05/add-to-eax 4/imm32
1354 # eax = skip-string-in-slice(eax, ecx)
1359 e8/call skip-string-in-slice/disp32
1361 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
1362 # check-ints-equal(ecx-eax, 3, msg) # number of chars remaining after the string literal
1364 68/push "F - test-skip-string-in-slice-ignores-spaces"/imm32
1367 29/subtract 3/mod/direct 1/rm32/ecx . . . 0/r32/eax . . # subtract eax from ecx
1370 e8/call check-ints-equal/disp32
1372 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
1374 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
1378 test-skip-string-in-slice-ignores-escapes:
1381 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
1382 # setup: (eax..ecx) = "\"a\\\"b\"/yz"
1383 b8/copy-to-eax "\"a\\\"b\"/yz"/imm32
1384 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
1385 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
1386 05/add-to-eax 4/imm32
1387 # eax = skip-string-in-slice(eax, ecx)
1392 e8/call skip-string-in-slice/disp32
1394 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
1395 # check-ints-equal(ecx-eax, 3, msg) # number of chars remaining after the string literal
1397 68/push "F - test-skip-string-in-slice-ignores-escapes"/imm32
1400 29/subtract 3/mod/direct 1/rm32/ecx . . . 0/r32/eax . . # subtract eax from ecx
1403 e8/call check-ints-equal/disp32
1405 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
1407 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
1411 test-skip-string-in-slice-stops-at-end:
1414 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
1415 # setup: (eax..ecx) = "\"abc" # unbalanced dquote
1416 b8/copy-to-eax "\"abc"/imm32
1417 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
1418 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
1419 05/add-to-eax 4/imm32
1420 # eax = skip-string-in-slice(eax, ecx)
1425 e8/call skip-string-in-slice/disp32
1427 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
1428 # check-ints-equal(ecx-eax, 0, msg) # skipped to end of slice
1430 68/push "F - test-skip-string-in-slice-stops-at-end"/imm32
1433 29/subtract 3/mod/direct 1/rm32/ecx . . . 0/r32/eax . . # subtract eax from ecx
1436 e8/call check-ints-equal/disp32
1438 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
1440 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
1444 # update line->read to ')'
1445 # line->read ends at ')'
1446 skip-until-close-paren: # line: (addr stream byte)
1449 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
1455 8b/copy 1/mod/*+disp8 5/rm32/ebp . . 1/r32/ecx 8/disp8 . # copy *(ebp+8) to ecx
1456 # eax = skip-until-close-paren-in-slice(&line->data[line->read], &line->data[line->write])
1457 # . . push &line->data[line->write]
1458 8b/copy 1/mod/*+disp8 1/rm32/ecx . . 2/r32/edx 8/disp8 . # copy *(ecx+8) to edx
1459 8d/copy-address 1/mod/*+disp8 4/rm32/sib 1/base/ecx 2/index/edx . 2/r32/edx 0xc/disp8 . # copy ecx+edx+12 to edx
1461 # . . push &line->data[line->read]
1462 8b/copy 1/mod/*+disp8 1/rm32/ecx . . 2/r32/edx 4/disp8 . # copy *(ecx+4) to edx
1463 8d/copy-address 1/mod/*+disp8 4/rm32/sib 1/base/ecx 2/index/edx . 2/r32/edx 0xc/disp8 . # copy ecx+edx+12 to edx
1466 e8/call skip-until-close-paren-in-slice/disp32
1468 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
1469 # line->read = eax - line->data
1470 29/subtract 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # subtract ecx from eax
1471 2d/subtract-from-eax 0xc/imm32
1472 89/copy 1/mod/*+disp8 1/rm32/ecx . . 0/r32/eax 4/disp8 . # copy eax to *(ecx+4)
1473 $skip-until-close-paren:end:
1474 # . restore registers
1479 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
1483 test-skip-until-close-paren:
1486 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
1488 # . clear-stream(_test-stream)
1490 68/push _test-stream/imm32
1492 e8/call clear-stream/disp32
1494 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
1495 # . write(_test-stream, "*(abc) def")
1496 # . indices: 0123 45
1498 68/push "*(abc) def"/imm32
1499 68/push _test-stream/imm32
1501 e8/call write/disp32
1503 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
1504 # precondition: line->read == 0
1506 68/push "F - test-skip-until-close-paren/precondition"/imm32
1508 b8/copy-to-eax _test-stream/imm32
1509 ff 6/subop/push 1/mod/*+disp8 0/rm32/eax . . . . 4/disp8 . # push *(eax+4)
1511 e8/call check-ints-equal/disp32
1513 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
1514 # skip-until-close-paren(_test-stream)
1516 68/push _test-stream/imm32
1518 e8/call skip-until-close-paren/disp32
1520 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
1521 # check-ints-equal(line->read, 5, msg)
1523 68/push "F - test-skip-until-close-paren"/imm32
1525 b8/copy-to-eax _test-stream/imm32
1526 ff 6/subop/push 1/mod/*+disp8 0/rm32/eax . . . . 4/disp8 . # push *(eax+4)
1528 e8/call check-ints-equal/disp32
1530 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
1532 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
1536 test-skip-until-close-paren-ignores-spaces:
1539 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
1541 # . clear-stream(_test-stream)
1543 68/push _test-stream/imm32
1545 e8/call clear-stream/disp32
1547 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
1548 # . write(_test-stream, "*(a b)/yz")
1550 68/push "*(a b)/yz"/imm32
1551 68/push _test-stream/imm32
1553 e8/call write/disp32
1555 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
1556 # precondition: line->read == 0
1558 68/push "F - test-skip-until-close-paren-ignores-spaces/precondition"/imm32
1560 b8/copy-to-eax _test-stream/imm32
1561 ff 6/subop/push 1/mod/*+disp8 0/rm32/eax . . . . 4/disp8 . # push *(eax+4)
1563 e8/call check-ints-equal/disp32
1565 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
1566 # skip-until-close-paren(_test-stream)
1568 68/push _test-stream/imm32
1570 e8/call skip-until-close-paren/disp32
1572 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
1573 # check-ints-equal(line->read, 5, msg)
1575 68/push "F - test-skip-until-close-paren-ignores-spaces"/imm32
1577 b8/copy-to-eax _test-stream/imm32
1578 ff 6/subop/push 1/mod/*+disp8 0/rm32/eax . . . . 4/disp8 . # push *(eax+4)
1580 e8/call check-ints-equal/disp32
1582 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
1584 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
1588 test-skip-until-close-paren-works-from-mid-stream:
1591 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
1593 # . clear-stream(_test-stream)
1595 68/push _test-stream/imm32
1597 e8/call clear-stream/disp32
1599 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
1600 # . write(_test-stream, "0 *(a b)/yz")
1602 68/push "0 *(a b)/yz"/imm32
1603 68/push _test-stream/imm32
1605 e8/call write/disp32
1607 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
1608 # precondition: _test-stream->read == 2
1609 b8/copy-to-eax _test-stream/imm32
1610 c7 0/subop/copy 1/mod/*+disp8 0/rm32/eax . . . . 4/disp8 2/imm32 # copy to *(eax+4)
1611 # skip-until-close-paren(_test-stream)
1613 68/push _test-stream/imm32
1615 e8/call skip-until-close-paren/disp32
1617 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
1618 # check-ints-equal(_test-stream->read, 7, msg)
1620 68/push "F - test-skip-until-close-paren-works-from-mid-stream"/imm32
1622 b8/copy-to-eax _test-stream/imm32
1623 ff 6/subop/push 1/mod/*+disp8 0/rm32/eax . . . . 4/disp8 . # push *(eax+4)
1625 e8/call check-ints-equal/disp32
1627 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
1629 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
1633 skip-until-close-paren-in-slice: # curr: (addr byte), end: (addr byte) -> curr/eax: (addr byte)
1636 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
1641 8b/copy 1/mod/*+disp8 5/rm32/ebp . . 1/r32/ecx 8/disp8 . # copy *(ebp+8) to ecx
1643 8b/copy 1/mod/*+disp8 5/rm32/ebp . . 2/r32/edx 0xc/disp8 . # copy *(ebp+12) to edx
1644 # var c/eax: byte = 0
1645 31/xor 3/mod/direct 0/rm32/eax . . . 0/r32/eax . . # clear eax
1646 # skip initial dquote
1648 $skip-until-close-paren-in-slice:loop:
1649 # if (curr >= end) break
1650 39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx
1651 73/jump-if-addr>= $skip-until-close-paren-in-slice:break/disp8
1653 8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 0/r32/AL . . # copy byte at *ecx to AL
1654 $skip-until-close-paren-in-slice:check-close:
1655 # if (c == ')') break
1656 3d/compare-eax-and 0x29/imm32/close-paren
1657 74/jump-if-= $skip-until-close-paren-in-slice:break/disp8
1660 eb/jump $skip-until-close-paren-in-slice:loop/disp8
1661 $skip-until-close-paren-in-slice:break:
1663 89/copy 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # copy ecx to eax
1664 $skip-until-close-paren-in-slice:end:
1665 # . restore registers
1669 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
1673 test-skip-until-close-paren-in-slice:
1676 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
1677 # setup: (eax..ecx) = "*(abc) def"
1678 b8/copy-to-eax "*(abc) def"/imm32
1679 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
1680 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
1681 05/add-to-eax 4/imm32
1682 # eax = skip-until-close-paren-in-slice(eax, ecx)
1687 e8/call skip-until-close-paren-in-slice/disp32
1689 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
1690 # check-ints-equal(ecx-eax, 5, msg) # eax is at the ')'
1692 68/push "F - test-skip-until-close-paren-in-slice"/imm32
1695 29/subtract 3/mod/direct 1/rm32/ecx . . . 0/r32/eax . . # subtract eax from ecx
1698 e8/call check-ints-equal/disp32
1700 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
1702 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
1706 test-skip-until-close-paren-in-slice-ignores-spaces:
1709 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
1710 # setup: (eax..ecx) = "*(a b)/yz"
1711 b8/copy-to-eax "*(a b)/yz"/imm32
1712 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
1713 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
1714 05/add-to-eax 4/imm32
1715 # eax = skip-until-close-paren-in-slice(eax, ecx)
1720 e8/call skip-until-close-paren-in-slice/disp32
1722 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
1723 # check-ints-equal(ecx-eax, 4, msg) # eax is at the ')'
1725 68/push "F - test-skip-until-close-paren-in-slice-ignores-spaces"/imm32
1728 29/subtract 3/mod/direct 1/rm32/ecx . . . 0/r32/eax . . # subtract eax from ecx
1731 e8/call check-ints-equal/disp32
1733 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
1735 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
1739 test-skip-until-close-paren-in-slice-stops-at-end:
1742 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
1743 # setup: (eax..ecx) = "*(abc" # unbalanced dquote
1744 b8/copy-to-eax "*(abc"/imm32
1745 8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
1746 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
1747 05/add-to-eax 4/imm32
1748 # eax = skip-until-close-paren-in-slice(eax, ecx)
1753 e8/call skip-until-close-paren-in-slice/disp32
1755 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
1756 # check-ints-equal(ecx-eax, 0, msg) # skipped to end of slice
1758 68/push "F - test-skip-until-close-paren-in-slice-stops-at-end"/imm32
1761 29/subtract 3/mod/direct 1/rm32/ecx . . . 0/r32/eax . . # subtract eax from ecx
1764 e8/call check-ints-equal/disp32
1766 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
1768 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
1772 # . . vim:nowrap:textwidth=0