Skip to content

Instantly share code, notes, and snippets.

@euhmeuh
Created July 30, 2017 21:16
Show Gist options
  • Save euhmeuh/c2b1abd37c7048e9cb8e2377d11b0782 to your computer and use it in GitHub Desktop.
Save euhmeuh/c2b1abd37c7048e9cb8e2377d11b0782 to your computer and use it in GitHub Desktop.
Brainfuck interpreter in C
/*
Brainfuck interpreter by euhmeuh
*/
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <errno.h>
#include <string.h>
#define MEMORY_SIZE 1024
#define CODE_BUFFER_SIZE 256
#define JUMP_BUFFER_SIZE 8
/* --- DynamicArray --- */
typedef struct {
int* string;
unsigned int buffer_size;
unsigned int size;
unsigned int cursor;
} DynamicArray;
DynamicArray* array_create(unsigned int buffer_size) {
DynamicArray* array = malloc(sizeof(DynamicArray));
array->string = malloc(sizeof(int) * buffer_size);
array->buffer_size = buffer_size;
array->size = buffer_size;
array->cursor = 0;
return array;
}
void array_append(DynamicArray* array, int c) {
array->string[array->cursor] = c;
array->cursor++;
if (array->cursor >= array->size) {
array->size += array->buffer_size;
array->string = realloc(array->string, sizeof(int) * array->size);
}
}
int array_pop(DynamicArray* array) {
array->cursor--;
return array->string[array->cursor];
}
void array_destroy(DynamicArray* array) {
free(array->string);
free(array);
}
/* --- Interpreter --- */
/*
Evaluate the current character under the codeptr.
'+' and '-' will change the data in memory.
'>' and '<' will change the dataptr.
'.' and ',' will print and read a character respectively.
'[' and ']' will jump the codeptr around.
Any other character is ignored.
*/
void
eval_character(DynamicArray* code,
unsigned int* codeptr,
int* memory,
unsigned int* dataptr,
unsigned int* jump_table)
{
switch(code->string[*codeptr])
{
case '+':
memory[*dataptr]++;
break;
case '-':
memory[*dataptr]--;
break;
case '>':
(*dataptr)++;
if(*dataptr >= MEMORY_SIZE) {
*dataptr = 0;
}
break;
case '<':
(*dataptr)--;
if(*dataptr < 0) {
*dataptr = MEMORY_SIZE - 1;
}
break;
case '.':
fprintf(stdout, "%c", memory[*dataptr]);
break;
case ',':
memory[*dataptr] = getchar();
break;
case '[':
if (memory[*dataptr] == 0) {
*codeptr = jump_table[*codeptr] + 1;
return;
}
break;
case ']':
if (memory[*dataptr] != 0) {
*codeptr = jump_table[*codeptr] + 1;
return;
}
break;
default:
// noop
break;
}
(*codeptr)++;
}
/*
Generates a registers that indexes all jump destinations in the code
*/
unsigned int* index_jumps(DynamicArray* code)
{
unsigned int* jump_table = malloc(sizeof(unsigned int) * code->cursor);
unsigned int codeptr = 0;
DynamicArray* stack = array_create(JUMP_BUFFER_SIZE);
for (codeptr; codeptr < code->cursor; codeptr++) {
if (code->string[codeptr] == '[') {
array_append(stack, codeptr);
} else if (code->string[codeptr] == ']') {
jump_table[codeptr] = array_pop(stack);
jump_table[jump_table[codeptr]] = codeptr;
}
}
array_destroy(stack);
return jump_table;
}
/*
Execute a piece of code
*/
void execute(DynamicArray* code)
{
int memory[MEMORY_SIZE] = {0};
unsigned int dataptr = 0;
unsigned int codeptr = 0;
unsigned int* jump_table = index_jumps(code);
while(codeptr < code->cursor) {
eval_character(code, &codeptr, memory, &dataptr, jump_table);
}
free(jump_table);
}
DynamicArray* parse_file(FILE* input)
{
int c;
DynamicArray* array = array_create(CODE_BUFFER_SIZE);
while(c != EOF) {
c = fgetc(input);
array_append(array, c);
}
return array;
}
FILE* get_input_from_args(int argc, char** argv)
{
if (argc > 1) {
if (!strcmp(argv[1], "-")) {
return stdin;
} else {
return fopen(argv[1], "r");
}
} else {
return stdin;
}
}
int main(int argc, char** argv)
{
FILE* input;
DynamicArray* code = NULL;
input = get_input_from_args(argc, argv);
if (input == NULL) {
fprintf(stderr, "Unable to open '%s': %s\n", argv[1], strerror(errno));
exit(EXIT_FAILURE);
}
code = parse_file(input);
fclose(input);
execute(code);
array_destroy(code);
return EXIT_SUCCESS;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment