Ich weiß, dass es "da draußen" genügend Brainfuck-Interpreter gibt. Also warum einen eigenen schreiben? Nun, es ist eine gewisse Herausforderung und es macht einfach Spaß. Also fangen wir an.
Die Sprache Brainfuck
Die Programmiersprache Brainfuck zählt zu den esoterischen Programmiersprachen. Mit ihren 8 Befehlen ist sie turing-vollständig. Ein Brainfuck-Programm weißt eine Trennung zwischen Daten und Programm auf. Ein Programm besteht aus einer Liste von Befehlen, die sequentiell abgearbeitet wird. Dazu gibt es ein unendlichen Band an Speicherzellen. Im Gegensatz zur klassischen Turing-Maschine ist dieses Band nach einer Seite begrenzt.
Der Interpreter
Der Interpreter nutzt einen objektorientierten Ansatz. Es gibt Klassen für den Interpreter und für die Ein- und Ausgabe. In einer While-Schleife wird das Bf-Programm solange durchlaufen, bis es eventuell terminiert. Das Programm wird aus einer Datei gelesen und geparst. Das Parsing findet so statt, dass alle gelesenen Zeichen, die keine Bf-Befehle sind, ignoriert werden. Das daraus gewonnene Programm wird dann zeichenweise abgearbeitet. Wenn durch die Abarbeitung das "Ende" des Speicherbandes erreicht wird, wird es entsprechend erweitert. Dies kann natürlich schnell dazu führen, dass der Speicher knapp wird (z.B. durch "+[>+]").
Die Assembler-Version
Im Rahmen des Uni-Kurses soll eine Implementierung in Assembler geschrieben werden. Dazu hier meine Implementierung:
section .text extern printc extern readc extern allocmem global bfintr bfintr: ;Parameter in eigene Register verschieben mov r8, rdi ; r8 BF-Programm mov r9, rsi ; r9 BF-Speicher mov r10, rdx ; r10 BF-Speicher-Größe mov r11, 0 ; r11 Programmposition mov r12, 0 ; r12 Speicherposition mov r13, 0 ; r13 Anzahl an Klammern mov rax, 0 bfintr_while: mov r14, [r8 + r11] and r14, 0xFF cmp r14, 0 je bfintr_end cmp r14, '>' je bfintr_greater cmp r14, '<' je bfintr_smaller cmp r14, '+' je bfintr_plus cmp r14, '-' je bfintr_minus cmp r14, '.' je bfintr_point cmp r14, ',' je bfintr_comma cmp r14, '[' je bfintr_opening cmp r14, ']' je bfintr_closing jmp bfintr_while_end bfintr_while_end: inc r11 jmp bfintr_while bfintr_end: mov rax, r11 mov rsi, r9 ret bfintr_greater: inc r12 cmp r12, r10 mov rax, 1 je bfintr_greater_alloc jmp bfintr_while_end bfintr_greater_alloc: push r8 push r10 push r11 push r12 push r13 mov rdi, r9 mov rsi, r10 call allocmem mov r9, rax pop r13 pop r12 pop r11 pop r10 pop r8 add r10, 1024 jmp bfintr_while_end bfintr_smaller: cmp r12, 0 mov rax, 2 je bfintr_end dec r12 jmp bfintr_while_end bfintr_plus: mov r15, [r9 + r12] inc r15 mov [r9 + r12], r15 jmp bfintr_while_end bfintr_minus: mov r15, [r9 + r12] dec r15 mov [r9 + r12], r15 jmp bfintr_while_end bfintr_point: mov rax, 3 push r8 push r9 push r10 push r11 push r12 push r13 mov rdi, [r9 + r12] call printc pop r13 pop r12 pop r11 pop r10 pop r9 pop r8 jmp bfintr_while_end bfintr_comma: mov rax, 4 push r8 push r9 push r10 push r11 push r12 push r13 call readc pop r13 pop r12 pop r11 pop r10 pop r9 pop r8 mov [r9 + r12], al jmp bfintr_while_end bfintr_opening: mov r15, [r9 + r12] and r15, 0xFF cmp r15, 0 je bfintr_skip push r11 inc r13 ; Anzahl an Klammern inkrementieren jmp bfintr_while_end bfintr_closing: pop r11 dec r11 dec r13 jmp bfintr_while_end bfintr_skip: push r13 mov r13, 0 bfintr_skip_while: inc r11 mov r14, [r8 + r11] and r14, 0xFF cmp r14, '[' je bfintr_skip_opening cmp r14, ']' je bfintr_skip_closing jmp bfintr_skip_while bfintr_skip_end: pop r13 ;inc r11 jmp bfintr_while_end bfintr_skip_opening: inc r13 jmp bfintr_skip_while bfintr_skip_closing: cmp r13, 0 je bfintr_skip_end dec r13 jmp bfintr_skip_while