forked from kinderjosh/mint
-
Notifications
You must be signed in to change notification settings - Fork 0
/
mint.asm
715 lines (661 loc) · 12.4 KB
/
mint.asm
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
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
section .text
global _start
_start:
pop rdi
cmp rdi, 2
jl .missing_arg
pop rdi
pop rdi
mov rax, rdi
mov rsi, help_str
mov rcx, help_str_len
repe cmpsb
mov rdi, rax
je .show_help
mov rcx, -1
.loop:
inc rcx
mov al, byte [rdi+rcx]
mov byte [filename+rcx], al
test al, al
jnz .loop
inc rcx
mov dword [filename_len], ecx
call read_file
call mint_start
xor rdi, rdi
call exit
.missing_arg:
mov rax, 1
mov rdi, 1
mov rsi, missing_arg_msg
mov rdx, missing_arg_msg_len
syscall
mov rdi, 1
call exit
.show_help:
mov rax, 1
mov rdi, 1
mov rsi, help_msg
mov rdx, help_msg_len
syscall
mov rdi, 1
call exit
; in:
; - rdi: exit code
exit:
mov rax, 60
xor rdi, rdi
syscall
; in:
; - al: character
; out:
; - rdi: 0 = true, 1 = false
isspace:
cmp al, ' '
je .true
cmp al, 10 ; \n
je .true
cmp al, 9 ; \t
je .true
cmp al, 13 ; \r
je .true
mov rdi, 1
ret
.true:
xor rdi, rdi
ret
; in:
; - al: character
; out:
; - rdi: 0 = true, 1 = false
isalpha:
cmp al, 'A'
jl .false
cmp al, 'z'
jg .false
xor rdi, rdi
ret
.false:
mov rdi, 1
ret
; in:
; - al: character
; out:
; - rdi: 0 = true, 1 = false
isdigit:
cmp al, '0'
jl .false
cmp al, '9'
jg .false
xor rdi, rdi
ret
.false:
mov rdi, 1
ret
read_file:
mov rax, 2
mov rdi, filename
xor rsi, rsi
syscall
cmp rax, 0
jl .open_fail
push rax
mov rdi, rax
xor rax, rax
mov rsi, src
mov rdx, SRC_CAP-1
syscall
cmp rax, 0
jl .read_fail
mov byte [src+SRC_CAP-1], 0
mov rax, 3
pop rdi
syscall
cmp rax, 0
jl .close_fail
ret
.open_fail:
mov rax, 1
mov rdi, 1
mov rsi, open_fail_msg
mov rdx, open_fail_msg_len
syscall
mov rdi, 1
call exit
.read_fail:
mov rax, 1
mov rdi, 1
mov rsi, read_fail_msg
mov rdx, read_fail_msg_len
syscall
mov rdi, 1
call exit
.close_fail:
mov rax, 1
mov rdi, 1
mov rsi, close_fail_msg
mov rdx, close_fail_msg_len
syscall
mov rdi, 1
call exit
; in:
; - rdi: string length
clear_buf:
push rcx
mov rcx, -1
.loop:
inc rcx
mov byte [buf+rcx], 0
cmp rcx, rdi
jle .loop
cmp rcx, BUF_CAP-1
jge .loop
pop rcx
ret
; in:
; - rdi: string pointer
; out:
; - rax: converted number
atoi:
push rcx
push rbx
xor rcx, rcx
xor rbx, rbx
.loop:
mov al, byte [rdi+rcx]
test al, al
jz .done
sub rax, '0'
imul rbx, 10
add rbx, rax
inc rcx
jmp .loop
.done:
mov rax, rbx
pop rbx
pop rcx
ret
; in:
; - rdi: number to convert
; out:
; - buf: converted string
; - rcx: string length
itoa:
test rdi, rdi
jnz .not_zero
mov byte [buf], '0'
mov byte [buf+1], 0
ret
.not_zero:
push rax
push rbx
push rdx
push rsi
push r8
push r9
mov rbx, 10
xor rcx, rcx
xor r8, r8
cmp rdi, 0
jge .loop
mov r8, 1
neg rdi
.loop:
cmp rdi, 0
je .loop_done
mov rax, rdi
xor rdx, rdx
idiv rbx
cmp rdx, 9
jg .above_nine
add rdx, '0'
jmp .add_done
.above_nine:
add rdx, 87 ; (remainder - 10) + 'a'
.add_done:
mov byte [buf+rcx], dl
inc rcx
mov rax, rdi
cqo
idiv rbx
mov rdi, rax
jmp .loop
.loop_done:
test r8, r8
jz .positive
mov byte [buf+rcx], '-'
inc rcx
.positive:
mov byte [buf+rcx], 0
xor rbx, rbx
mov rdx, rcx
dec rdx
.reverse_loop:
cmp rbx, rdx
jge .done
mov sil, byte [buf+rbx]
mov r9b, byte [buf+rdx]
mov byte [buf+rbx], r9b
mov byte [buf+rdx], sil
dec rdx
inc rbx
.done:
pop r9
pop r8
pop rsi
pop rdx
pop rbx
pop rax
ret
; in:
; - al: var name
; out:
; - rdi: pointer to var
get_var_ptr:
push rcx
mov rcx, -1
.loop:
inc rcx
cmp rcx, VAR_CAP-1
jge .not_found
cmp al, byte [var_names+rcx]
jne .loop
lea rdi, [var_values+rcx*8]
pop rcx
ret
.not_found:
push rax
mov rax, 1
mov rdi, 1
mov rsi, var_not_found_msg
mov rdx, var_not_found_msg_len
syscall
pop rax
mov byte [rsp], al
mov rax, 1
mov rdi, 1
lea rsi, [rsp]
mov rdx, 1
syscall
mov qword [rsp], 10
mov rax, 1
mov rdi, 1
lea rsi, [rsp]
mov rdx, 1
syscall
add rsp, 8
mov rdi, 1
call exit
mint_start:
xor rcx, rcx
.loop:
xor rax, rax
mov al, byte [src+rcx]
test al, al
jz .done
call isspace
test rdi, rdi
jz .next
xor r8, r8
mov r9, TOK_ID
call isalpha
test rdi, rdi
jz .parse
mov r9, TOK_DIGIT
call isdigit
test rdi, rdi
jz .parse
cmp al, '+'
je .add_ops
cmp al, '-'
je .sub_ops
cmp al, '*'
je .mul_ops
cmp al, '/'
je .div_ops
cmp al, '%'
je .mod_ops
push rax
mov rax, 1
mov rdi, 1
mov rsi, unknown_ch_msg
mov rdx, unknown_ch_msg_len
syscall
mov rax, 1
mov rdi, 1
lea rsi, [rsp]
mov rdx, 1
syscall
mov byte [rsp], 10
mov rax, 1
mov rdi, 1
lea rsi, [rsp]
mov rdx, 1
syscall
add rsp, 8
mov rdi, 1
call exit
.parse:
mov al, byte [src+rcx]
test al, al
jz .parse_done
call isspace
test rdi, rdi
jz .parse_done
mov byte [buf+r8], al
inc rcx
inc r8
jmp .parse
.parse_done:
mov dword [buf_len], r8d
cmp r9, TOK_DIGIT
je .do_digit
cmp r8, 1
je .do_var
push rsi
push rcx
mov rsi, buf
mov rdi, dup_str
mov rcx, 3
repe cmpsb
je .do_dup
mov rsi, buf
mov rdi, drop_str
mov rcx, 4
repe cmpsb
je .do_drop
mov rsi, buf
mov rdi, out_str
mov rcx, 3
repe cmpsb
je .do_out
mov rsi, buf
mov rdi, over_str
mov rcx, 4
repe cmpsb
je .do_over
mov rsi, buf
mov rdi, swap_str
mov rcx, 4
repe cmpsb
je .do_swap
mov rsi, buf
mov rdi, store_str
mov rcx, 4
repe cmpsb
je .do_store
mov rsi, buf
mov rdi, load_str
mov rcx, 4
repe cmpsb
je .do_load
mov rax, 1
mov rdi, 1
mov rsi, unknown_id_msg
mov rdx, unknown_id_msg_len
syscall
mov rax, 1
mov rdi, 1
mov rsi, buf
mov rdx, r8
syscall
mov byte [rsp], 10
mov rax, 1
mov rdi, 1
lea rsi, [rsp]
mov rdx, 1
syscall
add rsp, 8
mov rdi, 1
call exit
.do_dup:
cmp dword [stack_ptr], STACK_CAP
jge .stack_overflow
mov esi, dword [stack_ptr]
dec esi
mov rdi, qword [stack+rsi*8]
mov esi, dword [stack_ptr]
mov qword [stack+rsi*8], rdi
add dword [stack_ptr], 1
jmp .id_done
.do_drop:
cmp dword [stack_ptr], 0
jle .stack_underflow
sub dword [stack_ptr], 1
jmp .id_done
.do_out:
cmp dword [stack_ptr], 0
jle .stack_underflow
mov esi, dword [stack_ptr]
dec rsi
mov rdi, qword [stack+rsi*8]
call itoa
mov rax, 1
mov rdi, 1
mov rsi, buf
mov rdx, rcx
syscall
push 10
mov rax, 1
mov rdi, 1
lea rsi, [rsp]
mov rdx, 1
syscall
add rsp, 8
sub dword [stack_ptr], 1
jmp .id_done
.do_over:
cmp dword [stack_ptr], 1
jle .stack_underflow
cmp dword [stack_ptr], STACK_CAP
jge .stack_overflow
mov esi, dword [stack_ptr]
sub esi, 2
mov rdi, qword [stack+rsi*8]
mov esi, dword [stack_ptr]
mov qword [stack+rsi*8], rdi
add dword [stack_ptr], 1
jmp .id_done
.do_swap:
cmp dword [stack_ptr], 1
jle .stack_underflow
mov esi, dword [stack_ptr]
dec esi
mov rdi, qword [stack+rsi*8]
dec esi
mov rdx, qword [stack+rsi*8]
inc esi
mov qword [stack+rsi*8], rdx
dec esi
mov qword [stack+rsi*8], rdi
jmp .id_done
.do_store:
cmp dword [stack_ptr], 1
jle .stack_underflow
mov esi, dword [stack_ptr]
dec esi
mov rdi, qword [stack+rsi*8]
dec esi
mov rdx, qword [stack+rsi*8]
mov qword [rdi], rdx
sub dword [stack_ptr], 2
jmp .id_done
.do_load:
cmp dword [stack_ptr], 1
jl .stack_underflow
mov esi, dword [stack_ptr]
dec esi
mov rdi, qword [stack+rsi*8]
mov rdx, qword [rdi]
mov qword [stack+rsi*8], rdx
.id_done:
pop rcx
pop rsi
jmp .next
.do_digit:
cmp dword [stack_ptr], STACK_CAP
jge .stack_overflow
mov rdi, buf
call atoi
mov edi, dword [stack_ptr]
mov qword [stack+rdi*8], rax
add dword [stack_ptr], 1
jmp .next
.do_var:
cmp dword [stack_ptr], STACK_CAP
jge .stack_overflow
mov al, byte [buf]
call get_var_ptr
mov rax, rdi
mov edi, dword [stack_ptr]
mov qword [stack+rdi*8], rax
add dword [stack_ptr], 1
jmp .next
.add_ops:
cmp dword [stack_ptr], 1
jle .stack_underflow
cmp dword [stack_ptr], STACK_CAP
jge .stack_overflow
mov esi, dword [stack_ptr]
dec esi
mov rdx, qword [stack+rsi*8]
dec esi
mov rdi, qword [stack+rsi*8]
add rdi, rdx
mov esi, dword [stack_ptr]
mov qword [stack+rsi*8], rdi
add dword [stack_ptr], 1
jmp .next
.sub_ops:
cmp dword [stack_ptr], 1
jle .stack_underflow
cmp dword [stack_ptr], STACK_CAP
jge .stack_overflow
mov esi, dword [stack_ptr]
dec esi
mov rdx, qword [stack+rsi*8]
dec esi
mov rdi, qword [stack+rsi*8]
sub rdi, rdx
mov esi, dword [stack_ptr]
mov qword [stack+rsi*8], rdi
add dword [stack_ptr], 1
jmp .next
.mul_ops:
cmp dword [stack_ptr], 1
jle .stack_underflow
cmp dword [stack_ptr], STACK_CAP
jge .stack_overflow
mov esi, dword [stack_ptr]
dec esi
mov rdx, qword [stack+rsi*8]
dec esi
mov rdi, qword [stack+rsi*8]
imul rdi, rdx
mov esi, dword [stack_ptr]
mov qword [stack+rsi*8], rdi
add dword [stack_ptr], 1
jmp .next
.div_ops:
cmp dword [stack_ptr], 1
jle .stack_underflow
cmp dword [stack_ptr], STACK_CAP
jge .stack_overflow
mov esi, dword [stack_ptr]
dec esi
mov rbx, qword [stack+rsi*8]
dec esi
mov rax, qword [stack+rsi*8]
cqo
idiv rbx
mov esi, dword [stack_ptr]
mov qword [stack+rsi*8], rax
add dword [stack_ptr], 1
jmp .next
.mod_ops:
cmp dword [stack_ptr], 1
jle .stack_underflow
cmp dword [stack_ptr], STACK_CAP
jge .stack_overflow
mov esi, dword [stack_ptr]
dec esi
mov rbx, qword [stack+rsi*8]
dec esi
mov rax, qword [stack+rsi*8]
xor rdx, rdx
idiv rbx
mov esi, dword [stack_ptr]
mov qword [stack+rsi*8], rdx
add dword [stack_ptr], 1
jmp .next
.next:
mov rdi, r8
call clear_buf
inc rcx
jmp .loop
.stack_underflow:
mov rax, 1
mov rdi, 1
mov rsi, stack_underflow_msg
mov rdx, stack_underflow_msg_len
syscall
mov rdi, 1
call exit
.stack_overflow:
mov rax, 1
mov rdi, 1
mov rsi, stack_overflow_msg
mov rdx, stack_overflow_msg_len
syscall
mov rdi, 1
call exit
.done:
ret
section .data
missing_arg_msg: db "error: missing argument <input file>",10,0
missing_arg_msg_len equ $-missing_arg_msg
help_str: db "--help"
help_str_len equ $-help_str
help_msg: db "usage: mint <input file>",10,0
help_msg_len equ $-help_msg
open_fail_msg: db "error: failed to open file",10,0
open_fail_msg_len equ $-open_fail_msg
read_fail_msg: db "error: failed to read file",10,0
read_fail_msg_len equ $-read_fail_msg
close_fail_msg: db "error: failed to close file",10,0
close_fail_msg_len equ $-close_fail_msg
unknown_ch_msg: db "error: unknown character: ",0
unknown_ch_msg_len equ $-unknown_ch_msg
unknown_id_msg: db "error: unknown identifier: ",0
unknown_id_msg_len equ $-unknown_id_msg
stack_underflow_msg: db "error: stack underflow",10,0
stack_underflow_msg_len equ $-stack_underflow_msg
stack_overflow_msg: db "error: stack overflow",10,0
stack_overflow_msg_len equ $-stack_overflow_msg
var_not_found_msg: db "error: variable not found: ",0
var_not_found_msg_len equ $-var_not_found_msg
dup_str: db "dup"
drop_str: db "drop"
out_str: db "out"
over_str: db "over"
swap_str: db "swap"
store_str: db "store"
load_str: db "load"
STACK_CAP equ 64
stack: times STACK_CAP dq 0
stack_ptr: dd 0
VAR_CAP equ 11
var_names: db 'a','b','c','d','e','f','g','h','i','j','k'
var_values: times VAR_CAP dq 0
var_cnt: dd 0
SRC_CAP equ 1024
BUF_CAP equ 64
TOK_ID equ 1
TOK_DIGIT equ 2
section .bss
filename: resb 64
filename_len: resd 1
src: resb SRC_CAP
buf: resb BUF_CAP
buf_len: resd 1