https://github.com/akkartik/mu/blob/master/094next-word-or-string.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 # (re)compute the bounds of the next word or string literal in the line
  7 # return empty string on reaching end of file
  8 next-word-or-string:  # line : (address stream byte), out : (address slice)
  9     # . prologue
 10     55/push-ebp
 11     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
 12     # . save registers
 13     50/push-eax
 14     51/push-ecx
 15     56/push-esi
 16     57/push-edi
 17     # esi = line
 18     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
 19     # edi = out
 20     8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           7/r32/edi   0xc/disp8       .                 # copy *(ebp+12) to edi
 21     # skip-chars-matching(line, ' ')
 22     # . . push args
 23     68/push  0x20/imm32/space
 24     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
 25     # . . call
 26     e8/call  skip-chars-matching/disp32
 27     # . . discard args
 28     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
 29 $next-word-or-string:check0:
 30     # if (line->read >= line->write) clear out and return
 31     # . eax = line->read
 32     8b/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           0/r32/eax   4/disp8         .                 # copy *(esi+4) to eax
 33     # . if (eax < line->write) goto next check
 34     3b/compare                      0/mod/indirect  6/rm32/esi    .           .             .           0/r32/eax   .               .                 # compare eax with *esi
 35     7c/jump-if-lesser  $next-word-or-string:check-for-comment/disp8
 36     # . return out
 37     c7          0/subop/copy        0/mod/direct    7/rm32/edi    .           .             .           .           .               0/imm32           # copy to *edi
 38     c7          0/subop/copy        1/mod/*+disp8   7/rm32/edi    .           .             .           .           4/disp8         0/imm32           # copy to *(edi+4)
 39     eb/jump  $next-word-or-string:end/disp8
 40 $next-word-or-string:check-for-comment:
 41     # out->start = &line->data[line->read]
 42     8b/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   4/disp8         .                 # copy *(esi+4) to ecx
 43     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
 44     89/copy                         0/mod/indirect  7/rm32/edi    .           .             .           0/r32/eax   .               .                 # copy eax to *edi
 45     # if (line->data[line->read] != '#') goto next check
 46     # . eax = line->data[line->read]
 47     31/xor                          3/mod/direct    0/rm32/eax    .           .             .           0/r32/eax   .               .                 # clear eax
 48     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
 49     # . compare
 50     3d/compare-eax-and  0x23/imm32/pound
 51     75/jump-if-not-equal  $next-word-or-string:check-for-string-literal/disp8
 52 $next-word-or-string:comment:
 53     # out->end = &line->data[line->write]
 54     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           0/r32/eax   .               .                 # copy *esi to eax
 55     8d/copy-address                 1/mod/*+disp8   4/rm32/sib    6/base/esi  0/index/eax   .           0/r32/eax   0xc/disp8       .                 # copy esi+eax+12 to eax
 56     89/copy                         1/mod/*+disp8   7/rm32/edi    .           .             .           0/r32/eax   4/disp8         .                 # copy eax to *(edi+4)
 57     # line->read = line->write  # skip rest of line
 58     8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           0/r32/eax   .               .                 # copy *esi to eax
 59     89/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           0/r32/eax   4/disp8         .                 # copy eax to *(esi+4)
 60     # return
 61     eb/jump  $next-word-or-string:end/disp8
 62 $next-word-or-string:check-for-string-literal:
 63     # if (line->data[line->read] != '"') goto next check
 64     # . eax = line->data[line->read]
 65     31/xor                          3/mod/direct    0/rm32/eax    .           .             .           0/r32/eax   .               .                 # clear eax
 66     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
 67     # . compare
 68     3d/compare-eax-and  0x22/imm32/dquote
 69     75/jump-if-not-equal  $next-word-or-string:regular-word/disp8
 70 $next-word-or-string:string-literal:
 71     # skip-string(line)
 72     # . . push args
 73     56/push-esi
 74     # . . call
 75     e8/call  skip-string/disp32
 76     # . . discard args
 77     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
 78     # fall through
 79 $next-word-or-string:regular-word:
 80     # skip-chars-not-matching-whitespace(line)  # including trailing newline
 81     # . . push args
 82     ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
 83     # . . call
 84     e8/call  skip-chars-not-matching-whitespace/disp32
 85     # . . discard args
 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)
 91 $next-word-or-string:end:
 92     # . restore registers
 93     5f/pop-to-edi
 94     5e/pop-to-esi
 95     59/pop-to-ecx
 96     58/pop-to-eax
 97     # . epilogue
 98     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
 99     5d/pop-to-ebp
100     c3/return
101 
102 test-next-word-or-string:
103     # . prologue
104     55/push-ebp
105     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
106     # setup
107     # . clear-stream(_test-input-stream)
108     # . . push args
109     68/push  _test-input-stream/imm32
110     # . . call
111     e8/call  clear-stream/disp32
112     # . . discard args
113     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
114     # var slice/ecx : (ref slice)
115     68/push  0/imm32/end
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-input-stream, "  ab")
119     # . . push args
120     68/push  "  ab"/imm32
121     68/push  _test-input-stream/imm32
122     # . . call
123     e8/call  write/disp32
124     # . . discard args
125     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
126     # next-word-or-string(_test-input-stream, slice)
127     # . . push args
128     51/push-ecx
129     68/push  _test-input-stream/imm32
130     # . . call
131     e8/call  next-word-or-string/disp32
132     # . . discard args
133     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
134     # check-ints-equal(_test-input-stream->read, 4, msg)
135     # . . push args
136     68/push  "F - test-next-word-or-string/updates-stream-read-correctly"/imm32
137     68/push  4/imm32
138     b8/copy-to-eax  _test-input-stream/imm32
139     ff          6/subop/push        1/mod/*+disp8   0/rm32/eax    .           .             .           .           4/disp8         .                 # push *(eax+4)
140     # . . call
141     e8/call  check-ints-equal/disp32
142     # . . discard args
143     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
144     # check-ints-equal(slice->start - _test-input-stream->data, 2, msg)
145     # . check-ints-equal(slice->start - _test-input-stream, 14, msg)
146     # . . push args
147     68/push  "F - test-next-word-or-string: start"/imm32
148     68/push  0xe/imm32
149     # . . push slice->start - _test-input-stream
150     8b/copy                         0/mod/indirect  1/rm32/ecx    .           .             .           0/r32/eax   .               .                 # copy *ecx to eax
151     81          5/subop/subtract    3/mod/direct    0/rm32/eax    .           .             .           .           .               _test-input-stream/imm32 # subtract from eax
152     50/push-eax
153     # . . call
154     e8/call  check-ints-equal/disp32
155     # . . discard args
156     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
157     # check-ints-equal(slice->end - _test-input-stream->data, 4, msg)
158     # . check-ints-equal(slice->end - _test-input-stream, 16, msg)
159     # . . push args
160     68/push  "F - test-next-word-or-string: end"/imm32
161     68/push  0x10/imm32
162     # . . push slice->end - _test-input-stream
163     8b/copy                         1/mod/*+disp8   1/rm32/ecx    .           .             .           0/r32/eax   4/disp8         .                 # copy *(ecx+4) to eax
164     81          5/subop/subtract    3/mod/direct    0/rm32/eax    .           .             .           .           .               _test-input-stream/imm32 # subtract from eax
165     50/push-eax
166     # . . call
167     e8/call  check-ints-equal/disp32
168     # . . discard args
169     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
170     # . epilogue
171     89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
172     5d/pop-to-ebp
173     c3/return
174 
175 test-next-word-or-string-returns-whole-comment:
176     # . prologue
177     55/push-ebp
178     89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
179     # setup
180     # . clear-stream(_test-input-stream)
181     # . . push args
182     68/push  _test-input-stream/imm32
183     # . . call
184     e8/call  clear-stream/disp32
185     # . . discard args
186     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
187     # var slice/ecx : (ref slice)
188     68/push  0/imm32/end
189     68/push  0/imm32/start
190     89/copy                         3/mod/direct    1/rm32/ecx    .           .             .           4/r32/esp   .               .                 # copy esp to ecx
191     # write(_test-input-stream, "  # a")
192     # . . push args
193     68/push  "  # a"/imm32
194     68/push  _test-input-stream/imm32
195     # . . call
196     e8/call  write/disp32
197     # . . discard args
198     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
199     # next-word-or-string(_test-input-stream, slice)
200     # . . push args
201     51/push-ecx
202     68/push  _test-input-stream/imm32
203     # . . call
204     e8/call  next-word-or-string/disp32
205     # . . discard args
206     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
207     # check-ints-equal(_test-input-stream->read, 5, msg)
208     # . . push args
209     68/push  "F - test-next-word-or-string-returns-whole-comment/updates-stream-read-correctly"/imm32
210     68/push  5/imm32
211     b8/copy-to-eax  _test-input-stream/imm32
212     ff          6/subop/push        1/mod/*+disp8   0/rm32/eax    .           .             .           .           4/disp8         .                 # push *(eax+4)
213     # . . call
214     e8/call  check-ints-equal/disp32
215     # . . discard args
216     81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
# . . push args 220 68/push "F - test-next-word-or-string-returns-whole-comment: start"/imm32 221 68/push 0xe/imm32 222 # . . push slice->start - _test-input-stream 223 8b/copy 0/mod/indirect 1/rm32/ecx . . . 0/r32/eax . . # copy *ecx to eax 224 81 5/subop/subtract 3/mod/direct 0/rm32/eax . . . . . _test-input-stream/imm32 # subtract from eax 225 50/push-eax 226 # . . call 227 e8/call check-ints-equal/disp32 228 # . . discard args 229 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 230 # check-ints-equal(slice->end - _test-input-stream->data, 5, msg) 231 # . check-ints-equal(slice->end - _test-input-stream, 17, msg) 232 # . . push args 233 68/push "F - test-next-word-or-string-returns-whole-comment: end"/imm32 234 68/push 0x11/imm32 235 # . . push slice->end - _test-input-stream 236 8b/copy 1/mod/*+disp8 1/rm32/ecx . . . 0/r32/eax 4/disp8 . # copy *(ecx+4) to eax 237 81 5/subop/subtract 3/mod/direct 0/rm32/eax . . . . . _test-input-stream/imm32 # subtract from eax 238 50/push-eax 239 # . . call 240 e8/call check-ints-equal/disp32 241 # . . discard args 242 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 243 # . epilogue 244 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 245 5d/pop-to-ebp 246 c3/return 247 248 test-next-word-or-string-returns-empty-slice-on-eof: 249 # . prologue 250 55/push-ebp 251 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 252 # setup 253 # . clear-stream(_test-input-stream) 254 # . . push args 255 68/push _test-input-stream/imm32 256 # . . call 257 e8/call clear-stream/disp32 258 # . . discard args 259 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 260 # var slice/ecx : (ref slice) 261 68/push 0/imm32/end 262 68/push 0/imm32/start 263 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 264 # write nothing to _test-input-stream 265 # next-word-or-string(_test-input-stream, slice) 266 # . . push args 267 51/push-ecx 268 68/push _test-input-stream/imm32 269 # . . call 270 e8/call next-word-or-string/disp32 271 # . . discard args 272 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 273 # check-ints-equal(slice->end - slice->start, 0, msg) 274 # . . push args 275 68/push "F - test-next-word-or-string-returns-empty-string-on-eof"/imm32 276 68/push 0/imm32 277 # . . push slice->end - slice->start 278 8b/copy 1/mod/*+disp8 1/rm32/ecx . . . 0/r32/eax 4/disp8 . # copy *(ecx+4) to eax 279 2b/subtract 0/mod/indirect 1/rm32/ecx . . . 0/r32/eax . . # subtract *ecx from eax 280 50/push-eax 281 # . . call 282 e8/call check-ints-equal/disp32 283 # . . discard args 284 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 285 # . epilogue 286 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 287 5d/pop-to-ebp 288 c3/return 289 290 test-next-word-or-string-returns-string-literal: 291 # . prologue 292 55/push-ebp 293 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 294 # setup 295 # . clear-stream(_test-input-stream) 296 # . . push args 297 68/push _test-input-stream/imm32 298 # . . call 299 e8/call clear-stream/disp32 300 # . . discard args 301 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 302 # var slice/ecx : (ref slice) 303 68/push 0/imm32/end 304 68/push 0/imm32/start 305 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 306 # write(_test-input-stream, " \"a b\"/imm32 ") 307 # . . push args 308 68/push " \"a b\"/imm32 "/imm32 309 68/push _test-input-stream/imm32 310 # . . call 311 e8/call write/disp32 312 # . . discard args 313 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 314 # next-word-or-string(_test-input-stream, slice) 315 # . . push args 316 51/push-ecx 317 68/push _test-input-stream/imm32 318 # . . call 319 e8/call next-word-or-string/disp32 320 # . . discard args 321 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 322 # check-ints-equal(slice->start - _test-input-stream->data, 1, msg) 323 # . check-ints-equal(slice->start - _test-input-stream, 13, msg) 324 # . . push args 325 68/push "F - test-next-word-or-string-returns-string-literal: start"/imm32 326 68/push 0xd/imm32 327 # . . push slice->start - _test-input-stream 328 8b/copy 0/mod/indirect 1/rm32/ecx . . . 0/r32/eax . . # copy *ecx to eax 329 81 5/subop/subtract 3/mod/direct 0/rm32/eax . . . . . _test-input-stream/imm32 # subtract from eax 330 50/push-eax 331 # . . call 332 e8/call check-ints-equal/disp32 333 # . . discard args 334 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 335 # check-ints-equal(slice->end - _test-input-stream->data, 12, msg) 336 # . check-ints-equal(slice->end - _test-input-stream, 24, msg) 337 # . . push args 338 68/push "F - test-next-word-or-string-returns-string-literal: end"/imm32 339 68/push 0x18/imm32 340 # . . push slice->end - _test-input-stream 341 8b/copy 1/mod/*+disp8 1/rm32/ecx . . . 0/r32/eax 4/disp8 . # copy *(ecx+4) to eax 342 81 5/subop/subtract 3/mod/direct 0/rm32/eax . . . . . _test-input-stream/imm32 # subtract from eax 343 50/push-eax 344 # . . call 345 e8/call check-ints-equal/disp32 346 # . . discard args 347 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 348 # . epilogue 349 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 350 5d/pop-to-ebp 351 c3/return 352 353 test-next-word-or-string-returns-string-with-escapes: 354 # . prologue 355 55/push-ebp 356 89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp 357 # setup 358 # . clear-stream(_test-input-stream) 359 # . . push args 360 68/push _test-input-stream/imm32 361 # . . call 362 e8/call clear-stream/disp32 363 # . . discard args 364 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 365 # var slice/ecx : (ref slice) 366 68/push 0/imm32/end 367 68/push 0/imm32/start 368 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx 369 # write(_test-input-stream, " \"a\\\"b\"/x") 370 # . . push args 371 68/push " \"a\\\"b\"/x"/imm32 372 68/push _test-input-stream/imm32 373 # . . call 374 e8/call write/disp32 375 # . . discard args 376 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 377 # next-word-or-string(_test-input-stream, slice) 378 # . . push args 379 51/push-ecx 380 68/push _test-input-stream/imm32 381 # . . call 382 e8/call next-word-or-string/disp32 383 # . . discard args 384 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 385 # check-ints-equal(slice->start - _test-input-stream->data, 1, msg) 386 # . check-ints-equal(slice->start - _test-input-stream, 13, msg) 387 # . . push args 388 68/push "F - test-next-word-or-string-returns-string-with-escapes: start"/imm32 389 68/push 0xd/imm32 390 # . . push slice->start - _test-input-stream 391 8b/copy 0/mod/indirect 1/rm32/ecx . . . 0/r32/eax . . # copy *ecx to eax 392 81 5/subop/subtract 3/mod/direct 0/rm32/eax . . . . . _test-input-stream/imm32 # subtract from eax 393 50/push-eax 394 # . . call 395 e8/call check-ints-equal/disp32 396 # . . discard args 397 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 398 # check-ints-equal(slice->end - _test-input-stream->data, 9, msg) 399 # . check-ints-equal(slice->end - _test-input-stream, 21, msg) 400 # . . push args 401 68/push "F - test-next-word-or-string-returns-string-with-escapes: end"/imm32 402 68/push 0x15/imm32 403 # . . push slice->end - _test-input-stream 404 8b/copy 1/mod/*+disp8 1/rm32/ecx . . . 0/r32/eax 4/disp8 . # copy *(ecx+4) to eax 405 81 5/subop/subtract 3/mod/direct 0/rm32/eax . . . . . _test-input-stream/imm32 # subtract from eax 406 50/push-eax 407 # . . call 408 e8/call check-ints-equal/disp32 409 # . . discard args 410 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 411 # . epilogue 412 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 413 5d/pop-to-ebp 414 c3/return 415 416 # . . vim:nowrap:textwidth=0