-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcompiler.asm
More file actions
467 lines (392 loc) · 7.38 KB
/
compiler.asm
File metadata and controls
467 lines (392 loc) · 7.38 KB
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
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
section .data
input_buffer db 256 dup(0)
output_buffer db 2048 dup(0)
token_buffer db 64 dup(0)
err_syntax db "Syntax error", 10, 0
err_div_zero db "Division by zero", 10, 0
err_invalid_char db "Invalid character", 10, 0
asm_header db "section .data", 10
db "section .text", 10
db "global _start", 10
db "_start:", 10, 0
asm_footer db " mov eax, 60", 10
db " mov edi, 0", 10
db " syscall", 10, 0
mov_rax db " mov rax, ", 0
add_rax db " add rax, ", 0
sub_rax db " sub rax, ", 0
mul_rax db " imul rax, ", 0
div_setup db " mov rdx, 0", 10, " mov rbx, ", 0
div_rax db " idiv rbx", 10, 0
newline db 10, 0
reg_counter dq 0
section .bss
input_ptr resq 1
output_ptr resq 1
current_token resq 1
token_type resq 1
token_value resq 1
section .text
global _start
%define TOKEN_NUMBER 1
%define TOKEN_PLUS 2
%define TOKEN_MINUS 3
%define TOKEN_MUL 4
%define TOKEN_DIV 5
%define TOKEN_LPAREN 6
%define TOKEN_RPAREN 7
%define TOKEN_EOF 8
_start:
call read_input
mov rax, input_buffer
mov [input_ptr], rax
mov rax, output_buffer
mov [output_ptr], rax
call write_header
call get_next_token
call parse_expression
call write_footer
call write_output
mov eax, 60
mov edi, 0
syscall
read_input:
mov eax, 0
mov edi, 0
mov rsi, input_buffer
mov rdx, 255
syscall
mov byte [input_buffer + rax], 0
ret
write_output:
mov rsi, output_buffer
call strlen
mov rdx, rax
mov eax, 1 ; sys_write
mov edi, 1 ; stdout
mov rsi, output_buffer
syscall
ret
strlen:
mov rax, 0
.loop:
cmp byte [rsi + rax], 0
je .done
inc rax
jmp .loop
.done:
ret
skip_whitespace:
mov rsi, [input_ptr]
.loop:
mov al, [rsi]
cmp al, ' '
je .skip
cmp al, '\t'
je .skip
cmp al, '\n'
je .skip
cmp al, '\r'
je .skip
jmp .done
.skip:
inc rsi
jmp .loop
.done:
mov [input_ptr], rsi
ret
is_digit:
cmp al, '0'
jl .no
cmp al, '9'
jg .no
mov rax, 1
ret
.no:
mov rax, 0
ret
parse_number:
mov rax, 0 ; result
mov rsi, [input_ptr]
.loop:
mov bl, [rsi]
mov al, bl
call is_digit
test rax, rax
jz .done
mov rax, [token_value]
mov rcx, 10
mul rcx
movzx rdx, bl
sub rdx, '0'
add rax, rdx
mov [token_value], rax
inc rsi
jmp .loop
.done:
mov [input_ptr], rsi
ret
get_next_token:
call skip_whitespace
mov rsi, [input_ptr]
mov al, [rsi]
test al, al
jz .eof
call is_digit
test rax, rax
jnz .number
cmp al, '+'
je .plus
cmp al, '-'
je .minus
cmp al, '*'
je .mul
cmp al, '/'
je .div
cmp al, '('
je .lparen
cmp al, ')'
je .rparen
call error_invalid_char
.eof:
mov qword [token_type], TOKEN_EOF
ret
.number:
mov qword [token_type], TOKEN_NUMBER
mov qword [token_value], 0
call parse_number
ret
.plus:
mov qword [token_type], TOKEN_PLUS
inc rsi
mov [input_ptr], rsi
ret
.minus:
mov qword [token_type], TOKEN_MINUS
inc rsi
mov [input_ptr], rsi
ret
.mul:
mov qword [token_type], TOKEN_MUL
inc rsi
mov [input_ptr], rsi
ret
.div:
mov qword [token_type], TOKEN_DIV
inc rsi
mov [input_ptr], rsi
ret
.lparen:
mov qword [token_type], TOKEN_LPAREN
inc rsi
mov [input_ptr], rsi
ret
.rparen:
mov qword [token_type], TOKEN_RPAREN
inc rsi
mov [input_ptr], rsi
ret
parse_expression:
call parse_term
.loop:
mov rax, [token_type]
cmp rax, TOKEN_PLUS
je .add
cmp rax, TOKEN_MINUS
je .sub
ret
.add:
call get_next_token
call parse_term
call emit_add
jmp .loop
.sub:
call get_next_token
call parse_term
call emit_sub
jmp .loop
parse_term:
call parse_factor
.loop:
mov rax, [token_type]
cmp rax, TOKEN_MUL
je .mul
cmp rax, TOKEN_DIV
je .div
ret
.mul:
call get_next_token
call parse_factor
call emit_mul
jmp .loop
.div:
call get_next_token
call parse_factor
call emit_div
jmp .loop
parse_factor:
mov rax, [token_type]
cmp rax, TOKEN_NUMBER
je .number
cmp rax, TOKEN_LPAREN
je .paren
call error_syntax
.number:
mov rax, [token_value]
call emit_load_immediate
call get_next_token
ret
.paren:
call get_next_token
call parse_expression
mov rax, [token_type]
cmp rax, TOKEN_RPAREN
jne .syntax_error
call get_next_token
ret
.syntax_error:
call error_syntax
emit_load_immediate:
call append_string_mov_rax
call append_number
call append_newline
ret
emit_add:
call append_string_add
call append_newline
ret
emit_sub:
call append_string_sub
call append_newline
ret
emit_mul:
call append_string_mul
call append_newline
ret
emit_div:
call append_string_div_setup
call append_string_div
ret
append_string_mov_rax:
mov rsi, mov_rax
call append_string
ret
append_string_add:
mov rsi, add_rax
call append_string
mov rsi, token_buffer
call append_string
ret
append_string_sub:
mov rsi, sub_rax
call append_string
mov rsi, token_buffer
call append_string
ret
append_string_mul:
mov rsi, mul_rax
call append_string
mov rsi, token_buffer
call append_string
ret
append_string_div_setup:
mov rsi, div_setup
call append_string
mov rsi, token_buffer
call append_string
call append_newline
ret
append_string_div:
mov rsi, div_rax
call append_string
ret
append_string:
mov rdi, [output_ptr]
.loop:
mov al, [rsi]
test al, al
jz .done
mov [rdi], al
inc rsi
inc rdi
jmp .loop
.done:
mov [output_ptr], rdi
ret
append_number:
mov rax, [token_value]
call number_to_string
ret
append_newline:
mov rsi, newline
call append_string
ret
number_to_string:
mov rbx, 10
mov rcx, 0 ; digit count
mov rdx, [output_ptr]
test rax, rax
jnz .convert
mov byte [rdx], '0'
inc rdx
mov [output_ptr], rdx
ret
.convert:
push rdx
.digit_loop:
test rax, rax
jz .reverse
mov rdx, 0
div rbx
add rdx, '0'
push rdx
inc rcx
jmp .digit_loop
.reverse:
pop rdx
.write_loop:
test rcx, rcx
jz .done
pop rax
mov [rdx], al
inc rdx
dec rcx
jmp .write_loop
.done:
mov [output_ptr], rdx
ret
write_header:
mov rsi, asm_header
call append_string
ret
write_footer:
mov rsi, asm_footer
call append_string
ret
error_syntax:
mov eax, 1
mov edi, 2 ; stderr
mov rsi, err_syntax
mov rdx, 13
syscall
mov eax, 60
mov edi, 1
syscall
error_invalid_char:
mov eax, 1
mov edi, 2
mov rsi, err_invalid_char
mov rdx, 17
syscall
mov eax, 60
mov edi, 1
syscall
error_div_zero:
mov eax, 1
mov edi, 2
mov rsi, err_div_zero
mov rdx, 15
syscall
mov eax, 60
mov edi, 1
syscall