119 lines
3.0 KiB
Plaintext
119 lines
3.0 KiB
Plaintext
## compute the factorial of 5, and return the result in the exit code
|
|
#
|
|
# Uses syntax sugar for:
|
|
# rm32 operands
|
|
#
|
|
# To run:
|
|
# $ ./ntranslate init.linux 0*.subx apps/factorial.subx -o apps/factorial
|
|
# $ ./subx run apps/factorial
|
|
# Expected result:
|
|
# $ echo $?
|
|
# 120
|
|
#
|
|
# You can also run the automated test suite:
|
|
# $ ./subx run apps/factorial test
|
|
# Expected output:
|
|
# ........
|
|
# Every '.' indicates a passing test. Failing tests get a 'F'.
|
|
|
|
== code
|
|
|
|
Entry: # run tests if necessary, compute `factorial(5)` if not
|
|
# . prologue
|
|
89/<- %ebp 4/r32/esp
|
|
|
|
# initialize heap
|
|
# . Heap = new-segment(Heap-size)
|
|
# . . push args
|
|
68/push Heap/imm32
|
|
ff 6/subop/push *Heap-size
|
|
# . . call
|
|
e8/call new-segment/disp32
|
|
# . . 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
|
|
81 7/subop/compare *ebp 1/imm32
|
|
7e/jump-if-lesser-or-equal $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 *(ebp+8)
|
|
# . . call
|
|
e8/call kernel-string-equal?/disp32
|
|
# . . discard args
|
|
81 0/subop/add %esp 8/imm32
|
|
# . if (eax == false) goto run-main
|
|
3d/compare-eax-and 0/imm32/false
|
|
74/jump-if-equal $run-main/disp8
|
|
# run-tests()
|
|
e8/call run-tests/disp32
|
|
# syscall(exit, *Num-test-failures)
|
|
8b/-> *Num-test-failures 3/r32/ebx
|
|
eb/jump $main:end/disp8
|
|
$run-main:
|
|
# - otherwise return factorial(5)
|
|
# eax = factorial(5)
|
|
# . . push args
|
|
68/push 5/imm32
|
|
# . . call
|
|
e8/call factorial/disp32
|
|
# . . discard args
|
|
81 0/subop/add %esp 4/imm32
|
|
# syscall(exit, eax)
|
|
89/<- %ebx 0/r32/eax
|
|
$main:end:
|
|
b8/copy-to-eax 1/imm32/exit
|
|
cd/syscall 0x80/imm8
|
|
|
|
factorial: # n : int -> int/eax
|
|
# . prologue
|
|
55/push-ebp
|
|
89/<- %ebp 4/r32/esp
|
|
53/push-ebx
|
|
# 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)
|
|
# . . push args
|
|
53/push-ebx
|
|
# . . call
|
|
e8/call factorial/disp32
|
|
# . . discard args
|
|
81 0/subop/add %esp 4/imm32
|
|
# return n * factorial(n-1)
|
|
f7 4/subop/multiply-into-eax *(ebp+8)
|
|
# TODO: check for overflow
|
|
$factorial:end:
|
|
# . epilogue
|
|
5b/pop-to-ebx
|
|
89/<- %esp 5/r32/ebp
|
|
5d/pop-to-ebp
|
|
c3/return
|
|
|
|
test-factorial:
|
|
# factorial(5)
|
|
# . . push args
|
|
68/push 5/imm32
|
|
# . . call
|
|
e8/call factorial/disp32
|
|
# . . discard args
|
|
81 0/subop/add %esp 4/imm32
|
|
# check-ints-equal(eax, 120, msg)
|
|
# . . push args
|
|
68/push "F - test-factorial"/imm32
|
|
68/push 0x78/imm32/expected-120
|
|
50/push-eax
|
|
# . . call
|
|
e8/call check-ints-equal/disp32
|
|
# . . discard args
|
|
81 0/subop/add %esp 0xc/imm32
|
|
# end
|
|
c3/return
|