7154
This commit is contained in:
parent
cc7dcdc3b8
commit
17623a628a
|
@ -8,6 +8,6 @@
|
|||
# $ echo $?
|
||||
# 42
|
||||
|
||||
fn main -> result/ebx: int {
|
||||
result <- copy 0x2a # Mu requires hexadecimal
|
||||
fn main -> _/ebx: int {
|
||||
return 0x2a # Mu requires hexadecimal
|
||||
}
|
||||
|
|
10
apps/ex2.mu
10
apps/ex2.mu
|
@ -7,11 +7,13 @@
|
|||
# $ echo $?
|
||||
# 7
|
||||
|
||||
fn main -> result/ebx: int {
|
||||
result <- do-add 3 4
|
||||
fn main -> _/ebx: int {
|
||||
var result/eax: int <- do-add 3 4
|
||||
return result
|
||||
}
|
||||
|
||||
fn do-add a: int, b: int -> result/ebx: int {
|
||||
result <- copy a
|
||||
fn do-add a: int, b: int -> _/eax: int {
|
||||
var result/ebx: int <- copy a
|
||||
result <- add b
|
||||
return result
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
# $ echo $?
|
||||
# 55
|
||||
|
||||
fn main -> result/ebx: int {
|
||||
fn main -> _/ebx: int {
|
||||
# populate a
|
||||
var a: (array int 0xb) # 11; we waste index 0
|
||||
var i/ecx: int <- copy 1
|
||||
|
@ -19,7 +19,7 @@ fn main -> result/ebx: int {
|
|||
loop
|
||||
}
|
||||
# sum
|
||||
result <- copy 0
|
||||
var result/edx: int <- copy 0
|
||||
i <- copy 1
|
||||
{
|
||||
compare i, 0xb
|
||||
|
@ -29,4 +29,5 @@ fn main -> result/ebx: int {
|
|||
i <- increment
|
||||
loop
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
# $ echo $?
|
||||
# 55
|
||||
|
||||
fn main -> result/ebx: int {
|
||||
result <- copy 0
|
||||
fn main -> _/ebx: int {
|
||||
var result/ebx: int <- copy 0
|
||||
var i/eax: int <- copy 1
|
||||
{
|
||||
compare i, 0xa
|
||||
|
@ -17,4 +17,5 @@ fn main -> result/ebx: int {
|
|||
i <- increment
|
||||
loop
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
|
BIN
apps/factorial
BIN
apps/factorial
Binary file not shown.
|
@ -16,21 +16,19 @@
|
|||
#
|
||||
# Compare apps/factorial4.subx
|
||||
|
||||
fn factorial n: int -> result/eax: int {
|
||||
fn factorial n: int -> _/eax: int {
|
||||
compare n, 1
|
||||
# if (n <= 1) return 1
|
||||
{
|
||||
break-if->
|
||||
# n <= 1; return 1
|
||||
result <- copy 1
|
||||
}
|
||||
{
|
||||
break-if-<=
|
||||
# n > 1; return n * factorial(n-1)
|
||||
var tmp/ecx: int <- copy n
|
||||
tmp <- decrement
|
||||
result <- factorial tmp
|
||||
result <- multiply n
|
||||
return 1
|
||||
}
|
||||
# n > 1; return n * factorial(n-1)
|
||||
var tmp/ecx: int <- copy n
|
||||
tmp <- decrement
|
||||
var result/eax: int <- factorial tmp
|
||||
result <- multiply n
|
||||
return result
|
||||
}
|
||||
|
||||
fn test-factorial {
|
||||
|
@ -38,27 +36,25 @@ fn test-factorial {
|
|||
check-ints-equal result, 0x78, "F - test-factorial"
|
||||
}
|
||||
|
||||
fn main args-on-stack: (addr array (addr array byte)) -> exit-status/ebx: int {
|
||||
fn main args-on-stack: (addr array (addr array byte)) -> _/ebx: int {
|
||||
var args/eax: (addr array addr array byte) <- copy args-on-stack
|
||||
# len = length(args)
|
||||
var len/ecx: int <- length args
|
||||
$main-body: {
|
||||
# if (len <= 1) return factorial(5)
|
||||
compare len, 1
|
||||
{
|
||||
break-if->
|
||||
var tmp/eax: int <- factorial 5
|
||||
exit-status <- copy tmp
|
||||
break $main-body
|
||||
}
|
||||
# if (args[1] == "test") run-tests()
|
||||
var tmp2/ecx: (addr addr array byte) <- index args, 1
|
||||
var tmp3/eax: boolean <- string-equal? *tmp2, "test"
|
||||
compare tmp3, 0
|
||||
{
|
||||
break-if-=
|
||||
run-tests
|
||||
exit-status <- copy 0 # TODO: get at Num-test-failures somehow
|
||||
}
|
||||
# if (len <= 1) return factorial(5)
|
||||
compare len, 1
|
||||
{
|
||||
break-if->
|
||||
var exit-status/eax: int <- factorial 5
|
||||
return exit-status
|
||||
}
|
||||
# if (args[1] == "test") run-tests()
|
||||
var tmp2/ecx: (addr addr array byte) <- index args, 1
|
||||
var tmp3/eax: boolean <- string-equal? *tmp2, "test"
|
||||
compare tmp3, 0
|
||||
{
|
||||
break-if-=
|
||||
run-tests
|
||||
# TODO: get at Num-test-failures somehow
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
|
|
@ -18,21 +18,21 @@
|
|||
# . 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
|
||||
|
||||
factorial: # n: int -> int/eax
|
||||
factorial: # n: int -> _/eax: int
|
||||
# . prologue
|
||||
55/push-ebp
|
||||
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
||||
53/push-ebx
|
||||
51/push-ecx
|
||||
# if (n <= 1) return 1
|
||||
b8/copy-to-eax 1/imm32
|
||||
81 7/subop/compare 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 1/imm32 # compare *(ebp+8)
|
||||
7e/jump-if-<= $factorial:end/disp8
|
||||
# var ebx: int = n-1
|
||||
8b/copy 1/mod/*+disp8 5/rm32/ebp . . 3/r32/ebx 8/disp8 . # copy *(ebp+8) to ebx
|
||||
4b/decrement-ebx
|
||||
# var ecx: int = n-1
|
||||
8b/copy 1/mod/*+disp8 5/rm32/ebp . . 1/r32/ecx 8/disp8 . # copy *(ebp+8) to ecx
|
||||
49/decrement-ecx
|
||||
# var eax: int = factorial(n-1)
|
||||
# . . push args
|
||||
53/push-ebx
|
||||
51/push-ecx
|
||||
# . . call
|
||||
e8/call factorial/disp32
|
||||
# . . discard args
|
||||
|
@ -41,8 +41,9 @@ factorial: # n: int -> int/eax
|
|||
f7 4/subop/multiply 1/mod/*+disp8 5/rm32/ebp . . 8/disp8 . # multiply *(ebp+8) into eax
|
||||
# TODO: check for overflow
|
||||
$factorial:end:
|
||||
# restore registers
|
||||
59/pop-to-ecx
|
||||
# . epilogue
|
||||
5b/pop-to-ebx
|
||||
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
|
||||
5d/pop-to-ebp
|
||||
c3/return
|
||||
|
@ -71,7 +72,7 @@ Entry: # run tests if necessary, compute `factorial(5)` if not
|
|||
# . prologue
|
||||
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
|
||||
|
||||
# initialize heap
|
||||
# initialize heap (needed by tests elsewhere)
|
||||
# . Heap = new-segment(Heap-size)
|
||||
# . . push args
|
||||
68/push Heap/imm32
|
||||
|
@ -81,29 +82,10 @@ Entry: # run tests if necessary, compute `factorial(5)` 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
|
||||
81 7/subop/compare 1/mod/*+disp8 5/rm32/ebp . . . . 0/disp8 1/imm32 # compare *ebp
|
||||
7e/jump-if-<= $run-main/disp8
|
||||
# if (!kernel-string-equal?(argv[1], "test")) goto run-main
|
||||
# . eax = kernel-string-equal?(argv[1], "test")
|
||||
# . . push args
|
||||
68/push "test"/imm32
|
||||
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
|
||||
# . . call
|
||||
e8/call kernel-string-equal?/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
||||
# . if (eax == false) goto run-main
|
||||
3d/compare-eax-and 0/imm32/false
|
||||
74/jump-if-= $run-main/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
|
||||
# if (argc <= 1) return factorial(5)
|
||||
$run-main:
|
||||
# - otherwise print factorial(5)
|
||||
81 7/subop/compare 1/mod/*+disp8 5/rm32/ebp . . . . 0/disp8 1/imm32 # compare *ebp
|
||||
7f/jump-if-> $main:run-tests/disp8
|
||||
# eax = factorial(5)
|
||||
# . . push args
|
||||
68/push 5/imm32
|
||||
|
@ -143,6 +125,28 @@ $run-main:
|
|||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
||||
#
|
||||
89/copy 3/mod/direct 3/rm32/ebx . . . 0/r32/eax . . # copy eax to ebx
|
||||
eb/jump $main:end/disp8
|
||||
$main:run-tests:
|
||||
# otherwise if first arg is "test", then return run_tests()
|
||||
# if (!kernel-string-equal?(argv[1], "test")) goto do-nothing
|
||||
# . eax = kernel-string-equal?(argv[1], "test")
|
||||
# . . push args
|
||||
68/push "test"/imm32
|
||||
ff 6/subop/push 1/mod/*+disp8 5/rm32/ebp . . . . 8/disp8 . # push *(ebp+8)
|
||||
# . . call
|
||||
e8/call kernel-string-equal?/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
|
||||
# . if (eax == false) goto do-nothing
|
||||
3d/compare-eax-and 0/imm32/false
|
||||
74/jump-if-= $main:do-nothing/disp8
|
||||
# run-tests()
|
||||
e8/call run-tests/disp32
|
||||
# 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
|
||||
$main:do-nothing:
|
||||
bb/copy-to-ebx 0/imm32
|
||||
$main:end:
|
||||
e8/call syscall_exit/disp32
|
||||
|
||||
|
|
|
@ -20,31 +20,33 @@
|
|||
|
||||
== code
|
||||
|
||||
factorial: # n: int -> int/eax
|
||||
factorial: # n: int -> _/eax: int
|
||||
# . prologue
|
||||
55/push-ebp
|
||||
89/<- %ebp 4/r32/esp
|
||||
53/push-ebx
|
||||
# save registers
|
||||
51/push-ecx
|
||||
# if (n <= 1) return 1
|
||||
b8/copy-to-eax 1/imm32
|
||||
81 7/subop/compare *(ebp+8) 1/imm32
|
||||
7e/jump-if-<= $factorial:end/disp8
|
||||
# var ebx: int = n-1
|
||||
8b/-> *(ebp+8) 3/r32/ebx
|
||||
4b/decrement-ebx
|
||||
# var eax: int = factorial(n-1)
|
||||
# n > 1; return n * factorial(n-1)
|
||||
8b/-> *(ebp+8) 1/r32/ecx
|
||||
49/decrement-ecx
|
||||
# var tmp/eax: int = factorial(n-1)
|
||||
# . . push args
|
||||
53/push-ebx
|
||||
51/push-ecx
|
||||
# . . call
|
||||
e8/call factorial/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add %esp 4/imm32
|
||||
# return n * factorial(n-1)
|
||||
# return n * tmp
|
||||
f7 4/subop/multiply-into-eax *(ebp+8)
|
||||
# TODO: check for overflow
|
||||
$factorial:end:
|
||||
# restore registers
|
||||
59/pop-to-ecx
|
||||
# . epilogue
|
||||
5b/pop-to-ebx
|
||||
89/<- %esp 5/r32/ebp
|
||||
5d/pop-to-ebp
|
||||
c3/return
|
||||
|
@ -73,7 +75,7 @@ Entry: # run tests if necessary, compute `factorial(5)` if not
|
|||
# . prologue
|
||||
89/<- %ebp 4/r32/esp
|
||||
|
||||
# initialize heap
|
||||
# initialize heap (needed by tests elsewhere)
|
||||
# . Heap = new-segment(Heap-size)
|
||||
# . . push args
|
||||
68/push Heap/imm32
|
||||
|
@ -83,11 +85,21 @@ Entry: # run tests if necessary, compute `factorial(5)` if not
|
|||
# . . discard args
|
||||
81 0/subop/add %esp 8/imm32
|
||||
|
||||
# - if argc > 1 and argv[1] == "test", then return run_tests()
|
||||
# if (argc <= 1) goto run-main
|
||||
# if (argc <= 1) return factorial(5)
|
||||
81 7/subop/compare *ebp 1/imm32
|
||||
7e/jump-if-<= $run-main/disp8
|
||||
# if (!kernel-string-equal?(argv[1], "test")) goto run-main
|
||||
7f/jump-if-> $main:run-tests/disp8
|
||||
# . . push args
|
||||
68/push 5/imm32
|
||||
# . . call
|
||||
e8/call factorial/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add %esp 4/imm32
|
||||
# .
|
||||
89/<- %ebx 0/r32/eax
|
||||
eb/jump $main:end/disp8
|
||||
$main:run-tests:
|
||||
# otherwise if first arg is "test", then return run_tests()
|
||||
# if (!kernel-string-equal?(argv[1], "test")) goto do-nothing
|
||||
# . eax = kernel-string-equal?(argv[1], "test")
|
||||
# . . push args
|
||||
68/push "test"/imm32
|
||||
|
@ -96,24 +108,15 @@ Entry: # run tests if necessary, compute `factorial(5)` if not
|
|||
e8/call kernel-string-equal?/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add %esp 8/imm32
|
||||
# . if (eax == false) goto run-main
|
||||
# . if (eax == false) goto do-nothing
|
||||
3d/compare-eax-and 0/imm32/false
|
||||
74/jump-if-= $run-main/disp8
|
||||
74/jump-if-= $main:do-nothing/disp8
|
||||
# run-tests()
|
||||
e8/call run-tests/disp32
|
||||
# syscall(exit, *Num-test-failures)
|
||||
# exit(*Num-test-failures)
|
||||
8b/-> *Num-test-failures 3/r32/ebx
|
||||
eb/jump $main:end/disp8
|
||||
$run-main:
|
||||
# - otherwise return factorial(5)
|
||||
# ebx = factorial(5)
|
||||
# . . push args
|
||||
68/push 5/imm32
|
||||
# . . call
|
||||
e8/call factorial/disp32
|
||||
# . . discard args
|
||||
81 0/subop/add %esp 4/imm32
|
||||
#
|
||||
89/<- %ebx 0/r32/eax
|
||||
$main:do-nothing:
|
||||
bb/copy-to-ebx 0/imm32
|
||||
$main:end:
|
||||
e8/call syscall_exit/disp32
|
||||
|
|
|
@ -21,27 +21,25 @@
|
|||
|
||||
== code
|
||||
|
||||
factorial: # n: int -> int/eax
|
||||
factorial: # n: int -> _/eax: int
|
||||
# . prologue
|
||||
55/push-ebp
|
||||
89/<- %ebp 4/r32/esp
|
||||
# save registers
|
||||
53/push-ebx
|
||||
51/push-ecx
|
||||
# if (n <= 1) return 1
|
||||
b8/copy-to-eax 1/imm32
|
||||
81 7/subop/compare *(ebp+8) 1/imm32
|
||||
7e/jump-if-<= $factorial:end/disp8
|
||||
# var ebx: int = n-1
|
||||
8b/-> *(ebp+8) 3/r32/ebx
|
||||
4b/decrement-ebx
|
||||
#
|
||||
(factorial %ebx) # => eax
|
||||
# return n * factorial(n-1)
|
||||
# n > 1; return n * factorial(n-1)
|
||||
8b/-> *(ebp+8) 1/r32/ecx
|
||||
49/decrement-ecx
|
||||
(factorial %ecx) # => eax
|
||||
f7 4/subop/multiply-into-eax *(ebp+8)
|
||||
# TODO: check for overflow
|
||||
$factorial:end:
|
||||
# restore registers
|
||||
5b/pop-to-ebx
|
||||
59/pop-to-ecx
|
||||
# . epilogue
|
||||
89/<- %esp 5/r32/ebp
|
||||
5d/pop-to-ebp
|
||||
|
@ -59,23 +57,24 @@ Entry: # run tests if necessary, compute `factorial(5)` if not
|
|||
# initialize heap (needed by tests elsewhere)
|
||||
(new-segment *Heap-size Heap)
|
||||
|
||||
# - if argc > 1 and argv[1] == "test", then return run_tests()
|
||||
# if (argc <= 1) goto run-main
|
||||
# if (argc <= 1) return factorial(5)
|
||||
81 7/subop/compare *ebp 1/imm32
|
||||
7e/jump-if-<= $run-main/disp8
|
||||
# if (!kernel-string-equal?(argv[1], "test")) goto run-main
|
||||
(kernel-string-equal? *(ebp+8) "test") # => eax
|
||||
# . if (eax == false) goto run-main
|
||||
3d/compare-eax-and 0/imm32/false
|
||||
74/jump-if-= $run-main/disp8
|
||||
#
|
||||
(run-tests)
|
||||
# syscall(exit, *Num-test-failures)
|
||||
8b/-> *Num-test-failures 3/r32/ebx
|
||||
eb/jump $main:end/disp8
|
||||
$run-main:
|
||||
# - otherwise
|
||||
7f/jump-if-> $main:run-tests/disp8
|
||||
(factorial 5) # => eax
|
||||
89/<- %ebx 0/r32/eax
|
||||
eb/jump $main:end/disp8
|
||||
$main:run-tests:
|
||||
# otherwise if first arg is "test", then return run_tests()
|
||||
# if (!kernel-string-equal?(argv[1], "test")) goto do-nothing
|
||||
(kernel-string-equal? *(ebp+8) "test") # => eax
|
||||
3d/compare-eax-and 0/imm32/false
|
||||
74/jump-if-= $main:do-nothing/disp8
|
||||
#
|
||||
(run-tests)
|
||||
# exit(*Num-test-failures)
|
||||
8b/-> *Num-test-failures 3/r32/ebx
|
||||
eb/jump $main:end/disp8
|
||||
$main:do-nothing:
|
||||
bb/copy-to-ebx 0/imm32
|
||||
$main:end:
|
||||
e8/call syscall_exit/disp32
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
== code
|
||||
|
||||
factorial: # n: int -> int/eax
|
||||
factorial: # n: int -> _/eax: int
|
||||
# . prologue
|
||||
55/push-ebp
|
||||
89/<- %ebp 4/r32/esp
|
||||
|
@ -33,16 +33,15 @@ factorial: # n: int -> int/eax
|
|||
{
|
||||
7f/jump-if-> break/disp8
|
||||
b8/copy-to-eax 1/imm32
|
||||
eb/jump $factorial:end/disp8
|
||||
}
|
||||
# if (n > 1) return n * factorial(n-1)
|
||||
{
|
||||
7e/jump-if-<= break/disp8
|
||||
# var tmp/ecx: int = n-1
|
||||
8b/-> *(ebp+8) 1/r32/ecx
|
||||
49/decrement-ecx
|
||||
(factorial %ecx) # => eax
|
||||
f7 4/subop/multiply-into-eax *(ebp+8)
|
||||
}
|
||||
# n > 1; return n * factorial(n-1)
|
||||
8b/-> *(ebp+8) 1/r32/ecx
|
||||
49/decrement-ecx
|
||||
(factorial %ecx) # => eax
|
||||
f7 4/subop/multiply-into-eax *(ebp+8)
|
||||
# TODO: check for overflow
|
||||
$factorial:end:
|
||||
# restore registers
|
||||
59/pop-to-ecx
|
||||
# . epilogue
|
||||
|
@ -70,20 +69,20 @@ Entry: # run tests if necessary, compute `factorial(5)` if not
|
|||
# ebx = factorial(5)
|
||||
(factorial 5) # => eax
|
||||
89/<- %ebx 0/r32/eax
|
||||
eb/jump $main:end/disp8
|
||||
}
|
||||
# otherwise if an arg exists and is "test", then return run_tests()
|
||||
# otherwise if first arg is "test", then return run_tests()
|
||||
{
|
||||
# if (argc <= 1) break
|
||||
81 7/subop/compare *ebp 1/imm32
|
||||
7e/jump-if-<= break/disp8
|
||||
# if (!kernel-string-equal?(argv[1], "test")) break
|
||||
(kernel-string-equal? *(ebp+8) "test") # => eax
|
||||
3d/compare-eax-and 0/imm32/false
|
||||
74/jump-if-= break/disp8
|
||||
#
|
||||
(run-tests)
|
||||
# ebx = *Num-test-failures
|
||||
# exit(*Num-test-failures)
|
||||
8b/-> *Num-test-failures 3/r32/ebx
|
||||
eb/jump $main:end/disp8
|
||||
}
|
||||
|
||||
bb/copy-to-ebx 0/imm32
|
||||
$main:end:
|
||||
e8/call syscall_exit/disp32
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
# $ ./translate_mu apps/hello.mu
|
||||
# $ ./a.elf
|
||||
|
||||
fn main -> exit-status/ebx: int {
|
||||
fn main -> _/ebx: int {
|
||||
print-string 0, "Hello world!\n"
|
||||
exit-status <- copy 0
|
||||
return 0
|
||||
}
|
||||
|
|
233
apps/mulisp.subx
233
apps/mulisp.subx
|
@ -1,233 +0,0 @@
|
|||
# Toy lisp interpreter. Incomplete.
|
||||
#
|
||||
# To run:
|
||||
# $ ./translate_subx init.linux 0*.subx apps/mulisp.subx
|
||||
# $ ./a.elf
|
||||
# 42
|
||||
# => 42
|
||||
# ^D
|
||||
# $
|
||||
|
||||
== code
|
||||
|
||||
Entry: # run tests if necessary, a REPL if not
|
||||
# . prologue
|
||||
89/<- %ebp 4/r32/esp
|
||||
# initialize heap
|
||||
(new-segment *Heap-size Heap)
|
||||
{
|
||||
# if (argc <= 1) break
|
||||
81 7/subop/compare *ebp 1/imm32
|
||||
7e/jump-if-<= break/disp8
|
||||
# if (argv[1] != "test")) break
|
||||
(kernel-string-equal? *(ebp+8) "test") # => eax
|
||||
3d/compare-eax-and 0/imm32/false
|
||||
74/jump-if-= break/disp8
|
||||
#
|
||||
(run-tests)
|
||||
# syscall(exit, *Num-test-failures)
|
||||
8b/-> *Num-test-failures 3/r32/ebx
|
||||
eb/jump $main:end/disp8
|
||||
}
|
||||
(repl Stdin Stdout)
|
||||
# syscall(exit, 0)
|
||||
bb/copy-to-ebx 0/imm32
|
||||
$main:end:
|
||||
e8/call syscall_exit/disp32
|
||||
|
||||
# Data structures
|
||||
#
|
||||
# Lisp is dynamically typed. Values always carry around knowledge of their
|
||||
# type.
|
||||
#
|
||||
# There's several types of types in the description below, so we need a
|
||||
# glossary and notational convention to disambiguate:
|
||||
# lisp type: what Lisp code can see. Looks how you type it at the prompt.
|
||||
# nil num char string symbol pair array
|
||||
# type tag: the numeric code for a lisp type. All caps.
|
||||
# NIL NUM CHAR STRING SYMBOL PAIR ARRAY
|
||||
# memory type: a type specifying memory layout at the SubX level. Starts
|
||||
# with a '$'.
|
||||
# $int $array $(addr _)
|
||||
#
|
||||
# Lisp values are represented in memory by the _cell_ data structure. A cell
|
||||
# is 12 bytes long:
|
||||
# tag: $int (4 bytes; we're not concerned about wasting space)
|
||||
# data: 8 bytes whose contents and meaning depend on tag
|
||||
#
|
||||
# What values of the different Lisp types look like in memory:
|
||||
# - nil: cell{ tag: 0/NIL, data: 0 0 }
|
||||
# - num: cell{ tag: 1/NUM, data: $int 0 }
|
||||
# data contains the number
|
||||
# - char: cell{ tag: 2/CHAR, data: $int 0 }
|
||||
# data contains the utf-8 code of the character (no compound glyphs, no
|
||||
# modifiers, etc., etc.)
|
||||
# - string: cell{ tag: 3/STRING, data: $(addr stream byte)
|
||||
# data contains an (addr array byte) containing the string in utf-8
|
||||
# - symbol: cell{ tag: 4/SYMBOL, data: $(addr array byte) 0 }
|
||||
# data contains an (addr array byte) containing the name of the symbol in utf-8
|
||||
# alternatively, data could contain an index into the table of interned symbols
|
||||
# - pair: cell{ tag: 5/PAIR, data: $(addr cell) $(addr cell) }
|
||||
# data contains pointers to car and cdr
|
||||
# - array: cell{ tag: 6/ARRAY, data: $tag $(addr stream data)
|
||||
# data contains a pointer to an array of 8-byte data fields and the common
|
||||
# tag for them all
|
||||
|
||||
repl: # in: (addr buffered-file), out: (addr buffered-file)
|
||||
# . prologue
|
||||
55/push-ebp
|
||||
89/<- %ebp 4/r32/esp
|
||||
# . save registers
|
||||
50/push-eax
|
||||
{
|
||||
(lisp-read Stdin) # => eax: (handle cell)
|
||||
# if (eax == 0) break
|
||||
3d/compare-eax-and 0/imm32
|
||||
74/jump-if-= break/disp8
|
||||
#
|
||||
(lisp-eval %eax) # => eax: (handle cell)
|
||||
(lisp-print Stdout %eax)
|
||||
eb/jump loop/disp8
|
||||
}
|
||||
$repl:end:
|
||||
# . restore registers
|
||||
58/pop-to-eax
|
||||
# . epilogue
|
||||
89/<- %esp 5/r32/ebp
|
||||
5d/pop-to-ebp
|
||||
c3/return
|
||||
|
||||
# numbers start with a digit and are always in hex
|
||||
# characters start with a backslash
|
||||
# pairs start with '('
|
||||
# arrays start with '['
|
||||
# symbols start with anything else but quote, backquote, unquote or splice
|
||||
# only one s-expression per line
|
||||
lisp-read: # in: (addr buffered-file) -> eax: (handle cell)
|
||||
# . prologue
|
||||
55/push-ebp
|
||||
89/<- %ebp 4/r32/esp
|
||||
# . save registers
|
||||
51/push-ecx
|
||||
# var s/ecx: (stream byte 512)
|
||||
81 5/subop/subtract %esp 0x200/imm32
|
||||
68/push 0x200/imm32/size
|
||||
68/push 0/imm32/read
|
||||
68/push 0/imm32/write
|
||||
89/<- %ecx 4/r32/esp
|
||||
{
|
||||
# read line into s
|
||||
(clear-stream %ecx)
|
||||
(read-line-buffered *(ebp+8) %ecx)
|
||||
# if (s->write == 0) return null
|
||||
{
|
||||
81 7/subop/compare *ecx 0/imm32
|
||||
75/jump-if-!= break/disp8
|
||||
b8/copy-to-eax 0/imm32/eof
|
||||
eb/jump $lisp-read:end/disp8
|
||||
}
|
||||
# ...
|
||||
#? eb/jump loop/disp8
|
||||
}
|
||||
# return s
|
||||
89/<- %eax 1/r32/ecx
|
||||
$lisp-read:end:
|
||||
# . reclaim locals
|
||||
81 0/subop/add %esp 0x20c/imm32
|
||||
# . restore registers
|
||||
59/pop-to-ecx
|
||||
# . epilogue
|
||||
89/<- %esp 5/r32/ebp
|
||||
5d/pop-to-ebp
|
||||
c3/return
|
||||
|
||||
# lisp-read: in: (addr buffered-file) -> (handle cell)
|
||||
# token tmp = next-mulisp-token(in)
|
||||
# if is-int(tmp) return cell(tmp)
|
||||
# if is-string(tmp) return cell(tmp)
|
||||
# if is-pair(tmp) ...
|
||||
# if is-array(tmp) ...
|
||||
|
||||
next-mulisp-token: # in: (addr buffered-file), line: (addr stream byte), result: (addr slice)
|
||||
# pseudocode:
|
||||
# if (line->read >= line->write)
|
||||
# read-line-buffered(in, line)
|
||||
# recurse
|
||||
# if (line->data[line->read] == ' ')
|
||||
# skip-chars-matching-whitespace(line)
|
||||
# recurse
|
||||
# if (line->data[line->read] == '#')
|
||||
# read-line-buffered(in, line)
|
||||
# recurse
|
||||
# eax = line->data[line->read]
|
||||
# if (eax == '"')
|
||||
# result->start = &line->data[line->read]
|
||||
# skip-string(in)
|
||||
# result->end = &line->data[line->read]
|
||||
# return
|
||||
# if (is-digit(eax))
|
||||
# result->start = &line->data[line->read]
|
||||
# skip-hex-int(in)
|
||||
# result->end = &line->data[line->read]
|
||||
# return
|
||||
# if (eax in '(' ')' '[' ']')
|
||||
# result->start = &line->data[line->read]
|
||||
# ++line->read
|
||||
# result->en = &line->data[line->read]
|
||||
# return
|
||||
# else
|
||||
# result->start = &line->data[line->read]
|
||||
# skip-lisp-word(line)
|
||||
# result->en = &line->data[line->read]
|
||||
# return
|
||||
#
|
||||
# . prologue
|
||||
55/push-ebp
|
||||
89/<- %ebp 4/r32/esp
|
||||
# . save registers
|
||||
$next-mulisp-token:end:
|
||||
# . reclaim locals
|
||||
# . restore registers
|
||||
# . epilogue
|
||||
89/<- %esp 5/r32/ebp
|
||||
5d/pop-to-ebp
|
||||
c3/return
|
||||
|
||||
new-int-cell: # in: (addr slice) -> eax: (handle cell)
|
||||
|
||||
new-string-cell: # in: (addr slice) -> eax: (handle cell)
|
||||
|
||||
lisp-eval: # in: (addr cell) -> eax: (handle cell)
|
||||
# . prologue
|
||||
55/push-ebp
|
||||
89/<- %ebp 4/r32/esp
|
||||
# . save registers
|
||||
8b/-> *(ebp+8) 0/r32/eax
|
||||
$lisp-eval:end:
|
||||
# . restore registers
|
||||
# . epilogue
|
||||
89/<- %esp 5/r32/ebp
|
||||
5d/pop-to-ebp
|
||||
c3/return
|
||||
|
||||
lisp-print: # out: (addr buffered-file), x: (addr cell)
|
||||
# . prologue
|
||||
55/push-ebp
|
||||
89/<- %ebp 4/r32/esp
|
||||
# . save registers
|
||||
# write(x)
|
||||
(write-buffered Stdout "=> ")
|
||||
(write-stream-data Stdout *(ebp+0xc))
|
||||
(flush Stdout)
|
||||
$lisp-print:end:
|
||||
# . restore registers
|
||||
# . epilogue
|
||||
89/<- %esp 5/r32/ebp
|
||||
5d/pop-to-ebp
|
||||
c3/return
|
||||
|
||||
== data
|
||||
|
||||
Nil:
|
||||
0/imm32/tag
|
||||
0/imm32/data
|
Loading…
Reference in New Issue