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