Skip to content

Instantly share code, notes, and snippets.

@Jookia
Created January 3, 2011 11:08
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/763359 to your computer and use it in GitHub Desktop.
Save Jookia/763359 to your computer and use it in GitHub Desktop.
BRAINFU 2
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
// Some defines useful for tweaking the interpreter.
#define CELL uint8_t
#define CELL_COUNT (30000)
#define LOOP_STACK_SIZE (256)
// Find the matching end bracket of the loop. loopStart should be the first
// bracket of the loop. Will return the matching end bracket or the start
// bracket if one can't be found.
char* getLoopEnd(char* loopStart)
{
char* currentInstruction = loopStart;
// loopDepth is used to make sure that nested loop brackets won't be mistaken
// for the loop's end bracket. It starts at 0 and increments whenever a loop
// opening bracket is encountered. Which means that it'll be automatically
// incremented to 1 as '[' is the first character encountered. Then whenever
// a loop closing bracket is encountered, loopDepth is decremented. So when
// a matching bracket for the first bracket is found, loopDepth will be
// decremented from 1 (the starting bracket's depth) to 0, which means that
// the end of the loop is there.
int loopDepth = 0;
while(*currentInstruction != '\0')
{
char operator = *currentInstruction;
switch(operator)
{
case '[':
++loopDepth;
break;
case ']':
{
--loopDepth;
if(loopDepth == 0) // End of loop.
{
return currentInstruction;
}
break;
}
default:
break;
}
++currentInstruction;
}
return loopStart;
}
// Returns 0 if everything went fine or 1 if something failed.
int interpret(char* code)
{
CELL cells[CELL_COUNT] = {0};
CELL* currentCell = &cells[0]; // Start at the leftmost cell.
char* currentInstruction = &code[0]; // Start at the beginning of the code.
// The loop stack is used to store positions for beginnings of loop. Used
// mainly for loops in loops.
char* loopStack[LOOP_STACK_SIZE] = {0};
int currentLoop = 0; // Current loop on the stack.
while(*currentInstruction != '\0')
{
char operator = *currentInstruction;
switch(operator)
{
case '>': // Move to the next cell.
{
if((currentCell - cells) == CELL_COUNT)
{
fprintf(stderr, "Trying to move to an out of bounds cell.\n");
return 1;
}
++currentCell;
break;
}
case '<': // Move to the previous cell.
{
if((currentCell - cells) == 0)
{
fprintf(stderr, "Trying to move to an out of bounds cell.\n");
return 1;
}
--currentCell;
break;
}
case '+': // Increment the current cell.
++(*currentCell);
break;
case '-': // Decrement the current cell.
--(*currentCell);
break;
case '.': // Print the current cell.
putchar(*currentCell);
break;
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(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. getEndLoop returns
// the matching bracket, but the increment of currentInstruction will
// make sure that no infinite loops happen.
loopStack[currentLoop] = 0;
--currentLoop;
currentInstruction = getLoopEnd(currentInstruction);
}
break;
}
case ']': // Go back to the start of the loop.
{
// 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;
}
++currentInstruction;
}
return 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*)calloc(fileLength, sizeof(char));
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