2036 lines
102 KiB
Plaintext
2036 lines
102 KiB
Plaintext
# Translate literal strings within double quotes.
|
|
# Replace them with references to new variables in the data segment.
|
|
#
|
|
# To run (from the subx/ directory):
|
|
# $ ./subx translate *.subx apps/dquote.subx -o apps/dquote
|
|
# $ cat x
|
|
# == code
|
|
# ab "cd ef"/imm32
|
|
# $ cat x |./subx run apps/dquote
|
|
# == 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
|
|
|
|
# for debugging: run a single test
|
|
#? # . Heap = new-segment(4096)
|
|
#? # . . push args
|
|
#? 68/push Heap/imm32
|
|
#? 68/push 0x1000/imm32
|
|
#? # . . call
|
|
#? e8/call new-segment/disp32
|
|
#? # . . discard args
|
|
#? 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
#? # . test()
|
|
#? e8/call test-convert-processes-string-literals/disp32
|
|
#? 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX Num-test-failures/disp32 # copy *Num-test-failures to EBX
|
|
#? eb/jump $main:end/disp8
|
|
|
|
# . prolog
|
|
89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP
|
|
# initialize heap
|
|
# . Heap = new-segment(4096)
|
|
# . . push args
|
|
68/push Heap/imm32
|
|
68/push 0x1000/imm32
|
|
# . . 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()
|
|
# . argc > 1
|
|
81 7/subop/compare 1/mod/*+disp8 5/rm32/EBP . . . . 0/disp8 1/imm32 # compare *EBP
|
|
7e/jump-if-lesser-or-equal $run-main/disp8
|
|
# . 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
|
|
# . check result
|
|
3d/compare-EAX-and 1/imm32
|
|
75/jump-if-not-equal $run-main/disp8
|
|
# . run-tests()
|
|
e8/call run-tests/disp32
|
|
8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX Num-test-failures/disp32 # copy *Num-test-failures to EBX
|
|
eb/jump $main:end/disp8
|
|
$run-main:
|
|
# - 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
|
|
# return convert(Stdin, 1/stdout, 2/stderr, ed)
|
|
# . . push args
|
|
50/push-EAX/ed
|
|
68/push Stderr/imm32
|
|
68/push Stdout/imm32
|
|
68/push Stdin/imm32
|
|
# . . call
|
|
e8/call convert/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
|
|
$main:end:
|
|
b8/copy-to-EAX 1/imm32/exit
|
|
cd/syscall 0x80/imm8
|
|
|
|
# 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 '/'
|
|
|
|
convert: # in : (address buffered-file), out : (address buffered-file) -> <void>
|
|
# pseudocode:
|
|
# var line = new-stream(512, 1)
|
|
# var new-data-segment = new-stream(Heap, Segment-size, 1)
|
|
# write-stream(new-data-segment, "== data\n")
|
|
# 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(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)
|
|
#
|
|
# . prolog
|
|
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 : (address stream byte) = stream(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 = {0, 0}
|
|
68/push 0/imm32/end
|
|
68/push 0/imm32/curr
|
|
89/copy 3/mod/direct 2/rm32/EDX . . . 4/r32/ESP . . # copy ESP to EDX
|
|
# new-data-segment/EDI = new-stream(Heap, Segment-size, 1)
|
|
# . EAX = new-stream(Heap, Segment-size, 1)
|
|
# . . push args
|
|
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 . . . . . 0xc/imm32 # add to ESP
|
|
# . EDI = 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
|
|
$convert: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
|
|
$convert:check0:
|
|
# if (line->write == 0) break
|
|
81 7/subop/compare 0/mod/indirect 1/rm32/ECX . . . . . 0/imm32 # compare *ECX
|
|
0f 84/jump-if-equal $convert:break/disp32
|
|
$convert:word-loop:
|
|
# next-word(line, word-slice)
|
|
# . . push args
|
|
52/push-EDX
|
|
51/push-ECX
|
|
# . . call
|
|
e8/call next-word/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
$convert: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 != 0) break
|
|
3d/compare-EAX-and 0/imm32
|
|
0f 85/jump-if-not-equal $convert:next-line/disp32
|
|
$convert:check-for-comment:
|
|
# if (slice-starts-with?(word-slice, "#")) continue
|
|
# . start/ESI = word-slice->start
|
|
8b/copy 0/mod/indirect 2/rm32/EDX . . . 6/r32/ESI . . # copy *EDX to ESI
|
|
# . c/EAX = *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 (EAX == '#') continue
|
|
3d/compare-EAX-and 0x23/imm32/hash
|
|
74/jump-if-equal $convert:word-loop/disp8
|
|
$convert:check-for-string-literal:
|
|
3d/compare-EAX-and 0x22/imm32/hash
|
|
75/jump-if-not-equal $convert:regular-word/disp8
|
|
$convert: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 $convert:next-word/disp8
|
|
$convert: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
|
|
$convert:next-word:
|
|
# write-buffered(out, " ")
|
|
# . . push args
|
|
68/push " "/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 $convert:word-loop/disp8
|
|
$convert: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 $convert:line-loop/disp32
|
|
$convert: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
|
|
$convert:end:
|
|
# . reclaim locals
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0x214/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
|
|
# . epilog
|
|
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 : (address slice), out : (address buffered-file), out-segment : (address stream)
|
|
# 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
|
|
#
|
|
# . prolog
|
|
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(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
|
|
# . print-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 print-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 . . . . 0x8/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
|
|
# . print-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 print-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
|
|
# . epilog
|
|
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
|
5d/pop-to-EBP
|
|
c3/return
|
|
|
|
test-convert-is-idempotent-by-default:
|
|
# . prolog
|
|
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+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 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+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 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
# initialize input (meta comments in parens)
|
|
# # comment 1
|
|
# # comment 2 indented
|
|
# == code (new segment)
|
|
# # comment 3 inside a segment
|
|
# 1
|
|
# (empty line)
|
|
# 2 3 # comment 4 inline with other contents
|
|
# == data (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\n")
|
|
# . . push args
|
|
68/push "== code\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 "\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 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\n")
|
|
# . . push args
|
|
68/push "== data\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
|
|
# convert(_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 convert/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
|
|
# (comment dropped for now)
|
|
# 1
|
|
# (comment dropped for now)
|
|
# 2 3
|
|
# == data
|
|
# 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-convert-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-convert-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 ", msg)
|
|
# . . push args
|
|
68/push "F - test-convert-is-idempotent-by-default/2"/imm32
|
|
68/push "== code "/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-convert-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-convert-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-convert-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-convert-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 ", msg)
|
|
# . . push args
|
|
68/push "F - test-convert-is-idempotent-by-default/7"/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, "4 5/imm32 ", msg)
|
|
# . . push args
|
|
68/push "F - test-convert-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
|
|
# . epilog
|
|
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
|
5d/pop-to-EBP
|
|
c3/return
|
|
|
|
test-convert-processes-string-literals:
|
|
# . prolog
|
|
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+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 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+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 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\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
|
|
# convert(_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 convert/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
|
|
# 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 ", msg)
|
|
# . . push args
|
|
68/push "F - test-convert-processes-string-literals/0"/imm32
|
|
68/push "== code "/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-convert-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-convert-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-convert-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-convert-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-convert-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-convert-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-convert-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
|
|
# . epilog
|
|
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 : (address stream), word : (address slice)
|
|
# pseudocode
|
|
# var len = word->end - word->start - 2 # ignore the double-quotes
|
|
# append-int32-hex(out, len)
|
|
# write(out, "/imm32")
|
|
# curr = word->start
|
|
# ++curr # skip '"'
|
|
# while true
|
|
# if (curr >= word->end) break
|
|
# c = *curr
|
|
# if (c == '"') break
|
|
# append-byte-hex(out, c)
|
|
# if c is alphanumeric:
|
|
# write(out, "/")
|
|
# append-byte(out, c)
|
|
# write(out, " ")
|
|
# ++curr
|
|
#
|
|
# . prolog
|
|
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
|
|
56/push-ESI
|
|
# ESI = word
|
|
8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 0xc/disp8 . # copy *(EBP+12) to ESI
|
|
# curr/EDX = word->start
|
|
8b/copy 0/mod/indirect 6/rm32/ESI . . . 2/r32/EDX . . # copy *ESI to EDX
|
|
$emit-string-literal-data:emit-length:
|
|
# TODO: handle metadata here
|
|
# print(out, "#{len}/imm32 ")
|
|
# . len/ECX = word->end - word->start - 2
|
|
8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 4/disp8 . # copy *(ESI+4) to ECX
|
|
29/subtract 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # subtract EDX from ECX
|
|
81 5/subop/subtract 3/mod/direct 1/rm32/ECX . . . . . 2/imm32 # subtract from ECX
|
|
# . print-int32(out, len)
|
|
# . . push args
|
|
51/push-ECX
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8)
|
|
# . . call
|
|
e8/call print-int32/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
|
|
# max/ESI = word->end
|
|
8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 6/r32/ESI 4/disp8 . # copy *(ESI+4) to ESI
|
|
# ECX = 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
|
|
7d/jump-if-greater-or-equal $emit-string-literal-data:end/disp8
|
|
# CL = *curr
|
|
8a/copy-byte 0/mod/indirect 2/rm32/EDX . . . 1/r32/CL . . # copy byte at *EDX to CL
|
|
# if (ECX == '"') break
|
|
81 7/subop/compare 3/mod/direct 1/rm32/ECX . . . . . 0x22/imm32/dquote # compare ECX
|
|
74/jump-if-equal $emit-string-literal-data:end/disp8
|
|
# 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 (is-alphanumeric?(*curr)) print(out, "/#{*curr}")
|
|
# . EAX = is-alphanumeric?(CL)
|
|
# . . push args
|
|
51/push-ECX
|
|
# . . call
|
|
e8/call is-alphanumeric?/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
# . if (EAX == 0) goto char-done
|
|
3d/compare-EAX-and 0/imm32
|
|
74/jump-if-equal $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
|
|
eb/jump $emit-string-literal-data:loop/disp8
|
|
$emit-string-literal-data:end:
|
|
# . restore registers
|
|
5e/pop-to-ESI
|
|
5a/pop-to-EDX
|
|
59/pop-to-ECX
|
|
58/pop-to-EAX
|
|
# . epilog
|
|
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
|
5d/pop-to-EBP
|
|
c3/return
|
|
|
|
is-alphanumeric?: # c : int -> EAX : boolean
|
|
# . prolog
|
|
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 (EAX < '0') return false
|
|
3d/compare-EAX-with 0x30/imm32/0
|
|
7c/jump-if-lesser $is-alphanumeric?:false/disp8
|
|
# if (EAX <= '9') return true
|
|
3d/compare-EAX-with 0x39/imm32/9
|
|
7e/jump-if-lesser-or-equal $is-alphanumeric?:true/disp8
|
|
# if (EAX < 'A') return false
|
|
3d/compare-EAX-with 0x41/imm32/A
|
|
7c/jump-if-lesser $is-alphanumeric?:false/disp8
|
|
# if (EAX <= 'Z') return true
|
|
3d/compare-EAX-with 0x5a/imm32/Z
|
|
7e/jump-if-lesser-or-equal $is-alphanumeric?:true/disp8
|
|
# if (EAX < 'a') return false
|
|
3d/compare-EAX-with 0x61/imm32/a
|
|
7c/jump-if-lesser $is-alphanumeric?:false/disp8
|
|
# if (EAX <= 'z') return true
|
|
3d/compare-EAX-with 0x7a/imm32/z
|
|
7e/jump-if-lesser-or-equal $is-alphanumeric?:true/disp8
|
|
# return false
|
|
$is-alphanumeric?:false:
|
|
b8/copy-to-EAX 0/imm32/false
|
|
eb/jump $is-alphanumeric?:end/disp8
|
|
$is-alphanumeric?:true:
|
|
b8/copy-to-EAX 1/imm32/true
|
|
$is-alphanumeric?:end:
|
|
# . epilog
|
|
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:
|
|
# . prolog
|
|
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"'
|
|
68/push _test-slice-abc-end/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
|
|
# . epilog
|
|
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:
|
|
# . prolog
|
|
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 _test-slice-empty-string-literal-end/imm32
|
|
68/push _test-slice-empty-string-literal/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, "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
|
|
# . epilog
|
|
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:
|
|
# . prolog
|
|
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-end/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
|
|
# . epilog
|
|
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:
|
|
# . prolog
|
|
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-end/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 "3/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
|
|
# . epilog
|
|
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 : (address buffered-file), word : (address slice)
|
|
# . prolog
|
|
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
|
|
|
|
# PSEUDOCODE
|
|
# ECX = (char *) word->start
|
|
# while true:
|
|
# if ECX == word->end: return
|
|
# if *(ECX++) == '/': break
|
|
# write-slice-buffered(out, {ECX, word->end})
|
|
|
|
# ECX = word
|
|
8b/copy/word 1/mod/*+disp8 5/rm32/EBP . . . 1/r32/ECX 0xc/disp8 . # copy *(EBP+12) to ECX
|
|
# EDX = word->end
|
|
8b/copy/word->end 1/mod/*+disp8 1/rm32/ECX . . . 2/r32/EDX 4/disp8 . # copy *(ECX+4) to EDX
|
|
# ECX = word->start
|
|
8b/copy/word->start 0/mod/indirect 1/rm32/ECX . . . 1/r32/ECX . . # copy *ECX to ECX
|
|
|
|
# clear out EAX
|
|
b8/copy-to-EAX 0/imm32
|
|
# while *start != '/':
|
|
$skip-datum-loop:
|
|
# . start == end?
|
|
39/compare-ECX-and 3/mod/direct 2/rm32/EDX . . . 1/r32/ECX . . # EDX == ECX
|
|
# . if so, return from function (it's only datum, or empty)
|
|
74/jump-if-equal $emit-metadata:end/disp8
|
|
|
|
# . start++
|
|
41/increment-ECX # ECX++
|
|
|
|
# . EAX = *start
|
|
8a/copy-byte 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # copy *ECX to EAX
|
|
|
|
# . EAX != '/'?
|
|
3d/compare-EAX-and 0x2f/imm32
|
|
# . if so, continue looping
|
|
75/jump-if-not-equal $skip-datum-loop/disp8
|
|
# end
|
|
|
|
# write-slice-buffered(out, &{start, end})
|
|
# . push end
|
|
52/push-EDX
|
|
# . push start
|
|
51/push-ECX
|
|
# . push &{start, end}
|
|
54/push-ESP
|
|
|
|
# . push out
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8)
|
|
|
|
e8/call write-slice-buffered/disp32
|
|
# . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . 0x10/imm32 . # add 16 to ESP
|
|
|
|
$emit-metadata:end:
|
|
# . restore registers
|
|
5a/pop-to-EDX
|
|
59/pop-to-ECX
|
|
58/pop-to-EAX
|
|
# . epilog
|
|
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
|
5d/pop-to-EBP
|
|
c3/return
|
|
|
|
test-emit-metadata:
|
|
# . prolog
|
|
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+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 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
# var slice/ECX = "abc/def"
|
|
68/push _test-slice-word-end/imm32
|
|
68/push _test-slice-word/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
|
|
# 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
|
|
# . epilog
|
|
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:
|
|
# . prolog
|
|
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+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 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
# var slice/ECX = "abc"
|
|
68/push _test-slice-word-datum-end/imm32
|
|
68/push _test-slice-word/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
|
|
# 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
|
|
# . epilog
|
|
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:
|
|
# . prolog
|
|
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+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 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
# var slice/ECX = "abc/def/ghi"
|
|
68/push _test-slice-word-end2/imm32
|
|
68/push _test-slice-word/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
|
|
# 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
|
|
# . epilog
|
|
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
|
5d/pop-to-EBP
|
|
c3/return
|
|
|
|
# (re)compute the bounds of the next word in the line
|
|
# return empty string on reaching end of file
|
|
next-word: # line : (address stream byte), out : (address slice)
|
|
# . prolog
|
|
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
|
|
56/push-ESI
|
|
57/push-EDI
|
|
# ESI = line
|
|
8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI
|
|
# EDI = out
|
|
8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 7/r32/EDI 0xc/disp8 . # copy *(EBP+12) to EDI
|
|
# skip-chars-matching(line, ' ')
|
|
# . . push args
|
|
68/push 0x20/imm32/space
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8)
|
|
# . . call
|
|
e8/call skip-chars-matching/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
$next-word:check0:
|
|
# if (line->read >= line->write) clear out and return
|
|
# . EAX = line->read
|
|
8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 4/disp8 . # copy *(ESI+4) to EAX
|
|
# . if (EAX < line->write) goto next check
|
|
3b/compare 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # compare EAX with *ESI
|
|
7c/jump-if-lesser $next-word:check-for-comment/disp8
|
|
# . return out = {0, 0}
|
|
c7 0/subop/copy 0/mod/direct 7/rm32/EDI . . . . . 0/imm32 # copy to *EDI
|
|
c7 0/subop/copy 1/mod/*+disp8 7/rm32/EDI . . . . 4/disp8 0/imm32 # copy to *(EDI+4)
|
|
eb/jump $next-word:end/disp8
|
|
$next-word:check-for-comment:
|
|
# out->start = &line->data[line->read]
|
|
8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 4/disp8 . # copy *(ESI+4) to ECX
|
|
8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/ESI 1/index/ECX . 0/r32/EAX 0xc/disp8 . # copy ESI+ECX+12 to EAX
|
|
89/copy 0/mod/indirect 7/rm32/EDI . . . 0/r32/EAX . . # copy EAX to *EDI
|
|
# if line->data[line->read] == '#'
|
|
# . EAX = line->data[line->read]
|
|
31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX
|
|
8a/copy-byte 1/mod/*+disp8 4/rm32/sib 6/base/ESI 1/index/ECX . 0/r32/AL 0xc/disp8 . # copy byte at *(ESI+ECX+12) to AL
|
|
# . compare
|
|
3d/compare-EAX-and 0x23/imm32/pound
|
|
75/jump-if-not-equal $next-word:check-for-string-literal/disp8
|
|
$next-word:comment:
|
|
# out->end = &line->data[line->write]
|
|
8b/copy 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # copy *ESI to EAX
|
|
8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/ESI 0/index/EAX . 0/r32/EAX 0xc/disp8 . # copy ESI+EAX+12 to EAX
|
|
89/copy 1/mod/*+disp8 7/rm32/EDI . . . 0/r32/EAX 4/disp8 . # copy EAX to *(EDI+4)
|
|
# line->read = line->write # skip rest of line
|
|
8b/copy 0/mod/indirect 6/rm32/ESI . . . 0/r32/EAX . . # copy *ESI to EAX
|
|
89/copy 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 4/disp8 . # copy EAX to *(ESI+4)
|
|
# return
|
|
eb/jump $next-word:end/disp8
|
|
$next-word:check-for-string-literal:
|
|
# if line->data[line->read] == '"'
|
|
# . EAX = line->data[line->read]
|
|
31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX
|
|
8a/copy-byte 1/mod/*+disp8 4/rm32/sib 6/base/ESI 1/index/ECX . 0/r32/AL 0xc/disp8 . # copy byte at *(ESI+ECX+12) to AL
|
|
# . compare
|
|
3d/compare-EAX-and 0x22/imm32/dquote
|
|
75/jump-if-not-equal $next-word:regular-word/disp8
|
|
$next-word:string-literal:
|
|
# ++line->read # skip '"'
|
|
# . persist line->read
|
|
89/copy 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 4/disp8 . # copy ECX to *(ESI+4)
|
|
# . ++line->read
|
|
ff 0/subop/increment 1/mod/*+disp8 6/rm32/ESI . . . . 4/disp8 . # increment *(ESI+4)
|
|
# parse-string(line, out)
|
|
# . . push args
|
|
57/push-EDI
|
|
56/push-ESI
|
|
# . . call
|
|
e8/call parse-string/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# fall through
|
|
$next-word:regular-word:
|
|
# otherwise skip-chars-not-matching-whitespace(line) # including trailing newline
|
|
# . . push args
|
|
ff 6/subop/push 1/mod/*+disp8 5/rm32/EBP . . . . 8/disp8 . # push *(EBP+8)
|
|
# . . call
|
|
e8/call skip-chars-not-matching-whitespace/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP
|
|
# out->end = &line->data[line->read]
|
|
8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 4/disp8 . # copy *(ESI+4) to ECX
|
|
8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/ESI 1/index/ECX . 0/r32/EAX 0xc/disp8 . # copy ESI+ECX+12 to EAX
|
|
89/copy 1/mod/*+disp8 7/rm32/EDI . . . 0/r32/EAX 4/disp8 . # copy EAX to *(EDI+4)
|
|
$next-word:end:
|
|
# . restore registers
|
|
5f/pop-to-EDI
|
|
5e/pop-to-ESI
|
|
59/pop-to-ECX
|
|
58/pop-to-EAX
|
|
# . epilog
|
|
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
|
5d/pop-to-EBP
|
|
c3/return
|
|
|
|
parse-string: # line : (address stream byte), out : (address slice)
|
|
# pseudocode:
|
|
# ESI = line
|
|
# curr/ECX = line->data[line->read]
|
|
# max/EDX = line->data[line->write]
|
|
# while curr >= max
|
|
# if (*curr == '"') ++curr, break
|
|
# if (*curr == '\\') curr+=2, continue
|
|
# ++curr
|
|
# line->read = curr - line->data
|
|
# out->end = curr
|
|
#
|
|
# . prolog
|
|
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
|
|
56/push-ESI
|
|
# ESI = line
|
|
8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI
|
|
# curr/ECX = &table->data[table->read]
|
|
# . ECX = table->read
|
|
8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 4/disp8 . # copy *(ESI+4) to ECX
|
|
# . ECX = table->data + ECX
|
|
8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/ESI 1/index/ECX . 1/r32/ECX 0xc/disp8 . # copy ESI+ECX+12 to ECX
|
|
# max/EDX = &table->data[table->write]
|
|
# . EDX = table->write
|
|
8b/copy 0/mod/indirect 6/rm32/ESI . . . 2/r32/EDX . . # copy *ESI to EDX
|
|
# . EDX = table->data + EDX
|
|
8d/copy-address 1/mod/*+disp8 4/rm32/sib 6/base/ESI 2/index/EDX . 2/r32/EDX 0xc/disp8 . # copy ESI+EDX+12 to EDX
|
|
# clear EAX
|
|
31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX
|
|
$parse-string:loop:
|
|
# if (curr >= max) break
|
|
39/compare 3/mod/direct 1/rm32/ECX . . . 2/r32/EDX . . # compare ECX with EDX
|
|
7d/jump-if-greater-or-equal $parse-string:break/disp8
|
|
# c/EAX = *curr
|
|
8a/copy-byte 0/mod/indirect 1/rm32/ECX . . . 0/r32/AL . . # copy byte at *ECX to AL
|
|
$parse-string:check1:
|
|
# if (c == '"') break # rely on caller to skip trailing non-whitespace
|
|
3d/compare-EAX-and 0x22/imm32/dquote
|
|
74/jump-if-equal $parse-string:break/disp8
|
|
$parse-string:check2:
|
|
# if (c == '\\') ++curr
|
|
3d/compare-EAX-and 0x5c/imm32/backslash
|
|
75/jump-if-not-equal $parse-string:continue/disp8
|
|
# . ++curr
|
|
41/increment-ECX
|
|
$parse-string:continue:
|
|
# ++curr
|
|
41/increment-ECX
|
|
# loop
|
|
eb/jump $parse-string:loop/disp8
|
|
$parse-string:break:
|
|
# out->end = curr
|
|
8b/copy 1/mod/*+disp8 5/rm32/EBP . . . 0/r32/EAX 0xc/disp8 . # copy *(EBP+12) to EDI
|
|
89/copy 1/mod/*+disp8 0/rm32/EAX . . . 1/r32/ECX 4/disp8 . # copy ECX to *(EAX+4)
|
|
# line->read = curr - line - 12
|
|
29/subtract 3/mod/direct 1/rm32/ECX . . . 6/r32/ESI . . # subtract ESI from ECX
|
|
81 5/subop/subtract 3/mod/direct 1/rm32/ECX . . . . . 0xc/imm32 # subtract from ECX
|
|
89/copy 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 4/disp8 . # copy ECX to *(ESI+4)
|
|
$parse-string:end:
|
|
# . restore registers
|
|
5e/pop-to-ESI
|
|
5a/pop-to-EDX
|
|
59/pop-to-ECX
|
|
58/pop-to-EAX
|
|
# . epilog
|
|
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
|
5d/pop-to-EBP
|
|
c3/return
|
|
|
|
test-next-word:
|
|
# . prolog
|
|
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
|
|
# var slice/ECX = {0, 0}
|
|
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
|
|
# 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 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# next-word(_test-input-stream, slice)
|
|
# . . push args
|
|
51/push-ECX
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call next-word/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# 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: start"/imm32
|
|
68/push 0xe/imm32
|
|
# . . push slice->start - _test-input-stream
|
|
8b/copy 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # copy *ECX to EAX
|
|
81 5/subop/subtract 3/mod/direct 0/rm32/EAX . . . . . _test-input-stream/imm32 # subtract from EAX
|
|
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
|
|
# 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: end"/imm32
|
|
68/push 0x10/imm32
|
|
# . . push slice->end - _test-input-stream
|
|
8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 4/disp8 . # copy *(ECX+4) to EAX
|
|
81 5/subop/subtract 3/mod/direct 0/rm32/EAX . . . . . _test-input-stream/imm32 # subtract from EAX
|
|
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
|
|
# . epilog
|
|
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
|
5d/pop-to-EBP
|
|
c3/return
|
|
|
|
test-next-word-returns-whole-comment:
|
|
# . prolog
|
|
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
|
|
# var slice/ECX = {0, 0}
|
|
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
|
|
# 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 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# next-word(_test-input-stream, slice)
|
|
# . . push args
|
|
51/push-ECX
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call next-word/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# 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-returns-whole-comment: start"/imm32
|
|
68/push 0xe/imm32
|
|
# . . push slice->start - _test-input-stream
|
|
8b/copy 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # copy *ECX to EAX
|
|
81 5/subop/subtract 3/mod/direct 0/rm32/EAX . . . . . _test-input-stream/imm32 # subtract from EAX
|
|
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
|
|
# 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-returns-whole-comment: end"/imm32
|
|
68/push 0x11/imm32
|
|
# . . push slice->end - _test-input-stream
|
|
8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 4/disp8 . # copy *(ECX+4) to EAX
|
|
81 5/subop/subtract 3/mod/direct 0/rm32/EAX . . . . . _test-input-stream/imm32 # subtract from EAX
|
|
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
|
|
# . epilog
|
|
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
|
5d/pop-to-EBP
|
|
c3/return
|
|
|
|
test-next-word-returns-empty-string-on-eof:
|
|
# . prolog
|
|
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
|
|
# var slice/ECX = {0, 0}
|
|
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
|
|
# write nothing to _test-input-stream
|
|
# next-word(_test-input-stream, slice)
|
|
# . . push args
|
|
51/push-ECX
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call next-word/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# check-ints-equal(slice->end - slice->start, 0, msg)
|
|
# . . push args
|
|
68/push "F - test-next-word-returns-empty-string-on-eof"/imm32
|
|
68/push 0/imm32
|
|
# . . push slice->end - slice->start
|
|
8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 4/disp8 . # copy *(ECX+4) to EAX
|
|
2b/subtract 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # subtract *ECX from EAX
|
|
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
|
|
# . epilog
|
|
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
|
5d/pop-to-EBP
|
|
c3/return
|
|
|
|
test-next-word-returns-whole-string:
|
|
# . prolog
|
|
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
|
|
# var slice/ECX = {0, 0}
|
|
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
|
|
# write(_test-input-stream, " \"a b\"/imm32 ")
|
|
# . . push args
|
|
68/push " \"a b\"/imm32 "/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
|
|
# next-word(_test-input-stream, slice)
|
|
# . . push args
|
|
51/push-ECX
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call next-word/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# 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-returns-whole-string: start"/imm32
|
|
68/push 0xd/imm32
|
|
# . . push slice->start - _test-input-stream
|
|
8b/copy 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # copy *ECX to EAX
|
|
81 5/subop/subtract 3/mod/direct 0/rm32/EAX . . . . . _test-input-stream/imm32 # subtract from EAX
|
|
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
|
|
# check-ints-equal(slice->end - _test-input-stream->data, 12, msg)
|
|
# . check-ints-equal(slice->end - _test-input-stream, 24, msg)
|
|
# . . push args
|
|
68/push "F - test-next-word-returns-whole-string: end"/imm32
|
|
68/push 0x18/imm32
|
|
# . . push slice->end - _test-input-stream
|
|
8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 4/disp8 . # copy *(ECX+4) to EAX
|
|
81 5/subop/subtract 3/mod/direct 0/rm32/EAX . . . . . _test-input-stream/imm32 # subtract from EAX
|
|
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
|
|
# . epilog
|
|
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
|
5d/pop-to-EBP
|
|
c3/return
|
|
|
|
test-next-word-returns-string-with-escapes:
|
|
# . prolog
|
|
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
|
|
# var slice/ECX = {0, 0}
|
|
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
|
|
# write(_test-input-stream, " \"a\\\"b\"/x")
|
|
# . . push args
|
|
68/push " \"a\\\"b\"/x"/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
|
|
# next-word(_test-input-stream, slice)
|
|
# . . push args
|
|
51/push-ECX
|
|
68/push _test-input-stream/imm32
|
|
# . . call
|
|
e8/call next-word/disp32
|
|
# . . discard args
|
|
81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP
|
|
# 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-returns-string-with-escapes: start"/imm32
|
|
68/push 0xd/imm32
|
|
# . . push slice->start - _test-input-stream
|
|
8b/copy 0/mod/indirect 1/rm32/ECX . . . 0/r32/EAX . . # copy *ECX to EAX
|
|
81 5/subop/subtract 3/mod/direct 0/rm32/EAX . . . . . _test-input-stream/imm32 # subtract from EAX
|
|
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
|
|
# check-ints-equal(slice->end - _test-input-stream->data, 9, msg)
|
|
# . check-ints-equal(slice->end - _test-input-stream, 21, msg)
|
|
# . . push args
|
|
68/push "F - test-next-word-returns-string-with-escapes: end"/imm32
|
|
68/push 0x15/imm32
|
|
# . . push slice->end - _test-input-stream
|
|
8b/copy 1/mod/*+disp8 1/rm32/ECX . . . 0/r32/EAX 4/disp8 . # copy *(ECX+4) to EAX
|
|
81 5/subop/subtract 3/mod/direct 0/rm32/EAX . . . . . _test-input-stream/imm32 # subtract from EAX
|
|
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
|
|
# . epilog
|
|
89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP
|
|
5d/pop-to-EBP
|
|
c3/return
|
|
|
|
== data
|
|
|
|
Segment-size:
|
|
# TODO: there's currently a tight size limit on segments because we aren't growing the heap
|
|
0x100/imm32
|
|
#? 0x1000/imm32/4KB
|
|
|
|
Next-string-literal: # tracks the next auto-generated variable name
|
|
1/imm32
|
|
|
|
Heap:
|
|
# curr
|
|
0/imm32
|
|
# limit
|
|
0/imm32
|
|
|
|
# length-prefixed string containing just a single space
|
|
Space:
|
|
# size
|
|
1/imm32
|
|
# data
|
|
20/space
|
|
|
|
# length-prefixed string containing just a single slash
|
|
Slash:
|
|
# size
|
|
1/imm32
|
|
# data
|
|
2f/slash
|
|
|
|
_test-slice-abc:
|
|
22/dquote 61/a 62/b 63/c 22/dquote # "abc"
|
|
_test-slice-abc-end:
|
|
|
|
_test-slice-empty-string-literal:
|
|
22/dquote 22/dquote # ""
|
|
_test-slice-empty-string-literal-end:
|
|
|
|
_test-slice-a-space-b:
|
|
22/dquote 61/a 20/space 62/b 22/dquote # "a b"
|
|
_test-slice-a-space-b-end:
|
|
|
|
_test-slice-a-dquote-b:
|
|
22/dquote 61/a 5c/backslash 22/dquote 62/b 22/dquote # "a\"b"
|
|
_test-slice-a-dquote-b-end:
|
|
|
|
# abc/def/ghi
|
|
_test-slice-word:
|
|
61/a 62/b 63/c # abc
|
|
_test-slice-word-datum-end:
|
|
2f/slash 64/d 65/e 66/f # /def
|
|
_test-slice-word-end:
|
|
2f/slash 67/g 68/h 69/i # /ghi
|
|
_test-slice-word-end2:
|
|
|
|
# . . vim:nowrap:textwidth=0
|