https://github.com/akkartik/mu/blob/master/apps/arith.mu
  1 # Integer arithmetic using conventional precedence.
  2 #
  3 # Follows part 2 of Jack Crenshaw's "Let's build a compiler!"
  4 #   https://compilers.iecc.com/crenshaw
  5 #
  6 # Limitations:
  7 #   Reads numbers in decimal, but prints numbers in hex :(
  8 #   No division yet.
  9 #
 10 # To build:
 11 #   $ ./translate_mu apps/arith.mu
 12 #
 13 # Example session:
 14 #   $ ./a.elf
 15 #   press ctrl-c or ctrl-d to exit
 16 #   > 1
 17 #   0x00000001
 18 #   > 1+1
 19 #   0x00000002
 20 #   > 1 + 1
 21 #   0x00000002
 22 #   > 1+2 +3
 23 #   0x00000006
 24 #   > 1+2 *3
 25 #   0x00000007
 26 #   > (1+2) *3
 27 #   0x00000009
 28 #   > 1 + 3*4
 29 #   0x0000000d
 30 #   > ^D
 31 #   $
 32 #
 33 # Error handling is non-existent. This is just a prototype.
 34 
 35 fn main -> exit-status/ebx: int {
 36   var look/esi: byte <- copy 0  # lookahead
 37   var n/eax: int <- copy 0  # result of each expression
 38   print-string-to-screen "press ctrl-c or ctrl-d to exit\n"
 39   # read-eval-print loop
 40   {
 41     # print prompt
 42     print-string-to-screen "> "
 43     # read and eval
 44     n, look <- simplify  # we explicitly thread 'look' everywhere
 45     # if (look == 0) break
 46     compare look, 0
 47     break-if-=
 48     # print
 49     print-int32-hex-to-screen n
 50     print-string-to-screen "\n"
 51     #
 52     loop
 53   }
 54   exit-status <- copy 0
 55 }
 56 
 57 fn simplify -> result/eax: int, look/esi: byte {
 58   # prime the pump
 59   look <- get-char
 60   # do it
 61   result, look <- expression look
 62 }
 63 
 64 fn expression _look: byte -> result/eax: int, look/esi: byte {
 65   look <- copy _look  # should be a no-op
 66   # read arg
 67   result, look <- term look
 68   $expression:loop: {
 69     # while next non-space char in ['+', '-']
 70     look <- skip-spaces look
 71     {
 72       var continue?/eax: boolean <- is-add-or-sub? look
 73       compare continue?, 0  # false
 74       break-if-= $expression:loop
 75     }
 76     # read operator
 77     var op/ecx: byte <- copy 0
 78     op, look <- operator look
 79     # read next arg
 80     var second/edx: int <- copy 0
 81     look <- skip-spaces look
 82     {
 83       var tmp/eax: int <- copy 0
 84       tmp, look <- term look
 85       second <- copy tmp
 86     }
 87     # reduce
 88     $expression:perform-op: {
 89       {
 90         compare op, 0x2b  # '+'
 91         break-if-!=
 92         result <- add second
 93         break $expression:perform-op
 94       }
 95       {
 96         compare op, 0x2d  # '-'
 97         break-if-!=
 98         result <- subtract second
 99         break $expression:perform-op
100       }
101     }
102     
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>Mu - edit/009-sandbox-test.mu</title>
<meta name="Generator" content="Vim/8.0">
<meta name="plugin-version" content="vim7.4_v2">
<meta name="syntax" content="none">
<meta name="settings" content="number_lines,use_css,pre_wrap,no_foldcolumn,expand_tabs,line_ids,prevent_copy=">
<meta name="colorscheme" content="minimal-light">
<style type="text/css">
<!--
pre { white-space: pre-wrap; font-family: monospace; color: #000000; background-color: #c6c6c6; }
body { font-size:12pt; font-family: monospace; color: #000000; background-color: #c6c6c6; }
a { color:inherit; }
* { font-size:12pt; font-size: 1em; }
.muControl { color: #804000; }
.muRecipe { color: #ff8700; }
.muScenario { color: #00af00; }
.LineNr { }
.muData { color: #ffff00; }
.Delimiter { color: #c000c0; }
.Constant { color: #008787; }
.Special { color: #ff6060; }
.Comment { color: #005faf; }
.SalientComment { color: #0000af; }
-->
</style>

<script type='text/javascript'>
<!--

/* function to open any folds containing a jumped-to line before jumping to it */
function JumpToLine()
{
  var lineNum;
  lineNum = window.location.hash;
  lineNum = lineNum.substr(1); /* strip off '#' */

  if (lineNum.indexOf('L') == -1) {
    lineNum = 'L'+lineNum;
  }
  lineElem = document.getElementById(lineNum);
  /* Always jump to new location even if the line was hidden inside a fold, or
   * we corrected the raw number to a line ID.
   */
  if (lineElem) {
    lineElem.scrollIntoView(true);
  }
  return true;
}
if ('onhashchange' in window) {
  window.onhashchange = JumpToLine;
}

-->
</script>
</head>
<body onload='JumpToLine();'>
<a href='https://github.com/akkartik/mu/blob/master/edit/009-sandbox-test.mu'>https://github.com/akkartik/mu/blob/master/edit/009-sandbox-test.mu</a>
<pre id='vimCodeElement'>
<span id="L1" class="LineNr">  1