# bf, a brainfuck interpreter
### Description
This is my implementation of a [brainfuck][bf] interpreter. It uses a
-potentially infinite stack by reallocating more when necessary.
+potentially infinite stack by reallocating more when necessary. `bf` is an
+implementation with arrays, `bfll` is an implementation where the tape is a
+doubly linked list.
### Installation
Compiling is as easy as running `make`
### Usage
Say you have a file containing a program on disk called `hello.bf`. Then you
-can run the file by running `./bf hello.bf`.
+can run the file by running `./bf hello.bf` or `./bfll hello.bf`.
### License
Do what ever you want with this code.
--- /dev/null
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+
+#define die(s, as...) {fprintf(stderr, s, ## as); return EXIT_FAILURE;}
+#define check_fail(v, s, f) if((v) == f) die("%s(): %s\n", s, strerror(errno))
+#define check_null(v, s) check_fail(v, s, NULL)
+
+#define INITIALBUFSIZE 2
+
+struct buf {
+ char v;
+ struct buf *n, *p;
+};
+
+struct cs {
+ long pl;
+ struct cs *next;
+};
+
+int main(int argc, char *argv[])
+{
+ size_t depth;
+ struct buf *p;
+ struct cs *temp, *cs;
+ FILE *in;
+
+ if(argc != 2)
+ die("Usage: %s PROGRAM\n", argv[0]);
+
+ check_null(in = fopen(argv[1], "r"), "fopen");
+ check_null(p = calloc(sizeof (struct buf), 1), "calloc");
+
+ while (1){
+ switch (fgetc(in)){
+ case EOF:
+ check_fail(fclose(in), "fclose", -1);
+ while(p->p != NULL)
+ p = p->p;
+ while(p->n != NULL)
+ free((p = p->n)->p);
+ free(p);
+ return EXIT_SUCCESS;
+ case '>':
+ if(p->n == NULL){
+ check_null(p->n = calloc(
+ sizeof (struct buf), 1), "calloc");
+ p->n->p = p;
+ }
+ p = p->n;
+ break;
+ case '<':
+ if(p->p == NULL){
+ check_null(p->p = calloc(
+ sizeof (struct buf), 1), "calloc");
+ p->p->n = p;
+ }
+ p = p->p;
+ break;
+ case '+':
+ ++(p->v);
+ break;
+ case '-':
+ --(p->v);
+ break;
+ case '.':
+ putchar(p->v);
+ break;
+ case ',':
+ p->v = getchar();
+ break;
+ case '[':
+ if (p->v){
+ temp = cs;
+ check_null(cs = malloc(
+ sizeof(struct cs)), "malloc");
+ cs->next = temp;
+ check_fail(cs->pl = ftell(in), "ftell", -1);
+ } else {
+ depth = 1;
+ while (depth > 0){
+ switch (fgetc(in)){
+ case ']':
+ depth--;
+ break;
+ case '[':
+ depth++;
+ }
+ }
+ }
+ break;
+ case ']':
+ check_fail(fseek(in, cs->pl-1, SEEK_SET), "fseek", -1);
+ temp = cs;
+ cs = cs->next;
+ free(temp);
+ }
+ }
+}