Code: Select all
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
size_t open;
size_t close;
} BracketPair;
typedef struct {
char *program;
size_t program_size;
size_t *bracket_map;
unsigned char *tape;
size_t tape_size;
size_t ip; // instruction pointer
size_t dp; // data pointer
} BrainfuckInterpreter;
void build_bracket_map(BrainfuckInterpreter *bf) {
size_t *stack = malloc(bf->program_size * sizeof(size_t));
size_t stack_size = 0;
for (size_t i = 0; i < bf->program_size; ++i) {
if (bf->program[i] == '[') {
stack[stack_size++] = i;
} else if (bf->program[i] == ']') {
if (stack_size == 0) {
fprintf(stderr, "Error: Unmatched ']' at position %zu\n", i);
exit(EXIT_FAILURE);
}
size_t open_pos = stack[--stack_size];
bf->bracket_map[open_pos] = i;
bf->bracket_map[i] = open_pos;
}
}
if (stack_size != 0) {
fprintf(stderr, "Error: Unmatched '[' at position %zu\n", stack[stack_size - 1]);
exit(EXIT_FAILURE);
}
free(stack);
}
void run(BrainfuckInterpreter *bf) {
while (bf->ip < bf->program_size) {
char cmd = bf->program[bf->ip];
switch (cmd) {
case '>':
bf->dp++;
if (bf->dp >= bf->tape_size) {
bf->tape_size *= 2;
bf->tape = realloc(bf->tape, bf->tape_size);
memset(bf->tape + bf->tape_size / 2, 0, bf->tape_size / 2);
}
break;
case '<':
if (bf->dp == 0) {
fprintf(stderr, "Error: Data pointer moved left of tape start.\n");
exit(EXIT_FAILURE);
}
bf->dp--;
break;
case '+':
bf->tape[bf->dp]++;
break;
case '-':
bf->tape[bf->dp]--;
break;
case '.':
putchar(bf->tape[bf->dp]);
break;
case ',':
{
int c = getchar();
if (c != EOF)
bf->tape[bf->dp] = (unsigned char)c;
else
bf->tape[bf->dp] = 0;
break;
}
case '[':
if (bf->tape[bf->dp] == 0)
bf->ip = bf->bracket_map[bf->ip];
break;
case ']':
if (bf->tape[bf->dp] != 0)
bf->ip = bf->bracket_map[bf->ip];
break;
default:
// Ignore non-Brainfuck characters
break;
}
bf->ip++;
}
}
char *read_file(const char *filename, size_t *out_size) {
FILE *file = fopen(filename, "rb");
if (!file) {
perror("Error opening file");
exit(EXIT_FAILURE);
}
fseek(file, 0, SEEK_END);
long size = ftell(file);
rewind(file);
char *buffer = malloc(size + 1);
if (!buffer) {
perror("Memory allocation failed");
exit(EXIT_FAILURE);
}
fread(buffer, 1, size, file);
buffer[size] = '\0';
fclose(file);
if (out_size)
*out_size = (size_t)size;
return buffer;
}
int main(int argc, char *argv[]) {
if (argc != 2) {
fprintf(stderr, "Usage: brainfuck <program_file>\n");
return EXIT_FAILURE;
}
BrainfuckInterpreter bf;
bf.program = read_file(argv[1], &bf.program_size);
bf.bracket_map = malloc(bf.program_size * sizeof(size_t));
bf.ip = 0;
bf.dp = 0;
// Initialize tape
bf.tape_size = 1024;
bf.tape = calloc(bf.tape_size, sizeof(unsigned char));
build_bracket_map(&bf);
run(&bf);
free(bf.program);
free(bf.bracket_map);
free(bf.tape);
return EXIT_SUCCESS;
}
Если что, компилируется и запускается примерно так:
Code: Select all
gcc -std=c99 -O2 -Wall -Wextra -o brainfuck brainfuck.c
./brainfuck hello.bf
Code: Select all
[ This program prints "Hello World!" and a newline to the screen; its
length is 106 active command characters. [It is not the shortest.]
This loop is an "initial comment loop", a simple way of adding a comment
to a BF program such that you don't have to worry about any command
characters. Any ".", ",", "+", "-", "<" and ">" characters are simply
ignored, the "[" and "]" characters just have to be balanced. This
loop and the commands it contains are ignored because the current cell
defaults to a value of 0; the 0 value causes this loop to be skipped.
]
++++++++ Set Cell #0 to 8
[
>++++ Add 4 to Cell #1; this will always set Cell #1 to 4
[ as the cell will be cleared by the loop
>++ Add 2 to Cell #2
>+++ Add 3 to Cell #3
>+++ Add 3 to Cell #4
>+ Add 1 to Cell #5
<<<<- Decrement the loop counter in Cell #1
] Loop until Cell #1 is zero; number of iterations is 4
>+ Add 1 to Cell #2
>+ Add 1 to Cell #3
>- Subtract 1 from Cell #4
>>+ Add 1 to Cell #6
[<] Move back to the first zero cell you find; this will
be Cell #1 which was cleared by the previous loop
<- Decrement the loop Counter in Cell #0
] Loop until Cell #0 is zero; number of iterations is 8
The result of this is:
Cell no : 0 1 2 3 4 5 6
Contents: 0 0 72 104 88 32 8
Pointer : ^
>>. Cell #2 has value 72 which is 'H'
>---. Subtract 3 from Cell #3 to get 101 which is 'e'
+++++++..+++. Likewise for 'llo' from Cell #3
>>. Cell #5 is 32 for the space
<-. Subtract 1 from Cell #4 for 87 to give a 'W'
<. Cell #3 was set to 'o' from the end of 'Hello'
+++.------.--------. Cell #3 for 'rl' and 'd'
>>+. Add 1 to Cell #5 gives us an exclamation point
>++. And finally a newline from Cell #6
