Last active
October 26, 2018 16:52
-
-
Save Sinthorion/2d2b350e4744d370f6566497047e2252 to your computer and use it in GitHub Desktop.
BFC interpreter in C, based on Erik Bosman's BF interpreter
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
/* | |
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