about summary refs log tree commit diff stats
path: root/apps/arith.mu
blob: 54ceffd0aecb6d2e017498ed4d6fb29453f9c867 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
fn main -> exit-status/ebx: int {
  var look/esi: byte <- copy 0  # lookahead
  var n/eax: int <- copy 0  # result of each expression
  # read-eval-print loop
  {
    # print prompt
    print-string "> "
    # read and eval
    n, look <- simplify
    # if (look == 0) break
    compare look, 0
    break-if-=
    # print
    print-int32-to-screen n
    print-string "\n"
    #
    loop
  }
  exit-status <- copy 0
}

fn simplify -> result/eax: int, look/esi: byte {
  look <- get-char  # prime the pump
  # first arg
  look <- skip-spaces look
  result, look <- num look
  # operator
  var op/ecx: byte <- copy 0
  look <- skip-spaces look
  op, look <- operator look
  # second arg
  var second/edx: int <- copy 0
  look <- skip-spaces look
  {
    var tmp/eax: int <- copy 0
    tmp, look <- num look
    second <- copy tmp
  }
  # perform op
  $simplify:perform-op: {
    {
      compare op, 0x2b  # '+'
      break-if-!=
      result <- add second
      break $simplify:perform-op
    }
    {
      compare op, 0x2d  # '-'
      break-if-!=
      result <- subtract second
      break $simplify:perform-op
    }
  }
  # trailing spaces
  look <- skip-spaces look
}

fn operator _look: byte -> op/ecx: byte, look/esi: byte {
  op <- copy _look
  look <- get-char
}

fn num _look: byte -> result/eax: int, look/esi: byte {
  look <- copy _look  # should be a no-op; guaranteed to be a digit
  var out/edi: int <- copy 0
  {
    var first-digit/eax: int <- to-decimal-digit look
    out <- copy first-digit
  }
  {
    look <- get-char
    # done?
    var digit?/eax: bool <- is-decimal-digit? look
    compare digit?, 0  # false
    break-if-=
    # out *= 10
    {
      var ten/eax: int <- copy 0xa
      out <- multiply ten
    }
    # out += digit(look)
    var digit/eax: int <- to-decimal-digit look
    out <- add digit
    loop
  }
  result <- copy out
}

fn skip-spaces _look: byte -> look/esi: byte {
  look <- copy _look  # should be a no-op
  {
    compare look, 0x20
    break-if-!=
    look <- get-char
    loop
  }
}

fn get-char -> look/esi: byte {
  var tmp/eax: byte <- read-key
  look <- copy tmp
  compare look, 0
  {
    break-if-!=
    print-string "^D\n"
    syscall_exit
  }
}