Skip to content

Instantly share code, notes, and snippets.

@Eckankar
Last active August 29, 2015 14:00
Show Gist options
  • Select an option

  • Save Eckankar/badf4f836ab4784fbcb0 to your computer and use it in GitHub Desktop.

Select an option

Save Eckankar/badf4f836ab4784fbcb0 to your computer and use it in GitHub Desktop.
/* Simple naïve brainfuck interpreter.
Author: Sebastian Paaske Tørholm <sebbe@diku.dk>
I release this code into the public domain. */
#include <stdio.h>
#include <stdlib.h>
// Memory cells. Implemented as a doubly linked list
typedef struct memory_t {
struct memory_t *prev;
struct memory_t *next;
unsigned char value;
} memory_t;
// Read the entire contents of a file into a char buffer.
char * read_all(char *filename) {
FILE *f = fopen(filename, "r");
if (!f) {
fprintf(stderr, "Cannot open %s\n", filename);
exit(1);
}
size_t size = 32;
size_t pos = 0;
char *res = malloc(size * sizeof(char));
char c;
while ((c = getc(f)) != EOF) {
res[pos++] = (char)c;
if (pos == size) {
size *= 2;
res = realloc(res, size * sizeof(char));
}
}
fclose(f);
return res;
}
// Allocates a memory_t and zeros it out
memory_t *mem_alloc() {
memory_t *mem = malloc(sizeof(memory_t));
mem->prev = NULL;
mem->next = NULL;
mem->value = 0;
return mem;
}
// Move to the next memory cell, allocating and initializing it if needed.
memory_t *mem_next(memory_t *mem) {
if (! mem->next) {
mem->next = mem_alloc();
mem->next->prev = mem;
}
return mem->next;
}
// Move to the previous memory cell, allocating and initializing it if needed.
memory_t *mem_prev(memory_t *mem) {
if (! mem->prev) {
mem->prev = mem_alloc();
mem->prev->next = mem;
}
return mem->prev;
}
int main(int argc, char *argv[]) {
if (argc < 2) {
fprintf(stderr,"Usage: %s <program>\n", argv[0]);
return 1;
}
char *pgm = read_all(argv[1]);
memory_t *cur = mem_alloc();
// Keeps track of currently open loops.
size_t loop_size = 10;
size_t *loop = malloc(loop_size * sizeof(size_t));
size_t loop_i = 0;
size_t pc = 0;
while (1) {
switch (pgm[pc]) {
case '+': cur->value += 1; pc++; break;
case '-': cur->value -= 1; pc++; break;
case '>': cur = mem_next(cur); pc++; break;
case '<': cur = mem_prev(cur); pc++; break;
case '.': putchar(cur->value); fflush(stdout); pc++; break;
case ',': cur->value = getchar(); pc++; break;
case '[':
if (cur->value == 0) {
// If cell has value 0; skip to matching ]
int cnt = 1;
while (cnt > 0) {
pc++;
switch (pgm[pc]) {
case '[': cnt++; break;
case ']': cnt--; break;
case '\0': fprintf(stderr, "Mismatched brackets in loop."); return 1;
default: break;
}
}
} else {
// Remember where the loop starts
if (loop_i == loop_size) {
loop_size *= 2;
loop = realloc(loop, loop_size * sizeof(size_t));
}
loop[loop_i++] = pc;
}
pc++;
break;
case ']':
if (loop_i < 0) {
fprintf(stderr, "Unexpected ] in program.");
return 1;
}
pc = loop[--loop_i];
break;
case '\0':
if (loop_i > 0) {
fprintf(stderr, "Unclosed loop.");
return 1;
}
return 0;
default: pc++; break;
}
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment