5675 - move helpers from subx-common into layers
This undoes 5672 in favor of a new plan: Layers 000 - 099 are for running without syntax sugar. We use them for building syntax-sugar passes. Layers 100 and up are for running with all syntax sugar. The layers are arranged in approximate order so more phases rely on earlier layers than later ones. I plan to not use intermediate syntax sugar (just sigils without calls, or sigils and calls without braces) anywhere except in the specific passes implementing them.
This commit is contained in:
parent
881c7f0270
commit
fd91f7f61b
|
@ -28,6 +28,8 @@ Heap:
|
|||
# a reasonable default
|
||||
Heap-size:
|
||||
0x200000/imm32/2MB
|
||||
#? # TODO: reclaim space allocated in tests.
|
||||
#? 0x2000000/imm32/32MB
|
||||
|
||||
== code
|
||||
# instruction effective address register displacement immediate
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
== 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
|
||||
|
||||
# write an entire stream's contents to a buffered-file
|
||||
# ways to do this:
|
||||
# - construct a 'maximal slice' and pass it to write-slice-buffered
|
||||
# - flush the buffered-file and pass the stream directly to its fd (disabling buffering)
|
||||
# we'll go with the first way for now
|
||||
write-stream-data: # f : (address buffered-file), s : (address stream) -> <void>
|
||||
# . 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
|
||||
# esi = s
|
||||
8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 0xc/disp8 . # copy *(ebp+12) to esi
|
||||
# var slice/ecx = {s->data, s->data + s->write}
|
||||
# . push s->data + s->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
|
||||
50/push-eax
|
||||
# . push s->data
|
||||
8d/copy-address 1/mod/*+disp8 6/rm32/esi . . . 0/r32/eax 0xc/disp8 . # copy esi+12 to eax
|
||||
50/push-eax
|
||||
# . ecx = esp
|
||||
89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
|
||||
# write-slice-buffered(f, slice)
|
||||
# . . push args
|
||||
51/push-ecx
|
||||
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
|
||||
$write-stream-data:end:
|
||||
# . restore locals
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
||||
# . restore registers
|
||||
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
|
||||
|
||||
test-write-stream-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
|
||||
# . 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
|
||||
# . 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
|
||||
# initialize input
|
||||
# . write(_test-input-stream, "abcd")
|
||||
# . . push args
|
||||
68/push "abcd"/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-stream-data(_test-output-buffered-file, _test-input-stream)
|
||||
# . . push args
|
||||
68/push _test-input-stream/imm32
|
||||
68/push _test-output-buffered-file/imm32
|
||||
# . . call
|
||||
e8/call write-stream-data/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
||||
# check that the write happened as expected
|
||||
# . 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, "abcd", msg)
|
||||
# . . push args
|
||||
68/push "F - test-write-stream-data"/imm32
|
||||
68/push "abcd"/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
|
|
@ -0,0 +1,252 @@
|
|||
# Tokenize by whitespace.
|
||||
|
||||
== 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
|
||||
|
||||
# (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] == '#') out->end = &line->data[line->write]), skip rest of stream and return
|
||||
# . 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:regular-word/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
|
||||
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: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
|
||||
|
||||
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-stream)
|
||||
# . . push args
|
||||
68/push _test-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-stream, " ab")
|
||||
# . . push args
|
||||
68/push " ab"/imm32
|
||||
68/push _test-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-stream, slice)
|
||||
# . . push args
|
||||
51/push-ecx
|
||||
68/push _test-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-stream->data, 2, msg)
|
||||
# . check-ints-equal(slice->start - _test-stream, 14, msg)
|
||||
# . . push args
|
||||
68/push "F - test-next-word: start"/imm32
|
||||
68/push 0xe/imm32
|
||||
# . . push slice->start - _test-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-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-stream->data, 4, msg)
|
||||
# . check-ints-equal(slice->end - _test-stream, 16, msg)
|
||||
# . . push args
|
||||
68/push "F - test-next-word: end"/imm32
|
||||
68/push 0x10/imm32
|
||||
# . . push slice->end - _test-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-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-stream)
|
||||
# . . push args
|
||||
68/push _test-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-stream, " # a")
|
||||
# . . push args
|
||||
68/push " # a"/imm32
|
||||
68/push _test-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-stream, slice)
|
||||
# . . push args
|
||||
51/push-ecx
|
||||
68/push _test-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-stream->data, 2, msg)
|
||||
# . check-ints-equal(slice->start - _test-stream, 14, msg)
|
||||
# . . push args
|
||||
68/push "F - test-next-word-returns-whole-comment: start"/imm32
|
||||
68/push 0xe/imm32
|
||||
# . . push slice->start - _test-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-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-stream->data, 5, msg)
|
||||
# . check-ints-equal(slice->end - _test-stream, 17, msg)
|
||||
# . . push args
|
||||
68/push "F - test-next-word-returns-whole-comment: end"/imm32
|
||||
68/push 0x11/imm32
|
||||
# . . push slice->end - _test-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-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-stream)
|
||||
# . . push args
|
||||
68/push _test-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-stream
|
||||
# next-word(_test-stream, slice)
|
||||
# . . push args
|
||||
51/push-ecx
|
||||
68/push _test-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
|
|
@ -0,0 +1,631 @@
|
|||
# Helpers for parsing SubX words, with their rules for hex, labels and metadata.
|
||||
|
||||
== 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
|
||||
|
||||
has-metadata?: # word : (address slice), s : (address string) -> eax : boolean
|
||||
# pseudocode:
|
||||
# var twig : &slice = next-token-from-slice(word->start, word->end, '/') # skip name
|
||||
# curr = twig->end
|
||||
# while true
|
||||
# twig = next-token-from-slice(curr, word->end, '/')
|
||||
# if (twig.empty()) break
|
||||
# if (slice-equal?(twig, s)) return true
|
||||
# curr = twig->end
|
||||
# return false
|
||||
# . prolog
|
||||
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
|
||||
56/push-esi
|
||||
57/push-edi
|
||||
# esi = word
|
||||
8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi
|
||||
# edx = word->end
|
||||
8b/copy 1/mod/*+disp8 6/rm32/esi . . . 2/r32/edx 4/disp8 . # copy *(esi+4) to edx
|
||||
# var twig/edi : (address slice) = {0, 0}
|
||||
68/push 0/imm32/end
|
||||
68/push 0/imm32/start
|
||||
89/copy 3/mod/direct 7/rm32/edi . . . 4/r32/esp . . # copy esp to edi
|
||||
# next-token-from-slice(word->start, word->end, '/', twig)
|
||||
# . . push args
|
||||
57/push-edi
|
||||
68/push 0x2f/imm32/slash
|
||||
52/push-edx
|
||||
ff 6/subop/push 0/mod/indirect 6/rm32/esi . . . . . . # push *esi
|
||||
# . . call
|
||||
e8/call next-token-from-slice/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp
|
||||
# curr/ecx = twig->end
|
||||
8b/copy 1/mod/*+disp8 7/rm32/edi . . . 1/r32/ecx 4/disp8 . # copy *(edi+4) to ecx
|
||||
$has-metadata?:loop:
|
||||
# next-token-from-slice(curr, word->end, '/', twig)
|
||||
# . . push args
|
||||
57/push-edi
|
||||
68/push 0x2f/imm32/slash
|
||||
52/push-edx
|
||||
51/push-ecx
|
||||
# . . call
|
||||
e8/call next-token-from-slice/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp
|
||||
# if (slice-empty?(twig)) return false
|
||||
# . eax = slice-empty?(twig)
|
||||
# . . push args
|
||||
57/push-edi
|
||||
# . . 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) return false
|
||||
3d/compare-eax-and 0/imm32
|
||||
75/jump-if-not-equal $has-metadata?:false/disp8
|
||||
# if (slice-equal?(twig, s)) return true
|
||||
# . eax = slice-equal?(twig, s)
|
||||
# . . push args
|
||||
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12)
|
||||
57/push-edi
|
||||
# . . call
|
||||
e8/call slice-equal?/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
||||
# . if (eax != 0) return true
|
||||
3d/compare-eax-and 0/imm32
|
||||
75/jump-if-not-equal $has-metadata?:true/disp8
|
||||
# curr = twig->end
|
||||
8b/copy 1/mod/*+disp8 7/rm32/edi . . . 1/r32/ecx 4/disp8 . # copy *(edi+4) to ecx
|
||||
eb/jump $has-metadata?:loop/disp8
|
||||
$has-metadata?:true:
|
||||
b8/copy-to-eax 1/imm32/true
|
||||
eb/jump $has-metadata?:end/disp8
|
||||
$has-metadata?:false:
|
||||
b8/copy-to-eax 0/imm32/false
|
||||
$has-metadata?:end:
|
||||
# . reclaim locals
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
||||
# . restore registers
|
||||
5f/pop-to-edi
|
||||
5e/pop-to-esi
|
||||
5a/pop-to-edx
|
||||
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-has-metadata-true:
|
||||
# . prolog
|
||||
55/push-ebp
|
||||
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
||||
# (eax..ecx) = "ab/imm32"
|
||||
b8/copy-to-eax "ab/imm32"/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 in/esi : (address slice) = {eax, ecx}
|
||||
51/push-ecx
|
||||
50/push-eax
|
||||
89/copy 3/mod/direct 6/rm32/esi . . . 4/r32/esp . . # copy esp to esi
|
||||
# eax = has-metadata?(esi, "imm32")
|
||||
# . . push args
|
||||
68/push "imm32"/imm32
|
||||
56/push-esi
|
||||
# . . call
|
||||
e8/call has-metadata?/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
||||
# check-ints-equal(eax, 1, msg)
|
||||
# . . push args
|
||||
68/push "F - test-has-metadata-true"/imm32
|
||||
68/push 1/imm32/true
|
||||
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-has-metadata-false:
|
||||
# . prolog
|
||||
55/push-ebp
|
||||
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
||||
# (eax..ecx) = "ab/c"
|
||||
b8/copy-to-eax "ab/c"/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 in/esi : (address slice) = {eax, ecx}
|
||||
51/push-ecx
|
||||
50/push-eax
|
||||
89/copy 3/mod/direct 6/rm32/esi . . . 4/r32/esp . . # copy esp to esi
|
||||
# eax = has-metadata?(esi, "d")
|
||||
# . . push args
|
||||
68/push "d"/imm32
|
||||
56/push-esi
|
||||
# . . call
|
||||
e8/call has-metadata?/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
||||
# check-ints-equal(eax, 0, msg)
|
||||
# . . push args
|
||||
68/push "F - test-has-metadata-false"/imm32
|
||||
68/push 0/imm32/false
|
||||
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-has-metadata-ignore-name:
|
||||
# . prolog
|
||||
55/push-ebp
|
||||
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
||||
# (eax..ecx) = "a/b"
|
||||
b8/copy-to-eax "a/b"/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 in/esi : (address slice) = {eax, ecx}
|
||||
51/push-ecx
|
||||
50/push-eax
|
||||
89/copy 3/mod/direct 6/rm32/esi . . . 4/r32/esp . . # copy esp to esi
|
||||
# eax = has-metadata?(esi, "a")
|
||||
# . . push args
|
||||
68/push "a"/imm32
|
||||
56/push-esi
|
||||
# . . call
|
||||
e8/call has-metadata?/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
||||
# check-ints-equal(eax, 0, msg)
|
||||
# . . push args
|
||||
68/push "F - test-has-metadata-ignore-name"/imm32
|
||||
68/push 0/imm32/false
|
||||
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-has-metadata-multiple-true:
|
||||
# . prolog
|
||||
55/push-ebp
|
||||
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
||||
# (eax..ecx) = "a/b/c"
|
||||
b8/copy-to-eax "a/b/c"/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 in/esi : (address slice) = {eax, ecx}
|
||||
51/push-ecx
|
||||
50/push-eax
|
||||
89/copy 3/mod/direct 6/rm32/esi . . . 4/r32/esp . . # copy esp to esi
|
||||
# eax = has-metadata?(esi, "c")
|
||||
# . . push args
|
||||
68/push "c"/imm32
|
||||
56/push-esi
|
||||
# . . call
|
||||
e8/call has-metadata?/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
||||
# check-ints-equal(eax, 1, msg)
|
||||
# . . push args
|
||||
68/push "F - test-has-metadata-multiple-true"/imm32
|
||||
68/push 1/imm32/true
|
||||
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-has-metadata-multiple-false:
|
||||
# . prolog
|
||||
55/push-ebp
|
||||
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
||||
# (eax..ecx) = "a/b/c"
|
||||
b8/copy-to-eax "a/b/c"/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 in/esi : (address slice) = {eax, ecx}
|
||||
51/push-ecx
|
||||
50/push-eax
|
||||
89/copy 3/mod/direct 6/rm32/esi . . . 4/r32/esp . . # copy esp to esi
|
||||
# eax = has-metadata?(esi, "d")
|
||||
# . . push args
|
||||
68/push "d"/imm32
|
||||
56/push-esi
|
||||
# . . call
|
||||
e8/call has-metadata?/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
||||
# check-ints-equal(eax, 0, msg)
|
||||
# . . push args
|
||||
68/push "F - test-has-metadata-multiple-false"/imm32
|
||||
68/push 0/imm32/false
|
||||
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
|
||||
|
||||
# conditions for 'valid' names that are not at risk of looking like hex numbers
|
||||
# keep in sync with the rules in labels.cc
|
||||
#: - if it starts with a digit, it's treated as a number. If it can't be
|
||||
#: parsed as hex it will raise an error.
|
||||
#: - if it starts with '-' it's treated as a number.
|
||||
#: - if it starts with '0x' it's treated as a number. (redundant)
|
||||
#: - if it's two characters long, it can't be a name. Either it's a hex
|
||||
#: byte, or it raises an error.
|
||||
is-valid-name?: # in : (address slice) -> eax : boolean
|
||||
# . prolog
|
||||
55/push-ebp
|
||||
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
||||
# . save registers
|
||||
51/push-ecx
|
||||
56/push-esi
|
||||
# esi = in
|
||||
8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi
|
||||
# start/ecx = in->start
|
||||
8b/copy 0/mod/indirect 6/rm32/esi . . . 1/r32/ecx . . # copy *esi to ecx
|
||||
# end/eax = in->end
|
||||
8b/copy 1/mod/*+disp8 6/rm32/esi . . . 0/r32/eax 4/disp8 . # copy *(esi+4) to eax
|
||||
$is-valid-name?:check0:
|
||||
# if (start >= end) return false
|
||||
39/compare 3/mod/direct 1/rm32/ecx . . . 0/r32/eax . . # compare ecx with eax
|
||||
73/jump-if-greater-or-equal-unsigned $is-valid-name?:false/disp8
|
||||
$is-valid-name?:check1:
|
||||
# eax -= ecx
|
||||
29/subtract 3/mod/direct 0/rm32/eax . . . 1/r32/ecx . . # subtract ecx from eax
|
||||
# if (eax == 2) return false
|
||||
3d/compare-eax-and 2/imm32
|
||||
74/jump-if-equal $is-valid-name?:false/disp8
|
||||
$is-valid-name?:check2:
|
||||
# c/eax = *ecx
|
||||
31/xor 3/mod/direct 0/rm32/eax . . . 0/r32/eax . . # clear eax
|
||||
8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 0/r32/AL . . # copy byte at *ecx to AL
|
||||
# if (c == "-") return false
|
||||
3d/compare-eax-and 2d/imm32/-
|
||||
74/jump-if-equal $is-valid-name?:false/disp8
|
||||
$is-valid-name?:check3a:
|
||||
# if (c < "0") return true
|
||||
3d/compare-eax-with 30/imm32/0
|
||||
7c/jump-if-lesser $is-valid-name?:true/disp8
|
||||
$is-valid-name?:check3b:
|
||||
# if (c > "9") return true
|
||||
3d/compare-eax-with 39/imm32/9
|
||||
7f/jump-if-greater $is-valid-name?:true/disp8
|
||||
$is-valid-name?:false:
|
||||
# return false
|
||||
b8/copy-to-eax 0/imm32/false
|
||||
eb/jump $is-valid-name?:end/disp8
|
||||
$is-valid-name?:true:
|
||||
# return true
|
||||
b8/copy-to-eax 1/imm32/true
|
||||
$is-valid-name?:end:
|
||||
# . restore registers
|
||||
5e/pop-to-esi
|
||||
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-is-valid-name-digit-prefix:
|
||||
# . prolog
|
||||
55/push-ebp
|
||||
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
||||
# (eax..ecx) = "34"
|
||||
b8/copy-to-eax "34"/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
|
||||
# eax = is-valid-name?(slice)
|
||||
# . . push args
|
||||
51/push-ecx
|
||||
# . . call
|
||||
e8/call is-valid-name?/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
||||
# check-ints-equal(eax, 0, msg)
|
||||
# . . push args
|
||||
68/push "F - test-is-valid-name-digit-prefix"/imm32
|
||||
68/push 0/imm32/false
|
||||
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-is-valid-name-negative-prefix:
|
||||
# . prolog
|
||||
55/push-ebp
|
||||
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
||||
# (eax..ecx) = "-0x34"
|
||||
b8/copy-to-eax "-0x34"/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
|
||||
# eax = is-valid-name?(slice)
|
||||
# . . push args
|
||||
51/push-ecx
|
||||
# . . call
|
||||
e8/call is-valid-name?/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
||||
# check-ints-equal(eax, 0, msg)
|
||||
# . . push args
|
||||
68/push "F - test-is-valid-name-negative-prefix"/imm32
|
||||
68/push 0/imm32/false
|
||||
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-is-valid-name-0x-prefix:
|
||||
# . prolog
|
||||
55/push-ebp
|
||||
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
||||
# (eax..ecx) = "0x34"
|
||||
b8/copy-to-eax "0x34"/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
|
||||
# eax = is-valid-name?(slice)
|
||||
# . . push args
|
||||
51/push-ecx
|
||||
# . . call
|
||||
e8/call is-valid-name?/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
||||
# check-ints-equal(eax, 0, msg)
|
||||
# . . push args
|
||||
68/push "F - test-is-valid-name-0x-prefix"/imm32
|
||||
68/push 0/imm32/false
|
||||
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-is-valid-name-starts-with-pre-digit:
|
||||
# . prolog
|
||||
55/push-ebp
|
||||
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
||||
# (eax..ecx) = "/03"
|
||||
b8/copy-to-eax "/03"/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
|
||||
# eax = is-valid-name?(slice)
|
||||
# . . push args
|
||||
51/push-ecx
|
||||
# . . call
|
||||
e8/call is-valid-name?/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
||||
# check-ints-equal(eax, 1, msg)
|
||||
# . . push args
|
||||
68/push "F - test-is-valid-name-starts-with-pre-digit"/imm32
|
||||
68/push 1/imm32/true
|
||||
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-is-valid-name-starts-with-post-digit:
|
||||
# . prolog
|
||||
55/push-ebp
|
||||
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
||||
# (eax..ecx) = "q34"
|
||||
b8/copy-to-eax "q34"/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
|
||||
# eax = is-valid-name?(slice)
|
||||
# . . push args
|
||||
51/push-ecx
|
||||
# . . call
|
||||
e8/call is-valid-name?/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
||||
# check-ints-equal(eax, 1, msg)
|
||||
# . . push args
|
||||
68/push "F - test-is-valid-name-starts-with-post-digit"/imm32
|
||||
68/push 1/imm32/true
|
||||
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-is-valid-name-starts-with-digit:
|
||||
# . prolog
|
||||
55/push-ebp
|
||||
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
||||
# (eax..ecx) = "0x34"
|
||||
b8/copy-to-eax "0x34"/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
|
||||
# eax = is-valid-name?(slice)
|
||||
# . . push args
|
||||
51/push-ecx
|
||||
# . . call
|
||||
e8/call is-valid-name?/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
||||
# check-ints-equal(eax, 0, msg)
|
||||
# . . push args
|
||||
68/push "F - test-is-valid-name-starts-with-digit"/imm32
|
||||
68/push 0/imm32/false
|
||||
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
|
||||
|
||||
is-label?: # word : (address slice) -> eax : boolean
|
||||
# . prolog
|
||||
55/push-ebp
|
||||
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
||||
# . save registers
|
||||
51/push-ecx
|
||||
# ecx = word
|
||||
8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 8/disp8 . # copy *(ebp+8) to ecx
|
||||
# ecx = word->end
|
||||
8b/copy 1/mod/*+disp8 1/rm32/ecx . . . 1/r32/ecx 4/disp8 . # copy *(ecx+4) to ecx
|
||||
# return *(word->end - 1) == ':'
|
||||
# . eax = 0
|
||||
31/xor 3/mod/direct 0/rm32/eax . . . 0/r32/eax . . # clear eax
|
||||
# . eax = *((char *) word->end - 1)
|
||||
8a/copy-byte 1/mod/*+disp8 1/rm32/ecx . . . 0/r32/AL -1/disp8 . # copy byte at *(ecx-1) to AL
|
||||
# . return (eax == ':')
|
||||
3d/compare-eax-and 0x3a/imm32/colon
|
||||
b8/copy-to-eax 1/imm32/true
|
||||
74/jump-if-equal $is-label?:end/disp8
|
||||
b8/copy-to-eax 0/imm32/false
|
||||
$is-label?:end:
|
||||
# . 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-is-label?:
|
||||
# . prolog
|
||||
55/push-ebp
|
||||
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
||||
$test-is-label?:true:
|
||||
# (eax..ecx) = "AAA:"
|
||||
b8/copy-to-eax "AAA:"/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
|
||||
# is-label?(slice/ecx)
|
||||
# . . push args
|
||||
51/push-ecx
|
||||
# . . call
|
||||
e8/call is-label?/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
||||
# check-ints-equal(eax, 1, msg)
|
||||
# . . push args
|
||||
68/push "F - test-is-label?:true"/imm32
|
||||
68/push 1/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
|
||||
$test-is-label?:false:
|
||||
# (eax..ecx) = "AAA"
|
||||
b8/copy-to-eax "AAA"/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
|
||||
# is-label?(slice/ecx)
|
||||
# . . push args
|
||||
51/push-ecx
|
||||
# . . call
|
||||
e8/call is-label?/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
||||
# check-ints-equal(eax, 0, msg)
|
||||
# . . push args
|
||||
68/push "F - test-is-label?:false"/imm32
|
||||
68/push 0/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
|
||||
# . epilog
|
||||
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
|
||||
5d/pop-to-ebp
|
||||
c3/return
|
||||
|
||||
# . . vim:nowrap:textwidth=0
|
|
@ -0,0 +1,249 @@
|
|||
== 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
|
||||
|
||||
# print 'n' in hex in 'width' bytes in lower-endian order, with a space after every byte
|
||||
emit-hex: # out : (address buffered-file), n : int, width : int -> <void>
|
||||
# . 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
|
||||
57/push-edi
|
||||
# edi = out
|
||||
8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 7/r32/edi 8/disp8 . # copy *(ebp+8) to edi
|
||||
# ebx = n
|
||||
8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 3/r32/ebx 0xc/disp8 . # copy *(ebp+12) to ebx
|
||||
# edx = width
|
||||
8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 2/r32/edx 0x10/disp8 . # copy *(ebp+16) to edx
|
||||
# var curr/ecx = 0
|
||||
31/xor 3/mod/direct 1/rm32/ecx . . . 1/r32/ecx . . # clear ecx
|
||||
$emit-hex:loop:
|
||||
# if (curr >= width) break
|
||||
39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx
|
||||
7d/jump-if-greater-or-equal $emit-hex:end/disp8
|
||||
# print-byte-buffered(out, ebx)
|
||||
# . . push args
|
||||
53/push-ebx
|
||||
57/push-edi
|
||||
# . . call
|
||||
e8/call print-byte-buffered/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
||||
# write-byte-buffered(out, ' ')
|
||||
# . . push args
|
||||
68/push 0x20/imm32/space
|
||||
57/push-edi
|
||||
# . . call
|
||||
e8/call write-byte-buffered/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
||||
# ebx = ebx >> 8
|
||||
c1/shift 5/subop/logic-right 3/mod/direct 3/rm32/ebx . . . . . 8/imm8 # shift ebx right by 8 bits, while padding zeroes
|
||||
$emit-hex:continue:
|
||||
# ++curr
|
||||
41/increment-ecx
|
||||
eb/jump $emit-hex:loop/disp8
|
||||
$emit-hex:end:
|
||||
# . restore registers
|
||||
5f/pop-to-edi
|
||||
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
|
||||
|
||||
test-emit-hex-single-byte:
|
||||
# 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
|
||||
# emit-hex(_test-output-buffered-file, 0xab, 1)
|
||||
# . . push args
|
||||
68/push 1/imm32
|
||||
68/push 0xab/imm32
|
||||
68/push _test-output-buffered-file/imm32
|
||||
# . . call
|
||||
e8/call emit-hex/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/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-ints-equal(*_test-output-stream->data, 'ab ', msg)
|
||||
# . . push args
|
||||
68/push "F - test-emit-hex-single-byte"/imm32
|
||||
68/push 0x206261/imm32
|
||||
# . . push *_test-output-stream->data
|
||||
b8/copy-to-eax _test-output-stream/imm32
|
||||
ff 6/subop/push 1/mod/*+disp8 0/rm32/eax . . . . 0xc/disp8 . # push *(eax+12)
|
||||
# . . call
|
||||
e8/call check-ints-equal/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
||||
# . end
|
||||
c3/return
|
||||
|
||||
test-emit-hex-multiple-byte:
|
||||
# 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
|
||||
# emit-hex(_test-output-buffered-file, 0x1234, 2)
|
||||
# . . push args
|
||||
68/push 2/imm32
|
||||
68/push 0x1234/imm32
|
||||
68/push _test-output-buffered-file/imm32
|
||||
# . . call
|
||||
e8/call emit-hex/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/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, "34 12 ", msg)
|
||||
# . . push args
|
||||
68/push "F - test-emit-hex-multiple-byte/1"/imm32
|
||||
68/push "34 12 "/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
|
||||
# . end
|
||||
c3/return
|
||||
|
||||
test-emit-hex-zero-pad:
|
||||
# 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
|
||||
# emit-hex(_test-output-buffered-file, 0xab, 2)
|
||||
# . . push args
|
||||
68/push 2/imm32
|
||||
68/push 0xab/imm32
|
||||
68/push _test-output-buffered-file/imm32
|
||||
# . . call
|
||||
e8/call emit-hex/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/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(_test-output-stream->data == 'ab 00 ')
|
||||
# . . push args
|
||||
68/push "F - test-emit-hex-zero-pad/1"/imm32
|
||||
68/push "ab 00 "/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
|
||||
# . end
|
||||
c3/return
|
||||
|
||||
test-emit-hex-negative:
|
||||
# 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
|
||||
# emit-hex(_test-output-buffered-file, -1, 2)
|
||||
# . . push args
|
||||
68/push 2/imm32
|
||||
68/push -1/imm32
|
||||
68/push _test-output-buffered-file/imm32
|
||||
# . . call
|
||||
e8/call emit-hex/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/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 == "ff ff ")
|
||||
# . . push args
|
||||
68/push "F - test-emit-hex-negative/1"/imm32
|
||||
68/push "ff ff "/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
|
||||
# . end
|
||||
c3/return
|
||||
|
||||
# . . vim:nowrap:textwidth=0
|
|
@ -0,0 +1,484 @@
|
|||
== 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
|
||||
|
||||
# If datum of 'word' is not a valid name, it must be a hex int. Parse and print
|
||||
# it in 'width' bytes of hex, least significant first.
|
||||
# Otherwise just print the entire word including metadata.
|
||||
# Always print a trailing space.
|
||||
emit: # out : (address buffered-file), word : (address slice), width : int -> <void>
|
||||
# . prolog
|
||||
55/push-ebp
|
||||
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
||||
# . save registers
|
||||
50/push-eax
|
||||
56/push-esi
|
||||
57/push-edi
|
||||
# esi = word
|
||||
8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 0xc/disp8 . # copy *(ebp+12) to esi
|
||||
# var name/edi : (address slice) = {0, 0}
|
||||
68/push 0/imm32/end
|
||||
68/push 0/imm32/start
|
||||
89/copy 3/mod/direct 7/rm32/edi . . . 4/r32/esp . . # copy esp to edi
|
||||
# datum = next-token-from-slice(word->start, word->end, '/')
|
||||
# . . push args
|
||||
57/push-edi
|
||||
68/push 0x2f/imm32/slash
|
||||
ff 6/subop/push 1/mod/*+disp8 6/rm32/esi . . . . 4/disp8 . # push *(esi+4)
|
||||
ff 6/subop/push 0/mod/indirect 6/rm32/esi . . . . . . # push *esi
|
||||
# . . call
|
||||
e8/call next-token-from-slice/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x10/imm32 # add to esp
|
||||
# if (is-valid-name?(datum)) write-slice-buffered(out, word) and return
|
||||
# . eax = is-valid-name?(name)
|
||||
# . . push args
|
||||
57/push-edi
|
||||
# . . call
|
||||
e8/call is-valid-name?/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
||||
# . if (eax != 0)
|
||||
3d/compare-eax-and 0/imm32
|
||||
74/jump-if-equal $emit:hex-int/disp8
|
||||
$emit:name:
|
||||
# . write-slice-buffered(out, word)
|
||||
# . . push args
|
||||
56/push-esi
|
||||
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
|
||||
# . write-buffered(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-buffered/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
||||
# . return
|
||||
eb/jump $emit:end/disp8
|
||||
# otherwise emit-hex(out, parse-hex-int(datum), width)
|
||||
# (Weird shit can happen here if the datum of 'word' isn't either a valid
|
||||
# name or a hex number, but we're only going to be passing in real legal
|
||||
# programs. We just want to make sure that valid names aren't treated as
|
||||
# (valid) hex numbers.)
|
||||
$emit:hex-int:
|
||||
# . value/eax = parse-hex-int(datum)
|
||||
# . . push args
|
||||
57/push-edi
|
||||
# . . call
|
||||
e8/call parse-hex-int/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
||||
# . emit-hex(out, value, width)
|
||||
# . . push args
|
||||
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x10/disp8 . # push *(ebp+16)
|
||||
50/push-eax
|
||||
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
|
||||
# . . call
|
||||
e8/call emit-hex/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
||||
$emit:end:
|
||||
# . reclaim locals
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
||||
# . restore registers
|
||||
5f/pop-to-edi
|
||||
5e/pop-to-esi
|
||||
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-number:
|
||||
# . 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
|
||||
# (eax..ecx) = "30"
|
||||
b8/copy-to-eax "30"/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(_test-output-buffered-file, slice, 1)
|
||||
# . . push args
|
||||
68/push 1/imm32
|
||||
51/push-ecx
|
||||
68/push _test-output-buffered-file/imm32
|
||||
# . . call
|
||||
e8/call emit/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/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, "30 ", msg)
|
||||
# . . push args
|
||||
68/push "F - test-emit-number/1"/imm32
|
||||
68/push "30 "/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-negative-number:
|
||||
# test support for sign-extending negative numbers
|
||||
# . 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
|
||||
# (eax..ecx) = "-2"
|
||||
b8/copy-to-eax "-2"/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(_test-output-buffered-file, slice, 2)
|
||||
# . . push args
|
||||
68/push 2/imm32
|
||||
51/push-ecx
|
||||
68/push _test-output-buffered-file/imm32
|
||||
# . . call
|
||||
e8/call emit/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/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, "fe ff ", msg)
|
||||
# . . push args
|
||||
68/push "F - test-emit-number/1"/imm32
|
||||
68/push "fe ff "/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-number-with-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
|
||||
# (eax..ecx) = "-2/foo"
|
||||
b8/copy-to-eax "-2/foo"/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(_test-output-buffered-file, slice, 2)
|
||||
# . . push args
|
||||
68/push 2/imm32
|
||||
51/push-ecx
|
||||
68/push _test-output-buffered-file/imm32
|
||||
# . . call
|
||||
e8/call emit/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/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
|
||||
# the '/foo' will have no impact on the output
|
||||
# check-stream-equal(_test-output-stream, "fe ff ", msg)
|
||||
# . . push args
|
||||
68/push "F - test-emit-number-with-metadata"/imm32
|
||||
68/push "fe ff "/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-non-number:
|
||||
# . 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
|
||||
# (eax..ecx) = "xyz"
|
||||
b8/copy-to-eax "xyz"/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(_test-output-buffered-file, slice, 2)
|
||||
# . . push args
|
||||
68/push 2/imm32
|
||||
51/push-ecx
|
||||
68/push _test-output-buffered-file/imm32
|
||||
# . . call
|
||||
e8/call emit/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/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, "xyz", msg)
|
||||
# . . push args
|
||||
68/push "F - test-emit-non-number"/imm32
|
||||
68/push "xyz "/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-non-number-with-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
|
||||
# (eax..ecx) = "xyz/"
|
||||
b8/copy-to-eax "xyz/"/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(_test-output-buffered-file, slice, 2)
|
||||
# . . push args
|
||||
68/push 2/imm32
|
||||
51/push-ecx
|
||||
68/push _test-output-buffered-file/imm32
|
||||
# . . call
|
||||
e8/call emit/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/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, "xyz/", msg)
|
||||
# . . push args
|
||||
68/push "F - test-emit-non-number-with-metadata"/imm32
|
||||
68/push "xyz/ "/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-non-number-with-all-hex-digits-and-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
|
||||
# (eax..ecx) = "abcd/xyz"
|
||||
b8/copy-to-eax "abcd/xyz"/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(_test-output-buffered-file, slice, 2)
|
||||
# . . push args
|
||||
68/push 2/imm32
|
||||
51/push-ecx
|
||||
68/push _test-output-buffered-file/imm32
|
||||
# . . call
|
||||
e8/call emit/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/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, "^")
|
||||
#? # . . push args
|
||||
#? 68/push "^"/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, "abcd/xyz")
|
||||
# . . push args
|
||||
68/push "F - test-emit-non-number-with-all-hex-digits"/imm32
|
||||
68/push "abcd/xyz "/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
|
|
@ -0,0 +1,238 @@
|
|||
== 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
|
||||
|
||||
compute-width: # word : (address array byte) -> eax : int
|
||||
# . prolog
|
||||
55/push-ebp
|
||||
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
||||
# . save registers
|
||||
51/push-ecx
|
||||
# eax = word
|
||||
8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 8/disp8 . # copy *(ebp+8) to ecx
|
||||
# ecx = word + word->length
|
||||
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
|
||||
# eax = word->data
|
||||
05/add-to-eax 4/imm32
|
||||
# var in/ecx : (address slice) = {eax, ecx}
|
||||
51/push-ecx
|
||||
50/push-eax
|
||||
89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
|
||||
# return compute-width-of-slice(ecx)
|
||||
# . . push args
|
||||
51/push-ecx
|
||||
# . . call
|
||||
e8/call compute-width-of-slice/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
||||
$compute-width:end:
|
||||
# . reclaim locals
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/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
|
||||
|
||||
compute-width-of-slice: # s : (address slice) -> eax : int
|
||||
# . prolog
|
||||
55/push-ebp
|
||||
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
||||
# . save registers
|
||||
51/push-ecx
|
||||
# ecx = s
|
||||
8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 8/disp8 . # copy *(ebp+8) to ecx
|
||||
# if (has-metadata?(word, "imm32")) return 4
|
||||
# . eax = has-metadata?(word, "imm32")
|
||||
# . . push args
|
||||
68/push "imm32"/imm32
|
||||
51/push-ecx
|
||||
# . . call
|
||||
e8/call has-metadata?/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
||||
# . if (eax != 0) return 4
|
||||
3d/compare-eax-and 0/imm32
|
||||
b8/copy-to-eax 4/imm32 # ZF is set, so we can overwrite eax now
|
||||
75/jump-if-not-equal $compute-width-of-slice:end/disp8
|
||||
# if (has-metadata?(word, "disp32")) return 4
|
||||
# . eax = has-metadata?(word, "disp32")
|
||||
# . . push args
|
||||
68/push "disp32"/imm32
|
||||
51/push-ecx
|
||||
# . . call
|
||||
e8/call has-metadata?/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
||||
# . if (eax != 0) return 4
|
||||
3d/compare-eax-and 0/imm32
|
||||
b8/copy-to-eax 4/imm32 # ZF is set, so we can overwrite eax now
|
||||
75/jump-if-not-equal $compute-width-of-slice:end/disp8
|
||||
# if (has-metadata?(word, "imm16")) return 2
|
||||
# . eax = has-metadata?(word, "imm16")
|
||||
# . . push args
|
||||
68/push "imm16"/imm32
|
||||
51/push-ecx
|
||||
# . . call
|
||||
e8/call has-metadata?/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
||||
# . if (eax != 0) return 2
|
||||
3d/compare-eax-and 0/imm32
|
||||
b8/copy-to-eax 2/imm32 # ZF is set, so we can overwrite eax now
|
||||
75/jump-if-not-equal $compute-width-of-slice:end/disp8
|
||||
# if (has-metadata?(word, "disp16")) return 2
|
||||
# . eax = has-metadata?(word, "disp16")
|
||||
# . . push args
|
||||
68/push "disp16"/imm32
|
||||
51/push-ecx
|
||||
# . . call
|
||||
e8/call has-metadata?/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
||||
# . if (eax != 0) return 2
|
||||
3d/compare-eax-and 0/imm32
|
||||
b8/copy-to-eax 2/imm32 # ZF is set, so we can overwrite eax now
|
||||
75/jump-if-not-equal $compute-width-of-slice:end/disp8
|
||||
# otherwise return 1
|
||||
b8/copy-to-eax 1/imm32
|
||||
$compute-width-of-slice:end:
|
||||
# . 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-compute-width:
|
||||
# . prolog
|
||||
55/push-ebp
|
||||
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
||||
$test-compute-width:imm8:
|
||||
# eax = compute-width("0x2/imm8")
|
||||
# . . push args
|
||||
68/push "0x2/imm8"/imm32
|
||||
# . . call
|
||||
e8/call compute-width/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
||||
# check-ints-equal(eax, 1, msg)
|
||||
# . . push args
|
||||
68/push "F - test-compute-width: 0x2/imm8"/imm32
|
||||
50/push-eax
|
||||
68/push 1/imm32
|
||||
# . . call
|
||||
e8/call check-ints-equal/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
||||
$test-compute-width:imm16:
|
||||
# eax = compute-width("4/imm16")
|
||||
# . . push args
|
||||
68/push "4/imm16"/imm32
|
||||
# . . call
|
||||
e8/call compute-width/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
||||
# check-ints-equal(eax, 2, msg)
|
||||
# . . push args
|
||||
68/push "F - test-compute-width: 4/imm16"/imm32
|
||||
50/push-eax
|
||||
68/push 2/imm32
|
||||
# . . call
|
||||
e8/call check-ints-equal/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
||||
$test-compute-width:imm32:
|
||||
# eax = compute-width("4/imm32")
|
||||
# . . push args
|
||||
68/push "4/imm32"/imm32
|
||||
# . . call
|
||||
e8/call compute-width/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
||||
# check-ints-equal(eax, 4, msg)
|
||||
# . . push args
|
||||
68/push "F - test-compute-width: 4/imm32"/imm32
|
||||
50/push-eax
|
||||
68/push 4/imm32
|
||||
# . . call
|
||||
e8/call check-ints-equal/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
||||
$test-compute-width:disp8:
|
||||
# eax = compute-width("foo/disp8")
|
||||
# . . push args
|
||||
68/push "foo/disp8"/imm32
|
||||
# . . call
|
||||
e8/call compute-width/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
||||
# check-ints-equal(eax, 1, msg)
|
||||
# . . push args
|
||||
68/push "F - test-compute-width: foo/disp8"/imm32
|
||||
50/push-eax
|
||||
68/push 1/imm32
|
||||
# . . call
|
||||
e8/call check-ints-equal/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
||||
$test-compute-width:disp16:
|
||||
# eax = compute-width("foo/disp16")
|
||||
# . . push args
|
||||
68/push "foo/disp16"/imm32
|
||||
# . . call
|
||||
e8/call compute-width/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
||||
# check-ints-equal(eax, 2, msg)
|
||||
# . . push args
|
||||
68/push "F - test-compute-width: foo/disp16"/imm32
|
||||
50/push-eax
|
||||
68/push 2/imm32
|
||||
# . . call
|
||||
e8/call check-ints-equal/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
||||
$test-compute-width:disp32:
|
||||
# eax = compute-width("foo/disp32")
|
||||
# . . push args
|
||||
68/push "foo/disp32"/imm32
|
||||
# . . call
|
||||
e8/call compute-width/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
||||
# check-ints-equal(eax, 4, msg)
|
||||
# . . push args
|
||||
68/push "F - test-compute-width: foo/disp32"/imm32
|
||||
50/push-eax
|
||||
68/push 4/imm32
|
||||
# . . call
|
||||
e8/call check-ints-equal/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
||||
$test-compute-width:no-metadata:
|
||||
# eax = compute-width("45")
|
||||
# . . push args
|
||||
68/push "45"/imm32
|
||||
# . . call
|
||||
e8/call compute-width/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
||||
# check-ints-equal(eax, 1, msg)
|
||||
# . . push args
|
||||
68/push "F - test-compute-width: 45 (no metadata)"/imm32
|
||||
50/push-eax
|
||||
68/push 1/imm32
|
||||
# . . 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
|
||||
|
||||
# . . vim:nowrap:textwidth=0
|
|
@ -0,0 +1,142 @@
|
|||
== 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
|
||||
|
||||
# print 'arr' in hex with a space after every byte
|
||||
emit-hex-array: # out : (address buffered-file), arr : (address array byte) -> <void>
|
||||
# . 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
|
||||
57/push-edi
|
||||
# edi = out
|
||||
8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 7/r32/edi 8/disp8 . # copy *(ebp+8) to edi
|
||||
# edx = arr # <== 0xbdffffe4
|
||||
8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 2/r32/edx 0xc/disp8 . # copy *(ebp+12) to edx
|
||||
# curr/ecx = arr->data
|
||||
8d/copy-address 1/mod/*+disp8 2/rm32/edx . . . 1/r32/ecx 4/disp8 . # copy edx+4 to ecx
|
||||
# max/edx = arr->data + arr->length
|
||||
8b/copy 0/mod/indirect 2/rm32/edx . . . 2/r32/edx . . # copy *edx to edx
|
||||
01/add 3/mod/direct 2/rm32/edx . . . 1/r32/ecx . . # add ecx to edx
|
||||
# eax = 0
|
||||
31/xor 3/mod/direct 0/rm32/eax . . . 0/r32/eax . . # clear eax
|
||||
$emit-hex-array:loop:
|
||||
# if (curr >= width) break
|
||||
39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx
|
||||
73/jump-if-greater-or-equal-unsigned $emit-hex-array:end/disp8
|
||||
# emit-hex(out, *curr, width=1)
|
||||
# . . push args
|
||||
68/push 1/imm32/width
|
||||
8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 0/r32/AL . . # copy byte at *ecx to AL
|
||||
50/push-eax
|
||||
57/push-edi
|
||||
# . . call
|
||||
e8/call emit-hex/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
||||
# ++curr
|
||||
41/increment-ecx
|
||||
eb/jump $emit-hex-array:loop/disp8
|
||||
$emit-hex-array:end:
|
||||
# . restore registers
|
||||
5f/pop-to-edi
|
||||
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-hex-array:
|
||||
# . 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 arr/ecx (address array byte) = [01, 02, 03]
|
||||
68/push 0x00030201/imm32 # bytes 01 02 03
|
||||
68/push 3/imm32/length
|
||||
89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
|
||||
# emit-hex-array(_test-output-buffered-file, arr)
|
||||
# . . push args
|
||||
51/push-ecx
|
||||
68/push _test-output-buffered-file/imm32
|
||||
# . . call
|
||||
e8/call emit-hex-array/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
|
||||
#? # . 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, "01 02 03 ", msg)
|
||||
# . . push args
|
||||
68/push "F - test-emit-hex-array"/imm32
|
||||
68/push "01 02 03 "/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
|
||||
|
||||
# . . vim:nowrap:textwidth=0
|
12
Readme.md
12
Readme.md
|
@ -104,12 +104,12 @@ You can use SubX to translate itself. For example, running natively on Linux:
|
|||
|
||||
```sh
|
||||
# generate translator phases using the C++ translator
|
||||
$ ./subx translate init.linux 0[0-6]*.subx 070---hex.subx -o hex
|
||||
$ ./subx translate init.linux 0*.subx apps/subx-common.subx apps/survey.subx -o survey
|
||||
$ ./subx translate init.linux 0*.subx apps/subx-common.subx apps/pack.subx -o pack
|
||||
$ ./subx translate init.linux 0*.subx apps/subx-common.subx apps/assort.subx -o assort
|
||||
$ ./subx translate init.linux 0*.subx apps/subx-common.subx apps/dquotes.subx -o dquotes
|
||||
$ ./subx translate init.linux 0*.subx apps/subx-common.subx apps/tests.subx -o tests
|
||||
$ ./subx translate init.linux 0*.subx apps/subx-params.subx apps/hex.subx -o hex
|
||||
$ ./subx translate init.linux 0*.subx apps/subx-params.subx apps/survey.subx -o survey
|
||||
$ ./subx translate init.linux 0*.subx apps/subx-params.subx apps/pack.subx -o pack
|
||||
$ ./subx translate init.linux 0*.subx apps/subx-params.subx apps/assort.subx -o assort
|
||||
$ ./subx translate init.linux 0*.subx apps/subx-params.subx apps/dquotes.subx -o dquotes
|
||||
$ ./subx translate init.linux 0*.subx apps/subx-params.subx apps/tests.subx -o tests
|
||||
$ chmod +x hex survey pack assort dquotes tests
|
||||
|
||||
# use the generated translator phases to translate SubX programs
|
||||
|
|
BIN
apps/assort
BIN
apps/assort
Binary file not shown.
|
@ -7,7 +7,7 @@
|
|||
# because we don't know if they refer to the line above or the line below.
|
||||
#
|
||||
# To run:
|
||||
# $ ./subx translate init.linux 0*.subx apps/subx-common.subx apps/assort.subx -o apps/assort
|
||||
# $ ./subx translate init.linux 0*.subx apps/subx-params.subx apps/assort.subx -o apps/assort
|
||||
# $ cat x
|
||||
# == code
|
||||
# abc
|
||||
|
@ -38,10 +38,10 @@ Entry: # run tests if necessary, convert stdin if not
|
|||
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 run-main
|
||||
# if (argc <= 1) goto interactive
|
||||
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
|
||||
# if (!kernel-string-equal?(argv[1], "test")) goto run-main
|
||||
7e/jump-if-lesser-or-equal $subx-assort-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
|
||||
|
@ -50,15 +50,15 @@ Entry: # run tests if necessary, convert stdin if not
|
|||
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 == 0) goto run-main
|
||||
# . if (eax == 0) goto interactive
|
||||
3d/compare-eax-and 0/imm32
|
||||
74/jump-if-equal $run-main/disp8
|
||||
74/jump-if-equal $subx-assort-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 $main:end/disp8
|
||||
$run-main:
|
||||
eb/jump $subx-assort-main:end/disp8
|
||||
$subx-assort-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
|
||||
|
@ -66,19 +66,19 @@ $run-main:
|
|||
# configure ed to really exit()
|
||||
# . ed->target = 0
|
||||
c7 0/subop/copy 0/mod/direct 0/rm32/eax . . . . . 0/imm32 # copy to *eax
|
||||
# convert(Stdin, Stdout, Stderr, ed)
|
||||
# subx-assort(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 convert/disp32
|
||||
e8/call subx-assort/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:
|
||||
$subx-assort-main:end:
|
||||
b8/copy-to-eax 1/imm32/exit
|
||||
cd/syscall 0x80/imm8
|
||||
|
||||
|
@ -86,7 +86,7 @@ $main:end:
|
|||
# table: (address stream {string, (address stream byte)}) (8 bytes per row)
|
||||
# inefficient; uses sequential search for looking up segments by name
|
||||
|
||||
convert: # in : (address buffered-file), out : (address buffered-file) -> <void>
|
||||
subx-assort: # in : (address buffered-file), out : (address buffered-file) -> <void>
|
||||
# pseudocode:
|
||||
# var table : (address stream) = new-stream(10 rows, 8 bytes each)
|
||||
# read-segments(in, table)
|
||||
|
@ -110,7 +110,7 @@ convert: # in : (address buffered-file), out : (address buffered-file) -> <void
|
|||
e8/call clear-stream/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
||||
$convert:read:
|
||||
$subx-assort:read:
|
||||
#? # print("read\n") {{{
|
||||
#? # . . push args
|
||||
#? 68/push "read\n"/imm32
|
||||
|
@ -128,7 +128,7 @@ $convert:read:
|
|||
e8/call read-segments/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
||||
$convert:write:
|
||||
$subx-assort:write:
|
||||
#? # print("write\n") {{{
|
||||
#? # . . push args
|
||||
#? 68/push "write\n"/imm32
|
||||
|
@ -146,7 +146,7 @@ $convert:write:
|
|||
e8/call write-segments/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
||||
$convert:end:
|
||||
$subx-assort:end:
|
||||
# . reclaim locals
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x5c/imm32 # add to esp
|
||||
# . restore registers
|
||||
|
@ -156,7 +156,7 @@ $convert:end:
|
|||
5d/pop-to-ebp
|
||||
c3/return
|
||||
|
||||
test-convert:
|
||||
test-subx-assort:
|
||||
# . prolog
|
||||
55/push-ebp
|
||||
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
||||
|
@ -320,12 +320,12 @@ test-convert:
|
|||
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)
|
||||
# subx-assort(_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
|
||||
e8/call subx-assort/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
||||
# . flush(_test-output-buffered-file)
|
||||
|
@ -379,7 +379,7 @@ test-convert:
|
|||
#? # }}}
|
||||
# . check-next-stream-line-equal(_test-output-stream, "== code 0x09000000", msg)
|
||||
# . . push args
|
||||
68/push "F - test-convert/0"/imm32
|
||||
68/push "F - test-subx-assort/0"/imm32
|
||||
68/push "== code 0x09000000"/imm32
|
||||
68/push _test-output-stream/imm32
|
||||
# . . call
|
||||
|
@ -388,7 +388,7 @@ test-convert:
|
|||
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/1"/imm32
|
||||
68/push "F - test-subx-assort/1"/imm32
|
||||
68/push "1"/imm32
|
||||
68/push _test-output-stream/imm32
|
||||
# . . call
|
||||
|
@ -397,7 +397,7 @@ test-convert:
|
|||
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 # comment 4 inline with other contents", msg)
|
||||
# . . push args
|
||||
68/push "F - test-convert/2"/imm32
|
||||
68/push "F - test-subx-assort/2"/imm32
|
||||
68/push "2 3 # comment 4 inline with other contents"/imm32
|
||||
68/push _test-output-stream/imm32
|
||||
# . . call
|
||||
|
@ -406,7 +406,7 @@ test-convert:
|
|||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
||||
# . check-next-stream-line-equal(_test-output-stream, "6 7", msg)
|
||||
# . . push args
|
||||
68/push "F - test-convert/3"/imm32
|
||||
68/push "F - test-subx-assort/3"/imm32
|
||||
68/push "6 7"/imm32
|
||||
68/push _test-output-stream/imm32
|
||||
# . . call
|
||||
|
@ -415,7 +415,7 @@ test-convert:
|
|||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
||||
# . check-next-stream-line-equal(_test-output-stream, "8 9", msg)
|
||||
# . . push args
|
||||
68/push "F - test-convert/4"/imm32
|
||||
68/push "F - test-subx-assort/4"/imm32
|
||||
68/push "8 9"/imm32
|
||||
68/push _test-output-stream/imm32
|
||||
# . . call
|
||||
|
@ -424,7 +424,7 @@ test-convert:
|
|||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
||||
# . check-next-stream-line-equal(_test-output-stream, "10 11", msg)
|
||||
# . . push args
|
||||
68/push "F - test-convert/5"/imm32
|
||||
68/push "F - test-subx-assort/5"/imm32
|
||||
68/push "10 11"/imm32
|
||||
68/push _test-output-stream/imm32
|
||||
# . . call
|
||||
|
@ -433,7 +433,7 @@ test-convert:
|
|||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
||||
# . check-next-stream-line-equal(_test-output-stream, "== data 0x0a000000", msg)
|
||||
# . . push args
|
||||
68/push "F - test-convert/6"/imm32
|
||||
68/push "F - test-subx-assort/6"/imm32
|
||||
68/push "== data 0x0a000000"/imm32
|
||||
68/push _test-output-stream/imm32
|
||||
# . . call
|
||||
|
@ -442,7 +442,7 @@ test-convert:
|
|||
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/7"/imm32
|
||||
68/push "F - test-subx-assort/7"/imm32
|
||||
68/push "4 5/imm32"/imm32
|
||||
68/push _test-output-stream/imm32
|
||||
# . . call
|
||||
|
|
BIN
apps/braces
BIN
apps/braces
Binary file not shown.
|
@ -1,7 +1,7 @@
|
|||
# Structured control flow using break/loop rather than jump.
|
||||
#
|
||||
# To run (on Linux):
|
||||
# $ ./ntranslate init.linux 0*.subx apps/subx-common.subx apps/calls.subx
|
||||
# $ ./ntranslate init.linux 0*.subx apps/subx-params.subx apps/calls.subx
|
||||
# $ mv a.elf apps/calls
|
||||
#
|
||||
# Example 1:
|
||||
|
|
BIN
apps/calls
BIN
apps/calls
Binary file not shown.
|
@ -1,7 +1,7 @@
|
|||
# Function calls in a single line.
|
||||
#
|
||||
# To run (on Linux):
|
||||
# $ ./ntranslate init.linux 0*.subx apps/subx-common.subx apps/calls.subx
|
||||
# $ ./ntranslate init.linux 0*.subx apps/subx-params.subx apps/calls.subx
|
||||
# $ mv a.elf apps/calls
|
||||
#
|
||||
# Example 1:
|
||||
|
|
BIN
apps/crenshaw2-1
BIN
apps/crenshaw2-1
Binary file not shown.
Binary file not shown.
BIN
apps/dquotes
BIN
apps/dquotes
Binary file not shown.
|
@ -2,7 +2,7 @@
|
|||
# Replace them with references to new variables in the data segment.
|
||||
#
|
||||
# To run:
|
||||
# $ ./subx translate init.linux 0*.subx apps/subx-common.subx apps/dquotes.subx -o apps/dquotes
|
||||
# $ ./subx translate init.linux 0*.subx apps/subx-params.subx apps/dquotes.subx -o apps/dquotes
|
||||
# $ cat x
|
||||
# == code
|
||||
# ab "cd ef"/imm32
|
||||
|
@ -33,11 +33,11 @@ Entry: # run tests if necessary, convert stdin if not
|
|||
# . . 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 run-main
|
||||
# - 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-lesser-or-equal $run-main/disp8
|
||||
# if (!kernel-string-equal?(argv[1], "test")) goto run-main
|
||||
7e/jump-if-lesser-or-equal $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
|
||||
|
@ -46,15 +46,15 @@ Entry: # run tests if necessary, convert stdin if not
|
|||
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 == 0) goto run-main
|
||||
# . if (eax == 0) goto interactive
|
||||
3d/compare-eax-and 0/imm32
|
||||
74/jump-if-equal $run-main/disp8
|
||||
74/jump-if-equal $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 $main:end/disp8
|
||||
$run-main:
|
||||
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
|
||||
|
@ -62,19 +62,19 @@ $run-main:
|
|||
# configure ed to really exit()
|
||||
# . ed->target = 0
|
||||
c7 0/subop/copy 0/mod/direct 0/rm32/eax . . . . . 0/imm32 # copy to *eax
|
||||
# convert(Stdin, 1/stdout, 2/stderr, ed)
|
||||
# subx-dquotes(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
|
||||
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
|
||||
$main:end:
|
||||
$subx-dquotes-main:end:
|
||||
b8/copy-to-eax 1/imm32/exit
|
||||
cd/syscall 0x80/imm8
|
||||
|
||||
|
@ -82,7 +82,7 @@ $main:end:
|
|||
# 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>
|
||||
subx-dquotes: # 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)
|
||||
|
@ -146,7 +146,7 @@ convert: # in : (address buffered-file), out : (address buffered-file) -> <void
|
|||
e8/call write/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
||||
$convert:line-loop:
|
||||
$subx-dquotes:line-loop:
|
||||
# clear-stream(line)
|
||||
# . . push args
|
||||
51/push-ecx
|
||||
|
@ -162,11 +162,11 @@ $convert:line-loop:
|
|||
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:
|
||||
$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-equal $convert:break/disp32
|
||||
$convert:word-loop:
|
||||
0f 84/jump-if-equal $subx-dquotes:break/disp32
|
||||
$subx-dquotes:word-loop:
|
||||
# next-word-or-string(line, word-slice)
|
||||
# . . push args
|
||||
52/push-edx
|
||||
|
@ -175,7 +175,7 @@ $convert:word-loop:
|
|||
e8/call next-word-or-string/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
||||
$convert:check1:
|
||||
$subx-dquotes:check1:
|
||||
# if (slice-empty?(word-slice)) break
|
||||
# . eax = slice-empty?(word-slice)
|
||||
# . . push args
|
||||
|
@ -186,8 +186,8 @@ $convert:check1:
|
|||
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:
|
||||
0f 85/jump-if-not-equal $subx-dquotes:next-line/disp32
|
||||
$subx-dquotes: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
|
||||
|
@ -196,12 +196,12 @@ $convert:check-for-comment:
|
|||
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:
|
||||
74/jump-if-equal $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-not-equal $convert:regular-word/disp8
|
||||
$convert:string-literal:
|
||||
75/jump-if-not-equal $subx-dquotes:regular-word/disp8
|
||||
$subx-dquotes:string-literal:
|
||||
# process-string-literal(word-slice, out, new-data-segment)
|
||||
# . . push args
|
||||
57/push-edi
|
||||
|
@ -212,8 +212,8 @@ $convert:string-literal:
|
|||
# . . 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:
|
||||
eb/jump $subx-dquotes:next-word/disp8
|
||||
$subx-dquotes:regular-word:
|
||||
# write-slice-buffered(out, word-slice)
|
||||
# . . push args
|
||||
52/push-edx
|
||||
|
@ -223,7 +223,7 @@ $convert:regular-word:
|
|||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
||||
# fall through
|
||||
$convert:next-word:
|
||||
$subx-dquotes:next-word:
|
||||
# write-buffered(out, " ")
|
||||
# . . push args
|
||||
68/push Space/imm32
|
||||
|
@ -233,8 +233,8 @@ $convert:next-word:
|
|||
# . . 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:
|
||||
eb/jump $subx-dquotes:word-loop/disp8
|
||||
$subx-dquotes:next-line:
|
||||
# write-buffered(out, "\n")
|
||||
# . . push args
|
||||
68/push Newline/imm32
|
||||
|
@ -244,8 +244,8 @@ $convert:next-line:
|
|||
# . . 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:
|
||||
e9/jump $subx-dquotes:line-loop/disp32
|
||||
$subx-dquotes:break:
|
||||
# write-stream-data(out, new-data-segment)
|
||||
# . . push args
|
||||
57/push-edi
|
||||
|
@ -261,7 +261,7 @@ $convert:break:
|
|||
e8/call flush/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
||||
$convert:end:
|
||||
$subx-dquotes:end:
|
||||
# . reclaim locals
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x214/imm32 # add to esp
|
||||
# . restore registers
|
||||
|
@ -383,7 +383,7 @@ $process-string-literal:end:
|
|||
5d/pop-to-ebp
|
||||
c3/return
|
||||
|
||||
test-convert-is-idempotent-by-default:
|
||||
test-subx-dquotes-is-idempotent-by-default:
|
||||
# . prolog
|
||||
55/push-ebp
|
||||
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
||||
|
@ -502,12 +502,12 @@ test-convert-is-idempotent-by-default:
|
|||
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)
|
||||
# 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 convert/disp32
|
||||
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)
|
||||
|
@ -556,7 +556,7 @@ test-convert-is-idempotent-by-default:
|
|||
#? # }}}
|
||||
# . check-next-stream-line-equal(_test-output-stream, "", msg)
|
||||
# . . push args
|
||||
68/push "F - test-convert-is-idempotent-by-default/0"/imm32
|
||||
68/push "F - test-subx-dquotes-is-idempotent-by-default/0"/imm32
|
||||
68/push ""/imm32
|
||||
68/push _test-output-stream/imm32
|
||||
# . . call
|
||||
|
@ -565,7 +565,7 @@ test-convert-is-idempotent-by-default:
|
|||
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 "F - test-subx-dquotes-is-idempotent-by-default/1"/imm32
|
||||
68/push ""/imm32
|
||||
68/push _test-output-stream/imm32
|
||||
# . . call
|
||||
|
@ -574,7 +574,7 @@ test-convert-is-idempotent-by-default:
|
|||
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-convert-is-idempotent-by-default/2"/imm32
|
||||
68/push "F - test-subx-dquotes-is-idempotent-by-default/2"/imm32
|
||||
68/push "== code 0x1 "/imm32
|
||||
68/push _test-output-stream/imm32
|
||||
# . . call
|
||||
|
@ -583,7 +583,7 @@ test-convert-is-idempotent-by-default:
|
|||
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 "F - test-subx-dquotes-is-idempotent-by-default/3"/imm32
|
||||
68/push ""/imm32
|
||||
68/push _test-output-stream/imm32
|
||||
# . . call
|
||||
|
@ -592,7 +592,7 @@ test-convert-is-idempotent-by-default:
|
|||
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 "F - test-subx-dquotes-is-idempotent-by-default/4"/imm32
|
||||
68/push "1 "/imm32
|
||||
68/push _test-output-stream/imm32
|
||||
# . . call
|
||||
|
@ -601,7 +601,7 @@ test-convert-is-idempotent-by-default:
|
|||
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 "F - test-subx-dquotes-is-idempotent-by-default/5"/imm32
|
||||
68/push ""/imm32
|
||||
68/push _test-output-stream/imm32
|
||||
# . . call
|
||||
|
@ -610,7 +610,7 @@ test-convert-is-idempotent-by-default:
|
|||
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 "F - test-subx-dquotes-is-idempotent-by-default/6"/imm32
|
||||
68/push "2 3 "/imm32
|
||||
68/push _test-output-stream/imm32
|
||||
# . . call
|
||||
|
@ -619,7 +619,7 @@ test-convert-is-idempotent-by-default:
|
|||
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-convert-is-idempotent-by-default/7"/imm32
|
||||
68/push "F - test-subx-dquotes-is-idempotent-by-default/7"/imm32
|
||||
68/push "== data 0x2 "/imm32
|
||||
68/push _test-output-stream/imm32
|
||||
# . . call
|
||||
|
@ -628,7 +628,7 @@ test-convert-is-idempotent-by-default:
|
|||
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 "F - test-subx-dquotes-is-idempotent-by-default/8"/imm32
|
||||
68/push "4 5/imm32 "/imm32
|
||||
68/push _test-output-stream/imm32
|
||||
# . . call
|
||||
|
@ -640,7 +640,7 @@ test-convert-is-idempotent-by-default:
|
|||
5d/pop-to-ebp
|
||||
c3/return
|
||||
|
||||
test-convert-processes-string-literals:
|
||||
test-subx-dquotes-processes-string-literals:
|
||||
# . prolog
|
||||
55/push-ebp
|
||||
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
||||
|
@ -703,12 +703,12 @@ test-convert-processes-string-literals:
|
|||
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)
|
||||
# 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 convert/disp32
|
||||
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)
|
||||
|
@ -769,7 +769,7 @@ test-convert-processes-string-literals:
|
|||
#? # }}}
|
||||
# . check-next-stream-line-equal(_test-output-stream, "== code 0x1 ", msg)
|
||||
# . . push args
|
||||
68/push "F - test-convert-processes-string-literals/0"/imm32
|
||||
68/push "F - test-subx-dquotes-processes-string-literals/0"/imm32
|
||||
68/push "== code 0x1 "/imm32
|
||||
68/push _test-output-stream/imm32
|
||||
# . . call
|
||||
|
@ -778,7 +778,7 @@ test-convert-processes-string-literals:
|
|||
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 "F - test-subx-dquotes-processes-string-literals/1"/imm32
|
||||
68/push "1 _string1/x "/imm32
|
||||
68/push _test-output-stream/imm32
|
||||
# . . call
|
||||
|
@ -787,7 +787,7 @@ test-convert-processes-string-literals:
|
|||
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 "F - test-subx-dquotes-processes-string-literals/2"/imm32
|
||||
68/push "2 _string2/y "/imm32
|
||||
68/push _test-output-stream/imm32
|
||||
# . . call
|
||||
|
@ -796,7 +796,7 @@ test-convert-processes-string-literals:
|
|||
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 "F - test-subx-dquotes-processes-string-literals/3"/imm32
|
||||
68/push "== data"/imm32
|
||||
68/push _test-output-stream/imm32
|
||||
# . . call
|
||||
|
@ -805,7 +805,7 @@ test-convert-processes-string-literals:
|
|||
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 "F - test-subx-dquotes-processes-string-literals/4"/imm32
|
||||
68/push "_string1:"/imm32
|
||||
68/push _test-output-stream/imm32
|
||||
# . . call
|
||||
|
@ -814,7 +814,7 @@ test-convert-processes-string-literals:
|
|||
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 "F - test-subx-dquotes-processes-string-literals/5"/imm32
|
||||
68/push "0x00000001/imm32 61/a "/imm32
|
||||
68/push _test-output-stream/imm32
|
||||
# . . call
|
||||
|
@ -823,7 +823,7 @@ test-convert-processes-string-literals:
|
|||
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 "F - test-subx-dquotes-processes-string-literals/6"/imm32
|
||||
68/push "_string2:"/imm32
|
||||
68/push _test-output-stream/imm32
|
||||
# . . call
|
||||
|
@ -832,7 +832,7 @@ test-convert-processes-string-literals:
|
|||
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 "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
|
||||
|
|
BIN
apps/factorial
BIN
apps/factorial
Binary file not shown.
BIN
apps/handle
BIN
apps/handle
Binary file not shown.
|
@ -3,7 +3,7 @@
|
|||
# comments between '#' and newline.
|
||||
#
|
||||
# To run:
|
||||
# $ ./subx translate init.linux 0*.subx apps/subx-common.subx apps/hex.subx -o apps/hex
|
||||
# $ ./subx translate init.linux 0*.subx apps/subx-params.subx apps/hex.subx -o apps/hex
|
||||
# $ echo '80 81 82 # comment' |./subx run apps/hex |xxd -
|
||||
# Expected output:
|
||||
# 00000000: 8081 82
|
||||
|
@ -32,10 +32,10 @@ Entry: # run tests if necessary, convert stdin if not
|
|||
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 run-main
|
||||
# if (argc <= 1) goto interactive
|
||||
81 7/subop/compare 1/mod/*+disp8 5/rm32/ebp . . . . 0/disp8 1/imm32 # compare *ebp
|
||||
7e/jump-if-lesser-or-equal $hex:run-main/disp8
|
||||
# if (!kernel-string-equal?(argv[1], "test")) goto run-main
|
||||
7e/jump-if-lesser-or-equal $subx-hex-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
|
||||
|
@ -44,15 +44,15 @@ Entry: # run tests if necessary, convert stdin if not
|
|||
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 == 0) goto run-main
|
||||
# . if (eax == 0) goto interactive
|
||||
3d/compare-eax-and 0/imm32
|
||||
74/jump-if-equal $hex:run-main/disp8
|
||||
74/jump-if-equal $subx-hex-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 $hex:end/disp8
|
||||
$hex:run-main:
|
||||
eb/jump $subx-hex-main:end/disp8
|
||||
$subx-hex-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
|
||||
|
@ -60,24 +60,24 @@ $hex:run-main:
|
|||
# configure ed to really exit()
|
||||
# . ed->target = 0
|
||||
c7 0/subop/copy 0/mod/direct 0/rm32/eax . . . . . 0/imm32 # copy to *eax
|
||||
# convert-hex(Stdin, 1/stdout, 2/stderr, ed)
|
||||
# subx-hex(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-hex/disp32
|
||||
e8/call subx-hex/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
|
||||
$hex:end:
|
||||
$subx-hex-main:end:
|
||||
b8/copy-to-eax 1/imm32/exit
|
||||
cd/syscall 0x80/imm8
|
||||
|
||||
# the main entry point
|
||||
convert-hex: # in : (address buffered-file), out : (address buffered-file), err : (address buffered-file), ed : (address exit-descriptor) -> <void>
|
||||
subx-hex: # in : (address buffered-file), out : (address buffered-file), err : (address buffered-file), ed : (address exit-descriptor) -> <void>
|
||||
# pseudocode:
|
||||
# while true
|
||||
# eax = convert-next-octet(in, err, ed)
|
||||
|
@ -90,7 +90,7 @@ convert-hex: # in : (address buffered-file), out : (address buffered-file), err
|
|||
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
||||
# . save registers
|
||||
50/push-eax
|
||||
$convert-hex:loop:
|
||||
$subx-hex:loop:
|
||||
# eax = convert-next-octet(in, err, ed)
|
||||
# . . push args
|
||||
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0x14/disp8 . # push *(ebp+20)
|
||||
|
@ -102,7 +102,7 @@ $convert-hex:loop:
|
|||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
||||
# if (eax == Eof) break
|
||||
3d/compare-eax-and 0xffffffff/imm32/Eof
|
||||
74/jump-if-equal $convert-hex:loop-end/disp8
|
||||
74/jump-if-equal $subx-hex:loop-end/disp8
|
||||
# write-byte-buffered(out, AL)
|
||||
# . . push args
|
||||
50/push-eax
|
||||
|
@ -112,8 +112,8 @@ $convert-hex:loop:
|
|||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
||||
# loop
|
||||
eb/jump $convert-hex:loop/disp8
|
||||
$convert-hex:loop-end:
|
||||
eb/jump $subx-hex:loop/disp8
|
||||
$subx-hex:loop-end:
|
||||
# flush(out)
|
||||
# . . push args
|
||||
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12)
|
||||
|
@ -121,7 +121,7 @@ $convert-hex:loop-end:
|
|||
e8/call flush/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
||||
$convert-hex:end:
|
||||
$subx-hex:end:
|
||||
# . restore registers
|
||||
58/pop-to-eax
|
||||
# . epilog
|
|
@ -1,7 +1,7 @@
|
|||
# Toy lisp interpreter
|
||||
#
|
||||
# To run:
|
||||
# $ ./ntranslate init.linux 0*.subx apps/subx-common.subx apps/mulisp.subx
|
||||
# $ ./ntranslate init.linux 0*.subx apps/subx-params.subx apps/mulisp.subx
|
||||
# $ ./a.elf
|
||||
# 42
|
||||
# => 42
|
||||
|
|
112
apps/pack.subx
112
apps/pack.subx
|
@ -3,7 +3,7 @@
|
|||
# uses are left untouched.
|
||||
#
|
||||
# To run:
|
||||
# $ ./subx translate init.linux 0*.subx apps/subx-common.subx apps/pack.subx -o apps/pack
|
||||
# $ ./subx translate init.linux 0*.subx apps/subx-params.subx apps/pack.subx -o apps/pack
|
||||
# $ echo '05/add-to-eax 0x20/imm32' |./subx run apps/pack
|
||||
# Expected output:
|
||||
# 05 20 00 00 00 # 05/add-to-eax 0x20/imm32
|
||||
|
@ -33,10 +33,10 @@ Entry: # run tests if necessary, convert stdin if not
|
|||
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 run-main
|
||||
# if (argc <= 1) goto interactive
|
||||
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
|
||||
# if (!kernel-string-equal?(argv[1], "test")) goto run-main
|
||||
7e/jump-if-lesser-or-equal $subx-pack-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
|
||||
|
@ -45,15 +45,15 @@ Entry: # run tests if necessary, convert stdin if not
|
|||
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 == 0) goto run-main
|
||||
# . if (eax == 0) goto interactive
|
||||
3d/compare-eax-and 0/imm32
|
||||
74/jump-if-equal $run-main/disp8
|
||||
74/jump-if-equal $subx-pack-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 $main:end/disp8
|
||||
$run-main:
|
||||
eb/jump $subx-pack-main:end/disp8
|
||||
$subx-pack-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
|
||||
|
@ -61,19 +61,19 @@ $run-main:
|
|||
# configure ed to really exit()
|
||||
# . ed->target = 0
|
||||
c7 0/subop/copy 0/mod/direct 0/rm32/eax . . . . . 0/imm32 # copy to *eax
|
||||
# convert(Stdin, Stdout, Stderr, ed)
|
||||
# subx-pack(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 convert/disp32
|
||||
e8/call subx-pack/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:
|
||||
$subx-pack-main:end:
|
||||
b8/copy-to-eax 1/imm32/exit
|
||||
cd/syscall 0x80/imm8
|
||||
|
||||
|
@ -97,7 +97,7 @@ $main:end:
|
|||
# next-token-from-slice(start, end, delim char) -> slice
|
||||
# slice-equal?(slice, string)
|
||||
|
||||
convert: # in : (address buffered-file), out : (address buffered-file) -> <void>
|
||||
subx-pack: # in : (address buffered-file), out : (address buffered-file) -> <void>
|
||||
# pseudocode:
|
||||
# var line = new-stream(512, 1)
|
||||
# var in-code? = false
|
||||
|
@ -140,7 +140,7 @@ convert: # in : (address buffered-file), out : (address buffered-file) -> <void
|
|||
89/copy 3/mod/direct 2/rm32/edx . . . 4/r32/esp . . # copy esp to edx
|
||||
# var in-code?/ebx = false
|
||||
31/xor 3/mod/direct 3/rm32/ebx . . . 3/r32/ebx . . # clear ebx
|
||||
$convert:loop:
|
||||
$subx-pack:loop:
|
||||
# clear-stream(line)
|
||||
# . . push args
|
||||
51/push-ecx
|
||||
|
@ -156,10 +156,10 @@ $convert:loop:
|
|||
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:
|
||||
$subx-pack: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
|
||||
0f 84/jump-if-equal $subx-pack:break/disp32
|
||||
#? # dump line {{{
|
||||
#? # . write(2/stderr, "LL: ")
|
||||
#? # . . push args
|
||||
|
@ -194,7 +194,7 @@ $convert:check0:
|
|||
e8/call next-word/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
||||
$convert:check1:
|
||||
$subx-pack:check1:
|
||||
# if (slice-empty?(word-slice)) write-stream-data(out, line)
|
||||
# . eax = slice-empty?(word-slice)
|
||||
# . . push args
|
||||
|
@ -205,8 +205,8 @@ $convert:check1:
|
|||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
||||
# . if (eax != 0) write-stream-data(out, line)
|
||||
3d/compare-eax-and 0/imm32
|
||||
0f 85/jump-if-not-equal $convert:pass-through/disp32
|
||||
$convert:check2:
|
||||
0f 85/jump-if-not-equal $subx-pack:pass-through/disp32
|
||||
$subx-pack:check2:
|
||||
#? # dump word-slice {{{
|
||||
#? # . write(2/stderr, "AA: ")
|
||||
#? # . . push args
|
||||
|
@ -260,7 +260,7 @@ $convert:check2:
|
|||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
||||
# . if (eax == 0) goto check3
|
||||
3d/compare-eax-and 0/imm32
|
||||
0f 84/jump-if-equal $convert:check3/disp32
|
||||
0f 84/jump-if-equal $subx-pack:check3/disp32
|
||||
# word-slice = next-word(line)
|
||||
# . . push args
|
||||
52/push-edx
|
||||
|
@ -322,8 +322,8 @@ $convert:check2:
|
|||
# . . in-code? = eax
|
||||
89/copy 3/mod/direct 3/rm32/ebx . . . 0/r32/eax . . # copy eax to ebx
|
||||
# write-stream-data(out, line)
|
||||
eb/jump $convert:pass-through/disp8
|
||||
$convert:check3:
|
||||
eb/jump $subx-pack:pass-through/disp8
|
||||
$subx-pack:check3:
|
||||
# else rewind-stream(line)
|
||||
# . rewind-stream(line)
|
||||
# . . push args
|
||||
|
@ -334,8 +334,8 @@ $convert:check3:
|
|||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
||||
# if (in-code? != 0) convert-instruction(line, out)
|
||||
81 7/subop/compare 3/mod/direct 3/rm32/ebx . . . . . 0/imm32 # compare ebx
|
||||
74/jump-if-equal $convert:data/disp8
|
||||
$convert:code:
|
||||
74/jump-if-equal $subx-pack:data/disp8
|
||||
$subx-pack:code:
|
||||
# . convert-instruction(line, out)
|
||||
# . . push args
|
||||
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12)
|
||||
|
@ -345,8 +345,8 @@ $convert:code:
|
|||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
||||
# . loop
|
||||
e9/jump $convert:loop/disp32
|
||||
$convert:data:
|
||||
e9/jump $subx-pack:loop/disp32
|
||||
$subx-pack:data:
|
||||
# else convert-data(line, out)
|
||||
# . . push args
|
||||
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12)
|
||||
|
@ -356,8 +356,8 @@ $convert:data:
|
|||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
||||
# . loop
|
||||
e9/jump $convert:loop/disp32
|
||||
$convert:pass-through:
|
||||
e9/jump $subx-pack:loop/disp32
|
||||
$subx-pack:pass-through:
|
||||
# write-stream-data(out, line)
|
||||
# . . push args
|
||||
51/push-ecx
|
||||
|
@ -367,8 +367,8 @@ $convert:pass-through:
|
|||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
||||
# . loop
|
||||
e9/jump $convert:loop/disp32
|
||||
$convert:break:
|
||||
e9/jump $subx-pack:loop/disp32
|
||||
$subx-pack:break:
|
||||
# flush(out)
|
||||
# . . push args
|
||||
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12)
|
||||
|
@ -376,7 +376,7 @@ $convert:break:
|
|||
e8/call flush/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
||||
$convert:end:
|
||||
$subx-pack:end:
|
||||
# . reclaim locals
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x214/imm32 # add to esp
|
||||
# . restore registers
|
||||
|
@ -389,7 +389,7 @@ $convert:end:
|
|||
5d/pop-to-ebp
|
||||
c3/return
|
||||
|
||||
test-convert-passes-empty-lines-through:
|
||||
test-subx-pack-passes-empty-lines-through:
|
||||
# if a line is empty, pass it along unchanged
|
||||
# . prolog
|
||||
55/push-ebp
|
||||
|
@ -428,12 +428,12 @@ test-convert-passes-empty-lines-through:
|
|||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
||||
# write nothing to input
|
||||
# convert(_test-input-buffered-file, _test-output-buffered-file)
|
||||
# subx-pack(_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
|
||||
e8/call subx-pack/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
||||
# check that the line just passed through
|
||||
|
@ -446,7 +446,7 @@ test-convert-passes-empty-lines-through:
|
|||
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-convert-passes-empty-lines-through"/imm32
|
||||
68/push "F - test-subx-pack-passes-empty-lines-through"/imm32
|
||||
68/push ""/imm32
|
||||
68/push _test-output-stream/imm32
|
||||
# . . call
|
||||
|
@ -458,7 +458,7 @@ test-convert-passes-empty-lines-through:
|
|||
5d/pop-to-ebp
|
||||
c3/return
|
||||
|
||||
test-convert-passes-lines-with-just-whitespace-through:
|
||||
test-subx-pack-passes-lines-with-just-whitespace-through:
|
||||
# if a line is empty, pass it along unchanged
|
||||
# . prolog
|
||||
55/push-ebp
|
||||
|
@ -505,12 +505,12 @@ test-convert-passes-lines-with-just-whitespace-through:
|
|||
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)
|
||||
# subx-pack(_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
|
||||
e8/call subx-pack/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
||||
# check that the line just passed through
|
||||
|
@ -523,7 +523,7 @@ test-convert-passes-lines-with-just-whitespace-through:
|
|||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
||||
# . check-next-stream-line-equal(_test-output-stream, " ", msg)
|
||||
# . . push args
|
||||
68/push "F - test-convert-passes-with-just-whitespace-through"/imm32
|
||||
68/push "F - test-subx-pack-passes-with-just-whitespace-through"/imm32
|
||||
68/push " "/imm32
|
||||
68/push _test-output-stream/imm32
|
||||
# . . call
|
||||
|
@ -535,7 +535,7 @@ test-convert-passes-lines-with-just-whitespace-through:
|
|||
5d/pop-to-ebp
|
||||
c3/return
|
||||
|
||||
test-convert-passes-segment-headers-through:
|
||||
test-subx-pack-passes-segment-headers-through:
|
||||
# if a line starts with '==', pass it along unchanged
|
||||
# . prolog
|
||||
55/push-ebp
|
||||
|
@ -582,12 +582,12 @@ test-convert-passes-segment-headers-through:
|
|||
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)
|
||||
# subx-pack(_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
|
||||
e8/call subx-pack/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
||||
# check that the line just passed through
|
||||
|
@ -600,7 +600,7 @@ test-convert-passes-segment-headers-through:
|
|||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
||||
# . check-stream-equal(_test-output-stream, "== abcd 0x1", msg)
|
||||
# . . push args
|
||||
68/push "F - test-convert-passes-segment-headers-through"/imm32
|
||||
68/push "F - test-subx-pack-passes-segment-headers-through"/imm32
|
||||
68/push "== abcd 0x1"/imm32
|
||||
68/push _test-output-stream/imm32
|
||||
# . . call
|
||||
|
@ -612,7 +612,7 @@ test-convert-passes-segment-headers-through:
|
|||
5d/pop-to-ebp
|
||||
c3/return
|
||||
|
||||
test-convert-in-data-segment:
|
||||
test-subx-pack-in-data-segment:
|
||||
# correctly process lines in the data segment
|
||||
# . prolog
|
||||
55/push-ebp
|
||||
|
@ -678,12 +678,12 @@ test-convert-in-data-segment:
|
|||
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)
|
||||
# subx-pack(_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
|
||||
e8/call subx-pack/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
||||
# check output
|
||||
|
@ -722,7 +722,7 @@ test-convert-in-data-segment:
|
|||
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-convert-in-data-segment/0"/imm32
|
||||
68/push "F - test-subx-pack-in-data-segment/0"/imm32
|
||||
68/push "== code 0x1"/imm32
|
||||
68/push _test-output-stream/imm32
|
||||
# . . call
|
||||
|
@ -731,7 +731,7 @@ test-convert-in-data-segment:
|
|||
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-convert-in-data-segment/1"/imm32
|
||||
68/push "F - test-subx-pack-in-data-segment/1"/imm32
|
||||
68/push "== data 0x2"/imm32
|
||||
68/push _test-output-stream/imm32
|
||||
# . . call
|
||||
|
@ -740,7 +740,7 @@ test-convert-in-data-segment:
|
|||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
||||
# . check-next-stream-line-equal(_test-output-stream, "03 04 00 00 00 ", msg)
|
||||
# . . push args
|
||||
68/push "F - test-convert-in-data-segment/2"/imm32
|
||||
68/push "F - test-subx-pack-in-data-segment/2"/imm32
|
||||
68/push "03 04 00 00 00 "/imm32
|
||||
68/push _test-output-stream/imm32
|
||||
# . . call
|
||||
|
@ -752,7 +752,7 @@ test-convert-in-data-segment:
|
|||
5d/pop-to-ebp
|
||||
c3/return
|
||||
|
||||
test-convert-code-and-data-segments:
|
||||
test-subx-pack-code-and-data-segments:
|
||||
# correctly process lines in both code and data segments
|
||||
# . prolog
|
||||
55/push-ebp
|
||||
|
@ -836,12 +836,12 @@ test-convert-code-and-data-segments:
|
|||
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)
|
||||
# subx-pack(_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
|
||||
e8/call subx-pack/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
||||
# check output
|
||||
|
@ -885,7 +885,7 @@ test-convert-code-and-data-segments:
|
|||
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-convert-code-and-data-segments/0"/imm32
|
||||
68/push "F - test-subx-pack-code-and-data-segments/0"/imm32
|
||||
68/push "== code 0x1"/imm32
|
||||
68/push _test-output-stream/imm32
|
||||
# . . call
|
||||
|
@ -894,7 +894,7 @@ test-convert-code-and-data-segments:
|
|||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
||||
# . check-next-stream-line-equal(_test-output-stream, "e8 20 00 00 00 # e8/call 20/disp32", msg)
|
||||
# . . push args
|
||||
68/push "F - test-convert-code-and-data-segments/1"/imm32
|
||||
68/push "F - test-subx-pack-code-and-data-segments/1"/imm32
|
||||
68/push "e8 20 00 00 00 # e8/call 20/disp32"/imm32
|
||||
68/push _test-output-stream/imm32
|
||||
# . . call
|
||||
|
@ -903,7 +903,7 @@ test-convert-code-and-data-segments:
|
|||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
||||
# . check-next-stream-line-equal(_test-output-stream, "68 20 # 68/push 0x20/imm8", msg)
|
||||
# . . push args
|
||||
68/push "F - test-convert-code-and-data-segments/2"/imm32
|
||||
68/push "F - test-subx-pack-code-and-data-segments/2"/imm32
|
||||
68/push "68 20 # 68/push 0x20/imm8"/imm32
|
||||
68/push _test-output-stream/imm32
|
||||
# . . call
|
||||
|
@ -912,7 +912,7 @@ test-convert-code-and-data-segments:
|
|||
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-convert-code-and-data-segments/3"/imm32
|
||||
68/push "F - test-subx-pack-code-and-data-segments/3"/imm32
|
||||
68/push "== data 0x2"/imm32
|
||||
68/push _test-output-stream/imm32
|
||||
# . . call
|
||||
|
@ -921,7 +921,7 @@ test-convert-code-and-data-segments:
|
|||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
||||
# . check-next-stream-line-equal(_test-output-stream, "03 04 00 00 00 ", msg)
|
||||
# . . push args
|
||||
68/push "F - test-convert-code-and-data-segments/4"/imm32
|
||||
68/push "F - test-subx-pack-code-and-data-segments/4"/imm32
|
||||
68/push "03 04 00 00 00 "/imm32
|
||||
68/push _test-output-stream/imm32
|
||||
# . . call
|
||||
|
|
BIN
apps/sigils
BIN
apps/sigils
Binary file not shown.
|
@ -2,7 +2,7 @@
|
|||
# other related arguments.
|
||||
#
|
||||
# To run:
|
||||
# $ ./subx translate init.linux 0*.subx apps/subx-common.subx apps/sigils.subx -o apps/sigils
|
||||
# $ ./subx translate init.linux 0*.subx apps/subx-params.subx apps/sigils.subx -o apps/sigils
|
||||
#
|
||||
# We currently support the following notations:
|
||||
#
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,5 +1,4 @@
|
|||
# Normally we introduce names in the layers that need them, but we'll make an
|
||||
# exception to colocate various knobs for translating SubX programs using SubX.
|
||||
# Various knobs for translating SubX programs using SubX.
|
||||
|
||||
== data
|
||||
|
BIN
apps/survey
BIN
apps/survey
Binary file not shown.
|
@ -5,7 +5,7 @@
|
|||
# b) add segment headers with addresses and offsets correctly filled in
|
||||
#
|
||||
# To build:
|
||||
# $ ./subx translate init.linux 0*.subx apps/subx-common.subx apps/survey.subx -o apps/survey
|
||||
# $ ./subx translate init.linux 0*.subx apps/subx-params.subx apps/survey.subx -o apps/survey
|
||||
#
|
||||
# The expected input is a stream of bytes with segment headers, comments and
|
||||
# some interspersed labels.
|
||||
|
@ -62,10 +62,10 @@ Entry: # run tests if necessary, convert stdin if not
|
|||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
||||
|
||||
# - if argc > 1 and argv[1] == "test", then return run_tests()
|
||||
# if (argc <= 1) goto run-main
|
||||
# if (argc <= 1) goto interactive
|
||||
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
|
||||
# if (!kernel-string-equal?(argv[1], "test")) goto run-main
|
||||
7e/jump-if-lesser-or-equal $subx-survey-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
|
||||
|
@ -74,22 +74,22 @@ Entry: # run tests if necessary, convert stdin if not
|
|||
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 == 0) goto run-main
|
||||
# . if (eax == 0) goto interactive
|
||||
3d/compare-eax-and 0/imm32
|
||||
74/jump-if-equal $run-main/disp8
|
||||
74/jump-if-equal $subx-survey-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 $main:end/disp8
|
||||
$run-main:
|
||||
eb/jump $subx-survey-main:end/disp8
|
||||
$subx-survey-main:interactive:
|
||||
# - otherwise convert stdin
|
||||
# convert(Stdin, Stdout)
|
||||
# subx-survey(Stdin, Stdout)
|
||||
# . . push args
|
||||
68/push Stdout/imm32
|
||||
68/push Stdin/imm32
|
||||
# . . call
|
||||
e8/call convert/disp32
|
||||
e8/call subx-survey/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
||||
#? # . write-stream(2/stderr, Trace-stream)
|
||||
|
@ -102,7 +102,7 @@ $run-main:
|
|||
#? 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
||||
# syscall(exit, 0)
|
||||
bb/copy-to-ebx 0/imm32
|
||||
$main:end:
|
||||
$subx-survey-main:end:
|
||||
b8/copy-to-eax 1/imm32/exit
|
||||
cd/syscall 0x80/imm8
|
||||
|
||||
|
@ -113,7 +113,7 @@ $main:end:
|
|||
# labels: (address stream {string, label-info}) (16 bytes per row)
|
||||
# these are all inefficient; use sequential scans for lookups
|
||||
|
||||
convert: # infile : (address buffered-file), out : (address buffered-file) -> <void>
|
||||
subx-survey: # infile : (address buffered-file), out : (address buffered-file) -> <void>
|
||||
# pseudocode
|
||||
# var in : (address stream byte) = stream(4096)
|
||||
# slurp(infile, in)
|
||||
|
@ -440,7 +440,7 @@ convert: # infile : (address buffered-file), out : (address buffered-file) -> <
|
|||
e8/call flush/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
||||
$convert:end:
|
||||
$subx-survey:end:
|
||||
# . reclaim locals
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0x30a0/imm32 # add to esp
|
||||
# . restore registers
|
||||
|
@ -452,7 +452,7 @@ $convert:end:
|
|||
5d/pop-to-ebp
|
||||
c3/return
|
||||
|
||||
test-convert-computes-addresses:
|
||||
test-subx-survey-computes-addresses:
|
||||
# input:
|
||||
# == code 0x1
|
||||
# Entry:
|
||||
|
@ -552,12 +552,12 @@ test-convert-computes-addresses:
|
|||
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)
|
||||
# subx-survey(_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
|
||||
e8/call subx-survey/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
||||
# check trace
|
||||
|
@ -589,7 +589,7 @@ test-convert-computes-addresses:
|
|||
#? # }}}
|
||||
# . check-trace-contains("label 'x' is at address 0x00001079.", msg)
|
||||
# . . push args
|
||||
68/push "F - test-convert-computes-addresses/0"/imm32
|
||||
68/push "F - test-subx-survey-computes-addresses/0"/imm32
|
||||
68/push "label 'x' is at address 0x00001079."/imm32
|
||||
# . . call
|
||||
e8/call check-trace-contains/disp32
|
||||
|
@ -597,7 +597,7 @@ test-convert-computes-addresses:
|
|||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
||||
# . check-trace-contains("segment 'code' starts at address 0x00000074.", msg)
|
||||
# . . push args
|
||||
68/push "F - test-convert-computes-addresses/1"/imm32
|
||||
68/push "F - test-subx-survey-computes-addresses/1"/imm32
|
||||
68/push "segment 'code' starts at address 0x00000074."/imm32
|
||||
# . . call
|
||||
e8/call check-trace-contains/disp32
|
||||
|
@ -605,7 +605,7 @@ test-convert-computes-addresses:
|
|||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
||||
# . check-trace-contains("segment 'code' has size 0x00000005.", msg)
|
||||
# . . push args
|
||||
68/push "F - test-convert-computes-addresses/2"/imm32
|
||||
68/push "F - test-subx-survey-computes-addresses/2"/imm32
|
||||
68/push "segment 'code' has size 0x00000005."/imm32
|
||||
# . . call
|
||||
e8/call check-trace-contains/disp32
|
||||
|
@ -613,7 +613,7 @@ test-convert-computes-addresses:
|
|||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
||||
# . check-trace-contains("segment 'data' starts at address 0x00001079.", msg)
|
||||
# . . push args
|
||||
68/push "F - test-convert-computes-addresses/3"/imm32
|
||||
68/push "F - test-subx-survey-computes-addresses/3"/imm32
|
||||
68/push "segment 'data' starts at address 0x00001079."/imm32
|
||||
# . . call
|
||||
e8/call check-trace-contains/disp32
|
||||
|
|
BIN
apps/tests
BIN
apps/tests
Binary file not shown.
|
@ -2,7 +2,7 @@
|
|||
# all functions starting with 'test-'.
|
||||
#
|
||||
# To build:
|
||||
# $ ./subx translate init.linux 0*.subx apps/subx-common.subx apps/tests.subx -o apps/tests
|
||||
# $ ./subx translate init.linux 0*.subx apps/subx-params.subx apps/tests.subx -o apps/tests
|
||||
|
||||
== code
|
||||
# instruction effective address register displacement immediate
|
||||
|
@ -33,7 +33,7 @@ Entry: # run tests if necessary, convert stdin if not
|
|||
# - if argc > 1 and argv[1] == "test", then return run_tests()
|
||||
# if (argc <= 1) goto run-main
|
||||
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
|
||||
7e/jump-if-lesser-or-equal $subx-tests-main:interactive/disp8
|
||||
# if (!kernel-string-equal?(argv[1], "test")) goto run-main
|
||||
# . eax = kernel-string-equal?(argv[1], "test")
|
||||
# . . push args
|
||||
|
@ -45,29 +45,29 @@ Entry: # run tests if necessary, convert stdin if not
|
|||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
||||
# . if (eax == 0) goto run-main
|
||||
3d/compare-eax-and 0/imm32
|
||||
74/jump-if-equal $run-main/disp8
|
||||
74/jump-if-equal $subx-tests-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 $main:end/disp8
|
||||
$run-main:
|
||||
eb/jump $subx-tests-main:end/disp8
|
||||
$subx-tests-main:interactive:
|
||||
# - otherwise convert stdin
|
||||
# convert(Stdin, Stdout)
|
||||
# subx-gen-run-tests(Stdin, Stdout)
|
||||
# . . push args
|
||||
68/push Stdout/imm32
|
||||
68/push Stdin/imm32
|
||||
# . . call
|
||||
e8/call convert/disp32
|
||||
e8/call subx-gen-run-tests/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
||||
# syscall(exit, 0)
|
||||
bb/copy-to-ebx 0/imm32
|
||||
$main:end:
|
||||
$subx-tests-main:end:
|
||||
b8/copy-to-eax 1/imm32/exit
|
||||
cd/syscall 0x80/imm8
|
||||
|
||||
convert: # in : (address buffered-file), out : (address buffered-file) -> <void>
|
||||
subx-gen-run-tests: # in : (address buffered-file), out : (address buffered-file) -> <void>
|
||||
# pseudocode
|
||||
# bool tests-found = false
|
||||
# var line = new-stream(512, 1)
|
||||
|
@ -141,7 +141,7 @@ convert: # in : (address buffered-file), out : (address buffered-file) -> <void
|
|||
e8/call write/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
||||
$convert:loop:
|
||||
$subx-gen-run-tests:loop:
|
||||
# clear-stream(line)
|
||||
# . . push args
|
||||
51/push-ecx
|
||||
|
@ -157,10 +157,10 @@ $convert:loop:
|
|||
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:
|
||||
$subx-gen-run-tests: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
|
||||
0f 84/jump-if-equal $subx-gen-run-tests:break/disp32
|
||||
# next-word(line, word-slice)
|
||||
# . . push args
|
||||
52/push-edx
|
||||
|
@ -169,7 +169,7 @@ $convert:check0:
|
|||
e8/call next-word/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
||||
$convert:check-for-label:
|
||||
$subx-gen-run-tests:check-for-label:
|
||||
# if (!is-label?(word-slice)) continue
|
||||
# . eax = is-label?(word-slice)
|
||||
# . . push args
|
||||
|
@ -180,8 +180,8 @@ $convert:check-for-label:
|
|||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
||||
# . if (eax == 0) continue
|
||||
3d/compare-eax-and 0/imm32
|
||||
74/jump-if-equal $convert:continue/disp8
|
||||
$convert:check-label-prefix:
|
||||
74/jump-if-equal $subx-gen-run-tests:continue/disp8
|
||||
$subx-gen-run-tests:check-label-prefix:
|
||||
# strip trailing ':' from word-slice
|
||||
ff 1/subop/decrement 1/mod/*+disp8 2/rm32/edx . . . . 4/disp8 . # decrement *(edx+4)
|
||||
# if !slice-starts-with?(word-slice, "test-") continue
|
||||
|
@ -194,8 +194,8 @@ $convert:check-label-prefix:
|
|||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
||||
# . if (eax == 0) break
|
||||
3d/compare-eax-and 0/imm32
|
||||
74/jump-if-equal $convert:continue/disp8
|
||||
$convert:call-test-function:
|
||||
74/jump-if-equal $subx-gen-run-tests:continue/disp8
|
||||
$subx-gen-run-tests:call-test-function:
|
||||
# tests-found? = true
|
||||
bb/copy-to-ebx 1/imm32/true
|
||||
# write(new-code-segment, " e8/call ")
|
||||
|
@ -222,7 +222,7 @@ $convert:call-test-function:
|
|||
e8/call write/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
||||
$convert:continue:
|
||||
$subx-gen-run-tests:continue:
|
||||
# rewind-stream(line)
|
||||
# . . push args
|
||||
51/push-ecx
|
||||
|
@ -239,11 +239,11 @@ $convert:continue:
|
|||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
||||
# loop
|
||||
e9/jump $convert:loop/disp32
|
||||
$convert:break:
|
||||
e9/jump $subx-gen-run-tests:loop/disp32
|
||||
$subx-gen-run-tests:break:
|
||||
# if (!tests-found?) goto end
|
||||
81 7/subop/compare 3/mod/direct 3/rm32/ebx . . . . . 0/imm32 # compare ebx
|
||||
74/jump-if-equal $convert:end/disp8
|
||||
74/jump-if-equal $subx-gen-run-tests:end/disp8
|
||||
# write(new-code-segment, " c3/return\n")
|
||||
# . . push args
|
||||
68/push " c3/return\n"/imm32
|
||||
|
@ -260,7 +260,7 @@ $convert:break:
|
|||
e8/call write-stream-data/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
||||
$convert:end:
|
||||
$subx-gen-run-tests:end:
|
||||
# flush(out)
|
||||
# . . push args
|
||||
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 0xc/disp8 . # push *(ebp+12)
|
||||
|
|
50
build
50
build
|
@ -106,54 +106,4 @@ older_than subx_bin subx.cc *_list && {
|
|||
$CXX $CFLAGS subx.cc -o subx_bin
|
||||
}
|
||||
|
||||
# We ought to always rebuild all apps if any .subx layers are updated.
|
||||
# But during development it's too slow to update _all_ apps when we're
|
||||
# repeatedly running a single one.
|
||||
if [ ! $ONLY_CPP ]
|
||||
then
|
||||
|
||||
# Assumption: SubX programs don't need to be retranslated every time we
|
||||
# rebuild the C++ bootstrap.
|
||||
|
||||
OS=${OS:-linux}
|
||||
|
||||
# simple example programs
|
||||
for n in `seq 1 12`
|
||||
do
|
||||
older_than examples/ex$n init.$OS examples/ex$n.subx && {
|
||||
./subx_bin translate init.$OS examples/ex$n.subx -o examples/ex$n
|
||||
}
|
||||
done
|
||||
|
||||
# simple apps that use the standard library
|
||||
for app in factorial crenshaw2-1 crenshaw2-1b handle
|
||||
do
|
||||
older_than apps/$app init.$OS [0-9]*.subx apps/$app.subx && {
|
||||
./subx_bin translate init.$OS [0-9]*.subx apps/$app.subx -o apps/$app
|
||||
}
|
||||
done
|
||||
|
||||
# self-hosting translator
|
||||
|
||||
older_than apps/hex init.$OS 0[0-6]*.subx 070---hex.subx && {
|
||||
./subx_bin translate init.$OS 0[0-6]*.subx 070---hex.subx -o apps/hex
|
||||
}
|
||||
|
||||
for phase in hex survey pack assort dquotes tests
|
||||
do
|
||||
older_than apps/$phase init.$OS [0-9]*.subx apps/subx-common.subx apps/$phase.subx && {
|
||||
./subx_bin translate init.$OS [0-9]*.subx apps/subx-common.subx apps/$phase.subx -o apps/$phase
|
||||
}
|
||||
done
|
||||
|
||||
# higher-level syntax
|
||||
for phase in sigils
|
||||
do
|
||||
older_than apps/$phase init.$OS [0-9]*.subx apps/subx-common.subx apps/$phase.subx && {
|
||||
./subx_bin translate init.$OS [0-9]*.subx apps/subx-common.subx apps/$phase.subx -o apps/$phase
|
||||
}
|
||||
done
|
||||
|
||||
fi
|
||||
|
||||
exit 0
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
if [[ $2 == 'test-'* ]]
|
||||
then
|
||||
TEST_NAME=$2 envsubst '$TEST_NAME' < run_one_test.subx > /tmp/run_one_test.subx
|
||||
FILES=$(ls [0-9]*.subx apps/subx-common.subx $1 |sort |uniq)
|
||||
FILES=$(ls [0-9]*.subx apps/subx-params.subx $1 |sort |uniq)
|
||||
echo $FILES > /tmp/last_run_files
|
||||
elif [[ -e /tmp/last_run_files ]]
|
||||
then
|
||||
|
|
108
test_apps
108
test_apps
|
@ -225,82 +225,28 @@ test $NATIVE && {
|
|||
|
||||
# Phases of the self-hosted SubX translator.
|
||||
|
||||
echo hex
|
||||
./subx translate init.$OS $(enumerate/enumerate --until 070---hex.subx |grep '\.subx$') -o apps/hex
|
||||
test "$1" = 'record' || git diff --exit-code apps/hex
|
||||
test $EMULATED && {
|
||||
./subx run apps/hex test
|
||||
echo
|
||||
}
|
||||
test $NATIVE && {
|
||||
apps/hex test
|
||||
echo
|
||||
}
|
||||
|
||||
echo survey
|
||||
./subx translate init.$OS 0*.subx apps/subx-common.subx apps/survey.subx -o apps/survey
|
||||
test "$1" = 'record' || git diff --exit-code apps/survey
|
||||
test $EMULATED && {
|
||||
./subx run apps/survey test
|
||||
echo
|
||||
}
|
||||
test $NATIVE && {
|
||||
apps/survey test
|
||||
echo
|
||||
}
|
||||
|
||||
echo pack
|
||||
./subx translate init.$OS 0*.subx apps/subx-common.subx apps/pack.subx -o apps/pack
|
||||
test "$1" = 'record' || git diff --exit-code apps/pack
|
||||
test $EMULATED && {
|
||||
./subx run apps/pack test
|
||||
echo
|
||||
}
|
||||
test $NATIVE && {
|
||||
apps/pack test
|
||||
echo
|
||||
}
|
||||
|
||||
echo assort
|
||||
./subx translate init.$OS 0*.subx apps/subx-common.subx apps/assort.subx -o apps/assort
|
||||
test "$1" = 'record' || git diff --exit-code apps/assort
|
||||
test $EMULATED && {
|
||||
./subx run apps/assort test
|
||||
echo
|
||||
}
|
||||
test $NATIVE && {
|
||||
apps/assort test
|
||||
echo
|
||||
}
|
||||
|
||||
echo dquotes
|
||||
./subx translate init.$OS 0*.subx apps/subx-common.subx apps/dquotes.subx -o apps/dquotes
|
||||
test "$1" = 'record' || git diff --exit-code apps/dquotes
|
||||
test $EMULATED && {
|
||||
./subx run apps/dquotes test
|
||||
echo
|
||||
}
|
||||
test $NATIVE && {
|
||||
apps/dquotes test
|
||||
echo
|
||||
}
|
||||
|
||||
echo tests
|
||||
./subx translate init.$OS 0*.subx apps/subx-common.subx apps/tests.subx -o apps/tests
|
||||
test "$1" = 'record' || git diff --exit-code apps/tests
|
||||
test $EMULATED && {
|
||||
./subx run apps/tests test
|
||||
echo
|
||||
}
|
||||
test $NATIVE && {
|
||||
apps/tests test
|
||||
echo
|
||||
}
|
||||
for phase in hex survey pack assort dquotes tests
|
||||
do
|
||||
echo $phase
|
||||
./subx translate init.$OS 0*.subx apps/subx-params.subx apps/$phase.subx -o apps/$phase
|
||||
test "$1" = 'record' || git diff --exit-code apps/hex
|
||||
test $EMULATED && {
|
||||
./subx run apps/$phase test
|
||||
echo
|
||||
}
|
||||
test $NATIVE && {
|
||||
apps/$phase test
|
||||
echo
|
||||
}
|
||||
done
|
||||
|
||||
# Higher-level syntax.
|
||||
|
||||
# Certain phases of translation run native beyond this point. We're starting
|
||||
# to go beyond functionality of the C++ bootstrap.
|
||||
|
||||
echo sigils
|
||||
./subx translate init.$OS 0*.subx apps/subx-common.subx apps/sigils.subx -o apps/sigils
|
||||
./subx translate init.$OS 0*.subx apps/subx-params.subx apps/sigils.subx -o apps/sigils
|
||||
[ "$1" != record ] && git diff --exit-code apps/sigils
|
||||
./subx run apps/sigils test
|
||||
echo
|
||||
|
@ -310,7 +256,7 @@ test `uname` = 'Linux' && {
|
|||
}
|
||||
|
||||
echo calls
|
||||
cat init.$OS 0*.subx apps/subx-common.subx apps/calls.subx | apps/sigils > a.sigils
|
||||
cat init.$OS 0*.subx apps/subx-params.subx apps/calls.subx | apps/sigils > a.sigils
|
||||
./subx translate a.sigils -o apps/calls
|
||||
[ "$1" != record ] && git diff --exit-code apps/calls
|
||||
./subx run apps/calls test
|
||||
|
@ -321,7 +267,7 @@ test `uname` = 'Linux' && {
|
|||
}
|
||||
|
||||
echo braces
|
||||
cat init.$OS 0*.subx apps/subx-common.subx apps/braces.subx | apps/calls | apps/sigils > a.sigils
|
||||
cat init.$OS 0*.subx apps/subx-params.subx apps/braces.subx | apps/calls | apps/sigils > a.sigils
|
||||
./subx translate a.sigils -o apps/braces
|
||||
[ "$1" != record ] && git diff --exit-code apps/braces
|
||||
./subx run apps/braces test
|
||||
|
@ -331,12 +277,8 @@ test `uname` = 'Linux' && {
|
|||
echo
|
||||
}
|
||||
|
||||
# Only native runs beyond this point. We start using syntax that the emulator
|
||||
# doesn't support.
|
||||
test $EMULATED && echo "skipping remaining runs in emulated mode"
|
||||
test $NATIVE || exit 0
|
||||
|
||||
echo "== translating using SubX"
|
||||
echo "== translating using SubX (native only)"
|
||||
|
||||
# example programs
|
||||
|
||||
|
@ -358,14 +300,10 @@ done
|
|||
|
||||
# Phases of the self-hosted SubX translator.
|
||||
|
||||
echo hex
|
||||
./ntranslate init.$OS $(enumerate/enumerate --until 070---hex.subx |grep '\.subx$')
|
||||
diff apps/hex a.elf
|
||||
|
||||
for app in survey pack assort dquotes tests sigils calls braces
|
||||
for app in hex survey pack assort dquotes tests sigils calls braces
|
||||
do
|
||||
echo $app
|
||||
./ntranslate init.$OS 0*.subx apps/subx-common.subx apps/$app.subx
|
||||
./ntranslate init.$OS 0*.subx apps/subx-params.subx apps/$app.subx
|
||||
diff apps/$app a.elf
|
||||
done
|
||||
|
||||
|
|
|
@ -22,11 +22,11 @@ for f in [0-9]*.subx
|
|||
do
|
||||
echo "=== $f"
|
||||
./subx translate init.linux $(enumerate/enumerate --until $f |grep '\.subx$') -o a.elf
|
||||
./subx run a.elf
|
||||
./subx run a.elf test
|
||||
echo
|
||||
test `uname` = 'Linux' && {
|
||||
chmod +x a.elf
|
||||
./a.elf
|
||||
./a.elf test
|
||||
echo
|
||||
} || true
|
||||
done
|
||||
|
|
Loading…
Reference in New Issue