about summary refs log tree commit diff stats
path: root/baremetal/rpn.mu
diff options
context:
space:
mode:
authorKartik Agaram <vc@akkartik.com>2021-01-22 23:29:04 -0800
committerKartik Agaram <vc@akkartik.com>2021-01-22 23:29:04 -0800
commit0f73127ef1eba0a8ea814c26115523da3590ffe2 (patch)
treef2480aea129e680e5fc995e730e2083074c44b32 /baremetal/rpn.mu
parenta451b2e14f06c19eaf98f32dcc2b45e2940a570b (diff)
downloadmu-0f73127ef1eba0a8ea814c26115523da3590ffe2.tar.gz
7547 - baremetal: rpn calculator
Still in progress. Known bugs:
* Cursor management is broken. Every line currently seems to leave
  behind a shadow cursor.
* No shift-key support yet, which means no addition or multiplication.
  (This app doesn't have division yet.)
Diffstat (limited to 'baremetal/rpn.mu')
-rw-r--r--baremetal/rpn.mu152
1 files changed, 152 insertions, 0 deletions
diff --git a/baremetal/rpn.mu b/baremetal/rpn.mu
new file mode 100644
index 00000000..df894cbc
--- /dev/null
+++ b/baremetal/rpn.mu
@@ -0,0 +1,152 @@
+# Integer arithmetic using postfix notation
+#
+# Limitations:
+#   No division yet.
+#
+# To build:
+#   $ ./translate_mu_baremetal baremetal/rpn.mu
+#
+# Example session:
+#   $ qemu-system-i386 disk.img
+#   > 4
+#   4
+#   > 5 3 -
+#   2
+#
+# '+' and '*' not supported yet because they require the shift key.
+#
+# Error handling is non-existent. This is just a prototype.
+
+fn main -> _/ebx: int {
+  var in-storage: (stream byte 0x80)
+  var in/esi: (addr stream byte) <- address in-storage
+  var y/ecx: int <- copy 0
+  var space/edx: grapheme <- copy 0x20
+  # read-eval-print loop
+  {
+    # print prompt
+    var x/eax: int <- draw-text-rightward 0, "> ", 0, 0x80, y, 3
+    set-cursor-position 0, x, y, space
+    # read line from keyboard
+    clear-stream in
+    {
+      var key/eax: byte <- read-key 0
+      compare key, 0xa  # newline
+      break-if-=
+      compare key, 0
+      loop-if-=
+      var key2/eax: int <- copy key
+      append-byte in, key2
+      var g/eax: grapheme <- copy key2
+      draw-grapheme-at-cursor 0, g, 0xf
+      cursor-right 0
+      loop
+    }
+    # parse and eval
+    var out/eax: int <- simplify in
+    # print
+    y <- increment
+    out, y <- draw-int32-decimal-wrapping-right-then-down 0, out, 0, y, 0x80, 0x30, 0, y, 7
+    # newline
+    y <- increment
+    #
+    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 is-add?/eax: boolean <- slice-equal? word, "+"
+      compare is-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 is-sub?/eax: boolean <- slice-equal? word, "-"
+      compare is-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 is-mul?/eax: boolean <- slice-equal? word, "*"
+      compare is-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
+}