https://github.com/akkartik/mu/blob/master/apps/arith.mu
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 fn main -> exit-status/ebx: int {
36 var look/esi: byte <- copy 0
37 var n/eax: int <- copy 0
38 print-string 0, "press ctrl-c or ctrl-d to exit\n"
39
40 {
41
42 print-string 0, "> "
43
44 n, look <- simplify
45
46 compare look, 0
47 break-if-=
48
49 print-int32-hex 0, n
50 print-string 0, "\n"
51
52 loop
53 }
54 exit-status <- copy 0
55 }
56
57 fn simplify -> result/eax: int, look/esi: byte {
58
59 look <- get-char
60
61 result, look <- expression look
62 }
63
64 fn expression _look: byte -> result/eax: int, look/esi: byte {
65 look <- copy _look
66
67 result, look <- term look
68 $expression:loop: {
69
70 look <- skip-spaces look
71 {
72 var continue?/eax: boolean <- is-add-or-sub? look
73 compare continue?, 0
74 break-if-= $expression:loop
75 }
76
77 var op/ecx: byte <- copy 0
78 op, look <- operator look
79
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
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 loop
103 }
104 look <- skip-spaces look
105 }
106
107 fn term _look: byte -> result/eax: int, look/esi: byte {
108 look <- copy _look
109
110 look <- skip-spaces look
111 result, look <- factor look
112 $term:loop: {
113
114 look <- skip-spaces look
115 {
116 var continue?/eax: boolean <- is-mul-or-div? look
117 compare continue?, 0
118 break-if-= $term:loop
119 }
120
121 var op/ecx: byte <- copy 0
122 op, look <- operator look
123
124 var second/edx: int <- copy 0
125 look <- skip-spaces look
126 {
127 var tmp/eax: int <- copy 0
128 tmp, look <- factor look
129 second <- copy tmp
130 }
131
132 $term:perform-op: {
133 {
134 compare op, 0x2a
135 break-if-!=
136 result <- multiply second
137 break $term:perform-op
138 }
139
140
141
142
143
144
145 }
146 loop
147 }
148 }
149
150 fn factor _look: byte -> result/eax: int, look/esi: byte {
151 $factor:body: {
152 look <- copy _look
153 look <- skip-spaces look
154
155 compare look, 0x28
156 {
157 break-if-=
158 result, look <- num look
159 break $factor:body
160 }
161
162 look <- get-char
163 result, look <- expression look
164 look <- skip-spaces look
165 look <- get-char
166 }
167 }
168
169 fn is-mul-or-div? c: byte -> result/eax: boolean {
170 $is-mul-or-div?:body: {
171 compare c, 0x2a
172 {
173 break-if-!=
174 result <- copy 1
175 break $is-mul-or-div?:body
176 }
177 compare c, 0x2f
178 {
179 break-if-!=
180 result <- copy 1
181 break $is-mul-or-div?:body
182 }
183 result <- copy 0
184 }
185 }
186
187 fn is-add-or-sub? c: byte -> result/eax: boolean {
188 $is-add-or-sub?:body: {
189 compare c, 0x2b
190 {
191 break-if-!=
192 result <- copy 1
193 break $is-add-or-sub?:body
194 }
195 compare c, 0x2d
196 {
197 break-if-!=
198 result <- copy 1
199 break $is-add-or-sub?:body
200 }
201 result <- copy 0
202 }
203 }
204
205 fn operator _look: byte -> op/ecx: byte, look/esi: byte {
206 op <- copy _look
207 look <- get-char
208 }
209
210 fn num _look: byte -> result/eax: int, look/esi: byte {
211 look <- copy _look
212 var out/edi: int <- copy 0
213 {
214 var first-digit/eax: int <- to-decimal-digit look
215 out <- copy first-digit
216 }
217 {
218 look <- get-char
219
220 var digit?/eax: boolean <- is-decimal-digit? look
221 compare digit?, 0
222 break-if-=
223
224 {
225 var ten/eax: int <- copy 0xa
226 out <- multiply ten
227 }
228
229 var digit/eax: int <- to-decimal-digit look
230 out <- add digit
231 loop
232 }
233 result <- copy out
234 }
235
236 fn skip-spaces _look: byte -> look/esi: byte {
237 look <- copy _look
238 {
239 compare look, 0x20
240 break-if-!=
241 look <- get-char
242 loop
243 }
244 }
245
246 fn get-char -> look/esi: byte {
247 var tmp/eax: byte <- read-key
248 look <- copy tmp
249 compare look, 0
250 {
251 break-if-!=
252 print-string 0, "^D\n"
253 syscall_exit
254 }
255 }