mu/linux/rpn.mu

149 lines
3.7 KiB
Forth

# Integer arithmetic using postfix notation
#
# Limitations:
# No division yet.
#
# To build:
# $ ./translate rpn.mu
#
# Example session:
# $ ./a.elf
# press ctrl-c or ctrl-d to exit
# > 1
# 1
# > 1 1 +
# 2
# > 1 2 3 + +
# 6
# > 1 2 3 * +
# 7
# > 1 2 + 3 *
# 9
# > 1 3 4 * +
# 13
# > ^D
# $
#
# Error handling is non-existent. This is just a prototype.
fn main -> _/ebx: int {
var in-storage: (stream byte 0x100)
var in/esi: (addr stream byte) <- address in-storage
print-string 0/screen, "press ctrl-c or ctrl-d to exit\n"
# read-eval-print loop
{
# print prompt
print-string 0/screen, "> "
# read line
clear-stream in
read-line-from-real-keyboard in
var done?/eax: boolean <- stream-empty? in
compare done?, 0
break-if-!=
# parse and eval
var out/eax: int <- simplify in
# print
print-int32-decimal 0/screen, out
print-string 0/screen, "\n"
#
loop
}
return 0
}
type int-stack {
data: (handle array int)
top: int
}
fn simplify in: (addr stream byte) -> _/eax: int {
var word-storage: slice
var word/ecx: (addr slice) <- address word-storage
var stack-storage: int-stack
var stack/esi: (addr int-stack) <- address stack-storage
initialize-int-stack stack, 0x10
$simplify:word-loop: {
next-word in, word
var done?/eax: boolean <- slice-empty? word
compare done?, 0
break-if-!=
# if word is an operator, perform it
{
var add?/eax: boolean <- slice-equal? word, "+"
compare add?, 0
break-if-=
var _b/eax: int <- pop-int-stack stack
var b/edx: int <- copy _b
var a/eax: int <- pop-int-stack stack
a <- add b
push-int-stack stack, a
loop $simplify:word-loop
}
{
var sub?/eax: boolean <- slice-equal? word, "-"
compare sub?, 0
break-if-=
var _b/eax: int <- pop-int-stack stack
var b/edx: int <- copy _b
var a/eax: int <- pop-int-stack stack
a <- subtract b
push-int-stack stack, a
loop $simplify:word-loop
}
{
var mul?/eax: boolean <- slice-equal? word, "*"
compare mul?, 0
break-if-=
var _b/eax: int <- pop-int-stack stack
var b/edx: int <- copy _b
var a/eax: int <- pop-int-stack stack
a <- multiply b
push-int-stack stack, a
loop $simplify:word-loop
}
# otherwise it's an int
var n/eax: int <- parse-decimal-int-from-slice word
push-int-stack stack, n
loop
}
var result/eax: int <- pop-int-stack stack
return result
}
fn initialize-int-stack _self: (addr int-stack), n: int {
var self/esi: (addr int-stack) <- copy _self
var d/edi: (addr handle array int) <- get self, data
populate d, n
var top/eax: (addr int) <- get self, top
copy-to *top, 0
}
fn push-int-stack _self: (addr int-stack), _val: int {
var self/esi: (addr int-stack) <- copy _self
var top-addr/ecx: (addr int) <- get self, top
var data-ah/edx: (addr handle array int) <- get self, data
var data/eax: (addr array int) <- lookup *data-ah
var top/edx: int <- copy *top-addr
var dest-addr/edx: (addr int) <- index data, top
var val/eax: int <- copy _val
copy-to *dest-addr, val
add-to *top-addr, 1
}
fn pop-int-stack _self: (addr int-stack) -> _/eax: int {
var self/esi: (addr int-stack) <- copy _self
var top-addr/ecx: (addr int) <- get self, top
{
compare *top-addr, 0
break-if->
return 0
}
subtract-from *top-addr, 1
var data-ah/edx: (addr handle array int) <- get self, data
var data/eax: (addr array int) <- lookup *data-ah
var top/edx: int <- copy *top-addr
var result-addr/eax: (addr int) <- index data, top
var val/eax: int <- copy *result-addr
return val
}