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