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 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 {
     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/screen, "> ", 0/x, 0x80/xmax, y, 3/fg/cyan, 0/bg
     27     set-cursor-position 0/screen, x, y
     28     # read line from keyboard
     29     clear-stream in
     30     {
     31       draw-cursor 0/screen, space
     32       var key/eax: byte <- read-key 0/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 0/screen, g, 0xf/fg, 0/bg
     41       move-cursor-right 0
     42       loop
     43     }
     44     # clear cursor
     45     draw-grapheme-at-cursor 0/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 0/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 }