Skip to content

Instantly share code, notes, and snippets.

@Jookia
Created January 3, 2011 02:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Jookia/763047 to your computer and use it in GitHub Desktop.
Save Jookia/763047 to your computer and use it in GitHub Desktop.
BRAINFU
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Some defines useful for tweaking the interpreter.
#define DATA char
#define CELL unsigned char
#define CELL_COUNT 30000
#define LOOP_STACK_SIZE 32
// data is a string of characters.
void interpret(DATA* data)
{
CELL cells[CELL_COUNT] = {0};
CELL* currentCell = &cells[0]; // Start at the leftmost cell.
DATA* currentInstruction = &data[0]; // Start at the beginning of the data.
// The loop stack is used to store positions for beginnings of loop. Used
// mainly for loops in loops.
DATA* loopStack[LOOP_STACK_SIZE] = {0};
int currentLoop = 0; // Current loop on the stack.
int loopJumping = 0; // Boolean used if the loop is being jumped over.
// When jumping through a loop and ignoring everything inside, loopsToJump
// is incremented and decremented when faced with loops inside the loop that's
// being jumped through. The purpose of this is to make sure that the end of
// the jump is the matching loop bracket and not one inside or outside.
int loopsToJump = 0;
do
{
char operator = *currentInstruction;
if(loopJumping != 0 && operator != '[' && operator != ']')
{
// Ignore anything that isn't brackets for a loop when jumping past
// loops. Brackets are only acknowledged as to increment or decrement
// loopsToJump.
continue;
}
switch(operator)
{
case '>': ++currentCell; break; // Increment the current cell.
case '<': --currentCell; break; // Decrement the current cell.
case '+': ++(*currentCell); break; // Move to the next cell.
case '-': --(*currentCell); break; // Move to the previous cell.
case '.': putchar(*currentCell); break; // Print the current cell.
case ',': // Get input.
{
// Just grab the first character from stdin. Will overflow if more than
// one character is entered in to undefined memory after buffer.
char buffer;
fscanf(stdin, "%s", &buffer);
*currentCell = buffer;
break;
}
case '[': // Iterate over a loop or jump over it if currentCell is 0.
{
if(loopJumping != 0)
{
// Jumping through a loop, increment loopsToJump as to not mistake
// a closing loop bracket for the jumping loop's closing bracket.
++loopsToJump;
break;
}
if(loopStack[currentLoop] != currentInstruction)
{
// Entering a loop. Push the instruction to the loop stack.
++currentLoop;
loopStack[currentLoop] = currentInstruction;
}
if(*currentCell == 0)
{
// No iterations to do, jump to end of the loop.
loopJumping = 1;
}
break;
}
case ']': // Go back to the start of the loop.
{
if(loopJumping != 0)
{
if(loopsToJump != 0)
{
// Jumping through a loop and just passed a loop that's inside a
// loop, continue jumping to find the real end to this loop and
// not the end to another.
--loopsToJump;
break;
}
// Done jumping.
loopJumping = 0;
--currentLoop;
break;
}
// Go back to the start of the loop. Take one away as to make up for
// the current instruction pointer being incremented.
currentInstruction = loopStack[currentLoop] - 1;
break;
}
// Nothing to do with non-operators.
default: break;
}
}
// Move to the next instruction in the data. If the instruction is a null
// terminator, interpreting is done.
while(*(++currentInstruction) != '\0');
}
// Helper function to load a file in to a char array in memory. Don't forget to
// free the array after use.
char* loadFile(const char* filename)
{
FILE* file = fopen(filename, "r");
if(file == NULL)
{
fprintf(stderr, "Unable to open '%s'.\n", filename);
return 0;
}
if(fseek(file, 0L, SEEK_END) == -1)
{
fprintf(stderr, "Unable to seek to the end of the file.\n");
fclose(file);
return 0;
}
int fileLength = (sizeof(char) * ftell(file));
char* fileContents = (char*)malloc(fileLength);
memset(fileContents, 0, fileLength);
if(fileContents == NULL)
{
fprintf(stderr, "Unable to allocate space for the file contents.\n");
fclose(file);
return 0;
}
rewind(file);
fread(fileContents, sizeof(char) * fileLength, 1, file);
fclose(file);
return fileContents;
}
int main(int argc, const char** argv)
{
if(argc != 2)
{
printf("Usage: %s FILE\n", argv[0]);
return 0;
}
char* fileContents = loadFile(argv[1]);
if(fileContents == 0)
{
return 1;
}
// Print BRAINFU to the screen.
interpret(">+++++++[<++++++++++>-]<----.>++[<++++++++++>-]<----.>--[<+++++++"\
"+++>-]<+++.>+[<++++++++++>-]<--.+++++.>-[<++++++++++>-]<++.>+[<++++++++++"\
">-]<+++++.>>+[<++++++++++>-]<.");
interpret(fileContents);
free(fileContents);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment