https://github.com/akkartik/mu/blob/main/baremetal/rpn.mu
  1 # Integer arithmetic using postfix notation
  2 #
  3 # Limitations:
  4 #   No division yet.
  5 #
  6 # To build:
  7 #   $ ./translate_mu_baremetal baremetal/rpn.mu
  8 #
  9 # Example session:
 10 #   $ qemu-system-i386 disk.img
 11 #   > 4
 12 #   4
 13 #   > 5 3 -
 14 #   2
 15 #
 16 # '+' and '*' not supported yet because they require the shift key.
 17 #
 18 # Error handling is non-existent. This is just a prototype.
 19 
 20 fn main -> _/ebx: int {
 21   var in-storage: (stream byte 0x80)
 22   var in/esi: (addr stream byte) <- address in-storage
 23   var y/ecx: int <- copy 0
 24   var space/edx: grapheme <- copy 0x20
 25   # read-eval-print loop
 26   {
 27     # print prompt
 28     var x/eax: int <- draw-text-rightward 0, "> ", 0, 0x80, y, 3
 29     set-cursor-position 0, x, y
 30     # read line from keyboard
 31     clear-stream in
 32     {
 33       show-cursor 0, space
 34       var key/eax: byte <- read-key 0
 35       compare key, 0xa  # newline
 36       break-if-=
 37       compare key, 0
 38       loop-if-=
 39       var key2/eax: int <- copy key
 40       append-byte in, key2
 41       var g/eax: grapheme <- copy key2
 42       draw-grapheme-at-cursor 0, g, 0xf
 43       cursor-right 0
 44       loop
 45     }
 46     # clear cursor
 47     draw-grapheme-at-cursor 0, space, 3  # 3=foreground color, which is never used
 48     # parse and eval
 49     var out/eax: int <- simplify in
 50     # print
 51     y <- increment
 52     out, y <- draw-int32-decimal-wrapping-right-then-down 0, out, 0, y, 0x80, 0x30, 0, y, 7
 53     # newline
 54     y <- increment
 55     #
 56     loop
 57   }
 58   return 0
 59 }
 60 
 61 type int-stack {
 62   data: (handle array int)
 63   top: int
 64 }
 65 
 66 fn simplify in: (addr stream byte) -> _/eax: int {
 67   var word-storage: slice
 68   var word/ecx: (addr slice) <- address word-storage
 69   var stack-storage: int-stack
 70   var stack/esi: (addr int-stack) <- address stack-storage
 71   initialize-int-stack stack, 0x10
 72   $simplify:word-loop: {
 73     next-word in, word
 74     var done?/eax: boolean <- slice-empty? word
 75     compare done?, 0
 76     break-if-!=
 77     # if word is an operator, perform it
 78     {
 79       var is-add?/eax: boolean <- slice-equal? word, "+"
 80       compare is-add?, 0
 81       break-if-=
 82       var _b/eax: int <- pop-int-stack stack
 83       var b/edx: int <- copy _b
 84       var a/eax: int <- pop-int-stack stack
 85       a <- add b
 86       push-int-stack stack, a
 87       loop $simplify:word-loop
 88     }
 89     {
 90       var is-sub?/eax: boolean <- slice-equal? word, "-"
 91       compare is-sub?, 0
 92       break-if-=
 93       var _b/eax: int <- pop-int-stack stack
 94       var b/edx: int <- copy _b
 95       var a/eax: int <- pop-int-stack stack
 96       a <- subtract b
 97       push-int-stack stack, a
 98       loop $simplify:word-loop
 99     }
100     {
101       var is-mul?/eax: boolean <- slice-equal? word, "*"
102       compare is-mul?, 0
103       break-if-=
104       var _b/eax: int <- pop-int-stack stack
105       var b/edx: int <- copy _b
106       var a/eax: int <- pop-int-stack stack
107       a <- multiply b
108       push-int-stack stack, a
109       loop $simplify:word-loop
110     }
111     # otherwise it's an int
112     var n/eax: int <- parse-decimal-int-from-slice word
113     push-int-stack stack, n
114     loop
115   }
116   var result/eax: int <- pop-int-stack stack
117   return result
118 }
119 
120 fn initialize-int-stack _self: (addr int-stack), n: int {
121   var self/esi: (addr int-stack) <- copy _self
122   var d/edi: (addr handle array int) <- get self, data
123   populate d, n
124   var top/eax: (addr int) <- get self, top
125   copy-to *top, 0
126 }
127 
128 fn push-int-stack _self: (addr int-stack), _val: int {
129   var self/esi: (addr int-stack) <- copy _self
130   var top-addr/ecx: (addr int) <- get self, top
131   var data-ah/edx: (addr handle array int) <- get self, data
132   var data/eax: (addr array int) <- lookup *data-ah
133   var top/edx: int <- copy *top-addr
134   var dest-addr/edx: (addr int) <- index data, top
135   var val/eax: int <- copy _val
136   copy-to *dest-addr, val
137   add-to *top-addr, 1
138 }
139 
140 fn pop-int-stack _self: (addr int-stack) -> _/eax: int {
141   var self/esi: (addr int-stack) <- copy _self
142   var top-addr/ecx: (addr int) <- get self, top
143   {
144     compare *top-addr, 0
145     break-if->
146     return 0
147   }
148   subtract-from *top-addr, 1
149   var data-ah/edx: (addr handle array int) <- get self, data
150   var data/eax: (addr array int) <- lookup *data-ah
151   var top/edx: int <- copy *top-addr
152   var result-addr/eax: (addr int) <- index data, top
153   var val/eax: int <- copy *result-addr
154   return val
155 }