Last active
July 12, 2016 19:02
-
-
Save spacelatte/ac28e5b95759d4786a5c25c98028f5df to your computer and use it in GitHub Desktop.
extended* Brainfuck interpreter in C
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 <limits.h> // for int_max | |
#include <unistd.h> // for usleep (delay) | |
#include <math.h> // for log function | |
#define DEF_MEM_SIZE 32 // memory size | |
#define COLS 16 // print column count | |
typedef enum { false, true, } bool; | |
typedef enum CMD { | |
PRINT, | |
INPUT, | |
SHIFT_R, | |
SHIFT_L, | |
INC, | |
DEC, | |
LOOP_B, | |
LOOP_E, | |
IF, | |
ELSE, | |
NOT, | |
JUMP, | |
DUMP, | |
CMD_COUNT, | |
} cmd_t; | |
const char cmds[CMD_COUNT] = ".,><+-[]?:!;/"; | |
// print current status of memory | |
void print(char *mem, int pos) | |
{ | |
// print header with pointer | |
printf("\n%*c |",1+(int)(log(DEF_MEM_SIZE)/log(16))+1,' '); | |
for(int j=0;j<COLS;j++) | |
if(pos%COLS == j) | |
printf(" %2s","*"); | |
else | |
printf(" %2hhx",(char)j); | |
// print table | |
for(int j=0;j<DEF_MEM_SIZE;j++) | |
{ | |
if( !(j%COLS) ) | |
printf("\n%c%*x |",(pos/COLS == j/COLS)?'*':' ',(int)(log(DEF_MEM_SIZE)/log(16))+1,j); | |
printf(" %02hhx",mem[j]); | |
} | |
// %c is for pointer | |
// log function calculates memory size of the app then assigns first column witdh accordingly | |
printf("\n"); | |
return; | |
} | |
int main(int argc, char **argv) | |
{ | |
for(int i=1;i<argc;i++) // for every given filename as argument | |
{ | |
FILE *fp = fopen(argv[i],"r"); // open that file | |
if(!fp) // on failure | |
{ | |
fprintf(stderr,"%s: file not found!\n",argv[i]); | |
continue; // continue to open next file (argument) | |
}else | |
fprintf(stderr,"Executing: %s\n",argv[i]); | |
char tmp; | |
bool not = false; | |
int pos = 0; // current memory position of program | |
// lets allocate memory | |
char *mem = (char*)malloc(sizeof(char)*DEF_MEM_SIZE); | |
while( mem && !feof(fp) && pos != -1) // while not end of file and no error | |
{ | |
tmp = fgetc(fp); // get current char and do some stuff | |
if(tmp == cmds[DUMP]) | |
{ | |
print(mem,pos); | |
printf("Enter to continue execution..."); | |
fgetc(stdin); | |
} | |
if(tmp == cmds[SHIFT_R]) | |
{ | |
// too much increment condition | |
if(pos > DEF_MEM_SIZE || pos > INT_MAX) | |
{ | |
fprintf(stderr,"memory overflow!\n"); | |
pos = 0; | |
}else | |
pos += 1; | |
} | |
if(tmp == cmds[SHIFT_L]) | |
{ | |
// too much decrement condition | |
if(pos < 0 || pos > INT_MAX) | |
{ | |
fprintf(stderr,"memory underflow!\n"); | |
pos = DEF_MEM_SIZE-1; | |
}else | |
pos -= 1; | |
} | |
if(tmp == cmds[LOOP_B]) | |
{ | |
// if current pointer is zero then go to end of the loop | |
if( (!*(mem+pos) && !not) || (*(mem+pos) && not) ) | |
{ | |
tmp = 1; | |
while(tmp) | |
{ | |
char c = fgetc(fp); | |
if(c == EOF) | |
break; | |
if(c == ']') | |
tmp -= 1; | |
if(c == '[') | |
tmp += 1; | |
continue; | |
} | |
} | |
} | |
if(tmp == cmds[LOOP_E]) | |
{ | |
// if current pointer is non zero, go to start of the loop | |
if( (*(mem+pos) && !not) || (!*(mem+pos) && not) ) | |
{ | |
tmp = 1; | |
while(tmp) | |
{ | |
fseek(fp,-2,SEEK_CUR); | |
char c = fgetc(fp); | |
if(c == EOF) | |
break; | |
if(c == '[') | |
tmp -= 1; | |
if(c == ']') | |
tmp += 1; | |
continue; | |
} | |
// fprintf("%ld\n",ftell(fp)); // debug :) | |
} | |
} | |
if(tmp == cmds[IF]) | |
{ | |
// if else implementation | |
if( (!*(mem+pos) && !not) || (*(mem+pos) && not) ) | |
{ | |
tmp = 1; | |
while(tmp) | |
{ | |
tmp = fgetc(fp); | |
if(tmp == EOF) | |
break; | |
if(tmp == ':') | |
break; | |
continue; | |
} | |
} | |
} | |
if(tmp == cmds[INC]) | |
*(mem+pos) += 1; | |
if(tmp == cmds[DEC]) | |
*(mem+pos) -= 1; | |
if(tmp == cmds[PRINT]) | |
fputc(*(mem+pos),stdout); | |
if(tmp == cmds[INPUT]) | |
*(mem+pos) = fgetc(stdin); | |
// if(tmp == cmds[ELSE]) | |
// not = !not; | |
if(tmp == cmds[NOT]) | |
// not condition, easy peasy | |
not = !not; | |
if(tmp == cmds[JUMP]) | |
// jump condition | |
pos += *(mem+pos); | |
//usleep(1000); // 1ms delay :) | |
if(tmp != '!' && not) not = !not; | |
continue; | |
} | |
// free alloced stuff (if allocated properly) | |
if(mem) | |
free(mem); | |
printf("\n"); | |
continue; | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment