Created
January 3, 2011 02:25
-
-
Save Jookia/763047 to your computer and use it in GitHub Desktop.
BRAINFU
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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