-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.S
342 lines (286 loc) · 5.54 KB
/
main.S
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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
.section .rodata
# Original task:
# if x >= 16
# then: (x - 11)^2 + 125
# else: x^2 + 72*x + 6400
cond_prompt: .string "if x "
then_prompt: .string "then: "
else_prompt: .string "else: "
prompt: .string "x = "
result_sep: .string " = "
err_read: .string "Could not read the input!\n"
err_nan: .string "You should enter an integer!\n"
err_unex: .string "Unexpected symbol: "
err_unex_len = . - err_unex - 1
err_parens: .string "Parentheses don't match!\n"
cmd_quit: .string "quit"
.section .data
buf_len = 64 # universal buf len
buf: .fill buf_len
expr_then_buf: .fill buf_len
expr_else_buf: .fill buf_len
.section .bss
.lcomm expr_then, 64 * 16 # token_size = 16
.lcomm expr_else, 64 * 16 # token_size = 16
.section .text
.global _start
_start:
/* parse the condition */
# print the condition prompt
mov $cond_prompt, %rsi
call print
# read the full condition
mov $buf, %rsi
mov $buf_len, %rdx
call readline
jz 1f # success
mov $err_read, %rsi # read error, panic
call panic
1:
/* parse the operator, set %r15 to the corresponding function */
mov $buf, %rsi
call skip_ws
add $2, %rsi
movw -2(%rsi), %ax
cmp $'<', %al # <x
je .ilx
cmp $'=', %al # =x
je .iex
cmp $'>', %al # >x
je .igx
cmp $'!', %al # !x
je .inx
jmp _start
.ilx:
cmp $'=', %ah # <=
je .ile
dec %rsi
.il:
mov $fjl, %r15
jmp .cond_set
.ile:
mov $fjle, %r15
jmp .cond_set
.igx:
cmp $'=', %ah # >=
je .ige
dec %rsi
.ig:
mov $fjg, %r15
jmp .cond_set
.ige:
mov $fjge, %r15
jmp .cond_set
.iex:
cmp $'=', %ah # ==
jne _start
mov $fje, %r15
jmp .cond_set
.inx:
cmp $'=', %ah # !=
jne _start
mov $fjne, %r15
jmp .cond_set
.cond_set:
# %rsi is already set to the next char after the operator
call skip_ws
# parse the operand
mov $10, %rbx
xor %r10, %r10
call stoi64
test %rbx, %rbx # check for stoi64 errors
jz 1f # success
mov $err_nan, %rsi
call print
jmp _start
1:
mov %rax, %r14 # save the condition operand
/*
* Parse expressions
*/
/* parse the "then" expression */
1:
mov $then_prompt, %rsi
mov $expr_then_buf, %r12
mov $buf_len, %rdx
mov $expr_then, %r13
call get_expr
test %rax, %rax
jnz 1b
/* parse the "else" expression */
1:
mov $else_prompt, %rsi
mov $expr_else_buf, %r12
mov $buf_len, %rdx
mov $expr_else, %r13
call get_expr
test %rax, %rax
jnz 1b
/*
* Expressions parsed.
*/
/* read the value */
.read_x:
# print the prompt
mov $prompt, %rsi
call print
mov $buf, %rsi
mov $buf_len, %rdx
call readline
jz 1f # success
mov $err_read, %rsi # read error, panic
call panic
1:
mov $buf, %rsi # convert buf
mov $10, %rbx # base 10
xor %r10, %r10 # error on non-numeric
call stoi64 # to u64
/* handle errors and commands */
test %rbx, %rbx # check for stoi64 errors
jz 1f
cmp $-2, %rbx # NaN, check if it's a command
je .cmd
mov $err_nan, %rsi
call print
jmp _start
.cmd:
movw (buf), %bx # fetch 2 bytes of a string in reversed order
cmp $'q', %bx # "q" - short for quit (\0 in the higher half)
je .exit
mov $buf, %rsi # |
mov $cmd_quit, %rdi # | full "quit" command
call strcmp
test %rsi, %rsi
jz .exit
jmp .read_x
1:
# pass the input into the condition
# (rax contains input after the conversion)
mov %r14, %rbx # the const operand
mov $.meets, %rcx # jmp to .meets
call *%r15 # call the comparison function
jmp .else
/* input meets the condition */
.meets:
pushq $expr_then_buf
mov $expr_then, %rsi
mov %rax, %rdi
call exec_postfix
jmp .done
/* input doesn't meet the condition */
.else:
pushq $expr_else_buf
mov $expr_else, %rsi
mov %rax, %rdi
call exec_postfix
.done:
mov $10, %rbx # base 10
mov $buf, %rdi # into the buf
call i64tos # rax to string
# print the expression
popq %rsi
call print
# print " = "
mov $result_sep, %rsi
call print
# print the result
mov $buf, %rsi
call print
mov $'\n', %rax
call putchar
mov $'\n', %rax
call putchar
jmp .read_x
.exit:
/* sys_exit */
mov $60, %rax
xor %rdi, %rdi
syscall
/*
* panic() - print an error message and exit with an error
*
* Args: %rsi - error message
*
* Never returns
*/
panic:
mov $2, %rdi # stderr
call fprint
/* sys_exit */
mov $60, %rax
mov $-1, %rdi
syscall
/*
* get_expr() - prompt for, read and parse an expression
*
* Args: %rsi - prompt
* %r12 - buf
* %rdx - buf size
* %r13 - parsed expr destination
*
* Returns: %rax - error code
*/
get_expr:
# print the prompt
push %rdx
call print # prompt is in %rsi
pop %rdx
# read the expression
mov %r12, %rsi
call readline # buf size is in %rdx
jz 1f # success
mov $err_read, %rsi # read error, panic
call panic
1:
# tokenize the expression
mov %r12, %rsi # string
mov %r13, %rdi # dest
push %r12
call tokenize
pop %r12
test %rax, %rax # check for tokenize errors
jz 1f # jump on success
cmp $-2, %rax # | parentheses?
je .parens_err # |
mov %rsi, %r9 # unexpected symbol pointer
sub %r12, %r9 # unexpected symbol index
mov %r12, %rbx
call print_unex
mov $-1, %rax
ret
.parens_err:
mov $err_parens, %rsi
call print
mov $-1, %rax
ret
1:
# transform to a postfix form
mov %r13, %rsi
call transform_postfix
xor %rax, %rax
ret
/*
* print_unex() - print an 'unexpected symbol' error message
* with a pointer to the said symbol
*
* Args: %r9 - symbol index
* %rbx - expression string
*/
print_unex:
mov $err_unex, %rsi
call print
mov %rbx, %rsi
call print
mov $'\n', %rax
call putchar
add $err_unex_len, %r9
1:
mov $' ', %rax
call putchar
dec %r9
jnz 1b
mov $'^', %rax
call putchar
mov $'\n', %rax
call putchar
ret