Wrote a simple brainfuck interpreter that supports nested subroutines ([ ] commands).
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <assert.h>
#define MIN_MEMORY_SIZE 30000
typedef struct
{
uint8_t *memory;
size_t pointer;
} BrainfuckState;
static void init(BrainfuckState *bf, size_t size)
{
assert(size <= MIN_MEMORY_SIZE);
bf->memory = calloc(size, 1);
assert(!(bf == NULL));
bf->pointer = 0;
}
static void deinit(BrainfuckState *bf)
{
free(bf->memory);
bf->pointer = 0;
}
static void interpret(BrainfuckState *bf, const char* source, size_t sourceSize)
{
size_t unmatchedBracketCount = 0;
for (size_t i = 0; i < sourceSize; i++)
{
switch (source[i])
{
case '.':
printf("%c", bf->memory[bf->pointer]);
break;
case ',':
scanf("%c", &(bf->memory[bf->pointer]));
break;
case '+':
bf->memory[bf->pointer]++;
break;
case '-':
bf->memory[bf->pointer]--;
break;
case '>':
bf->pointer++;
break;
case '<':
bf->pointer--;
break;
case '[':
if (bf->memory[bf->pointer] == 0)
{
unmatchedBracketCount++;
while (source[i] != ']' || unmatchedBracketCount)
{
i++;
if (source[i] == '[')
unmatchedBracketCount++;
else if (source[i] == ']')
unmatchedBracketCount--;
}
}
break;
case ']':
if (bf->memory[bf->pointer])
{
unmatchedBracketCount++;
while (source[i] != '[' || unmatchedBracketCount)
{
i--;
if (source[i] == ']')
unmatchedBracketCount++;
else if (source[i] == '[')
unmatchedBracketCount--;
}
}
break;
}
}
}
int main(int argc, char** argv)
{
if (argc < 2)
fprintf(stderr, "Pass a filename as a command line arguement.\n");
else
{
FILE *fp = fopen(argv[1], "r");
assert(fp);
fseek(fp, 0, SEEK_END);
size_t sourceSize = ftell(fp);
char *source = malloc(sourceSize);
assert(source);
rewind(fp);
for (size_t i = 0; i < sourceSize; i++)
source[i] = fgetc(fp);
fclose(fp);
BrainfuckState bf;
init(&bf, MIN_MEMORY_SIZE);
interpret(&bf, source, sourceSize);
deinit(&bf);
free(source);
}
return EXIT_SUCCESS;
}
My goal was to keep it as simple and short as possible.