Skip to content

Instantly share code, notes, and snippets.

@Johann150
Last active August 17, 2019 00:10
Show Gist options
  • Save Johann150/4cbfb6e7c3a91093e187e839612c4963 to your computer and use it in GitHub Desktop.
Save Johann150/4cbfb6e7c3a91093e187e839612c4963 to your computer and use it in GitHub Desktop.
stream brainfuck interpreter (Also supports Alphuck,Ecstatic
/*
A stream brainfuck interpreter, the input will be read only once.
Also supports Alphuc (https://esolangs.org/wiki/Alphuck),
FuckbeEs (https://esolangs.org/wiki/FuckbeEs),
ReverseFuck (https://esolangs.org/wiki/ReverseFuck),
and the whole TrivialBrainfuckSubstitution (https://esolangs.org/wiki/TrivialBrainfuckSubstitution) language family.
*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void usage(char *name){
fprintf(stderr,"USAGE:\n\t%s [-a <alphabet>] [<file>]\n\tOR\n\tbf -?\n\tOR\n\tbf --help"
"\n\t-? / --help\tA switch to show this help menu. The program will terminate after showing this usage information."
"\n\t<alphabet>\t[OPTIONAL] A sequence of eight unique characters to be used instead of the default alphabet of \"<>+-,.[]\"."
"\n\t<file>\t[OPTIONAL] The file to be interpreted. If not supplied, stdin will be used.\n"
"\n\tThe program will put only the output generated by the Brainfuck program to stdout and any errors to stderr.",name);
}
char alphabet[8];
char *buf=NULL;
unsigned long buf_pos=0;
unsigned long buf_size=0;
unsigned long *loops=NULL;
unsigned long level=0;
// true if currently reading from the buffer instead of stdin
short readback=0;
char memory[30000];
int mem_pos=0;
int skip(){
int level=1;
char c;
do{
if(readback){
c=buf[buf_pos++];
}else{
c=getchar();
}
if(c==']'){
level--;
}else if(c=='['){
level++;
}
}while(level>0);
}
int buf_put(char c){
// keep chars in buffer
if(buf_size==buf_pos){
// try to resize the buffer to fit the additional characters
buf=realloc(buf,(buf_size+=40)*sizeof(char));
if(buf==NULL){
fputs("?memory\n",stderr);
return 1;
}
}
buf[buf_pos++]=c;
}
int check_alph(char* a){
// check alphabet length
if(strlen(a)!=8) return 0;
/*
check that characters are unique;
check does not have to be performed for last character,
since it has been crosschecked by every other character before
*/
for(int i=0;i<7;i++)
if(strchr(a+i+1,a[i])!=NULL) return 0;
return 1;
}
int main(int argc,char** argv){
memcpy(alphabet,"<>+-,.[]",8); // setup default alphabet
for(int i=1;i<argc;i++){
if(strcmp(argv[i],"-?")==0||strcmp(argv[i],"--help")==0){
fputs("Brainfuck interpreter\n",stderr);
usage(argv[0]);
return 0;
}else if(strcmp(argv[i],"-a")==0){
if(check_alph(argv[++i])){
memcpy(alphabet,argv[i++],8);
}else{
fputs("?alphabet",stderr);
usage(argv[0]);
return 1;
}
}else{
// just redirect file and read from stdin anyway
if(freopen(argv[1],"r",stdin)==NULL){
fputs("file not found\n",stderr);
usage(argv[0]);
return 1;
}
}
}
while(!feof(stdin)){
char c;
if(readback){
c=buf[buf_pos++];
}else{
// transformed to alphabet index
c=getchar();
if(strchr(alphabet,c)==NULL)
// this character is not relevant
continue;
c=strchr(alphabet,c)-alphabet;
}
switch(c){// switch on the index in the alphabet
case 0:
if(mem_pos==0)
mem_pos=30000;
mem_pos--;
break;
case 1:
mem_pos=(mem_pos+1)%30000;
break;
case 2:
memory[mem_pos]++;
break;
case 3:
memory[mem_pos]--;
break;
case 4:
printf("%d",memory[mem_pos]);
break;
case 5:
printf("%c",memory[mem_pos]);
break;
case 6:
if(memory[mem_pos]==0){
skip();
}else if (!readback){
// if readback is already set, this will have already been saved
loops=realloc(loops,(level++)*sizeof(unsigned long));
if(level>1){
if(loops==NULL){
fputs("?memory\n",stderr);
return 1;
}
loops[level-2]=buf_pos;
}
}
break;
case 7:
if(level==0){
fputs("?syntax missing opening bracket\n",stderr);
return 2;
}
if(memory[mem_pos]==0){
level--;
if(level==0){
readback=0;
// reset buffer
buf=realloc(buf,buf_pos=buf_size=0);
}
}else{
if(!readback){
buf_put(']');
// go back to beginning of loop
readback=1;
}
if(level==1){
buf_pos=0;
}else{
buf_pos=loops[level-2];
}
}
break;
}
if(level&&!readback&&c!=']'){
// make sure the caracter is saved if needed
buf_put(c);
}
}
if(level){
fputs("?syntax missing closing bracket\n",stderr);
// free used memory
free(buf);
free(loops);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment