6520 - new app: parse-int
Several bugs fixed in the process, and expectation of further bugs is growing. I'd somehow started assuming I don't need to have separate cases for rm32 as a register vs mem. That's not right. We might need more reg-reg Primitives.
This commit is contained in:
parent
ead3d08e77
commit
ad61776f49
|
@ -402,4 +402,65 @@ test-is-decimal-digit-above-9:
|
|||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
|
||||
c3/return
|
||||
|
||||
to-decimal-digit: # in: byte -> out/eax: int
|
||||
# . prologue
|
||||
55/push-ebp
|
||||
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
||||
# eax = in
|
||||
8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 8/disp8 . # copy *(ebp+8) to eax
|
||||
$to-decimal-digit:check0:
|
||||
# if (eax < '0') goto abort
|
||||
3d/compare-eax-with 0x30/imm32/0
|
||||
7c/jump-if-< $to-decimal-digit:abort/disp8
|
||||
$to-decimal-digit:check1:
|
||||
# if (eax > '9') goto abort
|
||||
3d/compare-eax-with 0x39/imm32/f
|
||||
7f/jump-if-> $to-decimal-digit:abort/disp8
|
||||
$to-decimal-digit:digit:
|
||||
# return eax - '0'
|
||||
2d/subtract-from-eax 0x30/imm32/0
|
||||
$to-decimal-digit:end:
|
||||
# . epilogue
|
||||
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
|
||||
5d/pop-to-ebp
|
||||
c3/return
|
||||
|
||||
$to-decimal-digit:abort:
|
||||
# . write-buffered(stderr, error)
|
||||
# . . push args
|
||||
68/push "to-decimal-digit: not a digit character: "/imm32
|
||||
68/push Stderr/imm32
|
||||
# . . call
|
||||
e8/call write-buffered/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
||||
# . write-byte-buffered(stderr, %eax)
|
||||
# . . push args
|
||||
50/push-eax
|
||||
68/push Stderr/imm32
|
||||
# . . call
|
||||
#? e8/call write-byte-buffered/disp32
|
||||
e8/call print-int32-buffered/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
||||
# . write-buffered(stderr, "\n")
|
||||
# . . push args
|
||||
68/push Newline/imm32
|
||||
68/push Stderr/imm32
|
||||
# . . call
|
||||
e8/call write-buffered/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
||||
# . flush(Stderr)
|
||||
# . . push args
|
||||
68/push Stderr/imm32
|
||||
# . . call
|
||||
e8/call flush/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
|
||||
# . syscall(exit, 1)
|
||||
bb/copy-to-ebx 1/imm32
|
||||
e8/call syscall_exit/disp32
|
||||
# never gets here
|
||||
|
||||
# . . vim:nowrap:textwidth=0
|
||||
|
|
BIN
apps/assort
BIN
apps/assort
Binary file not shown.
BIN
apps/braces
BIN
apps/braces
Binary file not shown.
BIN
apps/calls
BIN
apps/calls
Binary file not shown.
BIN
apps/crenshaw2-1
BIN
apps/crenshaw2-1
Binary file not shown.
Binary file not shown.
BIN
apps/dquotes
BIN
apps/dquotes
Binary file not shown.
BIN
apps/factorial
BIN
apps/factorial
Binary file not shown.
187
apps/mu.subx
187
apps/mu.subx
|
@ -6138,6 +6138,7 @@ parse-mu-var-def: # line: (addr stream byte), vars: (addr stack live-var), out:
|
|||
{
|
||||
0f 84/jump-if-= break/disp32
|
||||
# TODO: disallow vars of type 'byte' in registers 'esi' or 'edi'
|
||||
# TODO: vars of type 'byte' should only be initialized by clearing to 0
|
||||
# ensure that the next word is '<-'
|
||||
(next-mu-token *(ebp+8) %ecx)
|
||||
(slice-equal? %ecx "<-") # => eax
|
||||
|
@ -7968,17 +7969,24 @@ compute-size-of-type-id: # t: type-id -> result/eax: int
|
|||
89/<- %ecx 4/r32/esp
|
||||
# eax = t
|
||||
8b/-> *(ebp+8) 0/r32/eax
|
||||
# if v is a literal, return 0
|
||||
# if t is a literal, return 0
|
||||
3d/compare-eax-and 0/imm32/literal
|
||||
74/jump-if-= $compute-size-of-type-id:end/disp8 # eax changes type from type-id to int
|
||||
# if v is a byte, return 1
|
||||
{
|
||||
0f 84/jump-if-= $compute-size-of-type-id:end/disp32 # eax changes type from type-id to int
|
||||
# if t is a byte, return 1
|
||||
3d/compare-eax-and 8/imm32/byte
|
||||
{
|
||||
75/jump-if-!= break/disp8
|
||||
b8/copy-to-eax 1/imm32
|
||||
eb/jump $compute-size-of-type-id:end/disp8
|
||||
}
|
||||
# if v has a user-defined type, compute its size
|
||||
# if t is a handle, return 8
|
||||
3d/compare-eax-and 4/imm32/handle
|
||||
{
|
||||
75/jump-if-!= break/disp8
|
||||
b8/copy-to-eax 8/imm32
|
||||
eb/jump $compute-size-of-type-id:end/disp8 # eax changes type from type-id to int
|
||||
}
|
||||
# if t is a user-defined type, compute its size
|
||||
# TODO: support non-atom type
|
||||
(find-typeinfo %eax %ecx)
|
||||
{
|
||||
|
@ -8490,7 +8498,14 @@ size-of-type-id: # t: type-id -> result/eax: int
|
|||
8b/-> *(ebp+8) 0/r32/eax
|
||||
# if t is a literal, return 0
|
||||
3d/compare-eax-and 0/imm32
|
||||
74/jump-if-= $size-of-type-id:end/disp8 # eax changes type from type-id to int
|
||||
0f 84/jump-if-= $size-of-type-id:end/disp32 # eax changes type from type-id to int
|
||||
# if v is a byte, return 1
|
||||
3d/compare-eax-and 8/imm32/byte
|
||||
{
|
||||
75/jump-if-!= break/disp8
|
||||
b8/copy-to-eax 1/imm32
|
||||
eb/jump $size-of-type-id:end/disp8
|
||||
}
|
||||
# if t is a handle, return 8
|
||||
3d/compare-eax-and 4/imm32/handle
|
||||
{
|
||||
|
@ -9857,6 +9872,7 @@ translate-mu-length-stmt: # out: (addr buffered-file), stmt: (addr stmt), err:
|
|||
{
|
||||
81 7/subop/compare %ecx 1/imm32
|
||||
75/jump-if-!= break/disp8
|
||||
$translate-mu-length-stmt:size-1:
|
||||
(emit-save-size-to *(ebp+8) %ebx %edx)
|
||||
e9/jump $translate-mu-length-stmt:end/disp32
|
||||
}
|
||||
|
@ -9867,6 +9883,7 @@ translate-mu-length-stmt: # out: (addr buffered-file), stmt: (addr stmt), err:
|
|||
74/jump-if-= break/disp8
|
||||
81 7/subop/compare %ecx 0xff/imm32
|
||||
7f/jump-if-> break/disp8
|
||||
$translate-mu-length-stmt:size-power-of-2:
|
||||
(emit-save-size-to *(ebp+8) %ebx %edx)
|
||||
(emit-divide-by-shift-right *(ebp+8) %edx %ecx)
|
||||
e9/jump $translate-mu-length-stmt:end/disp32
|
||||
|
@ -9874,6 +9891,7 @@ translate-mu-length-stmt: # out: (addr buffered-file), stmt: (addr stmt), err:
|
|||
# otherwise, the complex case
|
||||
# . emit register spills
|
||||
{
|
||||
$translate-mu-length-stmt:complex:
|
||||
(string-equal? %edx "eax") # => eax
|
||||
3d/compare-eax-and 0/imm32/false
|
||||
75/break-if-!= break/disp8
|
||||
|
@ -11733,8 +11751,26 @@ _Primitive-address: # (payload primitive)
|
|||
0/imm32/no-disp32
|
||||
1/imm32/output-is-write-only
|
||||
0x11/imm32/alloc-id:fake
|
||||
_Primitive-compare-mem-with-reg/imm32/next
|
||||
_Primitive-compare-reg-with-reg/imm32/next
|
||||
# - compare
|
||||
_Primitive-compare-reg-with-reg: # (payload primitive)
|
||||
0x11/imm32/alloc-id:fake:payload
|
||||
# compare var1/reg1 var2/reg2 => 39/compare var1/rm32 var2/r32
|
||||
0x11/imm32/alloc-id:fake
|
||||
_string-compare/imm32/name
|
||||
0x11/imm32/alloc-id:fake
|
||||
Two-int-args-in-regs/imm32/inouts
|
||||
0/imm32/no-outputs
|
||||
0/imm32/no-outputs
|
||||
0x11/imm32/alloc-id:fake
|
||||
_string_39_compare->/imm32/subx-name
|
||||
1/imm32/rm32-is-first-inout
|
||||
2/imm32/r32-is-second-inout
|
||||
0/imm32/no-imm32
|
||||
0/imm32/no-disp32
|
||||
0/imm32/output-is-write-only
|
||||
0x11/imm32/alloc-id:fake
|
||||
_Primitive-compare-mem-with-reg/imm32/next
|
||||
_Primitive-compare-mem-with-reg: # (payload primitive)
|
||||
0x11/imm32/alloc-id:fake:payload
|
||||
# compare var1 var2/reg => 39/compare var1/rm32 var2/r32
|
||||
|
@ -11824,8 +11860,26 @@ _Primitive-compare-mem-with-literal: # (payload primitive)
|
|||
0/imm32/no-disp32
|
||||
0/imm32/output-is-write-only
|
||||
0x11/imm32/alloc-id:fake
|
||||
_Primitive-multiply-reg-by-mem/imm32/next
|
||||
_Primitive-multiply-reg-by-reg/imm32/next
|
||||
# - multiply
|
||||
_Primitive-multiply-reg-by-reg: # (payload primitive)
|
||||
0x11/imm32/alloc-id:fake:payload
|
||||
# var1/reg <- multiply var2 => 0f af/multiply var2/rm32 var1/r32
|
||||
0x11/imm32/alloc-id:fake
|
||||
_string-multiply/imm32/name
|
||||
0x11/imm32/alloc-id:fake
|
||||
Single-int-var-in-some-register/imm32/inouts
|
||||
0x11/imm32/alloc-id:fake
|
||||
Single-int-var-in-some-register/imm32/outputs
|
||||
0x11/imm32/alloc-id:fake
|
||||
_string_0f_af_multiply/imm32/subx-name
|
||||
1/imm32/rm32-is-first-inout
|
||||
3/imm32/r32-is-first-output
|
||||
0/imm32/no-imm32
|
||||
0/imm32/no-disp32
|
||||
0/imm32/output-is-write-only
|
||||
0x11/imm32/alloc-id:fake
|
||||
_Primitive-multiply-reg-by-mem/imm32/next
|
||||
_Primitive-multiply-reg-by-mem: # (payload primitive)
|
||||
0x11/imm32/alloc-id:fake:payload
|
||||
# var1/reg <- multiply var2 => 0f af/multiply var2/rm32 var1/r32
|
||||
|
@ -13269,6 +13323,13 @@ Two-args-int-stack-int-reg: # (payload list var)
|
|||
0x11/imm32/alloc-id:fake
|
||||
Single-int-var-in-some-register/imm32/next
|
||||
|
||||
Two-int-args-in-regs: # (payload list var)
|
||||
0x11/imm32/alloc-id:fake:payload
|
||||
0x11/imm32/alloc-id:fake
|
||||
Int-var-in-some-register/imm32
|
||||
0x11/imm32/alloc-id:fake
|
||||
Single-int-var-in-some-register/imm32/next
|
||||
|
||||
# Not really legal, but closest we can currently represent a dereference of an (addr byte)
|
||||
Two-args-byte-stack-byte-reg: # (payload list var)
|
||||
0x11/imm32/alloc-id:fake:payload
|
||||
|
@ -15671,6 +15732,116 @@ $test-add-literal-to-mem:initialize-stmt-operation:
|
|||
5d/pop-to-ebp
|
||||
c3/return
|
||||
|
||||
test-compare-reg-with-reg:
|
||||
# compare var1/ecx, var2/eax
|
||||
# =>
|
||||
# 39/compare %ecx 0/r32/eax
|
||||
#
|
||||
# . prologue
|
||||
55/push-ebp
|
||||
89/<- %ebp 4/r32/esp
|
||||
# setup
|
||||
(clear-stream _test-output-stream)
|
||||
(clear-stream $_test-output-buffered-file->buffer)
|
||||
$test-compare-reg-with-reg:initialize-type:
|
||||
# var type/ecx: (payload tree type-id) = int
|
||||
68/push 0/imm32/right:null
|
||||
68/push 0/imm32/right:null
|
||||
68/push 0/imm32/left:unused
|
||||
68/push 1/imm32/value:int
|
||||
68/push 1/imm32/is-atom?:true
|
||||
68/push 0x11/imm32/alloc-id:fake:payload
|
||||
89/<- %ecx 4/r32/esp
|
||||
$test-compare-reg-with-reg:initialize-var1:
|
||||
# var var1/ecx: (payload var)
|
||||
68/push 0/imm32/register
|
||||
68/push 0/imm32/register
|
||||
68/push 0/imm32/no-stack-offset
|
||||
68/push 1/imm32/block-depth
|
||||
51/push-ecx
|
||||
68/push 0x11/imm32/alloc-id:fake
|
||||
68/push 0/imm32/name
|
||||
68/push 0/imm32/name
|
||||
68/push 0x11/imm32/alloc-id:fake:payload
|
||||
89/<- %ecx 4/r32/esp
|
||||
$test-compare-reg-with-reg:initialize-var1-name:
|
||||
# var1->name = "var1"
|
||||
8d/copy-address *(ecx+4) 0/r32/eax # Var-name + 4
|
||||
(copy-array Heap "var1" %eax)
|
||||
$test-compare-reg-with-reg:initialize-var1-register:
|
||||
# var1->register = "ecx"
|
||||
8d/copy-address *(ecx+0x1c) 0/r32/eax # Var-register + 4
|
||||
(copy-array Heap "ecx" %eax)
|
||||
$test-compare-reg-with-reg:initialize-var2:
|
||||
# var var2/edx: (payload var)
|
||||
68/push 0/imm32/register
|
||||
68/push 0/imm32/register
|
||||
68/push 0/imm32/no-stack-offset
|
||||
68/push 1/imm32/block-depth
|
||||
ff 6/subop/push *(ecx+0x10)
|
||||
68/push 0x11/imm32/alloc-id:fake
|
||||
68/push 0/imm32/name
|
||||
68/push 0/imm32/name
|
||||
68/push 0x11/imm32/alloc-id:fake:payload
|
||||
89/<- %edx 4/r32/esp
|
||||
$test-compare-reg-with-reg:initialize-var2-name:
|
||||
# var2->name = "var2"
|
||||
8d/copy-address *(edx+4) 0/r32/eax # Var-name + 4
|
||||
(copy-array Heap "var2" %eax)
|
||||
$test-compare-reg-with-reg:initialize-var2-register:
|
||||
# var2->register = "eax"
|
||||
8d/copy-address *(edx+0x1c) 0/r32/eax # Var-register + 4
|
||||
(copy-array Heap "eax" %eax)
|
||||
$test-compare-reg-with-reg:initialize-inouts:
|
||||
# var inouts/esi: (payload stmt-var) = [var2]
|
||||
68/push 0/imm32/is-deref:false
|
||||
68/push 0/imm32/next
|
||||
68/push 0/imm32/next
|
||||
52/push-edx/var2
|
||||
68/push 0x11/imm32/alloc-id:fake
|
||||
68/push 0x11/imm32/alloc-id:fake:payload
|
||||
89/<- %esi 4/r32/esp
|
||||
# inouts = [var1, var2]
|
||||
68/push 0/imm32/is-deref:false
|
||||
56/push-esi/next
|
||||
68/push 0x11/imm32/alloc-id:fake
|
||||
51/push-ecx/var1
|
||||
68/push 0x11/imm32/alloc-id:fake
|
||||
68/push 0x11/imm32/alloc-id:fake:payload
|
||||
89/<- %esi 4/r32/esp
|
||||
$test-compare-reg-with-reg:initialize-stmt:
|
||||
# var stmt/esi: (addr statement)
|
||||
68/push 0/imm32/next
|
||||
68/push 0/imm32/next
|
||||
68/push 0/imm32/outputs
|
||||
68/push 0/imm32/outputs
|
||||
56/push-esi/inouts
|
||||
68/push 0x11/imm32/alloc-id:fake
|
||||
68/push 0/imm32/operation
|
||||
68/push 0/imm32/operation
|
||||
68/push 1/imm32/tag:stmt1
|
||||
89/<- %esi 4/r32/esp
|
||||
$test-compare-reg-with-reg:initialize-stmt-operation:
|
||||
# stmt->operation = "compare"
|
||||
8d/copy-address *(esi+4) 0/r32/eax # Stmt1-operation
|
||||
(copy-array Heap "compare" %eax)
|
||||
# convert
|
||||
c7 0/subop/copy *Curr-block-depth 0/imm32
|
||||
(emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
|
||||
(flush _test-output-buffered-file)
|
||||
#? # dump _test-output-stream {{{
|
||||
#? (write 2 "^")
|
||||
#? (write-stream 2 _test-output-stream)
|
||||
#? (write 2 "$\n")
|
||||
#? (rewind-stream _test-output-stream)
|
||||
#? # }}}
|
||||
# check output
|
||||
(check-next-stream-line-equal _test-output-stream "39/compare-> %ecx 0x00000000/r32" "F - test-compare-reg-with-reg")
|
||||
# . epilogue
|
||||
89/<- %esp 5/r32/ebp
|
||||
5d/pop-to-ebp
|
||||
c3/return
|
||||
|
||||
test-compare-mem-with-reg:
|
||||
# compare var1, var2/eax
|
||||
# =>
|
||||
|
|
50
apps/parse-int.mu
Normal file
50
apps/parse-int.mu
Normal file
|
@ -0,0 +1,50 @@
|
|||
# parse a decimal int at the commandline
|
||||
#
|
||||
# To run:
|
||||
# $ ./translate_mu apps/parse-int.mu
|
||||
# $ ./a.elf 123
|
||||
# $ echo $?
|
||||
# 123
|
||||
|
||||
fn main _args: (addr array (addr array byte)) -> exit-status/ebx: int {
|
||||
$main-body: {
|
||||
# if no args, print a message and exit
|
||||
var args/esi: (addr array (addr array byte)) <- copy _args
|
||||
var n/ecx: int <- length args
|
||||
compare n, 1
|
||||
{
|
||||
break-if->
|
||||
print-string "usage: parse-int <integer>\n"
|
||||
exit-status <- copy 1
|
||||
break $main-body
|
||||
}
|
||||
# otherwise parse the first arg as an integer
|
||||
var in/ecx: (addr addr array byte) <- index args, 1
|
||||
var out/eax: int <- parse-int *in
|
||||
exit-status <- copy out
|
||||
}
|
||||
}
|
||||
|
||||
fn parse-int _in: (addr array byte) -> result/eax: int {
|
||||
var in/esi: (addr array byte) <- copy _in
|
||||
var len/edx: int <- length in
|
||||
var i/ecx: int <- copy 0
|
||||
var out/edi: int <- copy 0
|
||||
{
|
||||
compare i, len
|
||||
break-if->=
|
||||
# out *= 10
|
||||
var ten/eax: int <- copy 0xa
|
||||
out <- multiply ten
|
||||
# c = in[i]
|
||||
var tmp/ebx: (addr byte) <- index in, i
|
||||
var c/eax: byte <- copy 0
|
||||
c <- copy-byte *tmp
|
||||
#
|
||||
var digit/eax: int <- to-decimal-digit c
|
||||
out <- add digit
|
||||
i <- increment
|
||||
loop
|
||||
}
|
||||
result <- copy out
|
||||
}
|
BIN
apps/sigils
BIN
apps/sigils
Binary file not shown.
BIN
apps/survey
BIN
apps/survey
Binary file not shown.
BIN
apps/tests
BIN
apps/tests
Binary file not shown.
Loading…
Reference in New Issue
Block a user