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