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