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