commit
8727e0be0f
@ -0,0 +1,7 @@ |
||||
brainfuck: brainfuck.asm |
||||
nasm -felf64 brainfuck.asm
|
||||
gcc -m64 -o brainfuck brainfuck.o
|
||||
|
||||
clean: |
||||
rm -f brainfuck brainfuck.o
|
||||
|
||||
@ -0,0 +1,168 @@ |
||||
; Interpreter języka Brainfuck (https://en.wikipedia.org/wiki/Brainfuck) |
||||
; Autor: Szymon Karpiński |
||||
|
||||
; Wczytuje program na standardowe wejście. |
||||
; Nie sprawdza poprawności programu, zachowanie dla niepoprawnych programów niezdefiniowane. |
||||
; W ramach wstępnego przetwarzania programu paruje nawiasy kwadratowe, ale poza tym wykonuje |
||||
; program instrukcja po instrukcji, bez wstępnych optymalizacji, na przykład zamiany |
||||
; wielokrotnie powtórzonego '+' na dodawanie itd. |
||||
|
||||
; maksymalny rozmiar taśmy na dane |
||||
%define PROG_SIZE (1<<20) |
||||
|
||||
; maksymalny rozmiar programu |
||||
%define TAPE_SIZE (1<<20) |
||||
|
||||
global main |
||||
|
||||
extern putchar |
||||
extern getchar |
||||
extern gets |
||||
extern exit |
||||
extern fflush |
||||
|
||||
|
||||
section .bss |
||||
bf_program: resb PROG_SIZE |
||||
bf_jumps: resq PROG_SIZE*8 |
||||
bf_tape: resb TAPE_SIZE |
||||
|
||||
|
||||
section .text: |
||||
|
||||
; Podczas interpretacji programu znaczenia rejestrów są następujące: |
||||
; - rsi jest wskaźnikiem programu |
||||
; - rbx jest wskaźnikiem na aktualne pole na taśmie |
||||
|
||||
; Tablica 8-bajtowych kawałków kodu, w której na miejscu 8*i znajduje się kod zakończony |
||||
; instrukcją powrotu, który należy wykonać dla znaku o kodzie ascii równym i. Operacje, |
||||
; których kod nie mieści się w 8 bajtach (etykiety *_stub) wykonują skok do pełnej wersji |
||||
; kodu. |
||||
bf_instructions: |
||||
bf_exit: ; NULL kończy program |
||||
xor rdi, rdi |
||||
call exit |
||||
align 8 |
||||
times 8*('+'-1) ret |
||||
bf_increment: ; '+' ascii 43 |
||||
inc byte [rsi] |
||||
inc rbx |
||||
ret |
||||
align 8 |
||||
bf_in_stub: ; ',' ascii 44 |
||||
jmp bf_in |
||||
align 8 |
||||
bf_decr: ; '-' ascii 45 |
||||
dec byte [rsi] |
||||
inc rbx |
||||
ret |
||||
align 8 |
||||
bf_out_stub: ; '.' ascii 46 |
||||
jmp bf_out |
||||
ret |
||||
align 8 |
||||
times 8*('<'-'.'-1) ret |
||||
bf_left: ; '<' ascii 60 |
||||
dec rsi |
||||
inc rbx |
||||
ret |
||||
align 8 |
||||
times 8*('>'-'<'-1) ret |
||||
bf_right: ; '>' ascii 62 |
||||
inc rsi |
||||
inc rbx |
||||
ret |
||||
align 8 |
||||
times 8*('['-'>'-1) ret |
||||
bf_forward_stub: ; '[' ascii 91 |
||||
jmp bf_forward |
||||
align 8 |
||||
times 8*(']'-'['-1) ret |
||||
bf_backward_stub: ; ']' ascii 93 |
||||
jmp bf_backward |
||||
align 8 |
||||
|
||||
bf_forward: |
||||
cmp byte [rsi], 0 |
||||
jne bf_forward_end |
||||
jmp bf_jump |
||||
bf_forward_end: |
||||
inc rbx |
||||
ret |
||||
|
||||
bf_backward: |
||||
cmp byte [rsi], 0 |
||||
je bf_backward_end |
||||
jmp bf_jump |
||||
bf_backward_end: |
||||
inc rbx |
||||
ret |
||||
|
||||
bf_jump: |
||||
sub rbx, bf_program |
||||
mov rbx, [8*rbx + bf_jumps] |
||||
inc rbx |
||||
ret |
||||
|
||||
bf_out: |
||||
movzx rdi, byte [rsi] |
||||
push rsi |
||||
call putchar |
||||
xor rdi, rdi |
||||
call fflush |
||||
pop rsi |
||||
inc rbx |
||||
ret |
||||
|
||||
bf_in: |
||||
push rsi |
||||
call getchar |
||||
pop rsi |
||||
mov byte [rsi], al |
||||
inc rbx |
||||
ret |
||||
|
||||
|
||||
main: |
||||
|
||||
; wczytuję program |
||||
lea rdi, [bf_program] |
||||
call gets |
||||
|
||||
; Buduję tablicę skoków dla ']'. Jeśli i-ty znak programu to nawias, to na 8*i-tym miejscu w tablicy |
||||
; skoków znajdzie się adres odpowiadającego mu nawiasu. |
||||
lea rbx, [bf_program] |
||||
lea r12, [bf_jumps] |
||||
_jump_loop: |
||||
cmp byte [rbx], '[' |
||||
jne .else |
||||
push r12 |
||||
push rbx |
||||
jmp .end |
||||
.else: |
||||
cmp byte [rbx], ']' |
||||
jne .end |
||||
pop rax |
||||
mov qword [r12], rax |
||||
pop rax |
||||
mov qword [rax], rbx |
||||
.end: |
||||
inc rbx |
||||
add r12, 8 |
||||
cmp byte [rbx], 0 |
||||
jnz _jump_loop |
||||
|
||||
|
||||
lea rbx, [bf_program] |
||||
lea rsi, [bf_tape] |
||||
_program_loop: |
||||
movzx rax, byte [rbx] |
||||
lea rax, [bf_instructions + 8*rax] |
||||
call rax |
||||
jmp _program_loop |
||||
|
||||
xor rdi, rdi |
||||
call exit |
||||
|
||||
|
||||
|
||||
Loading…
Reference in new issue