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