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