Created
January 3, 2011 11:08
-
-
Save Jookia/763359 to your computer and use it in GitHub Desktop.
BRAINFU 2
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> | |
#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