Skip to content

Instantly share code, notes, and snippets.

@spacelatte
Last active July 12, 2016 19:02
Show Gist options
  • Save spacelatte/ac28e5b95759d4786a5c25c98028f5df to your computer and use it in GitHub Desktop.
Save spacelatte/ac28e5b95759d4786a5c25c98028f5df to your computer and use it in GitHub Desktop.
extended* Brainfuck interpreter in C
#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