https://github.com/akkartik/mu/blob/main/shell/parse.mu

      1 fn parse-input tokens: (addr stream cell), out: (addr handle cell), trace: (addr trace) {
      2   rewind-stream tokens
      3   var empty?/eax: boolean <- stream-empty? tokens
      4   compare empty?, 0/false
      5   {
      6     break-if-=
      7     error trace, "nothing to parse"
      8     return
      9   }
     10   var close-paren?/eax: boolean <- parse-sexpression tokens, out, trace
     11   {
     12     compare close-paren?, 0/false
     13     break-if-=
     14     error trace, "')' is not a valid expression"
     15     return
     16   }
     17   {
     18     var empty?/eax: boolean <- stream-empty? tokens
     19     compare empty?, 0/false
     20     break-if-!=
     21     error trace, "unexpected tokens at end; only type in a single expression at a time"
     22   }
     23 }
     24
     25 # return value: true if close-paren was encountered
     26 fn parse-sexpression tokens: (addr stream cell), _out: (addr handle cell), trace: (addr trace) -> _/eax: boolean {
     27   trace-text trace, "read", "parse"
     28   trace-lower trace
     29   var curr-token-storage: cell
     30   var curr-token/ecx: (addr cell) <- address curr-token-storage
     31   var empty?/eax: boolean <- stream-empty? tokens
     32   compare empty?, 0/false
     33   {
     34     break-if-=
     35     error trace, "end of stream; never found a balancing ')'"
     36     return 1/true
     37   }
     38   read-from-stream tokens, curr-token
     39   $parse-sexpression:type-check: {
     40     # not bracket -> parse atom
     41     var bracket-token?/eax: boolean <- bracket-token? curr-token
     42     compare bracket-token?, 0/false
     43     {
     44       break-if-!=
     45       parse-atom curr-token, _out, trace
     46       break $parse-sexpression:type-check
     47     }
     48     # open paren -> parse list
     49     var open-paren?/eax: boolean <- open-paren-token? curr-token
     50     compare open-paren?, 0/false
     51     {
     52       break-if-=
     53       var curr/esi: (addr handle cell) <- copy _out
     54       $parse-sexpression:list-loop: {
     55         allocate-pair curr
     56         var curr-addr/eax: (addr cell) <- lookup *curr
     57         var left/ecx: (addr handle cell) <- get curr-addr, left
     58         {
     59           var close-paren?/eax: boolean <- parse-sexpression tokens, left, trace
     60           compare close-paren?, 0/false
     61           break-if-!= $parse-sexpression:list-loop
     62         }
     63         #
     64         curr <- get curr-addr, right
     65         loop
     66       }
     67       break $parse-sexpression:type-check
     68     }
     69     # close paren -> parse list
     70     var close-paren?/eax: boolean <- close-paren-token? curr-token
     71     compare close-paren?, 0/false
     72     {
     73       break-if-=
     74       trace-higher trace
     75       return 1/true
     76     }
     77     # otherwise abort
     78     var stream-storage: (stream byte 0x40)
     79     var stream/edx: (addr stream byte) <- address stream-storage
     80     write stream, "unexpected token "
     81     var curr-token-data-ah/eax: (addr handle stream byte) <- get curr-token, text-data
     82     var curr-token-data/eax: (addr stream byte) <- lookup *curr-token-data-ah
     83     rewind-stream curr-token-data
     84     write-stream stream, curr-token-data
     85     trace trace, "error", stream
     86   }
     87   trace-higher trace
     88   return 0/false
     89 }
     90
     91 fn parse-atom _curr-token: (addr cell), _out: (addr handle cell), trace: (addr trace) {
     92   trace-text trace, "read", "parse atom"
     93   var curr-token/ecx: (addr cell) <- copy _curr-token
     94   var curr-token-data-ah/eax: (addr handle stream byte) <- get curr-token, text-data
     95   var _curr-token-data/eax: (addr stream byte) <- lookup *curr-token-data-ah
     96   var curr-token-data/esi: (addr stream byte) <- copy _curr-token-data
     97   trace trace, "read", curr-token-data
     98   # number
     99   var number-token?/eax: boolean <- number-token? curr-token
    100   compare number-token?, 0/false
    101   {
    102     break-if-=
    103     rewind-stream curr-token-data
    104     var _val/eax: int <- parse-decimal-int-from-stream curr-token-data
    105     var val/ecx: int <- copy _val
    106     var val-float/xmm0: float <- convert val
    107     allocate-number _out
    108     var out/eax: (addr handle cell) <- copy _out
    109     var out-addr/eax: (addr cell) <- lookup *out
    110     var dest/edi: (addr float) <- get out-addr, number-data
    111     copy-to *dest, val-float
    112     {
    113       var stream-storage: (stream byte 0x40)
    114       var stream/ecx: (addr stream byte) <- address stream-storage
    115       write stream, "=> number "
    116       print-number out-addr, stream, 0/no-trace
    117       trace trace, "read", stream
    118     }
    119     return
    120   }
    121   # default: symbol
    122   # just copy token data
    123   allocate-symbol _out
    124   var out/eax: (addr handle cell) <- copy _out
    125   var out-addr/eax: (addr cell) <- lookup *out
    126   var curr-token-data-ah/ecx: (addr handle stream byte) <- get curr-token, text-data
    127   var dest-ah/edx: (addr handle stream byte) <- get out-addr, text-data
    128   copy-object curr-token-data-ah, dest-ah
    129   {
    130     var stream-storage: (stream byte 0x40)
    131     var stream/ecx: (addr stream byte) <- address stream-storage
    132     write stream, "=> symbol "
    133     print-symbol out-addr, stream, 0/no-trace
    134     trace trace, "read", stream
    135   }
    136 }