Skip to content

Instantly share code, notes, and snippets.

@Sinthorion
Last active October 26, 2018 16:52
Show Gist options
  • Save Sinthorion/2d2b350e4744d370f6566497047e2252 to your computer and use it in GitHub Desktop.
Save Sinthorion/2d2b350e4744d370f6566497047e2252 to your computer and use it in GitHub Desktop.
BFC interpreter in C, based on Erik Bosman's BF interpreter
/*
bfc.c: A BFC Layer 1 interpreter
Based on a Brainfuck interpreter written by Erik Bosman <ejbosman@cs.vu.nl>.
Modified by Sinthorion.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MEMORY_UNIT char
//#define MEMORY_UNIT unsigned short int
#define INITIAL_MEMORY 1024*sizeof(MEMORY_UNIT)
#define MEMORY_INCREASE 1024*sizeof(MEMORY_UNIT)
typedef struct
{
char type;
long quantity;
void *loop;
void *next;
} Instruction;
FILE *programFile;
MEMORY_UNIT *memory, *limit, *p;
Instruction *program;
// Error messages
int die(char *msg)
{
fprintf(stderr, "Error: %s\n", msg);
exit(1);
return 1; //Avoid warnings
}
// Dynamic memory allocation
void initialize_memory(size_t size)
{
(memory = (MEMORY_UNIT *)malloc(size)) || die("Cannot allocate memory");
limit = memory + size;
memset(memory, 0, size);
}
void expand_memory(size_t size)
{
size_t memsize = limit - memory + size;
size_t p_relative = p - memory;
(memory = (MEMORY_UNIT *)realloc(memory, memsize)) || die("Cannot allocate memory");
limit = memory + memsize;
p = p_relative + memory;
memset(limit - size, 0, size);
}
void free_list(Instruction *list)
{
Instruction *next;
while (list->type != ']')
{
next = list->next;
if (list->type == '[') free_list(list->loop);
free(list);
list = next;
}
free(list);
}
// Loading
int is_hex(char c)
{
return
(c >= '0' && c <= '9') ||
(c >= 'A' && c <= 'Z') ||
(c >= 'a' && c <= 'z');
}
long parse_hex(char c)
{
if (c >= '0' && c <= '9') return c - '0';
if (c >= 'A' && c <= 'Z') return 10 + c - 'A';
if (c >= 'a' && c <= 'z') return 10 + c - 'a';
die("c is no char");
}
Instruction *load()
{
char c, c2=0;
long l = 0;
Instruction *i = (Instruction *)malloc(sizeof(Instruction));
Instruction *first = i;
while (!feof(programFile))
{
c = fgetc(programFile);
i->type = c;
if (is_hex(c)) {
l = l * 16 + parse_hex(c);
continue;
}
switch (c)
{
case '[':
i->loop = load();
l = 0;
break;
case ']':
l = 0;
return first;
case '_':
l = 0;
break;
case '<': case '>': case '+': case '-': case ',': case '.':
if (l == 0) l = 1;
if (!feof(programFile))
{
while (!feof(programFile) && (c2 = fgetc(programFile)) == c) l++;
ungetc(c2, programFile);
}
i->quantity = l;
l = 0;
break;
default:
l = 0;
continue;
}
i->next = (Instruction *)malloc(sizeof(Instruction));
i = i->next;
}
i->type = ']';
return first;
}
// Program execution
void execute(Instruction *i);
void run(Instruction *list)
{
while (list->type != ']')
{
execute(list);
list = list->next;
}
}
void execute(Instruction *i)
{
long l;
switch (i->type)
{
case '>':
p += i->quantity;
while(p >= limit) expand_memory(MEMORY_INCREASE);
return;
case '<':
if (p - i->quantity < memory) die("Negative memory pointer");
p -= i->quantity;
return;
case '+':
*p += i->quantity;
return;
case '-':
*p -= i->quantity;
return;
case '.':
for (l=0; l<i->quantity; l++) putchar(*p);
return;
case ',':
for (l=0; l<i->quantity; l++) *p = getchar();
return;
case '[':
while (*p) run(i->loop);
return;
case '_':
*p = 0;
return;
default:
return;
}
}
// Main
int main(int argc, char **argv)
{
if (argc == 1)
{
fprintf(stderr, "usage: %s file\n", argv[0]);
exit(1);
}
if (!(programFile = fopen(argv[1], "r")))
{
fprintf(stderr, "Error: Cannot open file: %s\n", argv[1]);
exit(1);
}
initialize_memory(INITIAL_MEMORY);
p = memory + 0;
program = load();
run(program);
free_list(program);
free(memory);
fclose(programFile);
exit(0);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment