From 8727e0be0fcc3d0877abad3ff751eb44b6b3168e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Karpi=C5=84ski?= Date: Sat, 18 Apr 2020 13:52:16 +0200 Subject: [PATCH] initial --- Makefile | 7 +++ brainfuck.asm | 168 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 175 insertions(+) create mode 100644 Makefile create mode 100644 brainfuck.asm diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..ba62b6c --- /dev/null +++ b/Makefile @@ -0,0 +1,7 @@ +brainfuck: brainfuck.asm + nasm -felf64 brainfuck.asm + gcc -m64 -o brainfuck brainfuck.o + +clean: + rm -f brainfuck brainfuck.o + diff --git a/brainfuck.asm b/brainfuck.asm new file mode 100644 index 0000000..7bb6604 --- /dev/null +++ b/brainfuck.asm @@ -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 + + +