1940 lines
96 KiB
Plaintext
1940 lines
96 KiB
Plaintext
# Translate literal strings within double quotes.
|
|
# Replace them with references to new variables in the data segment.
|
|
#
|
|
# To run:
|
|
# $ bootstrap/bootstrap translate [01]*.subx subx-params.subx dquotes.subx -o dquotes
|
|
# $ cat x
|
|
# == code
|
|
# ab "cd ef"/imm32
|
|
# $ cat x |bootstrap/bootstrap run dquotes
|
|
# == code
|
|
# ab __string1/imm32
|
|
# == data
|
|
# __string1:
|
|
# 5/imm32
|
|
# 0x63/c 0x64/d 0x20/ 0x65/e 0x66/f
|
|
|
|
== code
|
|
# instruction effective address register displacement immediate
|
|
# . op subop mod rm32 base index scale r32
|
|
# . 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
|
|
|
|
Entry: # run tests if necessary, convert stdin if not
|
|
# . prologue
|
|
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
|
|
|
# initialize heap
|
|
# . Heap = new-segment(Heap-size)
|
|
# . . push args
|
|
68/push Heap/imm32
|
|
ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Heap-size/disp32 # push *Heap-size
|
|
# . . call
|
|
e8/call new-segment/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
|
|
# - if argc > 1 and argv[1] == "test", then return run-tests()
|
|
# if (argc <= 1) goto interactive
|
|
81 7/subop/compare 1/mod/*+disp8 5/rm32/ebp . . . . 0/disp8 1/imm32 # compare *ebp
|
|
7e/jump-if-<= $subx-dquotes-main:interactive/disp8
|
|
# if (!kernel-string-equal?(argv[1], "test")) goto interactive
|
|
# . eax = kernel-string-equal?(argv[1], "test")
|
|
# . . push args
|
|
68/push "test"/imm32
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
|
|
# . . call
|
|
e8/call kernel-string-equal?/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# . if (eax == false) goto interactive
|
|
3d/compare-eax-and 0/imm32/false
|
|
74/jump-if-= $subx-dquotes-main:interactive/disp8
|
|
# run-tests()
|
|
e8/call run-tests/disp32
|
|
# syscall_exit(*Num-test-failures)
|
|
8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/ebx Num-test-failures/disp32 # copy *Num-test-failures to ebx
|
|
eb/jump $subx-dquotes-main:end/disp8
|
|
$subx-dquotes-main:interactive:
|
|
# - otherwise convert stdin
|
|
# var ed/eax: exit-descriptor
|
|
81 5/subop/subtract 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # subtract from esp
|
|
89/copy 3/mod/direct 0/rm32/eax . . . 4/r32/esp . . # copy esp to eax
|
|
# configure ed to really exit()
|
|
# . ed->target = 0
|
|
c7 0/subop/copy 0/mod/direct 0/rm32/eax . . . . . 0/imm32 # copy to *eax
|
|
# subx-dquotes(Stdin, Stdout, Stderr, ed)
|
|
# . . push args
|
|
50/push-eax/ed
|
|
68/push Stderr/imm32
|
|
68/push Stdout/imm32
|
|
68/push Stdin/imm32
|
|
# . . call
|
|
e8/call subx-dquotes/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp
|
|
# syscall_exit(0)
|
|
bb/copy-to-ebx 0/imm32
|
|
$subx-dquotes-main:end:
|
|
e8/call syscall_exit/disp32
|
|
|
|
# conceptual hierarchy within a line:
|
|
# line = words separated by ' ', maybe followed by comment starting with '#'
|
|
# word = datum until '/', then 0 or more metadata separated by '/'
|
|
|
|
subx-dquotes: # in: (addr buffered-file), out: (addr buffered-file)
|
|
# pseudocode:
|
|
# var line: (stream byte 512)
|
|
# var new-data-segment-handle: (handle stream byte)
|
|
# new-stream(Heap, Segment-size, 1, new-data-segment-handle)
|
|
# var new-data-segment: (addr stream byte) = lookup(new-data-segment-handle)
|
|
#
|
|
# write(new-data-segment, "== data\n")
|
|
# # TODO: When it was originally written dquotes ran before assort, so
|
|
# # it assumes lots of segment headers, and emits a new segment of its
|
|
# # own. We've since had to reorder the phases (see the explanation
|
|
# # for a.assort2 in translate_subx). We could clean up a.assort2 if we
|
|
# # conditionally emit the previous line. But this would require
|
|
# # teaching dquotes to parse segment headers, so maybe that's not
|
|
# # best..
|
|
#
|
|
# while true
|
|
# clear-stream(line)
|
|
# read-line-buffered(in, line)
|
|
# if (line->write == 0) break # end of file
|
|
# while true
|
|
# var word-slice = next-word-or-string(line)
|
|
# if slice-empty?(word-slice) # end of line
|
|
# break
|
|
# if slice-starts-with?(word-slice, "#") # comment
|
|
# continue
|
|
# if slice-starts-with?(word-slice, '"') # string literal <== what we're here for
|
|
# process-string-literal(word-slice, out, new-data-segment)
|
|
# else
|
|
# write-slice-buffered(out, word-slice)
|
|
# write(out, " ")
|
|
# write(out, "\n\n")
|
|
# write-stream-data(out, new-data-segment)
|
|
# flush(out)
|
|
#
|
|
# . prologue
|
|
55/push-ebp
|
|
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
|
# . save registers
|
|
50/push-eax
|
|
51/push-ecx
|
|
52/push-edx
|
|
53/push-ebx
|
|
56/push-esi
|
|
57/push-edi
|
|
# var line/ecx: (stream byte 512)
|
|
81 5/subop/subtract 3/mod/direct 4/rm32/esp . . . . . 0x200/imm32 # subtract from esp
|
|
68/push 0x200/imm32/length
|
|
68/push 0/imm32/read
|
|
68/push 0/imm32/write
|
|
89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
|
|
# var word-slice/edx: slice
|
|
68/push 0/imm32/end
|
|
68/push 0/imm32/start
|
|
89/copy 3/mod/direct 2/rm32/edx . . . 4/r32/esp . . # copy esp to edx
|
|
# var new-data-segment-handle/edi: (handle stream byte)
|
|
68/push 0/imm32
|
|
68/push 0/imm32
|
|
89/copy 3/mod/direct 7/rm32/edi . . . 4/r32/esp . . # copy esp to edi
|
|
# new-stream(Heap, Segment-size, 1, new-data-segment-handle)
|
|
# . . push args
|
|
57/push-edi
|
|
68/push 1/imm32
|
|
ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Segment-size/disp32 # push *Segment-size
|
|
68/push Heap/imm32
|
|
# . . call
|
|
e8/call new-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp
|
|
# var new-data-segment/edi: (addr stream byte) = lookup(*new-data-segment-handle)
|
|
# . eax = lookup(*new-data-segment-handle)
|
|
# . . push args
|
|
ff 6/subop/push 1/mod/*+disp8 7/rm32/edi . . . . 4/disp8 . # push *(edi+4)
|
|
ff 6/subop/push 0/mod/indirect 7/rm32/edi . . . . . . # push *edi
|
|
# . . call
|
|
e8/call lookup/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# . new-data-segment = eax
|
|
89/copy 3/mod/direct 7/rm32/edi . . . 0/r32/eax . . # copy eax to edi
|
|
# write(new-data-segment, "== data\n")
|
|
# . . push args
|
|
68/push "== data\n"/imm32
|
|
57/push-edi
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
$subx-dquotes:line-loop:
|
|
# clear-stream(line)
|
|
# . . push args
|
|
51/push-ecx
|
|
# . . call
|
|
e8/call clear-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
|
# read-line-buffered(in, line)
|
|
# . . push args
|
|
51/push-ecx
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
|
|
# . . call
|
|
e8/call read-line-buffered/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
$subx-dquotes:check0:
|
|
# if (line->write == 0) break
|
|
81 7/subop/compare 0/mod/indirect 1/rm32/ecx . . . . . 0/imm32 # compare *ecx
|
|
0f 84/jump-if-= $subx-dquotes:break/disp32
|
|
$subx-dquotes:word-loop:
|
|
# next-word-or-string(line, word-slice)
|
|
# . . push args
|
|
52/push-edx
|
|
51/push-ecx
|
|
# . . call
|
|
e8/call next-word-or-string/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
$subx-dquotes:check1:
|
|
# if (slice-empty?(word-slice)) break
|
|
# . eax = slice-empty?(word-slice)
|
|
# . . push args
|
|
52/push-edx
|
|
# . . call
|
|
e8/call slice-empty?/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
|
# . if (eax != false) break
|
|
3d/compare-eax-and 0/imm32/false
|
|
0f 85/jump-if-!= $subx-dquotes:next-line/disp32
|
|
$subx-dquotes:check-for-comment:
|
|
# if (slice-starts-with?(word-slice, "#")) continue
|
|
# . var start/esi: (addr byte) = word-slice->start
|
|
8b/copy 0/mod/indirect 2/rm32/edx . . . 6/r32/esi . . # copy *edx to esi
|
|
# . var c/eax: byte = *start
|
|
31/xor 3/mod/direct 0/rm32/eax . . . 0/r32/eax . . # clear eax
|
|
8a/copy-byte 0/mod/indirect 6/rm32/esi . . . 0/r32/AL . . # copy byte at *esi to AL
|
|
# . if (c == '#') continue
|
|
3d/compare-eax-and 0x23/imm32/hash
|
|
74/jump-if-= $subx-dquotes:word-loop/disp8
|
|
$subx-dquotes:check-for-string-literal:
|
|
# if (slice-starts-with?(word-slice, '"')) continue
|
|
3d/compare-eax-and 0x22/imm32/dquote
|
|
75/jump-if-!= $subx-dquotes:regular-word/disp8
|
|
$subx-dquotes:string-literal:
|
|
# process-string-literal(word-slice, out, new-data-segment)
|
|
# . . push args
|
|
57/push-edi
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12)
|
|
52/push-edx
|
|
# . . call
|
|
e8/call process-string-literal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
# continue
|
|
eb/jump $subx-dquotes:next-word/disp8
|
|
$subx-dquotes:regular-word:
|
|
# write-slice-buffered(out, word-slice)
|
|
# . . push args
|
|
52/push-edx
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12)
|
|
# . . call
|
|
e8/call write-slice-buffered/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# fall through
|
|
$subx-dquotes:next-word:
|
|
# write-buffered(out, " ")
|
|
# . . push args
|
|
68/push Space/imm32
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12)
|
|
# . . call
|
|
e8/call write-buffered/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# loop
|
|
eb/jump $subx-dquotes:word-loop/disp8
|
|
$subx-dquotes:next-line:
|
|
# write-buffered(out, "\n")
|
|
# . . push args
|
|
68/push Newline/imm32
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12)
|
|
# . . call
|
|
e8/call write-buffered/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# loop
|
|
e9/jump $subx-dquotes:line-loop/disp32
|
|
$subx-dquotes:break:
|
|
# write-stream-data(out, new-data-segment)
|
|
# . . push args
|
|
57/push-edi
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12)
|
|
# . . call
|
|
e8/call write-stream-data/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# flush(out)
|
|
# . . push args
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12)
|
|
# . . call
|
|
e8/call flush/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
|
$subx-dquotes:end:
|
|
# . reclaim locals
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x21c/imm32 # add to esp
|
|
# . restore registers
|
|
5f/pop-to-edi
|
|
5e/pop-to-esi
|
|
5b/pop-to-ebx
|
|
5a/pop-to-edx
|
|
59/pop-to-ecx
|
|
58/pop-to-eax
|
|
# . epilogue
|
|
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
# Write out 'string-literal' in a new format to 'out-segment', assign it a new
|
|
# label, and write the new label out to 'out'.
|
|
process-string-literal: # string-literal: (addr slice), out: (addr buffered-file), out-segment: (addr stream byte)
|
|
# pseudocode:
|
|
# print(out-segment, "_string#{Next-string-literal}:\n")
|
|
# emit-string-literal-data(out-segment, string-literal)
|
|
# print(out, "_string#{Next-string-literal}")
|
|
# emit-metadata(out, string-literal)
|
|
# ++ *Next-string-literal
|
|
#
|
|
# . prologue
|
|
55/push-ebp
|
|
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
|
# . save registers
|
|
51/push-ecx
|
|
# var int32-stream/ecx: (stream byte 10) # number of decimal digits a 32-bit number can have
|
|
81 5/subop/subtract 3/mod/direct 4/rm32/esp . . . . . 0xa/imm32 # subtract from esp
|
|
68/push 0xa/imm32/decimal-digits-in-32bit-number
|
|
68/push 0/imm32/read
|
|
68/push 0/imm32/write
|
|
89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
|
|
# print(out-segment, "_string#{Next-string-literal}:\n")
|
|
# . write(out-segment, "_string")
|
|
# . . push args
|
|
68/push "_string"/imm32
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x10/disp8 . # push *(ebp+16)
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# . write-int32-decimal(out-segment, *Next-string-literal)
|
|
# . . push args
|
|
ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Next-string-literal/disp32 # push *Next-string-literal
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x10/disp8 . # push *(ebp+16)
|
|
# . . call
|
|
e8/call write-int32-decimal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# . write(out-segment, ":\n")
|
|
# . . push args
|
|
68/push ":\n"/imm32
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x10/disp8 . # push *(ebp+16)
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# emit-string-literal-data(out-segment, string-literal)
|
|
# . . push args
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x10/disp8 . # push *(ebp+16)
|
|
# . . call
|
|
e8/call emit-string-literal-data/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# write(out-segment, "\n")
|
|
# . . push args
|
|
68/push Newline/imm32
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x10/disp8 . # push *(ebp+16)
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# print(out, "_string#{Next-string-literal}")
|
|
# . write-buffered(out, "_string")
|
|
# . . push args
|
|
68/push "_string"/imm32
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12)
|
|
# . . call
|
|
e8/call write-buffered/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# . write-int32-decimal(int32-stream, *Next-string-literal)
|
|
# . . push args
|
|
ff 6/subop/push 0/mod/indirect 5/rm32/.disp32 . . . Next-string-literal/disp32 # push *Next-string-literal
|
|
51/push-ecx
|
|
# . . call
|
|
e8/call write-int32-decimal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# . write-stream-data(out, int32-stream)
|
|
# . . push args
|
|
51/push-ecx
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12)
|
|
# . . call
|
|
e8/call write-stream-data/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# emit-metadata(out, string-literal)
|
|
# . . push args
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12)
|
|
# . . call
|
|
e8/call emit-metadata/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# ++ *Next-string-literal
|
|
ff 0/subop/increment 0/mod/indirect 5/rm32/.disp32 . . . Next-string-literal/disp32 # increment *Num-test-failures
|
|
$process-string-literal:end:
|
|
# . reclaim locals
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x16/imm32 # add to esp
|
|
# . restore registers
|
|
59/pop-to-ecx
|
|
# . epilogue
|
|
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
test-subx-dquotes-is-idempotent-by-default:
|
|
# . prologue
|
|
55/push-ebp
|
|
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
|
# 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 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
|
# . clear-stream($_test-input-buffered-file->buffer)
|
|
# . . push args
|
|
68/push $_test-input-buffered-file->buffer/imm32
|
|
# . . call
|
|
e8/call clear-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
|
# . 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 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
|
# . clear-stream($_test-output-buffered-file->buffer)
|
|
# . . push args
|
|
68/push $_test-output-buffered-file->buffer/imm32
|
|
# . . call
|
|
e8/call clear-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
|
# initialize input (meta comments in parens)
|
|
# # comment 1
|
|
# # comment 2 indented
|
|
# == code 0x1 (new segment)
|
|
# # comment 3 inside a segment
|
|
# 1
|
|
# (empty line)
|
|
# 2 3 # comment 4 inline with other contents
|
|
# == data 0x2 (new segment)
|
|
# 4 5/imm32
|
|
# . write(_test-input-stream, "# comment 1\n")
|
|
# . . push args
|
|
68/push "# comment 1\n"/imm32
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# . write(_test-input-stream, " # comment 2 indented\n")
|
|
# . . push args
|
|
68/push " # comment 2 indented\n"/imm32
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# . write(_test-input-stream, "== code 0x1\n")
|
|
# . . push args
|
|
68/push "== code 0x1\n"/imm32
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# . write(_test-input-stream, "# comment 3 inside a segment\n")
|
|
# . . push args
|
|
68/push "# comment 3 inside a segment\n"/imm32
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# . write(_test-input-stream, "1\n")
|
|
# . . push args
|
|
68/push "1\n"/imm32
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# . write(_test-input-stream, "\n") # empty line
|
|
# . . push args
|
|
68/push Newline/imm32
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# . write(_test-input-stream, "2 3 # comment 4 inline with other contents\n")
|
|
# . . push args
|
|
68/push "2 3 # comment 4 inline with other contents\n"/imm32
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# . write(_test-input-stream, "== data 0x2\n")
|
|
# . . push args
|
|
68/push "== data 0x2\n"/imm32
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# . write(_test-input-stream, "4 5/imm32\n")
|
|
# . . push args
|
|
68/push "4 5/imm32\n"/imm32
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# subx-dquotes(_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-dquotes/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# . 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 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
|
# check output
|
|
# (comment dropped for now)
|
|
# (comment dropped for now)
|
|
# == code 0x1
|
|
# (comment dropped for now)
|
|
# 1
|
|
# (comment dropped for now)
|
|
# 2 3
|
|
# == data 0x2
|
|
# 4 5/imm32
|
|
# We don't care right now what exactly happens to comments. Trailing spaces are also minor details.
|
|
#? # dump output {{{
|
|
#? # . write(2/stderr, "result: ^")
|
|
#? # . . push args
|
|
#? 68/push "result: ^"/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
#? # . 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 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
#? # . 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 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
#? # }}}
|
|
# . check-next-stream-line-equal(_test-output-stream, "", msg)
|
|
# . . push args
|
|
68/push "F - test-subx-dquotes-is-idempotent-by-default/0"/imm32
|
|
68/push ""/imm32
|
|
68/push _test-output-stream/imm32
|
|
# . . call
|
|
e8/call check-next-stream-line-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
# . check-next-stream-line-equal(_test-output-stream, "", msg)
|
|
# . . push args
|
|
68/push "F - test-subx-dquotes-is-idempotent-by-default/1"/imm32
|
|
68/push ""/imm32
|
|
68/push _test-output-stream/imm32
|
|
# . . call
|
|
e8/call check-next-stream-line-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
# . check-next-stream-line-equal(_test-output-stream, "== code 0x1 ", msg)
|
|
# . . push args
|
|
68/push "F - test-subx-dquotes-is-idempotent-by-default/2"/imm32
|
|
68/push "== code 0x1 "/imm32
|
|
68/push _test-output-stream/imm32
|
|
# . . call
|
|
e8/call check-next-stream-line-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
# . check-next-stream-line-equal(_test-output-stream, "", msg)
|
|
# . . push args
|
|
68/push "F - test-subx-dquotes-is-idempotent-by-default/3"/imm32
|
|
68/push ""/imm32
|
|
68/push _test-output-stream/imm32
|
|
# . . call
|
|
e8/call check-next-stream-line-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
# . check-next-stream-line-equal(_test-output-stream, "1 ", msg)
|
|
# . . push args
|
|
68/push "F - test-subx-dquotes-is-idempotent-by-default/4"/imm32
|
|
68/push "1 "/imm32
|
|
68/push _test-output-stream/imm32
|
|
# . . call
|
|
e8/call check-next-stream-line-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
# . check-next-stream-line-equal(_test-output-stream, "", msg)
|
|
# . . push args
|
|
68/push "F - test-subx-dquotes-is-idempotent-by-default/5"/imm32
|
|
68/push ""/imm32
|
|
68/push _test-output-stream/imm32
|
|
# . . call
|
|
e8/call check-next-stream-line-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
# . check-next-stream-line-equal(_test-output-stream, "2 3 ", msg)
|
|
# . . push args
|
|
68/push "F - test-subx-dquotes-is-idempotent-by-default/6"/imm32
|
|
68/push "2 3 "/imm32
|
|
68/push _test-output-stream/imm32
|
|
# . . call
|
|
e8/call check-next-stream-line-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
# . check-next-stream-line-equal(_test-output-stream, "== data 0x2 ", msg)
|
|
# . . push args
|
|
68/push "F - test-subx-dquotes-is-idempotent-by-default/7"/imm32
|
|
68/push "== data 0x2 "/imm32
|
|
68/push _test-output-stream/imm32
|
|
# . . call
|
|
e8/call check-next-stream-line-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
# . check-next-stream-line-equal(_test-output-stream, "4 5/imm32 ", msg)
|
|
# . . push args
|
|
68/push "F - test-subx-dquotes-is-idempotent-by-default/8"/imm32
|
|
68/push "4 5/imm32 "/imm32
|
|
68/push _test-output-stream/imm32
|
|
# . . call
|
|
e8/call check-next-stream-line-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
# . epilogue
|
|
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
test-subx-dquotes-processes-string-literals:
|
|
# . prologue
|
|
55/push-ebp
|
|
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
|
# 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 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
|
# . clear-stream($_test-input-buffered-file->buffer)
|
|
# . . push args
|
|
68/push $_test-input-buffered-file->buffer/imm32
|
|
# . . call
|
|
e8/call clear-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
|
# . 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 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
|
# . clear-stream($_test-output-buffered-file->buffer)
|
|
# . . push args
|
|
68/push $_test-output-buffered-file->buffer/imm32
|
|
# . . call
|
|
e8/call clear-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
|
# initialize input (meta comments in parens)
|
|
# == code (new segment)
|
|
# 1 "a"/x
|
|
# 2 "bc"/y
|
|
68/push "== code 0x1\n"/imm32
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# . write(_test-input-stream, "1 \"a\"/x\n")
|
|
# . . push args
|
|
68/push "1 \"a\"/x\n"/imm32
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# . write(_test-input-stream, "2 \"bc\"/y\n")
|
|
# . . push args
|
|
68/push "2 \"bc\"/y\n"/imm32
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# subx-dquotes(_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-dquotes/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# . 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 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
|
# check output
|
|
# == code 0x1
|
|
# 1 _string1/x
|
|
# 2 _string2/y
|
|
# == data
|
|
# _string1:
|
|
# 1/imm32 61/a
|
|
# _string2:
|
|
# 2/imm32 62/b 63/c
|
|
# We don't care right now what exactly happens to comments. Trailing spaces are also minor details.
|
|
#
|
|
# Open question: how to make this check more robust.
|
|
# We don't actually care what the auto-generated string variables are
|
|
# called. We just want to make sure instructions using string literals
|
|
# switch to a string variable with the right value.
|
|
# (Modifying string literals completely off the radar for now.)
|
|
#? # dump output {{{
|
|
#? # . write(2/stderr, "result: ^")
|
|
#? # . . push args
|
|
#? 68/push "result: ^"/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
#? # . 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 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
#? # . 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 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
#? # . 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 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
|
#? # }}}
|
|
# . check-next-stream-line-equal(_test-output-stream, "== code 0x1 ", msg)
|
|
# . . push args
|
|
68/push "F - test-subx-dquotes-processes-string-literals/0"/imm32
|
|
68/push "== code 0x1 "/imm32
|
|
68/push _test-output-stream/imm32
|
|
# . . call
|
|
e8/call check-next-stream-line-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
# . check-next-stream-line-equal(_test-output-stream, "1 _string1/x ", msg)
|
|
# . . push args
|
|
68/push "F - test-subx-dquotes-processes-string-literals/1"/imm32
|
|
68/push "1 _string1/x "/imm32
|
|
68/push _test-output-stream/imm32
|
|
# . . call
|
|
e8/call check-next-stream-line-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
# . check-next-stream-line-equal(_test-output-stream, "2 _string2/y ", msg)
|
|
# . . push args
|
|
68/push "F - test-subx-dquotes-processes-string-literals/2"/imm32
|
|
68/push "2 _string2/y "/imm32
|
|
68/push _test-output-stream/imm32
|
|
# . . call
|
|
e8/call check-next-stream-line-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
# . check-next-stream-line-equal(_test-output-stream, "== data", msg)
|
|
# . . push args
|
|
68/push "F - test-subx-dquotes-processes-string-literals/3"/imm32
|
|
68/push "== data"/imm32
|
|
68/push _test-output-stream/imm32
|
|
# . . call
|
|
e8/call check-next-stream-line-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
# . check-next-stream-line-equal(_test-output-stream, "_string1: ", msg)
|
|
# . . push args
|
|
68/push "F - test-subx-dquotes-processes-string-literals/4"/imm32
|
|
68/push "_string1:"/imm32
|
|
68/push _test-output-stream/imm32
|
|
# . . call
|
|
e8/call check-next-stream-line-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
# . check-next-stream-line-equal(_test-output-stream, "1/imm32 61/a ", msg)
|
|
# . . push args
|
|
68/push "F - test-subx-dquotes-processes-string-literals/5"/imm32
|
|
68/push "0x00000001/imm32 61/a "/imm32
|
|
68/push _test-output-stream/imm32
|
|
# . . call
|
|
e8/call check-next-stream-line-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
# . check-next-stream-line-equal(_test-output-stream, "_string2: ", msg)
|
|
# . . push args
|
|
68/push "F - test-subx-dquotes-processes-string-literals/6"/imm32
|
|
68/push "_string2:"/imm32
|
|
68/push _test-output-stream/imm32
|
|
# . . call
|
|
e8/call check-next-stream-line-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
# . check-next-stream-line-equal(_test-output-stream, "2/imm32 62/b 63/c ", msg)
|
|
# . . push args
|
|
68/push "F - test-subx-dquotes-processes-string-literals/7"/imm32
|
|
68/push "0x00000002/imm32 62/b 63/c "/imm32
|
|
68/push _test-output-stream/imm32
|
|
# . . call
|
|
e8/call check-next-stream-line-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
# . epilogue
|
|
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
# generate the data segment contents byte by byte for a given slice
|
|
emit-string-literal-data: # out: (addr stream byte), word: (addr slice)
|
|
# pseudocode
|
|
# len = string-length-at-start-of-slice(word->start, word->end)
|
|
# print(out, "#{len}/imm32 ")
|
|
# curr = word->start
|
|
# ++curr # skip '"'
|
|
# idx = 0
|
|
# while true
|
|
# if (curr >= word->end) break
|
|
# c = *curr
|
|
# if (c == '"') break
|
|
# if (c == '\') {
|
|
# ++curr
|
|
# c = *curr
|
|
# if (c == 'n')
|
|
# c = newline
|
|
# }
|
|
# append-byte-hex(out, c)
|
|
# if c is alphanumeric:
|
|
# write(out, "/")
|
|
# append-byte(out, c)
|
|
# write(out, " ")
|
|
# ++curr
|
|
# ++idx
|
|
# if idx >= 0x40
|
|
# idx = 0
|
|
# write(out, "\n")
|
|
#
|
|
# . prologue
|
|
55/push-ebp
|
|
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
|
# . save registers
|
|
50/push-eax
|
|
51/push-ecx
|
|
52/push-edx
|
|
53/push-ebx
|
|
56/push-esi
|
|
# esi = word
|
|
8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 0xc/disp8 . # copy *(ebp+12) to esi
|
|
# var idx/ebx: int = 0
|
|
31/xor 3/mod/direct 3/rm32/ebx . . . 3/r32/ebx . . # clear ebx
|
|
# var curr/edx: (addr byte) = word->start
|
|
8b/copy 0/mod/indirect 6/rm32/esi . . . 2/r32/edx . . # copy *esi to edx
|
|
# var max/esi: (addr byte) = word->end
|
|
8b/copy 1/mod/*+disp8 6/rm32/esi . . . 6/r32/esi 4/disp8 . # copy *(esi+4) to esi
|
|
$emit-string-literal-data:emit-length:
|
|
# var len/eax: int = string-length-at-start-of-slice(word->start, word->end)
|
|
# . . push args
|
|
56/push-esi
|
|
52/push-edx
|
|
# . . call
|
|
e8/call string-length-at-start-of-slice/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# print(out, "#{len}/imm32 ")
|
|
# . write-int32-hex(out, len)
|
|
# . . push args
|
|
50/push-eax
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
|
|
# . . call
|
|
e8/call write-int32-hex/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# . write(out, "/imm32 ")
|
|
# . . push args
|
|
68/push "/imm32 "/imm32
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
$emit-string-literal-data:loop-init:
|
|
# ++curr # skip initial '"'
|
|
42/increment-edx
|
|
# var c/ecx: byte = 0
|
|
31/xor 3/mod/direct 1/rm32/ecx . . . 1/r32/ecx . . # clear ecx
|
|
$emit-string-literal-data:loop:
|
|
# if (curr >= max) break
|
|
39/compare 3/mod/direct 2/rm32/edx . . . 6/r32/esi . . # compare edx with esi
|
|
0f 83/jump-if-addr>= $emit-string-literal-data:end/disp32
|
|
# CL = *curr
|
|
8a/copy-byte 0/mod/indirect 2/rm32/edx . . . 1/r32/CL . . # copy byte at *edx to CL
|
|
# if (c == '"') break
|
|
81 7/subop/compare 3/mod/direct 1/rm32/ecx . . . . . 0x22/imm32/dquote # compare ecx
|
|
0f 84/jump-if-= $emit-string-literal-data:end/disp32
|
|
# if (c != '\') goto emit
|
|
81 7/subop/compare 3/mod/direct 1/rm32/ecx . . . . . 0x5c/imm32/backslash # compare ecx
|
|
75/jump-if-!= $emit-string-literal-data:emit/disp8
|
|
# ++curr
|
|
42/increment-edx
|
|
# if (curr >= max) break
|
|
39/compare 3/mod/direct 2/rm32/edx . . . 6/r32/esi . . # compare edx with esi
|
|
0f 83/jump-if-addr>= $emit-string-literal-data:end/disp32
|
|
# c = *curr
|
|
8a/copy-byte 0/mod/indirect 2/rm32/edx . . . 1/r32/CL . . # copy byte at *edx to CL
|
|
# if (c == 'n') c = newline
|
|
81 7/subop/compare 3/mod/direct 1/rm32/ecx . . . . . 0x6e/imm32/n # compare ecx
|
|
75/jump-if-!= $emit-string-literal-data:emit/disp8
|
|
b9/copy-to-ecx 0x0a/imm32/newline
|
|
$emit-string-literal-data:emit:
|
|
# append-byte-hex(out, CL)
|
|
# . . push args
|
|
51/push-ecx
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
|
|
# . . call
|
|
e8/call append-byte-hex/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# if (alphanumeric?(*curr)) print(out, "/#{*curr}")
|
|
# . var eax: boolean = alphanumeric?(CL)
|
|
# . . push args
|
|
51/push-ecx
|
|
# . . call
|
|
e8/call alphanumeric?/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
|
# . if (eax == false) goto char-done
|
|
3d/compare-eax-and 0/imm32/false
|
|
74/jump-if-= $emit-string-literal-data:char-done/disp8
|
|
# . write(out, "/")
|
|
# . . push args
|
|
68/push Slash/imm32
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# . append-byte(out, *curr)
|
|
# . . push args
|
|
51/push-ecx
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
|
|
# . . call
|
|
e8/call append-byte/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
$emit-string-literal-data:char-done:
|
|
# write(out, " ")
|
|
# . . push args
|
|
68/push Space/imm32
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# ++curr
|
|
42/increment-edx
|
|
# ++ idx
|
|
43/increment-ebx
|
|
# if (idx < 0x40) continue
|
|
81 7/subop/compare 3/mod/direct 3/rm32/ebx . . . . . 0x40/imm32 # compare ebx
|
|
7c/jump-if-< $emit-string-literal-data:next-char/disp8
|
|
# idx = 0
|
|
31/xor 3/mod/direct 3/rm32/ebx . . . 3/r32/ebx . . # clear ebx
|
|
# write(out, "\n")
|
|
# . . push args
|
|
68/push Newline/imm32
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
|
|
# . . call
|
|
e8/call write/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
$emit-string-literal-data:next-char:
|
|
e9/jump $emit-string-literal-data:loop/disp32
|
|
$emit-string-literal-data:end:
|
|
# . restore registers
|
|
5e/pop-to-esi
|
|
5b/pop-to-ebx
|
|
5a/pop-to-edx
|
|
59/pop-to-ecx
|
|
58/pop-to-eax
|
|
# . epilogue
|
|
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
alphanumeric?: # c: int -> eax: boolean
|
|
# . prologue
|
|
55/push-ebp
|
|
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
|
# eax = c
|
|
8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 8/disp8 . # copy *(ebp+8) to eax
|
|
# if (c < '0') return false
|
|
3d/compare-eax-with 0x30/imm32/0
|
|
7c/jump-if-< $alphanumeric?:false/disp8
|
|
# if (c <= '9') return true
|
|
3d/compare-eax-with 0x39/imm32/9
|
|
7e/jump-if-<= $alphanumeric?:true/disp8
|
|
# if (c < 'A') return false
|
|
3d/compare-eax-with 0x41/imm32/A
|
|
7c/jump-if-< $alphanumeric?:false/disp8
|
|
# if (c <= 'Z') return true
|
|
3d/compare-eax-with 0x5a/imm32/Z
|
|
7e/jump-if-<= $alphanumeric?:true/disp8
|
|
# if (c < 'a') return false
|
|
3d/compare-eax-with 0x61/imm32/a
|
|
7c/jump-if-< $alphanumeric?:false/disp8
|
|
# if (c <= 'z') return true
|
|
3d/compare-eax-with 0x7a/imm32/z
|
|
7e/jump-if-<= $alphanumeric?:true/disp8
|
|
# return false
|
|
$alphanumeric?:false:
|
|
b8/copy-to-eax 0/imm32/false
|
|
eb/jump $alphanumeric?:end/disp8
|
|
$alphanumeric?:true:
|
|
b8/copy-to-eax 1/imm32/true
|
|
$alphanumeric?:end:
|
|
# . epilogue
|
|
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
test-emit-string-literal-data:
|
|
# . prologue
|
|
55/push-ebp
|
|
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
|
# setup
|
|
# . 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 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
|
# var slice/ecx = '"abc"/d'
|
|
68/push _test-slice-abc-limit/imm32
|
|
68/push _test-slice-abc/imm32
|
|
89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
|
|
# emit-string-literal-data(_test-output-stream, slice)
|
|
# . . push args
|
|
51/push-ecx
|
|
68/push _test-output-stream/imm32
|
|
# . . call
|
|
e8/call emit-string-literal-data/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
#? # dump output {{{
|
|
#? # . write(2/stderr, "result: ^")
|
|
#? # . . push args
|
|
#? 68/push "result: ^"/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
#? # . 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 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
#? # . 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 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
#? # }}}
|
|
# . check-stream-equal(_test-output-stream, "3/imm32 61/a 62/b 63/c ", msg)
|
|
# . . push args
|
|
68/push "F - test-emit-string-literal-data"/imm32
|
|
68/push "0x00000003/imm32 61/a 62/b 63/c "/imm32
|
|
68/push _test-output-stream/imm32
|
|
# . . call
|
|
e8/call check-stream-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
# . epilogue
|
|
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
test-emit-string-literal-data-empty:
|
|
# . prologue
|
|
55/push-ebp
|
|
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
|
# setup
|
|
# . 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 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
|
# var slice/ecx = '""'
|
|
68/push 0/imm32/end
|
|
68/push 0/imm32/start
|
|
89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
|
|
# emit-string-literal-data(_test-output-stream, slice)
|
|
# . . push args
|
|
51/push-ecx
|
|
68/push _test-output-stream/imm32
|
|
# . . call
|
|
e8/call emit-string-literal-data/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
#? # dump output {{{
|
|
#? # . write(2/stderr, "result: ^")
|
|
#? # . . push args
|
|
#? 68/push "result: ^"/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
#? # . 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 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
#? # . 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 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
#? # }}}
|
|
# . check-stream-equal(_test-output-stream, "0/imm32 ", msg)
|
|
# . . push args
|
|
68/push "F - test-emit-string-literal-data-empty"/imm32
|
|
68/push "0x00000000/imm32 "/imm32
|
|
68/push _test-output-stream/imm32
|
|
# . . call
|
|
e8/call check-stream-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
# . epilogue
|
|
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
# just to keep things simple
|
|
test-emit-string-literal-data-no-metadata-for-non-alphanumerics:
|
|
# . prologue
|
|
55/push-ebp
|
|
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
|
# setup
|
|
# . 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 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
|
# var slice/ecx = '"a b"'
|
|
68/push _test-slice-a-space-b-limit/imm32
|
|
68/push _test-slice-a-space-b/imm32
|
|
89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
|
|
# emit-string-literal-data(_test-output-stream, slice)
|
|
# . . push args
|
|
51/push-ecx
|
|
68/push _test-output-stream/imm32
|
|
# . . call
|
|
e8/call emit-string-literal-data/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
#? # dump output {{{
|
|
#? # . write(2/stderr, "result: ^")
|
|
#? # . . push args
|
|
#? 68/push "result: ^"/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
#? # . 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 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
#? # . 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 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
#? # }}}
|
|
# . check-stream-equal(_test-output-stream, "3/imm32 61/a 20 62/b ", msg) # ideally we'd like to say '20/space' but that requires managing names for codepoints
|
|
# . . push args
|
|
68/push "F - test-emit-string-literal-data-no-metadata-for-non-alphanumerics"/imm32
|
|
68/push "0x00000003/imm32 61/a 20 62/b "/imm32
|
|
68/push _test-output-stream/imm32
|
|
# . . call
|
|
e8/call check-stream-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
# . epilogue
|
|
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
test-emit-string-literal-data-handles-escape-sequences:
|
|
# . prologue
|
|
55/push-ebp
|
|
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
|
# setup
|
|
# . 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 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
|
# var slice/ecx = '"a\"b"'
|
|
68/push _test-slice-a-dquote-b-limit/imm32
|
|
68/push _test-slice-a-dquote-b/imm32
|
|
89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
|
|
# emit-string-literal-data(_test-output-stream, slice)
|
|
# . . push args
|
|
51/push-ecx
|
|
68/push _test-output-stream/imm32
|
|
# . . call
|
|
e8/call emit-string-literal-data/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
#? # dump output {{{
|
|
#? # . write(2/stderr, "result: ^")
|
|
#? # . . push args
|
|
#? 68/push "result: ^"/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
#? # . 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 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
#? # . 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 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
#? # }}}
|
|
# . check-stream-equal(_test-output-stream, "3/imm32 61/a 22 62/b ", msg)
|
|
# . . push args
|
|
68/push "F - test-emit-string-literal-data-handles-escape-sequences"/imm32
|
|
68/push "0x00000003/imm32 61/a 22 62/b "/imm32
|
|
68/push _test-output-stream/imm32
|
|
# . . call
|
|
e8/call check-stream-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
# . epilogue
|
|
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
test-emit-string-literal-data-handles-newline-escape:
|
|
# . prologue
|
|
55/push-ebp
|
|
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
|
# setup
|
|
# . 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 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
|
# var slice/ecx = '"a\nb"'
|
|
68/push _test-slice-a-newline-b-limit/imm32
|
|
68/push _test-slice-a-newline-b/imm32
|
|
89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
|
|
# emit-string-literal-data(_test-output-stream, slice)
|
|
# . . push args
|
|
51/push-ecx
|
|
68/push _test-output-stream/imm32
|
|
# . . call
|
|
e8/call emit-string-literal-data/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
#? # dump output {{{
|
|
#? # . write(2/stderr, "result: ^")
|
|
#? # . . push args
|
|
#? 68/push "result: ^"/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
#? # . 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 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
#? # . 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 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
#? # }}}
|
|
# . check-stream-equal(_test-output-stream, "3/imm32 61/a 0a 62/b ", msg)
|
|
# . . push args
|
|
68/push "F - test-emit-string-literal-data-handles-newline-escape"/imm32
|
|
68/push "0x00000003/imm32 61/a 0a 62/b "/imm32
|
|
68/push _test-output-stream/imm32
|
|
# . . call
|
|
e8/call check-stream-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
# . epilogue
|
|
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
# emit everything from a word except the initial datum
|
|
emit-metadata: # out: (addr buffered-file), word: (addr slice)
|
|
# pseudocode
|
|
# var slice: slice = {0, word->end}
|
|
# curr = word->start
|
|
# if *curr == '"'
|
|
# curr = skip-string-in-slice(curr, word->end)
|
|
# else
|
|
# while true
|
|
# if curr == word->end
|
|
# return
|
|
# if *curr == '/'
|
|
# break
|
|
# ++curr
|
|
# slice->start = curr
|
|
# write-slice-buffered(out, slice)
|
|
#
|
|
# . prologue
|
|
55/push-ebp
|
|
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
|
# . save registers
|
|
50/push-eax
|
|
51/push-ecx
|
|
52/push-edx
|
|
53/push-ebx
|
|
56/push-esi
|
|
# esi = word
|
|
8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 0xc/disp8 . # copy *(ebp+12) to esi
|
|
# var curr/ecx: (addr byte) = word->start
|
|
8b/copy 0/mod/indirect 6/rm32/esi . . . 1/r32/ecx . . # copy *esi to ecx
|
|
# var end/edx: (addr byte) = word->end
|
|
8b/copy 1/mod/*+disp8 6/rm32/esi . . . 2/r32/edx 4/disp8 . # copy *(esi+4) to edx
|
|
# var slice/ebx: slice = {0, end}
|
|
52/push-edx
|
|
68/push 0/imm32
|
|
89/copy 3/mod/direct 3/rm32/ebx . . . 4/r32/esp . . # copy esp to ebx
|
|
# eax = 0
|
|
b8/copy-to-eax 0/imm32
|
|
$emit-metadata:check-for-string-literal:
|
|
# - if (*curr == '"') curr = skip-string-in-slice(curr, end)
|
|
8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 0/r32/AL . . # copy byte at *ecx to AL
|
|
3d/compare-eax-and 0x22/imm32/dquote
|
|
75/jump-if-!= $emit-metadata:skip-datum-loop/disp8
|
|
$emit-metadata:skip-string-literal:
|
|
# . eax = skip-string-in-slice(curr, end)
|
|
# . . push args
|
|
52/push-edx
|
|
51/push-ecx
|
|
# . . call
|
|
e8/call skip-string-in-slice/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# . curr = eax
|
|
89/copy 3/mod/direct 1/rm32/ecx . . . 0/r32/eax . . # copy eax to ecx
|
|
eb/jump $emit-metadata:emit/disp8
|
|
$emit-metadata:skip-datum-loop:
|
|
# - otherwise scan for '/'
|
|
# if (curr == end) return
|
|
39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx and edx
|
|
74/jump-if-= $emit-metadata:end/disp8
|
|
# if (*curr == '/') break
|
|
8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 0/r32/AL . . # copy byte at *ecx to AL
|
|
3d/compare-eax-and 0x2f/imm32/slash
|
|
74/jump-if-= $emit-metadata:emit/disp8
|
|
# ++curr
|
|
41/increment-ecx
|
|
eb/jump $emit-metadata:skip-datum-loop/disp8
|
|
$emit-metadata:emit:
|
|
# slice->start = ecx
|
|
89/copy 0/mod/indirect 3/rm32/ebx . . . 1/r32/ecx . . # copy ecx to *ebx
|
|
# write-slice-buffered(out, slice)
|
|
# . . push args
|
|
53/push-ebx
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
|
|
# . . call
|
|
e8/call write-slice-buffered/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . 8/imm32 . # add to esp
|
|
$emit-metadata:end:
|
|
# . reclaim locals
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . 8/imm32 . # add to esp
|
|
# . restore registers
|
|
5e/pop-to-esi
|
|
5b/pop-to-ebx
|
|
5a/pop-to-edx
|
|
59/pop-to-ecx
|
|
58/pop-to-eax
|
|
# . epilogue
|
|
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
test-emit-metadata:
|
|
# . prologue
|
|
55/push-ebp
|
|
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
|
# setup
|
|
# . 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 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
|
# . clear-stream($_test-output-buffered-file->buffer)
|
|
# . . push args
|
|
68/push $_test-output-buffered-file->buffer/imm32
|
|
# . . call
|
|
e8/call clear-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
|
# (eax..ecx) = "abc/def"
|
|
b8/copy-to-eax "abc/def"/imm32
|
|
8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
|
|
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
|
|
05/add-to-eax 4/imm32
|
|
# var slice/ecx = {eax, ecx}
|
|
51/push-ecx
|
|
50/push-eax
|
|
89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
|
|
# emit-metadata(_test-output-buffered-file, slice)
|
|
# . . push args
|
|
51/push-ecx
|
|
68/push _test-output-buffered-file/imm32
|
|
# . . call
|
|
e8/call emit-metadata/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# 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 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
|
# check-stream-equal(_test-output-stream, "/def", msg) # important that there's no leading space
|
|
# . . push args
|
|
68/push "F - test-emit-metadata"/imm32
|
|
68/push "/def"/imm32
|
|
68/push _test-output-stream/imm32
|
|
# . . call
|
|
e8/call check-stream-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
# . epilogue
|
|
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
test-emit-metadata-none:
|
|
# . prologue
|
|
55/push-ebp
|
|
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
|
# setup
|
|
# . 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 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
|
# . clear-stream($_test-output-buffered-file->buffer)
|
|
# . . push args
|
|
68/push $_test-output-buffered-file->buffer/imm32
|
|
# . . call
|
|
e8/call clear-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
|
# (eax..ecx) = "abc"
|
|
b8/copy-to-eax "abc"/imm32
|
|
8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
|
|
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
|
|
05/add-to-eax 4/imm32
|
|
# var slice/ecx = {eax, ecx}
|
|
51/push-ecx
|
|
50/push-eax
|
|
89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
|
|
# emit-metadata(_test-output-buffered-file, slice)
|
|
# . . push args
|
|
51/push-ecx
|
|
68/push _test-output-buffered-file/imm32
|
|
# . . call
|
|
e8/call emit-metadata/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# 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 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
|
# check-stream-equal(_test-output-stream, "", msg)
|
|
# . . push args
|
|
68/push "F - test-emit-metadata-none"/imm32
|
|
68/push ""/imm32
|
|
68/push _test-output-stream/imm32
|
|
# . . call
|
|
e8/call check-stream-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
# . epilogue
|
|
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
test-emit-metadata-multiple:
|
|
# . prologue
|
|
55/push-ebp
|
|
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
|
# setup
|
|
# . 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 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
|
# . clear-stream($_test-output-buffered-file->buffer)
|
|
# . . push args
|
|
68/push $_test-output-buffered-file->buffer/imm32
|
|
# . . call
|
|
e8/call clear-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
|
# (eax..ecx) = "abc/def/ghi"
|
|
b8/copy-to-eax "abc/def/ghi"/imm32
|
|
8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
|
|
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
|
|
05/add-to-eax 4/imm32
|
|
# var slice/ecx = {eax, ecx}
|
|
51/push-ecx
|
|
50/push-eax
|
|
89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
|
|
# emit-metadata(_test-output-buffered-file, slice)
|
|
# . . push args
|
|
51/push-ecx
|
|
68/push _test-output-buffered-file/imm32
|
|
# . . call
|
|
e8/call emit-metadata/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# 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 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
|
# check-stream-equal(_test-output-stream, "/def/ghi", msg) # important that there's no leading space
|
|
# . . push args
|
|
68/push "F - test-emit-metadata-multiple"/imm32
|
|
68/push "/def/ghi"/imm32
|
|
68/push _test-output-stream/imm32
|
|
# . . call
|
|
e8/call check-stream-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
# . epilogue
|
|
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
test-emit-metadata-when-no-datum:
|
|
# . prologue
|
|
55/push-ebp
|
|
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
|
# setup
|
|
# . 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 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
|
# . clear-stream($_test-output-buffered-file->buffer)
|
|
# . . push args
|
|
68/push $_test-output-buffered-file->buffer/imm32
|
|
# . . call
|
|
e8/call clear-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
|
# var slice/ecx = "/abc"
|
|
b8/copy-to-eax "/abc"/imm32
|
|
# . push end/ecx
|
|
8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
|
|
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
|
|
51/push-ecx
|
|
# . push curr/eax
|
|
05/add-to-eax 4/imm32
|
|
50/push-eax
|
|
# . save stack pointer
|
|
89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
|
|
# emit-metadata(_test-output-buffered-file, slice)
|
|
# . . push args
|
|
51/push-ecx
|
|
68/push _test-output-buffered-file/imm32
|
|
# . . call
|
|
e8/call emit-metadata/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# 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 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
|
# check-stream-equal(_test-output-stream, "/abc", msg) # nothing skipped
|
|
# . . push args
|
|
68/push "F - test-emit-metadata-when-no-datum"/imm32
|
|
68/push "/abc"/imm32
|
|
68/push _test-output-stream/imm32
|
|
# . . call
|
|
e8/call check-stream-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
# . epilogue
|
|
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
test-emit-metadata-in-string-literal:
|
|
# . prologue
|
|
55/push-ebp
|
|
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
|
# setup
|
|
# . 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 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
|
# . clear-stream($_test-output-buffered-file->buffer)
|
|
# . . push args
|
|
68/push $_test-output-buffered-file->buffer/imm32
|
|
# . . call
|
|
e8/call clear-stream/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
|
# var slice/ecx = "\"abc/def\"/ghi"
|
|
68/push _test-slice-literal-string-with-limit/imm32
|
|
68/push _test-slice-literal-string/imm32/start
|
|
89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
|
|
# emit-metadata(_test-output-buffered-file, slice)
|
|
# . . push args
|
|
51/push-ecx
|
|
68/push _test-output-buffered-file/imm32
|
|
# . . call
|
|
e8/call emit-metadata/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# 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 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
|
#? # dump output {{{
|
|
#? # . write(2/stderr, "result: ^")
|
|
#? # . . push args
|
|
#? 68/push "result: ^"/imm32
|
|
#? 68/push 2/imm32/stderr
|
|
#? # . . call
|
|
#? e8/call write/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
#? # . 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 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
#? # . 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 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
#? # }}}
|
|
# check-stream-equal(_test-output-stream, "/ghi", msg) # important that there's no leading space
|
|
# . . push args
|
|
68/push "F - test-emit-metadata-in-string-literal"/imm32
|
|
68/push "/ghi"/imm32
|
|
68/push _test-output-stream/imm32
|
|
# . . call
|
|
e8/call check-stream-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
# . epilogue
|
|
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
string-length-at-start-of-slice: # curr: (addr byte), end: (addr byte) -> length/eax
|
|
# . prologue
|
|
55/push-ebp
|
|
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
|
# . save registers
|
|
51/push-ecx
|
|
52/push-edx
|
|
53/push-ebx
|
|
# ecx = curr
|
|
8b/copy 1/mod/*+disp8 5/rm32/ebp . . 1/r32/ecx 8/disp8 . # copy *(ebp+8) to ecx
|
|
# edx = end
|
|
8b/copy 1/mod/*+disp8 5/rm32/ebp . . 2/r32/edx 0xc/disp8 . # copy *(ebp+12) to edx
|
|
# var length/eax: int = 0
|
|
31/xor 3/mod/direct 0/rm32/eax . . . 0/r32/eax . . # clear eax
|
|
# var c/ebx: byte = 0
|
|
31/xor 3/mod/direct 3/rm32/ebx . . . 3/r32/ebx . . # clear ebx
|
|
# skip initial dquote
|
|
41/increment-ecx
|
|
$string-length-at-start-of-slice:loop:
|
|
# if (curr >= end) return length
|
|
39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx
|
|
73/jump-if-addr>= $string-length-at-start-of-slice:end/disp8
|
|
# c = *curr
|
|
8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 3/r32/BL . . # copy byte at *ecx to BL
|
|
$string-length-at-start-of-slice:dquote:
|
|
# if (c == '"') break
|
|
81 7/subop/compare 3/mod/direct 3/rm32/ebx . . . . . 0x22/imm32/dquote # compare ebx
|
|
74/jump-if-= $string-length-at-start-of-slice:end/disp8
|
|
$string-length-at-start-of-slice:check-for-escape:
|
|
# if (c == '\') escape next char
|
|
81 7/subop/compare 3/mod/direct 3/rm32/ebx . . . . . 0x5c/imm32/backslash # compare ebx
|
|
75/jump-if-!= $string-length-at-start-of-slice:continue/disp8
|
|
$string-length-at-start-of-slice:escape:
|
|
# increment curr but not result
|
|
41/increment-ecx
|
|
$string-length-at-start-of-slice:continue:
|
|
# ++result
|
|
40/increment-eax
|
|
# ++curr
|
|
41/increment-ecx
|
|
eb/jump $string-length-at-start-of-slice:loop/disp8
|
|
$string-length-at-start-of-slice:end:
|
|
# . restore registers
|
|
5b/pop-to-ebx
|
|
5a/pop-to-edx
|
|
59/pop-to-ecx
|
|
# . epilogue
|
|
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
test-string-length-at-start-of-slice:
|
|
# . prologue
|
|
55/push-ebp
|
|
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
|
# setup: (eax..ecx) = "\"abc\" def"
|
|
b8/copy-to-eax "\"abc\" def"/imm32
|
|
8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
|
|
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
|
|
05/add-to-eax 4/imm32
|
|
# eax = string-length-at-start-of-slice(eax, ecx)
|
|
# . . push args
|
|
51/push-ecx
|
|
50/push-eax
|
|
# . . call
|
|
e8/call string-length-at-start-of-slice/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# check-ints-equal(eax, 3, msg)
|
|
# . . push args
|
|
68/push "F - test-string-length-at-start-of-slice"/imm32
|
|
68/push 3/imm32
|
|
50/push-eax
|
|
# . . call
|
|
e8/call check-ints-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
# . epilogue
|
|
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
test-string-length-at-start-of-slice-escaped:
|
|
# . prologue
|
|
55/push-ebp
|
|
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
|
# setup: (eax..ecx) = "\"ab\\c\" def"
|
|
b8/copy-to-eax "\"ab\\c\" def"/imm32
|
|
8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
|
|
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
|
|
05/add-to-eax 4/imm32
|
|
# eax = string-length-at-start-of-slice(eax, ecx)
|
|
# . . push args
|
|
51/push-ecx
|
|
50/push-eax
|
|
# . . call
|
|
e8/call string-length-at-start-of-slice/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
|
# check-ints-equal(eax, 3, msg)
|
|
# . . push args
|
|
68/push "F - test-string-length-at-start-of-slice-escaped"/imm32
|
|
68/push 3/imm32
|
|
50/push-eax
|
|
# . . call
|
|
e8/call check-ints-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
|
# . epilogue
|
|
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
== data
|
|
|
|
Next-string-literal: # tracks the next auto-generated variable name
|
|
1/imm32
|
|
|
|
_test-slice-abc:
|
|
22/dquote 61/a 62/b 63/c 22/dquote # "abc"
|
|
2f/slash 64/d
|
|
_test-slice-abc-limit:
|
|
|
|
_test-slice-a-space-b:
|
|
22/dquote 61/a 20/space 62/b 22/dquote # "a b"
|
|
_test-slice-a-space-b-limit:
|
|
|
|
_test-slice-a-dquote-b:
|
|
22/dquote 61/a 5c/backslash 22/dquote 62/b 22/dquote # "a\"b"
|
|
_test-slice-a-dquote-b-limit:
|
|
|
|
_test-slice-a-newline-b:
|
|
22/dquote 61/a 5c/backslash 6e/n 62/b 22/dquote # "a\nb"
|
|
_test-slice-a-newline-b-limit:
|
|
|
|
# "abc/def"/ghi
|
|
_test-slice-literal-string:
|
|
22/dquote
|
|
61/a 62/b 63/c # abc
|
|
2f/slash 64/d 65/e 66/f # /def
|
|
22/dquote
|
|
2f/slash 67/g 68/h 69/i # /ghi
|
|
_test-slice-literal-string-with-limit:
|
|
|
|
# . . vim:nowrap:textwidth=0
|