1 # Tokenize by whitespace.
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 # (re)compute the bounds of the next word in the line (surrounded by whitespace,
9 # treating '#' comments as a single word)
10 # return empty string on reaching end of file
11 next-word: # line: (addr stream byte), out: (addr slice)
14 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
21 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi
23 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 7/r32/edi 0xc/disp8 . # copy *(ebp+12) to edi
24 # skip-chars-matching-whitespace(line)
26 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
28 e8/call skip-chars-matching-whitespace/disp32
30 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
32 # if (line->read >= line->write) clear out and return
34 8b/copy 1/mod/*+disp8 6/rm32/esi . . . 0/r32/eax 4/disp8 . # copy *(esi+4) to eax
35 # . if (eax < line->write) goto next check
36 3b/compare 0/mod/indirect 6/rm32/esi . . . 0/r32/eax . . # compare eax with *esi
37 7c/jump-if-< $next-word:check-for-comment/disp8
39 c7 0/subop/copy 0/mod/direct 7/rm32/edi . . . . . 0/imm32 # copy to *edi
40 c7 0/subop/copy 1/mod/*+disp8 7/rm32/edi . . . . 4/disp8 0/imm32 # copy to *(edi+4)
41 e9/jump $next-word:end/disp32
42 $next-word:check-for-comment:
43 # out->start = &line->data[line->read]
44 8b/copy 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 4/disp8 . # copy *(esi+4) to ecx
45 8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/esi 1/index/ecx . 0/r32/eax 0xc/disp8 . # copy esi+ecx+12 to eax
46 89/copy 0/mod/indirect 7/rm32/edi . . . 0/r32/eax . . # copy eax to *edi
47 # if (line->data[line->read] == '#') return rest of line
48 # . eax = line->data[line->read]
49 31/xor 3/mod/direct 0/rm32/eax . . . 0/r32/eax . . # clear eax
50 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
52 3d/compare-eax-and 0x23/imm32/pound
53 0f 85/jump-if-!= $next-word:regular-word/disp32
55 # out->end = out->start
56 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
57 89/copy 1/mod/*+disp8 7/rm32/edi . . . 0/r32/eax 4/disp8 . # copy eax to *(edi+4)
58 # var write/ecx: int = line->write
59 8b/copy 0/mod/indirect 6/rm32/esi . . . 1/r32/ecx . . # copy *esi to ecx
60 $next-word:comment-loop:
61 # if (line->read >= line->write) break
62 39/compare 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 4/disp8 . # compare *(esi+4) with ecx
63 0f 8d/jump-if->= $next-word:comment-break/disp32
65 ff 0/subop/increment 1/mod/*+disp8 6/rm32/esi . . . . 4/disp8 . # increment *(esi+4)
67 ff 0/subop/increment 1/mod/*+disp8 7/rm32/edi . . . . 4/disp8 . # increment *(edi+4)
68 # if (*out->end == newline) break
69 8b/copy 1/mod/*+disp8 7/rm32/edi . . . 0/r32/eax 4/disp8 . # copy *(edi+4) to eax
70 8a/copy-byte 0/mod/indirect 0/rm32/eax . . . 0/r32/AL . . # copy byte at *eax to AL
71 25/and-eax-with 0xff/imm32
72 3d/compare-eax-and 0xa/imm32/newline
73 0f 84/jump-if-= $next-word:comment-break/disp32
75 e9/jump $next-word:comment-loop/disp32
76 $next-word:comment-break:
78 e9/jump $next-word:end/disp32
79 $next-word:regular-word:
80 # otherwise skip-chars-not-matching-whitespace(line) # including trailing newline
82 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
84 e8/call skip-chars-not-matching-whitespace/disp32
86 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
87 # out->end = &line->data[line->read]
88 8b/copy 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 4/disp8 . # copy *(esi+4) to ecx
89 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
90 89/copy 1/mod/*+disp8 7/rm32/edi . . . 0/r32/eax 4/disp8 . # copy eax to *(edi+4)
98 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
105 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
107 # . clear-stream(_test-stream)
109 68/push _test-stream/imm32
111 e8/call clear-stream/disp32
113 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
114 # var slice/ecx: slice
116 68/push 0/imm32/start
117 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
118 # write(_test-stream, " ab")
121 68/push _test-stream/imm32
125 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
126 # next-word(_test-stream, slice)
129 68/push _test-stream/imm32
131 e8/call next-word/disp32
133 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
134 # check-ints-equal(slice->start - _test-stream->data, 2, msg)
135 # . check-ints-equal(slice->start - _test-stream, 14, msg)
137 68/push "F - test-next-word: start"/imm32
139 # . . push slice->start - _test-stream
140 8b/copy 0/mod/indirect 1/rm32/ecx . . . 0/r32/eax . . # copy *ecx to eax
141 81 5/subop/subtract 3/mod/direct 0/rm32/eax . . . . . _test-stream/imm32 # subtract from eax
144 e8/call check-ints-equal/disp32
146 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
147 # check-ints-equal(slice->end - _test-stream->data, 4, msg)
148 # . check-ints-equal(slice->end - _test-stream, 16, msg)
150 68/push "F - test-next-word: end"/imm32
152 # . . push slice->end - _test-stream
153 8b/copy 1/mod/*+disp8 1/rm32/ecx . . . 0/r32/eax 4/disp8 . # copy *(ecx+4) to eax
154 81 5/subop/subtract 3/mod/direct 0/rm32/eax . . . . . _test-stream/imm32 # subtract from eax
157 e8/call check-ints-equal/disp32
159 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
161 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
165 test-next-word-returns-whole-comment:
168 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
170 # . clear-stream(_test-stream)
172 68/push _test-stream/imm32
174 e8/call clear-stream/disp32
176 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
177 # var slice/ecx: slice
179 68/push 0/imm32/start
180 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
181 # write(_test-stream, " # a")
184 68/push _test-stream/imm32
188 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
189 # next-word(_test-stream, slice)
192 68/push _test-stream/imm32
194 e8/call next-word/disp32
196 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
197 # check-ints-equal(slice->start - _test-stream->data, 2, msg)
198 # . check-ints-equal(slice->start - _test-stream, 14, msg)
200 68/push "F - test-next-word-returns-whole-comment: start"/imm32
202 # . . push slice->start - _test-stream
203 8b/copy 0/mod/indirect 1/rm32/ecx . . . 0/r32/eax . . # copy *ecx to eax
204 81 5/subop/subtract 3/mod/direct 0/rm32/eax . . . . . _test-stream/imm32 # subtract from eax
207 e8/call check-ints-equal/disp32
209 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
210 # check-ints-equal(slice->end - _test-stream->data, 5, msg)
211 # . check-ints-equal(slice->end - _test-stream, 17, msg)
213 68/push "F - test-next-word-returns-whole-comment: end"/imm32
215 # . . push slice->end - _test-stream
216 8b/copy 1/mod/*+disp8 1/rm32/ecx . . . 0/r32/eax 4/disp8 . # copy *(ecx+4) to eax
217 81 5/subop/subtract 3/mod/direct 0/rm32/eax . . . . . _test-stream/imm32 # subtract from eax
220 e8/call check-ints-equal/disp32
222 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
224 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
228 test-next-word-returns-empty-string-on-eof:
231 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
233 # . clear-stream(_test-stream)
235 68/push _test-stream/imm32
237 e8/call clear-stream/disp32
239 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
240 # var slice/ecx: slice
242 68/push 0/imm32/start
243 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
244 # write nothing to _test-stream
245 # next-word(_test-stream, slice)
248 68/push _test-stream/imm32
250 e8/call next-word/disp32
252 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
253 # check-ints-equal(slice->end - slice->start, 0, msg)
255 68/push "F - test-next-word-returns-empty-string-on-eof"/imm32
257 # . . push slice->end - slice->start
258 8b/copy 1/mod/*+disp8 1/rm32/ecx . . . 0/r32/eax 4/disp8 . # copy *(ecx+4) to eax
259 2b/subtract 0/mod/indirect 1/rm32/ecx . . . 0/r32/eax . . # subtract *ecx from eax
262 e8/call check-ints-equal/disp32
264 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
266 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
270 test-next-word-returns-empty-string-on-newline:
273 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
275 # . clear-stream(_test-stream)
277 68/push _test-stream/imm32
279 e8/call clear-stream/disp32
281 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
282 # var slice/ecx: slice
284 68/push 0/imm32/start
285 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
286 # write some whitespace and a newline
289 68/push _test-stream/imm32
293 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
294 # next-word(_test-stream, slice)
297 68/push _test-stream/imm32
299 e8/call next-word/disp32
301 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
302 # check-ints-equal(slice->end - slice->start, 0, msg)
304 68/push "F - test-next-word-returns-empty-string-on-newline"/imm32
306 # . . push slice->end - slice->start
307 8b/copy 1/mod/*+disp8 1/rm32/ecx . . . 0/r32/eax 4/disp8 . # copy *(ecx+4) to eax
308 2b/subtract 0/mod/indirect 1/rm32/ecx . . . 0/r32/eax . . # subtract *ecx from eax
311 e8/call check-ints-equal/disp32
313 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
315 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
319 # (re)compute the bounds of the next word in the line (separated by whitespace)
320 # return empty string on reaching end of file
321 next-raw-word: # line: (addr stream byte), out: (addr slice)
324 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
331 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi
333 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 7/r32/edi 0xc/disp8 . # copy *(ebp+12) to edi
334 # skip-chars-matching-whitespace(line)
336 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
338 e8/call skip-chars-matching-whitespace/disp32
340 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
341 $next-raw-word:check0:
342 # if (line->read >= line->write) clear out and return
344 8b/copy 1/mod/*+disp8 6/rm32/esi . . . 0/r32/eax 4/disp8 . # copy *(esi+4) to eax
345 # . if (eax < line->write) goto next check
346 3b/compare 0/mod/indirect 6/rm32/esi . . . 0/r32/eax . . # compare eax with *esi
347 7c/jump-if-< $next-raw-word:word-exists/disp8
349 c7 0/subop/copy 0/mod/direct 7/rm32/edi . . . . . 0/imm32 # copy to *edi
350 c7 0/subop/copy 1/mod/*+disp8 7/rm32/edi . . . . 4/disp8 0/imm32 # copy to *(edi+4)
351 eb/jump $next-raw-word:end/disp8
352 $next-raw-word:word-exists:
353 # out->start = &line->data[line->read]
354 8b/copy 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 4/disp8 . # copy *(esi+4) to ecx
355 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
356 89/copy 0/mod/indirect 7/rm32/edi . . . 0/r32/eax . . # copy eax to *edi
357 # skip-chars-not-matching-whitespace(line) # including trailing newline
359 ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
361 e8/call skip-chars-not-matching-whitespace/disp32
363 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
364 # out->end = &line->data[line->read]
365 8b/copy 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 4/disp8 . # copy *(esi+4) to ecx
366 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
367 89/copy 1/mod/*+disp8 7/rm32/edi . . . 0/r32/eax 4/disp8 . # copy eax to *(edi+4)
369 # . restore registers
375 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp