diff options
-rw-r--r-- | 069allocate.subx | 2 | ||||
-rw-r--r-- | 070new-stream.subx (renamed from 080new-stream.subx) | 0 | ||||
-rw-r--r-- | 071read-line.subx (renamed from 081read-line.subx) | 0 | ||||
-rw-r--r-- | 072slice.subx (renamed from 082slice.subx) | 0 | ||||
-rw-r--r-- | 073next-token.subx (renamed from 083next-token.subx) | 0 | ||||
-rw-r--r-- | 074write-stream-data.subx | 116 | ||||
-rw-r--r-- | 075print-int-decimal.subx (renamed from 084print-int-decimal.subx) | 0 | ||||
-rw-r--r-- | 076next-word.subx | 252 | ||||
-rw-r--r-- | 077subx-words.subx | 631 | ||||
-rw-r--r-- | 078emit-hex.subx | 249 | ||||
-rw-r--r-- | 079emit.subx | 484 | ||||
-rw-r--r-- | 080zero-out.subx (renamed from 086zero-out.subx) | 0 | ||||
-rw-r--r-- | 081table.subx (renamed from 088table.subx) | 0 | ||||
-rw-r--r-- | 082slurp.subx (renamed from 087slurp.subx) | 0 | ||||
-rw-r--r-- | 083subx-widths.subx | 238 | ||||
-rw-r--r-- | 084emit-hex-array.subx | 142 | ||||
-rw-r--r-- | 092write-int.subx (renamed from 089write-int.subx) | 0 | ||||
-rw-r--r-- | 093array-equal.subx (renamed from 085array-equal.subx) | 0 | ||||
-rw-r--r-- | Readme.md | 12 | ||||
-rwxr-xr-x | apps/assort | bin | 44323 -> 40203 bytes | |||
-rw-r--r-- | apps/assort.subx | 52 | ||||
-rwxr-xr-x | apps/braces | bin | 43717 -> 39565 bytes | |||
-rw-r--r-- | apps/braces.subx | 2 | ||||
-rwxr-xr-x | apps/calls | bin | 49078 -> 44926 bytes | |||
-rw-r--r-- | apps/calls.subx | 2 | ||||
-rwxr-xr-x | apps/crenshaw2-1 | bin | 38083 -> 39614 bytes | |||
-rwxr-xr-x | apps/crenshaw2-1b | bin | 38642 -> 40173 bytes | |||
-rwxr-xr-x | apps/dquotes | bin | 49512 -> 45445 bytes | |||
-rw-r--r-- | apps/dquotes.subx | 110 | ||||
-rwxr-xr-x | apps/factorial | bin | 37095 -> 38626 bytes | |||
-rwxr-xr-x | apps/handle | bin | 37988 -> 39519 bytes | |||
-rwxr-xr-x | apps/hex | bin | 19496 -> 42569 bytes | |||
-rw-r--r-- | apps/hex.subx (renamed from 070---hex.subx) | 34 | ||||
-rw-r--r-- | apps/mulisp.subx | 2 | ||||
-rwxr-xr-x | apps/pack | bin | 56994 -> 52864 bytes | |||
-rw-r--r-- | apps/pack.subx | 112 | ||||
-rwxr-xr-x | apps/sigils | bin | 57016 -> 52864 bytes | |||
-rw-r--r-- | apps/sigils.subx | 2 | ||||
-rw-r--r-- | apps/subx-common.subx | 2084 | ||||
-rw-r--r-- | apps/subx-params.subx (renamed from 071---subx-params.subx) | 3 | ||||
-rwxr-xr-x | apps/survey | bin | 53596 -> 49460 bytes | |||
-rw-r--r-- | apps/survey.subx | 40 | ||||
-rwxr-xr-x | apps/tests | bin | 43140 -> 38988 bytes | |||
-rw-r--r-- | apps/tests.subx | 44 | ||||
-rwxr-xr-x | build | 50 | ||||
-rwxr-xr-x | run_one_test | 2 | ||||
-rwxr-xr-x | test_apps | 108 | ||||
-rwxr-xr-x | test_layers | 4 |
48 files changed, 2347 insertions, 2430 deletions
diff --git a/069allocate.subx b/069allocate.subx index af3a7885..5e7a170d 100644 --- a/069allocate.subx +++ b/069allocate.subx @@ -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 diff --git a/080new-stream.subx b/070new-stream.subx index c3f204d2..c3f204d2 100644 --- a/080new-stream.subx +++ b/070new-stream.subx diff --git a/081read-line.subx b/071read-line.subx index bce42750..bce42750 100644 --- a/081read-line.subx +++ b/071read-line.subx diff --git a/082slice.subx b/072slice.subx index 09f45e18..09f45e18 100644 --- a/082slice.subx +++ b/072slice.subx diff --git a/083next-token.subx b/073next-token.subx index 73a658c1..73a658c1 100644 --- a/083next-token.subx +++ b/073next-token.subx diff --git a/074write-stream-data.subx b/074write-stream-data.subx new file mode 100644 index 00000000..d5d901b4 --- /dev/null +++ b/074write-stream-data.subx @@ -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 diff --git a/084print-int-decimal.subx b/075print-int-decimal.subx index f7898fe9..f7898fe9 100644 --- a/084print-int-decimal.subx +++ b/075print-int-decimal.subx diff --git a/076next-word.subx b/076next-word.subx new file mode 100644 index 00000000..efd99a64 --- /dev/null +++ b/076next-word.subx @@ -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 diff --git a/077subx-words.subx b/077subx-words.subx new file mode 100644 index 00000000..5bdf196a --- /dev/null +++ b/077subx-words.subx @@ -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 diff --git a/078emit-hex.subx b/078emit-hex.subx new file mode 100644 index 00000000..73912ea0 --- /dev/null +++ b/078emit-hex.subx @@ -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 diff --git a/079emit.subx b/079emit.subx new file mode 100644 index 00000000..b0c06de6 --- /dev/null +++ b/079emit.subx @@ -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 diff --git a/086zero-out.subx b/080zero-out.subx index 1a4c73d1..1a4c73d1 100644 --- a/086zero-out.subx +++ b/080zero-out.subx diff --git a/088table.subx b/081table.subx index 602cd872..602cd872 100644 --- a/088table.subx +++ b/081table.subx diff --git a/087slurp.subx b/082slurp.subx index 36a95d48..36a95d48 100644 --- a/087slurp.subx +++ b/082slurp.subx diff --git a/083subx-widths.subx b/083subx-widths.subx new file mode 100644 index 00000000..18fe9833 --- /dev/null +++ b/083subx-widths.subx @@ -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 diff --git a/084emit-hex-array.subx b/084emit-hex-array.subx new file mode 100644 index 00000000..eb79d07f --- /dev/null +++ b/084emit-hex-array.subx @@ -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 diff --git a/089write-int.subx b/092write-int.subx index 29ba8d2a..29ba8d2a 100644 --- a/089write-int.subx +++ b/092write-int.subx diff --git a/085array-equal.subx b/093array-equal.subx index d6dec878..d6dec878 100644 --- a/085array-equal.subx +++ b/093array-equal.subx diff --git a/Readme.md b/Readme.md index 733e1bb8..d4eefbcd 100644 --- a/Readme.md +++ b/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 diff --git a/apps/assort b/apps/assort index bdd302c3..0f876c2d 100755 --- a/apps/assort +++ b/apps/assort Binary files differdiff --git a/apps/assort.subx b/apps/assort.subx index 2e9fee47..6b3eadba 100644 --- a/apps/assort.subx +++ b/apps/assort.subx @@ -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 diff --git a/apps/braces b/apps/braces index 0c338864..53f14ae7 100755 --- a/apps/braces +++ b/apps/braces Binary files differdiff --git a/apps/braces.subx b/apps/braces.subx index cb0fa9dd..694f7314 100644 --- a/apps/braces.subx +++ b/apps/braces.subx @@ -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: diff --git a/apps/calls b/apps/calls index 04c8e297..dce364e3 100755 --- a/apps/calls +++ b/apps/calls Binary files differdiff --git a/apps/calls.subx b/apps/calls.subx index 2f6ff3aa..c5cf74d3 100644 --- a/apps/calls.subx +++ b/apps/calls.subx @@ -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: diff --git a/apps/crenshaw2-1 b/apps/crenshaw2-1 index 1a895801..bdf3c0de 100755 --- a/apps/crenshaw2-1 +++ b/apps/crenshaw2-1 Binary files differdiff --git a/apps/crenshaw2-1b b/apps/crenshaw2-1b index 5a1e448f..741d3c74 100755 --- a/apps/crenshaw2-1b +++ b/apps/crenshaw2-1b Binary files differdiff --git a/apps/dquotes b/apps/dquotes index 096a032d..790a6684 100755 --- a/apps/dquotes +++ b/apps/dquotes Binary files differdiff --git a/apps/dquotes.subx b/apps/dquotes.subx index 337992e4..f6976e47 100644 --- a/apps/dquotes.subx +++ b/apps/dquotes.subx @@ -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 diff --git a/apps/factorial b/apps/factorial index 2641faa9..07792615 100755 --- a/apps/factorial +++ b/apps/factorial Binary files differdiff --git a/apps/handle b/apps/handle index 21e66ccb..237003dc 100755 --- a/apps/handle +++ b/apps/handle Binary files differdiff --git a/apps/hex b/apps/hex index 9dd432b7..64218e10 100755 --- a/apps/hex +++ b/apps/hex Binary files differdiff --git a/070---hex.subx b/apps/hex.subx index ffe72d06..e5f13077 100644 --- a/070---hex.subx +++ b/apps/hex.subx @@ -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 diff --git a/apps/mulisp.subx b/apps/mulisp.subx index 4ae26e82..9bc2d0b7 100644 --- a/apps/mulisp.subx +++ b/apps/mulisp.subx @@ -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 diff --git a/apps/pack b/apps/pack index f9907948..95782b8b 100755 --- a/apps/pack +++ b/apps/pack Binary files differdiff --git a/apps/pack.subx b/apps/pack.subx index 69c37bd4..1be0c4c4 100644 --- a/apps/pack.subx +++ b/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 diff --git a/apps/sigils b/apps/sigils index fff9e7cd..c87a99f1 100755 --- a/apps/sigils +++ b/apps/sigils Binary files differdiff --git a/apps/sigils.subx b/apps/sigils.subx index 8c8beba7..f05bc6d4 100644 --- a/apps/sigils.subx +++ b/apps/sigils.subx @@ -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: # diff --git a/apps/subx-common.subx b/apps/subx-common.subx deleted file mode 100644 index 829ed277..00000000 --- a/apps/subx-common.subx +++ /dev/null @@ -1,2084 +0,0 @@ -== 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 - -# 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 - -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 - -# 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 - -# 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 - -# 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 - -# 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 - -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 - -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 - -== data - -_test-data-segment: - 64/d 61/a 74/t 61/a -_test-data-segment-end: - -# . . vim:nowrap:textwidth=0 diff --git a/071---subx-params.subx b/apps/subx-params.subx index aefb6639..38a34314 100644 --- a/071---subx-params.subx +++ b/apps/subx-params.subx @@ -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 diff --git a/apps/survey b/apps/survey index cc94c6ca..cc9da808 100755 --- a/apps/survey +++ b/apps/survey Binary files differdiff --git a/apps/survey.subx b/apps/survey.subx index 678ed116..b943fe72 100644 --- a/apps/survey.subx +++ b/apps/survey.subx @@ -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 diff --git a/apps/tests b/apps/tests index cb6f4a7f..30ef5fcd 100755 --- a/apps/tests +++ b/apps/tests Binary files differdiff --git a/apps/tests.subx b/apps/tests.subx index cb6bd034..290483f0 100644 --- a/apps/tests.subx +++ b/apps/tests.subx @@ -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) diff --git a/build b/build index 0d723656..9e95bb34 100755 --- a/build +++ b/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 diff --git a/run_one_test b/run_one_test index b8eeaad5..04af6ba0 100755 --- a/run_one_test +++ b/run_one_test @@ -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 diff --git a/test_apps b/test_apps index bb645e97..d69e5b83 100755 --- a/test_apps +++ b/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 diff --git a/test_layers b/test_layers index ea7551df..522e413b 100755 --- a/test_layers +++ b/test_layers @@ -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 |