TI2-Tutorium, 05.06.2013

Vorbesprechung

Brainfuck

Hier das versprochene C-Framework:

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
#include <stdio.h>
#include <sys/stat.h>
#include <stdlib.h>

// Definiere die Größe des Speichers, auf der wir arbeiten
#define MEMORY_SIZE 40000

// Definiere zwei Funktionen, die in Nasm aufgerufen werden können um ein
// Zeichen einzulesen bzw. auszugeben
extern void output(char c) {
    putc(c, stdout);
    fflush(stdout);
}
extern char input() {
    return getc(stdin);
}

// Definition unserer Nasm-Funktion
extern void brainfuck(char[], char[]);

int main(int argc, char *argv[]) {
    // Wir wollen genau einen Kommandozeilenparameter
    if (argc != 2) {
        printf("Usage: %s brainfuck-file.bf\n", argv[0]);
        return 0;
    }

    // Wir gucken, wie groß die Datei ist, wie viel Speicher wir also für das
    // Programm brauchen
    struct stat st;
    stat(argv[1], &st);
    // Hole dir Speicher
    char* program = malloc(st.st_size + 1);
    if (program == NULL) {
        fprintf(stderr, "Kann keinen Programmspeicher reservieren.\n");
        return 1;
    }

    // Wir brauchen auch noch Speicher auf dem das Brainfuck-Programm arbeiten
    // kann
    char* memory = calloc(MEMORY_SIZE, 1);
    if (memory == NULL) {
        fprintf(stderr, "Kann keinen Datenspeicher reservieren.\n");
        return 1;
    }

    // Jetzt lesen wir das Programm ein
    FILE *f;
    if (!(f = fopen(argv[1], "rb"))) {
        fprintf(stderr, "Konnte Datei %s nicht zum Lesen öffnen.\n", argv[1]);
        return 1;
    }
    if (fread(program, 1, st.st_size, f) != st.st_size) {
        fprintf(stderr, "Konnte Datei %s nicht komplett einlesen.\n", argv[1]);
        return 1;
    }
    fclose(f);

    // Programm endet mit einem Nullbyte
    program[st.st_size] = 0;

    // Führe die Nasm-Funktion aus
    brainfuck(program, memory);

    return 0;
}

Um die Funktionen output und input aus NASM heraus aufzurufen geht ihr folgendermaßen vor:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
section .text

; Hier wird NASM gesagt, dass es die beiden Funktionen gibt
extern output
extern input

global brainfuck

brainfuck:
    ; ...

    ; Rufe die Funktion input auf
    call input
    ; Jetzt steht in al der ASCII-Wert des gelesenen Zeichens

    ; ...

    ; Wir wollen ein großes A ausgaben
    mov rdi, 65 ; Statt 65 wäre auch 'A' möglich
    call output