#include #include #include // 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; }