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: 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 }