Last active
July 8, 2020 18:11
-
-
Save owenjones/cfca0c7b0ad098fdd797cce8c797e42c to your computer and use it in GitHub Desktop.
Brainfuck Interpreter
This file contains hidden or 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> | |
#define sblock 8 // Stack block length | |
#define lblock 4 // Loop-stack block length | |
#define readln 1024 // Length of input buffer | |
char* reallocate(char* array, int blocks, int blocksize, int loop, int debug) { | |
// Reallocates the input stack if current length is exceeded | |
int size = blocks * blocksize; | |
char* lstr = (loop) ? "loop " : ""; | |
if(debug) printf("[\e[1;105m^\e[0m] Increasing %sstack size (to %i)\n", lstr, size); | |
char* addr = realloc(array, size); | |
if(addr != NULL) return addr; | |
exit(EXIT_FAILURE); | |
} | |
void brainfuck(char *inp, int debug) { | |
char* stack = calloc(sblock, sizeof(char)); | |
int sblocks = 1; | |
char* sstart = stack; | |
char** loop = calloc(lblock, sizeof(char *)); | |
int lblocks = 1; | |
char** lstart = loop; | |
if(debug) printf("[\e[1;105m^\e[0m] Stack allocated at <%p>\n", sstart); | |
if(debug) printf("[\e[1;105m^\e[0m] Loop allocated at <%p>\n", lstart); | |
while(*inp != '\0') { | |
switch(*inp) { | |
case '.' : { | |
if(debug) printf("[\e[1;92m.\e[0m] Echoing character at <%p> (%i) -> ", stack, *stack); | |
putchar(*stack); | |
if(debug) printf("\n"); | |
break; | |
} | |
case ',' : { | |
if(debug) printf("[\e[1;92m,\e[0m] Taking Character for <%p>\n", stack); | |
*stack = getchar(); | |
break; | |
} | |
case '>' : { | |
stack++; | |
int diff = (stack - sstart); | |
if(diff > (sblocks * sblock)) { | |
sstart = reallocate(sstart, ++sblocks, sblock, 0, debug); | |
stack = (sstart + diff); | |
} | |
if(debug) printf("[\e[1;93m>\e[0m] Incrementing pointer <%p>\n", stack); | |
break; | |
} | |
case '<' : { | |
stack--; | |
if((stack - sstart) < 0) { | |
if(debug) printf("[\e[1;41m<\e[0m] Address <%p> out of range\n", stack); | |
exit(EXIT_FAILURE); | |
} | |
if(debug) printf("[\e[1;93m<\e[0m] Decrementing pointer <%p>\n", stack); | |
break; | |
} | |
case '+' : { | |
*stack = *stack + 1; | |
if(debug) printf("[\e[1;96m+\e[0m] Incrementing value at <%p> -> %i\n", stack, *stack); | |
break; | |
} | |
case '-' : { | |
*stack = *stack - 1; | |
if(debug) printf("[\e[1;96m-\e[0m] Decrementing value at <%p> -> %i\n", stack, *stack); | |
break; | |
} | |
case '[' : { | |
if(debug) printf("[\e[1;95m[\e[0m] Loop start -> counter <%p> = %i\n", stack, *stack); | |
loop++; | |
int diff = (loop - lstart); | |
if(diff > (lblocks * lblock)) { | |
*lstart = reallocate(*lstart, ++lblocks, lblock, 1, debug); | |
loop = (lstart + diff); | |
} | |
*loop = inp; | |
break; | |
} | |
case ']' : { | |
if(debug) printf("[\e[1;95m]\e[0m] Loop end -> "); | |
if(*stack <= 0) { | |
if(debug) printf("counter <%p> is zero, continuing with program.\n", stack); | |
*loop = 0; | |
loop--; | |
} | |
else { | |
if(debug) printf("counter <%p> is non-zero (%i), looping again.\n", stack, *stack); | |
inp = *(loop); | |
} | |
break; | |
} | |
case '\n' : { | |
// Newlines from STDIN | |
break; | |
} | |
default : { | |
if(debug) printf("[\e[1;41m?\e[0m] Unknown symbol \"%c\"\n", *inp); | |
exit(EXIT_FAILURE); | |
} | |
} | |
inp++; | |
} | |
free(sstart); | |
free(lstart); | |
} | |
char* rdstdin(char* input, int debug) { | |
if(debug) printf("[\e[1;41m!\e[0m] Reading from STDIN...\n"); | |
fgets(input, readln, stdin); | |
return input; | |
} | |
int main(int argc, char* argv[]) { | |
int debug = 0; | |
char* input = malloc(readln * sizeof(char)); | |
if((argc > 1) && (strncmp(argv[1], "--debug", 7) == 0)) { | |
debug = 1; | |
input = (argc > 2) ? strcpy(input, argv[2]) : rdstdin(input, debug); | |
} | |
else { | |
input = (argc > 1) ? strcpy(input, argv[1]) : rdstdin(input, debug); | |
} | |
brainfuck(input, debug); | |
free(input); | |
exit(EXIT_SUCCESS); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment