Skip to content

Instantly share code, notes, and snippets.

@wilfreddv
Last active November 2, 2021 21:47
Show Gist options
  • Save wilfreddv/e1c6886b75c066873c92c3662f6f4795 to your computer and use it in GitHub Desktop.
Save wilfreddv/e1c6886b75c066873c92c3662f6f4795 to your computer and use it in GitHub Desktop.
BrainF*ck interpreter and transpiler to C
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Bracemap
{
int left;
int right;
struct Bracemap *next;
} Bracemap;
char* read_file(const char* filename);
Bracemap* create_bracemap(char* code);
void run(const char* code, Bracemap* bracemap);
void compile(const char* code, const char* filename);
int main(int argc, char** argv)
{
FILE *fp;
char *code;
if( argc < 2 )
{
printf("Usage: %s FILENAME [-c]\n", argv[0]);
return 1;
}
code = read_file(argv[1]);
if( !code )
{
printf("Error opening file %s.", argv[1]);
return 1;
}
Bracemap *bracemap = create_bracemap(code);
if( !bracemap )
return 1;
if( argc == 3 && strcmp(argv[2], "-c") == 0 )
compile(code, argv[1]);
else
run(code, bracemap);
return 0;
}
char* read_file(const char* filename)
{
FILE *fp = fopen(filename, "r");
if( !fp )
return NULL;
char c, code[5000];
int code_ptr = 0;
while( (c = fgetc(fp)) != EOF )
switch(c)
{
case '<':
case '>':
case '-':
case '+':
case ',':
case '.':
case '[':
case ']':
code[code_ptr++] = c;
}
code[code_ptr++] = 0;
fclose(fp);
char* ret_code = malloc(sizeof(char) * code_ptr);
strcpy(ret_code, code);
return ret_code;
}
Bracemap* create_bracemap(char* code)
{
Bracemap *bracemap = malloc(sizeof(Bracemap));
Bracemap *current = NULL;
int brace_stack[100] = {0};
int sp = 0;
for( int i=0; code[i]; i++ )
if( code[i] == '[' )
{
brace_stack[sp++] = i;
}
else if( code[i] == ']' )
{
if( --sp < 0 )
{
printf("Too many closing brackets.\n");
return NULL;
}
if( current == NULL ) // Head
current = bracemap;
else
{
current->next = malloc(sizeof(Bracemap));
current = current->next;
current->next = NULL;
}
current->left = brace_stack[sp];
current->right = i;
}
if( sp > 0 )
{
printf("Too many opening brackets.\n");
return NULL;
}
return bracemap;
}
void error(const char* message)
{
puts(message);
exit(1);
}
int get_brace_pair(Bracemap* map, int index)
{
while(map)
{
if( map->left == index ) return map->right;
if( map->right == index ) return map->left;
map = map->next;
}
error("Bracket pair not found.");
}
void run(const char* code, Bracemap* bracemap)
{
int code_ptr=0, stack_ptr=0;
unsigned char stack[3000] = {0};
int code_len = strlen(code);
while( code_ptr < code_len )
{
switch(code[code_ptr])
{
case '+':
stack[stack_ptr]++;
break;
case '-':
stack[stack_ptr]--;
break;
case '>':
if( ++stack_ptr >= sizeof(stack) )
error("Stack size exceeded.");
break;
case '<':
if( --stack_ptr >= sizeof(stack) )
error("Stack below 0? Not possible!");
break;
case ',':
stack[stack_ptr] = getchar();
break;
case '.':
putchar(stack[stack_ptr]);
break;
case '[':
if( stack[stack_ptr] == 0 )
code_ptr = get_brace_pair(bracemap, code_ptr);
break;
case ']':
if( stack[stack_ptr] != 0 )
code_ptr = get_brace_pair(bracemap, code_ptr);
break;
}
code_ptr++;
}
}
void compile(const char* code, const char* filename)
{
char *fname = malloc(30*sizeof(char));
sprintf(fname, "%s.c", filename);
FILE *fp = fopen(fname, "w");
fputs("#include <stdio.h>\nint main()\n{\n", fp);
fputs(" unsigned char stack[30000] = {0};\n int sptr=0;\n", fp);
for( int i=0; code[i]; i++ )
{
switch(code[i])
{
case '>':
fputs(" ++sptr;\n", fp);
break;
case '<':
fputs(" --sptr;\n", fp);
break;
case '+':
fputs(" stack[sptr]++;\n", fp);
break;
case '-':
fputs(" stack[sptr]--;\n", fp);
break;
case '.':
fputs(" putchar(stack[sptr]);\n", fp);
break;
case ',':
fputs(" stack[sptr]=getchar();\n", fp);
break;
case '[':
fputs(" while(stack[sptr])\n {\n", fp);
break;
case ']':
fputs(" }\n", fp);
break;
}
}
fputs("return 0;\n}", fp);
fclose(fp);
char *command = malloc(40 * sizeof(char));
sprintf(command, "gcc %s -o %s.out", fname, filename);
system(command);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment