# Function calls in a single line. # # To run (on Linux): # $ ./ntranslate init.linux 0*.subx apps/subx-params.subx apps/calls.subx # $ mv a.elf apps/calls # # Example 1: # $ echo '(foo %eax)' | apps/calls # # . (foo %eax) # output has comments # ff 6/subop/push %eax # push # e8/call foo/disp32 # call # 81 0/subop/add %esp 4/imm32 # undo push # # Example 2: # $ echo '(foo Var1 *(eax + 4) "blah")' | apps/calls # # . (foo Var1 *(eax + 4) "blah") # 68/push "blah"/imm32 # ff 6/subop/push *(eax + 4) # push args in.. # 68/push Var1/imm32 # ..reverse order # e8/call foo/disp32 # 81 0/subop/add %esp 4/imm32 # undo pushes # # Calls always begin with '(' as the first non-whitespace on a line. == code Entry: # run tests if necessary, convert stdin if not # . prologue 89/<- %ebp 4/r32/esp # initialize heap # . Heap = new-segment(Heap-size) # . . push args 68/push Heap/imm32 ff 6/subop/push *Heap-size # . . call e8/call new-segment/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 # - if argc > 1 and argv[1] == "test", then return run_tests() # if (argc <= 1) goto run-main 81 7/subop/compare *ebp 1/imm32 7e/jump-if-lesser-or-equal $subx-calls-main:interactive/disp8 # if (!kernel-string-equal?(argv[1], "test")) goto run-main # . eax = kernel-string-equal?(argv[1], "test") # . . push args 68/push "test"/imm32 ff 6/subop/push *(ebp+8) # . . call e8/call kernel-string-equal?/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 # . if (eax == 0) goto run-main 3d/compare-eax-and 0/imm32 74/jump-if-equal $subx-calls-main:interactive/disp8 # run-tests() e8/call run-tests/disp32 # syscall(exit, *Num-test-failures) 8b/-> *Num-test-failures 3/r32/ebx eb/jump $subx-calls-main:end/disp8 $subx-calls-main:interactive: # - otherwise convert stdin # subx-calls(Stdin, Stdout) # . . push args 68/push Stdout/imm32 68/push Stdin/imm32 # . . call e8/call subx-calls/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 # syscall(exit, 0) bb/copy-to-ebx 0/imm32 $subx-calls-main:end: b8/copy-to-eax 1/imm32/exit cd/syscall 0x80/imm8 subx-calls: # in : (address buffered-file), out : (address buffered-file) -> # pseudocode: # var line = new-stream(512, 1) # var words : (address stream slice) = new-stream(16, 8) # at most function name and 15 args # while true # clear-stream(line) # read-line-buffered(in, line) # if (line->write == 0) break # end of file # skip-chars-matching-whitespace(line) # if line->data[line->read] != '(' # write-stream-data(out, line) # continue # # emit comment # write-buffered(out, "# . ") # write-stream-data(out, line) # # emit code # ++line->read to skip '(' # clear-stream(words) # words = parse-line(line) # emit-call(out, words) # flush(out) # # . prologue 55/push-ebp 89/<- %ebp 4/r32/esp # . save registers 50/push-eax 51/push-ecx 52/push-edx 56/push-esi # var line/esi : (address stream byte) = stream(512) 81 5/subop/subtract %esp 0x200/imm32 68/push 0x200/imm32/length 68/push 0/imm32/read 68/push 0/imm32/write 89/<- %esi 4/r32/esp # var words/edx : (address stream slice) = stream(16, 8) 81 5/subop/subtract %esp 0x80/imm32 68/push 0x80/imm32/length 68/push 0/imm32/read 68/push 0/imm32/write 89/<- %edx 4/r32/esp $subx-calls:loop: # clear-stream(line) # . . push args 56/push-esi # . . call e8/call clear-stream/disp32 # . . discard args 81 0/subop/add %esp 4/imm32 # read-line-buffered(in, line) # . . push args 56/push-esi ff 6/subop/push *(ebp+8) # . . call e8/call read-line-buffered/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 $subx-calls:check0: # if (line->write == 0) break 81 7/subop/compare *esi 0/imm32 0f 84/jump-if-equal $subx-calls:break/disp32 # skip-chars-matching-whitespace(line) # . . push args 56/push-esi # . . call e8/call skip-chars-matching-whitespace/disp32 # . . discard args 81 0/subop/add %esp 4/imm32 # if (line->data[line->read] == '(') goto convert-call # . ecx = line->read 8b/-> *(esi+4) 1/r32/ecx # . eax = line->data[line->read] 31/xor %eax 0/r32/eax 8a/copy-byte *(esi+ecx+0xc) 0/r32/AL # . if (eax == '(') goto convert-call 3d/compare-eax-and 0x28/imm32/open-paren 74/jump-if-equal $subx-calls:convert-call/disp8 $subx-calls:pass-through: # write-stream-data(out, line) # . . push args 56/push-esi ff 6/subop/push *(ebp+0xc) # . . call e8/call write-stream-data/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 # continue eb/jump $subx-calls:loop/disp8 $subx-calls:convert-call: # - emit comment # write-buffered(out, "# . ") # . . push args 68/push "# . "/imm32 ff 6/subop/push *(ebp+0xc) # . . call e8/call write-buffered/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 # write-stream-data(out, line) # . . push args 56/push-esi ff 6/subop/push *(ebp+0xc) # . . call e8/call write-stream-data/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 # - emit code # ++line->read to skip '(' ff 0/subop/increment *(esi+4) # clear-stream(words) # . . push args 52/push-edx # . . call e8/call clear-stream/disp32 # . . discard args 81 0/subop/add %esp 4/imm32 # words = parse-line(line) # . . push args 52/push-edx 56/push-esi # . . call e8/call parse-line/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 # emit-call(out, words) # . . push args 52/push-edx ff 6/subop/push *(ebp+0xc) # . . call e8/call emit-call/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 # loop e9/jump $subx-calls:loop/disp32 $subx-calls:break: # flush(out) # . . push args ff 6/subop/push *(ebp+0xc) # . . call e8/call flush/disp32 # . . discard args 81 0/subop/add %esp 4/imm32 $subx-calls:end: # . reclaim locals 81 0/subop/add %esp 0x298/imm32 # 0x20c + 0x8c # . restore registers 5e/pop-to-esi 5a/pop-to-edx 59/pop-to-ecx 58/pop-to-eax # . epilogue 89/<- %esp 5/r32/ebp 5d/pop-to-ebp c3/return parse-line: # line : (address stream byte), words : (address stream slice) # pseudocode: # var word-slice : (address slice) # while true # word-slice = next-word-string-or-expression-without-metadata(line) # if slice-empty?(word-slice) # break # end of line # write-int(words, word-slice->start) # write-int(words, word-slice->end) # # . prologue 55/push-ebp 89/<- %ebp 4/r32/esp # . save registers 51/push-ecx # var word-slice/ecx : (address slice) = {0, 0} 68/push 0/imm32/end 68/push 0/imm32/start 89/<- %ecx 4/r32/esp $parse-line:loop: # word-slice = next-word-string-or-expression-without-metadata(line) # . . push args 51/push-ecx ff 6/subop/push *(ebp+8) # . . call e8/call next-word-string-or-expression-without-metadata/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 $parse-line:check1: # if (slice-empty?(word-slice)) break # . eax = slice-empty?(word-slice) # . . push args 51/push-ecx # . . call e8/call slice-empty?/disp32 # . . discard args 81 0/subop/add %esp 4/imm32 # . if (eax != 0) break 3d/compare-eax-and 0/imm32 0f 85/jump-if-not-equal $parse-line:end/disp32 #? # dump word-slice {{{ #? # . write(2/stderr, "w: ") #? # . . push args #? 68/push "w: "/imm32 #? 68/push 2/imm32/stderr #? # . . call #? e8/call write/disp32 #? # . . discard args #? 81 0/subop/add %esp 8/imm32 #? # . clear-stream(Stderr+4) #? # . . save eax #? 50/push-eax #? # . . push args #? b8/copy-to-eax Stderr/imm32 #? 05/add-to-eax 4/imm32 #? 50/push-eax #? # . . call #? e8/call clear-stream/disp32 #? # . . discard args #? 81 0/subop/add %esp 4/imm32 #? # . . restore eax #? 58/pop-to-eax #? # . write-slice-buffered(Stderr, word-slice) #? # . . push args #? 51/push-ecx #? 68/push Stderr/imm32 #? # . . call #? e8/call write-slice-buffered/disp32 #? # . . discard args #? 81 0/subop/add %esp 8/imm32 #? # . flush(Stderr) #? # . . push args #? 68/push Stderr/imm32 #? # . . call #? e8/call flush/disp32 #? # . . discard args #? 81 0/subop/add %esp 4/imm32 #? # . write(2/stderr, "$\n") #? # . . push args #? 68/push "$\n"/imm32 #? 68/push 2/imm32/stderr #? # . . call #? e8/call write/disp32 #? # . . discard args #? 81 0/subop/add %esp 8/imm32 #? # }}} $parse-line:write-word: # write-int(words, word-slice->start) # . . push args ff 6/subop/push *ecx ff 6/subop/push *(ebp+0xc) # . . call e8/call write-int/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 # write-int(words, word-slice->end) # . . push args ff 6/subop/push *(ecx+4) ff 6/subop/push *(ebp+0xc) # . . call e8/call write-int/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 # loop e9/jump $parse-line:loop/disp32 $parse-line:end: # . reclaim locals 81 0/subop/add %esp 8/imm32 # . restore registers 59/pop-to-ecx # . epilogue 89/<- %esp 5/r32/ebp 5d/pop-to-ebp c3/return emit-call: # out : (address buffered-file), words : (address stream slice) # pseudocode: # if (words->write < 8) abort # curr = &words->data[words->write-8] # min = words->data # # emit pushes # while true # if (curr <= min) break # if *curr->start in '%' '*' # write-buffered(out, "ff 6/subop/push ") # write-slice-buffered(out, curr) # write-buffered(out, "\n") # else # write-buffered(out, "68/push ") # write-slice-buffered(out, curr) # write-buffered(out, "/imm32\n") # curr -= 8 # # emit call # write-buffered(out, "e8/call ") # write-slice-buffered(out, curr) # write-buffered(out, "/disp32\n") # # emit pops # write-buffered(out, "81 0/subop/add %esp ") # print-int32-buffered(out, words->write >> 1 - 4) # write-buffered(out, "/imm32\n") # # . prologue 55/push-ebp 89/<- %ebp 4/r32/esp # . save registers 50/push-eax 51/push-ecx 52/push-edx 56/push-esi # esi = words 8b/-> *(ebp+0xc) 6/r32/esi # if (words->write < 8) abort # . ecx = words->write - 8 8b/-> *esi 1/r32/ecx 81 5/subop/subtract %ecx 8/imm32 0f 8c/jump-if-lesser $emit-call:error1/disp32 # curr/ecx = &words->data[words->write-8] 8d/copy-address *(esi+ecx+0xc) 1/r32/ecx # min/edx = words->data 8d/copy-address *(esi+0xc) 2/r32/edx # - emit pushes $emit-call:push-loop: # if (curr <= min) break 39/compare %ecx 2/r32/edx 0f 8e/jump-if-lesser-or-equal $emit-call:call-instruction/disp32 # if (*curr->start in '%' '*') goto push-rm32 # . eax = curr->start 8b/-> *ecx 0/r32/eax # . eax = (byte)*eax 8b/-> *eax 0/r32/eax 81 4/subop/and %eax 0xff/imm32 # . if (eax == '%') goto push-rm32 3d/compare-eax-and 0x25/imm32/percent 74/jump-if-equal $emit-call:push-rm32/disp8 # . if (eax == '*') goto push-rm32 3d/compare-eax-and 0x2a/imm32/asterisk 74/jump-if-equal $emit-call:push-rm32/disp8 $emit-call:push-imm32: # write-buffered(out, "68/push ") 68/push "68/push "/imm32 ff 6/subop/push *(ebp+8) # . . call e8/call write-buffered/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 # write-slice-buffered(out, curr) # . . push args 51/push-ecx ff 6/subop/push *(ebp+8) # . . call e8/call write-slice-buffered/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 # write-buffered(out, "/imm32\n") 68/push "/imm32\n"/imm32 ff 6/subop/push *(ebp+8) # . . call e8/call write-buffered/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 # continue eb/jump $emit-call:next-push/disp8 $emit-call:push-rm32: # write-buffered(out, "ff 6/subop/push ") # . . push args 68/push "ff 6/subop/push "/imm32 ff 6/subop/push *(ebp+8) # . . call e8/call write-buffered/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 # write-slice-buffered(out, curr) # . . push args 51/push-ecx ff 6/subop/push *(ebp+8) # . . call e8/call write-slice-buffered/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 # write-buffered(out, "\n") 68/push Newline/imm32 ff 6/subop/push *(ebp+8) # . . call e8/call write-buffered/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 $emit-call:next-push: # curr -= 8 81 5/subop/subtract %ecx 8/imm32 # loop e9/jump $emit-call:push-loop/disp32 $emit-call:call-instruction: # write-buffered(out, "e8/call ") 68/push "e8/call "/imm32 ff 6/subop/push *(ebp+8) # . . call e8/call write-buffered/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 # write-slice-buffered(out, curr) # . . push args 51/push-ecx ff 6/subop/push *(ebp+8) # . . call e8/call write-slice-buffered/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 # write-buffered(out, "/disp32\n") 68/push "/disp32\n"/imm32 ff 6/subop/push *(ebp+8) # . . call e8/call write-buffered/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 $emit-call:pop-instruction: # write-buffered(out, "81 0/subop/add %esp ") 68/push "81 0/subop/add %esp "/imm32 ff 6/subop/push *(ebp+8) # . . call e8/call write-buffered/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 # print-int32-buffered(out, words->write >> 1 - 4) # . . push args 8b/-> *esi 0/r32/eax c1/shift 7/subop/arith-right %eax 1/imm8 2d/subtract-from-eax 4/imm32 50/push-eax ff 6/subop/push *(ebp+8) # . . call e8/call print-int32-buffered/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 # write-buffered(out, "/imm32\n") 68/push "/imm32\n"/imm32 ff 6/subop/push *(ebp+8) # . . call e8/call write-buffered/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 $emit-call:end: # . restore registers 5e/pop-to-esi 5a/pop-to-edx 59/pop-to-ecx 58/pop-to-eax # . epilogue 89/<- %esp 5/r32/ebp 5d/pop-to-ebp c3/return $emit-call:error1: # print(stderr, "error: calls.subx: '()' is not a valid call") # . write-buffered(Stderr, "error: calls.subx: '()' is not a valid call") # . . push args 68/push "error: calls.subx: '()' is not a valid call"/imm32 68/push Stderr/imm32 # . . call e8/call write-buffered/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 # . flush(Stderr) # . . push args 68/push Stderr/imm32 # . . call e8/call flush/disp32 # . . discard args 81 0/subop/add %esp 4/imm32 # . syscall(exit, 1) bb/copy-to-ebx 1/imm32 b8/copy-to-eax 1/imm32/exit cd/syscall 0x80/imm8 # never gets here test-subx-calls-passes-most-lines-through: # . prologue 55/push-ebp 89/<- %ebp 4/r32/esp # setup # . clear-stream(_test-input-stream) # . . push args 68/push _test-input-stream/imm32 # . . call e8/call clear-stream/disp32 # . . discard args 81 0/subop/add %esp 4/imm32 # . clear-stream(_test-input-buffered-file+4) # . . push args b8/copy-to-eax _test-input-buffered-file/imm32 05/add-to-eax 4/imm32 50/push-eax # . . call e8/call clear-stream/disp32 # . . discard args 81 0/subop/add %esp 4/imm32 # . clear-stream(_test-output-stream) # . . push args 68/push _test-output-stream/imm32 # . . call e8/call clear-stream/disp32 # . . discard args 81 0/subop/add %esp 4/imm32 # . clear-stream(_test-output-buffered-file+4) # . . push args b8/copy-to-eax _test-output-buffered-file/imm32 05/add-to-eax 4/imm32 50/push-eax # . . call e8/call clear-stream/disp32 # . . discard args 81 0/subop/add %esp 4/imm32 # . write(_test-input-stream, "== abcd 0x1\n") # . . push args 68/push "== abcd 0x1\n"/imm32 68/push _test-input-stream/imm32 # . . call e8/call write/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 # subx-calls(_test-input-buffered-file, _test-output-buffered-file) # . . push args 68/push _test-output-buffered-file/imm32 68/push _test-input-buffered-file/imm32 # . . call e8/call subx-calls/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 # check that the line just passed through # . flush(_test-output-buffered-file) # . . push args 68/push _test-output-buffered-file/imm32 # . . call e8/call flush/disp32 # . . discard args 81 0/subop/add %esp 4/imm32 # . check-stream-equal(_test-output-stream, "== abcd 0x1\n", msg) # . . push args 68/push "F - test-subx-calls-passes-most-lines-through"/imm32 68/push "== abcd 0x1\n"/imm32 68/push _test-output-stream/imm32 # . . call e8/call check-stream-equal/disp32 # . . discard args 81 0/subop/add %esp 0xc/imm32 # . epilogue 89/<- %esp 5/r32/ebp 5d/pop-to-ebp c3/return test-subx-calls-processes-calls: # . prologue 55/push-ebp 89/<- %ebp 4/r32/esp # setup # . clear-stream(_test-input-stream) # . . push args 68/push _test-input-stream/imm32 # . . call e8/call clear-stream/disp32 # . . discard args 81 0/subop/add %esp 4/imm32 # . clear-stream(_test-input-buffered-file+4) # . . push args b8/copy-to-eax _test-input-buffered-file/imm32 05/add-to-eax 4/imm32 50/push-eax # . . call e8/call clear-stream/disp32 # . . discard args 81 0/subop/add %esp 4/imm32 # . clear-stream(_test-output-stream) # . . push args 68/push _test-output-stream/imm32 # . . call e8/call clear-stream/disp32 # . . discard args 81 0/subop/add %esp 4/imm32 # . clear-stream(_test-output-buffered-file+4) # . . push args b8/copy-to-eax _test-output-buffered-file/imm32 05/add-to-eax 4/imm32 50/push-eax # . . call e8/call clear-stream/disp32 # . . discard args 81 0/subop/add %esp 4/imm32 # . write(_test-input-stream, "(foo %eax)\n") # . . push args 68/push "(foo %eax)\n"/imm32 68/push _test-input-stream/imm32 # . . call e8/call write/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 # subx-calls(_test-input-buffered-file, _test-output-buffered-file) # . . push args 68/push _test-output-buffered-file/imm32 68/push _test-input-buffered-file/imm32 # . . call e8/call subx-calls/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 # check that the line just passed through # . flush(_test-output-buffered-file) # . . push args 68/push _test-output-buffered-file/imm32 # . . call e8/call flush/disp32 # . . discard args 81 0/subop/add %esp 4/imm32 #? # dump _test-output-stream {{{ #? # . write(2/stderr, "^") #? # . . push args #? 68/push "^"/imm32 #? 68/push 2/imm32/stderr #? # . . call #? e8/call write/disp32 #? # . . discard args #? 81 0/subop/add %esp 8/imm32 #? # . write-stream(2/stderr, _test-output-stream) #? # . . push args #? 68/push _test-output-stream/imm32 #? 68/push 2/imm32/stderr #? # . . call #? e8/call write-stream/disp32 #? # . . discard args #? 81 0/subop/add %esp 8/imm32 #? # . write(2/stderr, "$\n") #? # . . push args #? 68/push "$\n"/imm32 #? 68/push 2/imm32/stderr #? # . . call #? e8/call write/disp32 #? # . . discard args #? 81 0/subop/add %esp 8/imm32 #? # . rewind-stream(_test-output-stream) #? # . . push args #? 68/push _test-output-stream/imm32 #? # . . call #? e8/call rewind-stream/disp32 #? # . . discard args #? 81 0/subop/add %esp 4/imm32 #? # }}} # . check-next-stream-line-equal(_test-output-stream, "# . (foo %eax)", msg) # . . push args 68/push "F - test-subx-calls-processes-calls: comment"/imm32 68/push "# . (foo %eax)"/imm32 68/push _test-output-stream/imm32 # . . call e8/call check-next-stream-line-equal/disp32 # . . discard args 81 0/subop/add %esp 0xc/imm32 # . check-next-stream-line-equal(_test-output-stream, "ff 6/subop/push %eax", msg) # . . push args 68/push "F - test-subx-calls-processes-calls: arg 0"/imm32 68/push "ff 6/subop/push %eax"/imm32 68/push _test-output-stream/imm32 # . . call e8/call check-next-stream-line-equal/disp32 # . . discard args 81 0/subop/add %esp 0xc/imm32 # . check-next-stream-line-equal(_test-output-stream, "e8/call foo/disp32", msg) # . . push args 68/push "F - test-subx-calls-processes-calls: call"/imm32 68/push "e8/call foo/disp32"/imm32 68/push _test-output-stream/imm32 # . . call e8/call check-next-stream-line-equal/disp32 # . . discard args 81 0/subop/add %esp 0xc/imm32 # . check-next-stream-line-equal(_test-output-stream, "81 0/subop/add %esp 4/imm32", msg) # . . push args 68/push "F - test-subx-calls-processes-calls: pops"/imm32 68/push "81 0/subop/add %esp 0x00000004/imm32"/imm32 68/push _test-output-stream/imm32 # . . call e8/call check-next-stream-line-equal/disp32 # . . discard args 81 0/subop/add %esp 0xc/imm32 # . epilogue 89/<- %esp 5/r32/ebp 5d/pop-to-ebp c3/return next-word-string-or-expression-without-metadata: # line : (address stream), out : (address slice) # pseudocode: # skip-chars-matching(line, ' ') # if line->read >= line->write # end of line # out = {0, 0} # return # out->start = &line->data[line->read] # if line->data[line->read] == '#' # comment # out->end = &line->data[line->write] # skip to end of line # return # if line->data[line->read] == '"' # string literal # skip-string(line) # out->end = &line->data[line->read] # no metadata # return # if line->data[line->read] == '*' # expression # if line->data[line->read + 1] == ' ' # abort # if line->data[line->read + 1] == '(' # skip-until-close-paren(line) # if (line->data[line->read] != ')' # abort # ++line->data[line->read] to skip ')' # out->end = &line->data[line->read] # return # if line->data[line->read] == ')' # ++line->read to skip ')' # # make sure there's nothing else of importance # if line->read >= line->write # out = {0, 0} # return # if line->data[line->read] != ' ' # abort # skip-chars-matching-whitespace(line) # if line->read >= line->write # out = {0, 0} # return # if line->data[line->read] == '#' # only thing permitted after ')' is a comment # out = {0, 0} # return # abort # # default case: read a word -- but no metadata # while true # if line->read >= line->write # break # if line->data[line->read] == ' ' # break # if line->data[line->read] == ')' # break # if line->data[line->read] == '/' # abort # ++line->read # out->end = &line->data[line->read] # # registers: # ecx: often line->read # eax: often line->data[line->read] # # . prologue 55/push-ebp 89/<- %ebp 4/r32/esp # . save registers 50/push-eax 51/push-ecx 56/push-esi 57/push-edi # esi = line 8b/-> *(ebp+8) 6/r32/esi # edi = out 8b/-> *(ebp+0xc) 7/r32/edi # skip-chars-matching(line, ' ') # . . push args 68/push 0x20/imm32/space ff 6/subop/push *(ebp+8) # . . call e8/call skip-chars-matching/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 $next-word-string-or-expression-without-metadata:check0: # if (line->read >= line->write) return out = {0, 0} # . ecx = line->read 8b/-> *(esi+4) 1/r32/ecx # . if (ecx >= line->write) return out = {0, 0} 3b/compare *esi 1/r32/ecx 0f 8d/jump-if-greater-or-equal $next-word-string-or-expression-without-metadata:return-eol/disp32 $next-word-string-or-expression-without-metadata:check-for-comment: # out->start = &line->data[line->read] 8d/copy-address *(esi+ecx+0xc) 0/r32/eax 89/<- *edi 0/r32/eax # if (line->data[line->read] != '#') goto next check # . eax = line->data[line->read] 31/xor %eax 0/r32/eax 8a/copy-byte *(esi+ecx+0xc) 0/r32/AL # . if (eax != '#') goto next check 3d/compare-eax-and 0x23/imm32/pound 75/jump-if-not-equal $next-word-string-or-expression-without-metadata:check-for-string-literal/disp8 $next-word-string-or-expression-without-metadata:comment: # out->end = &line->data[line->write] 8b/-> *esi 0/r32/eax 8d/copy-address *(esi+eax+0xc) 0/r32/eax 89/<- *(edi+4) 0/r32/eax # line->read = line->write # skip rest of line 8b/-> *esi 0/r32/eax 89/<- *(esi+4) 0/r32/eax # return e9/jump $next-word-string-or-expression-without-metadata:end/disp32 $next-word-string-or-expression-without-metadata:check-for-string-literal: # if (line->data[line->read] != '"') goto next check 3d/compare-eax-and 0x22/imm32/dquote 75/jump-if-not-equal $next-word-string-or-expression-without-metadata:check-for-expression/disp8 $next-word-string-or-expression-without-metadata:string-literal: # skip-string(line) # . . push args 56/push-esi # . . call e8/call skip-string/disp32 # . . discard args 81 0/subop/add %esp 4/imm32 # out->end = &line->data[line->read] 8b/-> *(esi+4) 1/r32/ecx 8d/copy-address *(esi+ecx+0xc) 0/r32/eax 89/<- *(edi+4) 0/r32/eax # return e9/jump $next-word-string-or-expression-without-metadata:end/disp32 $next-word-string-or-expression-without-metadata:check-for-expression: # if (line->data[line->read] != '*') goto next check 3d/compare-eax-and 0x2a/imm32/asterisk 75/jump-if-not-equal $next-word-string-or-expression-without-metadata:check-for-end-of-call/disp8 # if (line->data[line->read + 1] == ' ') goto error1 8a/copy-byte *(esi+ecx+0xd) 0/r32/AL 3d/compare-eax-and 0x20/imm32/space 0f 84/jump-if-equal $next-word-string-or-expression-without-metadata:error1/disp32 # if (line->data[line->read + 1] != '(') goto regular-word 3d/compare-eax-and 0x28/imm32/open-paren 0f 85/jump-if-not-equal $next-word-string-or-expression-without-metadata:regular-word-without-metadata/disp32 $next-word-string-or-expression-without-metadata:paren: # skip-until-close-paren(line) # . . push args 56/push-esi # . . call e8/call skip-until-close-paren/disp32 # . . discard args 81 0/subop/add %esp 4/imm32 # if (line->data[line->read] != ')') goto error2 # . eax = line->data[line->read] 8b/-> *(esi+4) 1/r32/ecx 8a/copy-byte *(esi+ecx+0xc) 0/r32/AL # . if (eax != ')') goto error2 3d/compare-eax-and 0x29/imm32/close-paren 0f 85/jump-if-not-equal $next-word-string-or-expression-without-metadata:error2/disp32 # ++line->read to skip ')' ff 0/subop/increment *(esi+4) # out->end = &line->data[line->read] 8b/-> *(esi+4) 1/r32/ecx 8d/copy-address *(esi+ecx+0xc) 0/r32/eax 89/<- *(edi+4) 0/r32/eax # return e9/jump $next-word-string-or-expression-without-metadata:end/disp32 $next-word-string-or-expression-without-metadata:check-for-end-of-call: # if (line->data[line->read] != ')') goto next check 3d/compare-eax-and 0x29/imm32/close-paren 75/jump-if-not-equal $next-word-string-or-expression-without-metadata:regular-word-without-metadata/disp8 # ++line->read to skip ')' ff 0/subop/increment *(esi+4) # - error checking: make sure there's nothing else of importance on the line # if (line->read >= line->write) return out = {0, 0} # . ecx = line->read 8b/-> *(esi+4) 1/r32/ecx # . if (ecx >= line->write) return {0, 0} 3b/compare *esi 1/r32/ecx 0f 8d/jump-if-greater-or-equal $next-word-string-or-expression-without-metadata:return-eol/disp32 # if (line->data[line->read] == '/') goto error3 # . eax = line->data[line->read] 8a/copy-byte *(esi+ecx+0xc) 0/r32/AL # . if (eax == '/') goto error3 3d/compare-eax-and 0x2f/imm32/slash 0f 84/jump-if-equal $next-word-string-or-expression-without-metadata:error3/disp32 # skip-chars-matching-whitespace(line) # . . push args 56/push-esi # . . call e8/call skip-chars-matching-whitespace/disp32 # . . discard args 81 0/subop/add %esp 4/imm32 # if (line->read >= line->write) return out = {0, 0} # . ecx = line->read 8b/-> *(esi+4) 1/r32/ecx # . if (ecx >= line->write) return {0, 0} 3b/compare *esi 1/r32/ecx 0f 8d/jump-if-greater-or-equal $next-word-string-or-expression-without-metadata:return-eol/disp32 # if (line->data[line->read] == '#') return out = {0, 0} # . eax = line->data[line->read] 8b/-> *(esi+4) 1/r32/ecx 8a/copy-byte *(esi+ecx+0xc) 0/r32/AL # . if (eax == '#') return out = {0, 0} 3d/compare-eax-and 0x23/imm32/pound 74/jump-if-equal $next-word-string-or-expression-without-metadata:return-eol/disp8 # otherwise goto error4 e9/jump $next-word-string-or-expression-without-metadata:error4/disp32 $next-word-string-or-expression-without-metadata:regular-word-without-metadata: # if (line->read >= line->write) break # . ecx = line->read 8b/-> *(esi+4) 1/r32/ecx # . if (ecx >= line->write) break 3b/compare *esi 1/r32/ecx 7d/jump-if-greater-or-equal $next-word-string-or-expression-without-metadata:regular-word-break/disp8 # if (line->data[line->read] == ' ') break # . eax = line->data[line->read] 8b/-> *(esi+4) 1/r32/ecx 8a/copy-byte *(esi+ecx+0xc) 0/r32/AL # . if (eax == ' ') break 3d/compare-eax-and 0x20/imm32/space 74/jump-if-equal $next-word-string-or-expression-without-metadata:regular-word-break/disp8 # if (line->data[line->read] == ')') break 3d/compare-eax-and 0x29/imm32/close-paren 0f 84/jump-if-equal $next-word-string-or-expression-without-metadata:regular-word-break/disp32 # if (line->data[line->read] == '/') goto error5 3d/compare-eax-and 0x2f/imm32/slash 0f 84/jump-if-equal $next-word-string-or-expression-without-metadata:error5/disp32 # ++line->read ff 0/subop/increment *(esi+4) # loop e9/jump $next-word-string-or-expression-without-metadata:regular-word-without-metadata/disp32 $next-word-string-or-expression-without-metadata:regular-word-break: # out->end = &line->data[line->read] 8b/-> *(esi+4) 1/r32/ecx 8d/copy-address *(esi+ecx+0xc) 0/r32/eax 89/<- *(edi+4) 0/r32/eax eb/jump $next-word-string-or-expression-without-metadata:end/disp8 $next-word-string-or-expression-without-metadata:return-eol: # return out = {0, 0} c7 0/subop/copy *edi 0/imm32 c7 0/subop/copy *(edi+4) 0/imm32 $next-word-string-or-expression-without-metadata:end: # . restore registers 5f/pop-to-edi 5e/pop-to-esi 59/pop-to-ecx 58/pop-to-eax # . epilogue 89/<- %esp 5/r32/ebp 5d/pop-to-ebp c3/return $next-word-string-or-expression-without-metadata:error1: # print(stderr, "error: no space allowed after '*' in '" line "'") # . write-buffered(Stderr, "error: no space allowed after '*' in '") # . . push args 68/push "error: no space allowed after '*' in '"/imm32 68/push Stderr/imm32 # . . call e8/call write-buffered/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 # . write-stream-data(Stderr, line) # . . push args 56/push-esi 68/push Stderr/imm32 # . . call e8/call write-stream-data/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 # . write-buffered(Stderr, "'") # . . push args 68/push "'"/imm32 68/push Stderr/imm32 # . . call e8/call write-buffered/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 # . flush(Stderr) # . . push args 68/push Stderr/imm32 # . . call e8/call flush/disp32 # . . discard args 81 0/subop/add %esp 4/imm32 # . syscall(exit, 1) bb/copy-to-ebx 1/imm32 b8/copy-to-eax 1/imm32/exit cd/syscall 0x80/imm8 # never gets here $next-word-string-or-expression-without-metadata:error2: # print(stderr, "error: *(...) expression must be all on a single line in '" line "'") # . write-buffered(Stderr, "error: *(...) expression must be all on a single line in '") # . . push args 68/push "error: *(...) expression must be all on a single line in '"/imm32 68/push Stderr/imm32 # . . call e8/call write-buffered/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 # . write-stream-data(Stderr, line) # . . push args 56/push-esi 68/push Stderr/imm32 # . . call e8/call write-stream-data/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 # . write-buffered(Stderr, "'") # . . push args 68/push "'"/imm32 68/push Stderr/imm32 # . . call e8/call write-buffered/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 # . flush(Stderr) # . . push args 68/push Stderr/imm32 # . . call e8/call flush/disp32 # . . discard args 81 0/subop/add %esp 4/imm32 # . syscall(exit, 1) bb/copy-to-ebx 1/imm32 b8/copy-to-eax 1/imm32/exit cd/syscall 0x80/imm8 # never gets here $next-word-string-or-expression-without-metadata:error3: # print(stderr, "error: no metadata after calls; just use a comment (in '" line "')") # . write-buffered(Stderr, "error: no metadata after calls; just use a comment (in '") # . . push args 68/push "error: no metadata after calls; just use a comment (in '"/imm32 68/push Stderr/imm32 # . . call e8/call write-buffered/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 # . write-stream-data(Stderr, line) # . . push args 56/push-esi 68/push Stderr/imm32 # . . call e8/call write-stream-data/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 # . write-buffered(Stderr, "')") # . . push args 68/push "')"/imm32 68/push Stderr/imm32 # . . call e8/call write-buffered/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 # . flush(Stderr) # . . push args 68/push Stderr/imm32 # . . call e8/call flush/disp32 # . . discard args 81 0/subop/add %esp 4/imm32 # . syscall(exit, 1) bb/copy-to-ebx 1/imm32 b8/copy-to-eax 1/imm32/exit cd/syscall 0x80/imm8 # never gets here $next-word-string-or-expression-without-metadata:error4: # print(stderr, "error: unexpected text after end of call in '" line "'") # . write-buffered(Stderr, "error: unexpected text after end of call in '") # . . push args 68/push "error: unexpected text after end of call in '"/imm32 68/push Stderr/imm32 # . . call e8/call write-buffered/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 # . write-stream-data(Stderr, line) # . . push args 56/push-esi 68/push Stderr/imm32 # . . call e8/call write-stream-data/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 # . write-buffered(Stderr, "'") # . . push args 68/push "'"/imm32 68/push Stderr/imm32 # . . call e8/call write-buffered/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 # . flush(Stderr) # . . push args 68/push Stderr/imm32 # . . call e8/call flush/disp32 # . . discard args 81 0/subop/add %esp 4/imm32 # . syscall(exit, 1) bb/copy-to-ebx 1/imm32 b8/copy-to-eax 1/imm32/exit cd/syscall 0x80/imm8 # never gets here $next-word-string-or-expression-without-metadata:error5: # print(stderr, "error: no metadata anywhere in calls (in '" line "')") # . write-buffered(Stderr, "error: no metadata anywhere in calls (in '") # . . push args 68/push "error: no metadata anywhere in calls (in '"/imm32 68/push Stderr/imm32 # . . call e8/call write-buffered/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 # . write-stream-data(Stderr, line) # . . push args 56/push-esi 68/push Stderr/imm32 # . . call e8/call write-stream-data/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 # . write-buffered(Stderr, "')") # . . push args 68/push "')"/imm32 68/push Stderr/imm32 # . . call e8/call write-buffered/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 # . flush(Stderr) # . . push args 68/push Stderr/imm32 # . . call e8/call flush/disp32 # . . discard args 81 0/subop/add %esp 4/imm32 # . syscall(exit, 1) bb/copy-to-ebx 1/imm32 b8/copy-to-eax 1/imm32/exit cd/syscall 0x80/imm8 # never gets here test-next-word-string-or-expression-without-metadata: # . prologue 55/push-ebp 89/<- %ebp 4/r32/esp # setup # . clear-stream(_test-input-stream) # . . push args 68/push _test-input-stream/imm32 # . . call e8/call clear-stream/disp32 # . . discard args 81 0/subop/add %esp 4/imm32 # var slice/ecx = {0, 0} 68/push 0/imm32/end 68/push 0/imm32/start 89/<- %ecx 4/r32/esp # write(_test-input-stream, " ab") # . . push args 68/push " ab"/imm32 68/push _test-input-stream/imm32 # . . call e8/call write/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 # next-word-string-or-expression-without-metadata(_test-input-stream, slice) # . . push args 51/push-ecx 68/push _test-input-stream/imm32 # . . call e8/call next-word-string-or-expression-without-metadata/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 # check-ints-equal(_test-input-stream->read, 4, msg) # . . push args 68/push "F - test-next-word-string-or-expression-without-metadata/updates-stream-read-correctly"/imm32 68/push 4/imm32 b8/copy-to-eax _test-input-stream/imm32 ff 6/subop/push *(eax+4) # . . call e8/call check-ints-equal/disp32 # . . discard args 81 0/subop/add %esp 0xc/imm32 # check-ints-equal(slice->start - _test-input-stream->data, 2, msg) # . check-ints-equal(slice->start - _test-input-stream, 14, msg) # . . push args 68/push "F - test-next-word-string-or-expression-without-metadata: start"/imm32 68/push 0xe/imm32 # . . push slice->start - _test-input-stream 8b/-> *ecx 0/r32/eax 81 5/subop/subtract %eax _test-input-stream/imm32 50/push-eax # . . call e8/call check-ints-equal/disp32 # . . discard args 81 0/subop/add %esp 0xc/imm32 # check-ints-equal(slice->end - _test-input-stream->data, 4, msg) # . check-ints-equal(slice->end - _test-input-stream, 16, msg) # . . push args 68/push "F - test-next-word-string-or-expression-without-metadata: end"/imm32 68/push 0x10/imm32 # . . push slice->end - _test-input-stream 8b/-> *(ecx+4) 0/r32/eax 81 5/subop/subtract %eax _test-input-stream/imm32 50/push-eax # . . call e8/call check-ints-equal/disp32 # . . discard args 81 0/subop/add %esp 0xc/imm32 # . epilogue 89/<- %esp 5/r32/ebp 5d/pop-to-ebp c3/return test-next-word-string-or-expression-without-metadata-returns-whole-comment: # . prologue 55/push-ebp 89/<- %ebp 4/r32/esp # setup # . clear-stream(_test-input-stream) # . . push args 68/push _test-input-stream/imm32 # . . call e8/call clear-stream/disp32 # . . discard args 81 0/subop/add %esp 4/imm32 # var slice/ecx = {0, 0} 68/push 0/imm32/end 68/push 0/imm32/start 89/<- %ecx 4/r32/esp # write(_test-input-stream, " # a") # . . push args 68/push " # a"/imm32 68/push _test-input-stream/imm32 # . . call e8/call write/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 # next-word-string-or-expression-without-metadata(_test-input-stream, slice) # . . push args 51/push-ecx 68/push _test-input-stream/imm32 # . . call e8/call next-word-string-or-expression-without-metadata/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 # check-ints-equal(_test-input-stream->read, 5, msg) # . . push args 68/push "F - test-next-word-string-or-expression-without-metadata-returns-whole-comment/updates-stream-read-correctly"/imm32 68/push 5/imm32 b8/copy-to-eax _test-input-stream/imm32 ff 6/subop/push *(eax+4) # . . call e8/call check-ints-equal/disp32 # . . discard args 81 0/subop/add %esp 0xc/imm32 # check-ints-equal(slice->start - _test-input-stream->data, 2, msg) # . check-ints-equal(slice->start - _test-input-stream, 14, msg) # . . push args 68/push "F - test-next-word-string-or-expression-without-metadata-returns-whole-comment: start"/imm32 68/push 0xe/imm32 # . . push slice->start - _test-input-stream 8b/-> *ecx 0/r32/eax 81 5/subop/subtract %eax _test-input-stream/imm32 50/push-eax # . . call e8/call check-ints-equal/disp32 # . . discard args 81 0/subop/add %esp 0xc/imm32 # check-ints-equal(slice->end - _test-input-stream->data, 5, msg) # . check-ints-equal(slice->end - _test-input-stream, 17, msg) # . . push args 68/push "F - test-next-word-string-or-expression-without-metadata-returns-whole-comment: end"/imm32 68/push 0x11/imm32 # . . push slice->end - _test-input-stream 8b/-> *(ecx+4) 0/r32/eax 81 5/subop/subtract %eax _test-input-stream/imm32 50/push-eax # . . call e8/call check-ints-equal/disp32 # . . discard args 81 0/subop/add %esp 0xc/imm32 # . epilogue 89/<- %esp 5/r32/ebp 5d/pop-to-ebp c3/return test-next-word-string-or-expression-without-metadata-returns-empty-slice-on-eof: # . prologue 55/push-ebp 89/<- %ebp 4/r32/esp # setup # . clear-stream(_test-input-stream) # . . push args 68/push _test-input-stream/imm32 # . . call e8/call clear-stream/disp32 # . . discard args 81 0/subop/add %esp 4/imm32 # var slice/ecx = {0, 0} 68/push 0/imm32/end 68/push 0/imm32/start 89/<- %ecx 4/r32/esp # write nothing to _test-input-stream # next-word-string-or-expression-without-metadata(_test-input-stream, slice) # . . push args 51/push-ecx 68/push _test-input-stream/imm32 # . . call e8/call next-word-string-or-expression-without-metadata/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 # check-ints-equal(slice->end - slice->start, 0, msg) # . . push args 68/push "F - test-next-word-string-or-expression-without-metadata-returns-empty-expression-on-eof"/imm32 68/push 0/imm32 # . . push slice->end - slice->start 8b/-> *(ecx+4) 0/r32/eax 2b/subtract-> *ecx 0/r32/eax # subtract *ecx from eax 50/push-eax # . . call e8/call check-ints-equal/disp32 # . . discard args 81 0/subop/add %esp 0xc/imm32 # . epilogue 89/<- %esp 5/r32/ebp 5d/pop-to-ebp c3/return test-next-word-string-or-expression-without-metadata-returns-string-literal: # . prologue 55/push-ebp 89/<- %ebp 4/r32/esp # setup # . clear-stream(_test-input-stream) # . . push args 68/push _test-input-stream/imm32 # . . call e8/call clear-stream/disp32 # . . discard args 81 0/subop/add %esp 4/imm32 # var slice/ecx = {0, 0} 68/push 0/imm32/end 68/push 0/imm32/start 89/<- %ecx 4/r32/esp # write(_test-input-stream, " \"a b\" ") # . . push args 68/push " \"a b\" "/imm32 68/push _test-input-stream/imm32 # . . call e8/call write/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 # next-word-string-or-expression-without-metadata(_test-input-stream, slice) # . . push args 51/push-ecx 68/push _test-input-stream/imm32 # . . call e8/call next-word-string-or-expression-without-metadata/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 # check-ints-equal(slice->start - _test-input-stream->data, 1, msg) # . check-ints-equal(slice->start - _test-input-stream, 13, msg) # . . push args 68/push "F - test-next-word-string-or-expression-without-metadata-returns-string-literal: start"/imm32 68/push 0xd/imm32 # . . push slice->start - _test-input-stream 8b/-> *ecx 0/r32/eax 81 5/subop/subtract %eax _test-input-stream/imm32 50/push-eax # . . call e8/call check-ints-equal/disp32 # . . discard args 81 0/subop/add %esp 0xc/imm32 # check-ints-equal(slice->end - _test-input-stream->data, 6, msg) # . check-ints-equal(slice->end - _test-input-stream, 18, msg) # . . push args 68/push "F - test-next-word-string-or-expression-without-metadata-returns-string-literal: end"/imm32 68/push 0x12/imm32 # . . push slice->end - _test-input-stream 8b/-> *(ecx+4) 0/r32/eax 81 5/subop/subtract %eax _test-input-stream/imm32 50/push-eax # . . call e8/call check-ints-equal/disp32 # . . discard args 81 0/subop/add %esp 0xc/imm32 # . epilogue 89/<- %esp 5/r32/ebp 5d/pop-to-ebp c3/return test-next-word-string-or-expression-without-metadata-returns-string-with-escapes: # . prologue 55/push-ebp 89/<- %ebp 4/r32/esp # setup # . clear-stream(_test-input-stream) # . . push args 68/push _test-input-stream/imm32 # . . call e8/call clear-stream/disp32 # . . discard args 81 0/subop/add %esp 4/imm32 # var slice/ecx = {0, 0} 68/push 0/imm32/end 68/push 0/imm32/start 89/<- %ecx 4/r32/esp # write(_test-input-stream, " \"a\\\"b\"") # . . push args 68/push " \"a\\\"b\""/imm32 68/push _test-input-stream/imm32 # . . call e8/call write/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 # next-word-string-or-expression-without-metadata(_test-input-stream, slice) # . . push args 51/push-ecx 68/push _test-input-stream/imm32 # . . call e8/call next-word-string-or-expression-without-metadata/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 # check-ints-equal(slice->start - _test-input-stream->data, 1, msg) # . check-ints-equal(slice->start - _test-input-stream, 13, msg) # . . push args 68/push "F - test-next-word-string-or-expression-without-metadata-returns-string-with-escapes: start"/imm32 68/push 0xd/imm32 # . . push slice->start - _test-input-stream 8b/-> *ecx 0/r32/eax 81 5/subop/subtract %eax _test-input-stream/imm32 50/push-eax # . . call e8/call check-ints-equal/disp32 # . . discard args 81 0/subop/add %esp 0xc/imm32 # check-ints-equal(slice->end - _test-input-stream->data, 7, msg) # . check-ints-equal(slice->end - _test-input-stream, 19, msg) # . . push args 68/push "F - test-next-word-string-or-expression-without-metadata-returns-string-with-escapes: end"/imm32 68/push 0x13/imm32 # . . push slice->end - _test-input-stream 8b/-> *(ecx+4) 0/r32/eax 81 5/subop/subtract %eax _test-input-stream/imm32 50/push-eax # . . call e8/call check-ints-equal/disp32 # . . discard args 81 0/subop/add %esp 0xc/imm32 # . epilogue 89/<- %esp 5/r32/ebp 5d/pop-to-ebp c3/return test-next-word-string-or-expression-without-metadata-returns-whole-expression: # . prologue 55/push-ebp 89/<- %ebp 4/r32/esp # setup # . clear-stream(_test-input-stream) # . . push args 68/push _test-input-stream/imm32 # . . call e8/call clear-stream/disp32 # . . discard args 81 0/subop/add %esp 4/imm32 # var slice/ecx = {0, 0} 68/push 0/imm32/end 68/push 0/imm32/start 89/<- %ecx 4/r32/esp # write(_test-input-stream, " *(a b) ") # . . push args 68/push " *(a b) "/imm32 68/push _test-input-stream/imm32 # . . call e8/call write/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 # next-word-string-or-expression-without-metadata(_test-input-stream, slice) # . . push args 51/push-ecx 68/push _test-input-stream/imm32 # . . call e8/call next-word-string-or-expression-without-metadata/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 # check-ints-equal(slice->start - _test-input-stream->data, 1, msg) # . check-ints-equal(slice->start - _test-input-stream, 13, msg) # . . push args 68/push "F - test-next-word-string-or-expression-without-metadata-returns-whole-expression: start"/imm32 68/push 0xd/imm32 # . . push slice->start - _test-input-stream 8b/-> *ecx 0/r32/eax 81 5/subop/subtract %eax _test-input-stream/imm32 50/push-eax # . . call e8/call check-ints-equal/disp32 # . . discard args 81 0/subop/add %esp 0xc/imm32 # check-ints-equal(slice->end - _test-input-stream->data, 7, msg) # . check-ints-equal(slice->end - _test-input-stream, 19, msg) # . . push args 68/push "F - test-next-word-string-or-expression-without-metadata-returns-whole-expression: end"/imm32 68/push 0x13/imm32 # . . push slice->end - _test-input-stream 8b/-> *(ecx+4) 0/r32/eax 81 5/subop/subtract %eax _test-input-stream/imm32 50/push-eax # . . call e8/call check-ints-equal/disp32 # . . discard args 81 0/subop/add %esp 0xc/imm32 # . epilogue 89/<- %esp 5/r32/ebp 5d/pop-to-ebp c3/return test-next-word-string-or-expression-without-metadata-returns-eol-on-trailing-close-paren: # . prologue 55/push-ebp 89/<- %ebp 4/r32/esp # setup # . clear-stream(_test-input-stream) # . . push args 68/push _test-input-stream/imm32 # . . call e8/call clear-stream/disp32 # . . discard args 81 0/subop/add %esp 4/imm32 # var slice/ecx = {0, 0} 68/push 0/imm32/end 68/push 0/imm32/start 89/<- %ecx 4/r32/esp # write(_test-input-stream, " ) ") # . . push args 68/push " ) "/imm32 68/push _test-input-stream/imm32 # . . call e8/call write/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 # next-word-string-or-expression-without-metadata(_test-input-stream, slice) # . . push args 51/push-ecx 68/push _test-input-stream/imm32 # . . call e8/call next-word-string-or-expression-without-metadata/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 # check-ints-equal(slice->start, 0, msg) # . . push args 68/push "F - test-next-word-string-or-expression-without-metadata-returns-eol-on-trailing-close-paren: start"/imm32 68/push 0/imm32 ff 6/subop/push *ecx # . . call e8/call check-ints-equal/disp32 # . . discard args 81 0/subop/add %esp 0xc/imm32 # check-ints-equal(slice->end, 0, msg) # . . push args 68/push "F - test-next-word-string-or-expression-without-metadata-returns-eol-on-trailing-close-paren: end"/imm32 68/push 0/imm32 ff 6/subop/push *(ecx+4) # . . call e8/call check-ints-equal/disp32 # . . discard args 81 0/subop/add %esp 0xc/imm32 # . epilogue 89/<- %esp 5/r32/ebp 5d/pop-to-ebp c3/return test-next-word-string-or-expression-without-metadata-handles-comment-after-trailing-close-paren: # . prologue 55/push-ebp 89/<- %ebp 4/r32/esp # setup # . clear-stream(_test-input-stream) # . . push args 68/push _test-input-stream/imm32 # . . call e8/call clear-stream/disp32 # . . discard args 81 0/subop/add %esp 4/imm32 # var slice/ecx = {0, 0} 68/push 0/imm32/end 68/push 0/imm32/start 89/<- %ecx 4/r32/esp # write(_test-input-stream, " ) # abc ") # . . push args 68/push " ) # abc "/imm32 68/push _test-input-stream/imm32 # . . call e8/call write/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 # next-word-string-or-expression-without-metadata(_test-input-stream, slice) # . . push args 51/push-ecx 68/push _test-input-stream/imm32 # . . call e8/call next-word-string-or-expression-without-metadata/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 # check-ints-equal(slice->start, 0, msg) # . . push args 68/push "F - test-next-word-string-or-expression-without-metadata-handles-comment-after-trailing-close-paren: start"/imm32 68/push 0/imm32 ff 6/subop/push *ecx # . . call e8/call check-ints-equal/disp32 # . . discard args 81 0/subop/add %esp 0xc/imm32 # check-ints-equal(slice->end, 0, msg) # . . push args 68/push "F - test-next-word-string-or-expression-without-metadata-handles-comment-after-trailing-close-paren: end"/imm32 68/push 0/imm32 ff 6/subop/push *(ecx+4) # . . call e8/call check-ints-equal/disp32 # . . discard args 81 0/subop/add %esp 0xc/imm32 # . epilogue 89/<- %esp 5/r32/ebp 5d/pop-to-ebp c3/return test-next-word-string-or-expression-without-metadata-handles-newline-after-trailing-close-paren: # . prologue 55/push-ebp 89/<- %ebp 4/r32/esp # setup # . clear-stream(_test-input-stream) # . . push args 68/push _test-input-stream/imm32 # . . call e8/call clear-stream/disp32 # . . discard args 81 0/subop/add %esp 4/imm32 # var slice/ecx = {0, 0} 68/push 0/imm32/end 68/push 0/imm32/start 89/<- %ecx 4/r32/esp # write(_test-input-stream, " )\n") # . . push args 68/push " )\n"/imm32 68/push _test-input-stream/imm32 # . . call e8/call write/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 # next-word-string-or-expression-without-metadata(_test-input-stream, slice) # . . push args 51/push-ecx 68/push _test-input-stream/imm32 # . . call e8/call next-word-string-or-expression-without-metadata/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 # check-ints-equal(slice->start, 0, msg) # . . push args 68/push "F - test-next-word-string-or-expression-without-metadata-handles-newline-after-trailing-close-paren: start"/imm32 68/push 0/imm32 ff 6/subop/push *ecx # . . call e8/call check-ints-equal/disp32 # . . discard args 81 0/subop/add %esp 0xc/imm32 # check-ints-equal(slice->end, 0, msg) # . . push args 68/push "F - test-next-word-string-or-expression-without-metadata-handles-newline-after-trailing-close-paren: end"/imm32 68/push 0/imm32 ff 6/subop/push *(ecx+4) # . . call e8/call check-ints-equal/disp32 # . . discard args 81 0/subop/add %esp 0xc/imm32 # . epilogue 89/<- %esp 5/r32/ebp 5d/pop-to-ebp c3/return test-next-word-string-or-expression-without-metadata-stops-at-close-paren: # . prologue 55/push-ebp 89/<- %ebp 4/r32/esp # setup # . clear-stream(_test-input-stream) # . . push args 68/push _test-input-stream/imm32 # . . call e8/call clear-stream/disp32 # . . discard args 81 0/subop/add %esp 4/imm32 # var slice/ecx = {0, 0} 68/push 0/imm32/end 68/push 0/imm32/start 89/<- %ecx 4/r32/esp # write(_test-input-stream, " abc) # def") # . . push args 68/push " abc) # def"/imm32 68/push _test-input-stream/imm32 # . . call e8/call write/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 # next-word-string-or-expression-without-metadata(_test-input-stream, slice) # . . push args 51/push-ecx 68/push _test-input-stream/imm32 # . . call e8/call next-word-string-or-expression-without-metadata/disp32 # . . discard args 81 0/subop/add %esp 8/imm32 # check-ints-equal(slice->start - _test-input-stream->data, 1, msg) # . check-ints-equal(slice->start - _test-input-stream, 13, msg) # . . push args 68/push "F - test-next-word-string-or-expression-without-metadata-stops-at-close-paren: start"/imm32 68/push 0xd/imm32 # . . push slice->start - _test-input-stream 8b/-> *ecx 0/r32/eax 81 5/subop/subtract %eax _test-input-stream/imm32 50/push-eax # . . call e8/call check-ints-equal/disp32 # . . discard args 81 0/subop/add %esp 0xc/imm32 # check-ints-equal(slice->end - _test-input-stream->data, 4, msg) # . check-ints-equal(slice->end - _test-input-stream, 16, msg) # . . push args 68/push "F - test-next-word-string-or-expression-without-metadata-stops-at-close-paren: end"/imm32 68/push 0x10/imm32 # . . push slice->end - _test-input-stream 8b/-> *(ecx+4) 0/r32/eax 81 5/subop/subtract %eax _test-input-stream/imm32 50/push-eax # . . call e8/call check-ints-equal/disp32 # . . discard args 81 0/subop/add %esp 0xc/imm32 # . epilogue 89/<- %esp 5/r32/ebp 5d/pop-to-ebp c3/return