Brainf**k Interpreter


goobers

Member
Joined
Jan 22, 2007
Messages
344
Location
The UK
Website
Visit site
Hi,

Out of boredom, I decided to write a brainfuck interpreter today. It runs some programs, such as this one:

CODE

++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.


(prints "hello world")

but not others... I was wondering if I might have made an error in the interpreter, or perhaps have missed something.

I know probably a lot of people won't be knowledgeable on such things, but I thought I'd post it for the heck of it...

Wikipedia page on brainfuck

here is the code:

CODE

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

unsigned char* p;
unsigned char PC;
char* bfProg;
char bfCommand;

int loadFile(char * pFileName){
FILE * pFile;
long fSize;
size_t result;
pFileName = "test.b";

char * buffer;

pFile = fopen ( pFileName, "rb");
if (pFile==NULL) {fprintf(stderr, "Error opening file"); exit(1);}
else
{
fseek (pFile, 0, SEEK_END);
fSize = ftell (pFile);
rewind (pFile);

// Size the memory buffer to the size of the input file
buffer = (char*) malloc ((sizeof(char)*fSize));

if (buffer == NULL) {fprintf(stderr, "Error loading file into memory buffer"); exit(1);}

// Copy the file into the memory buffer
result = fread (buffer,1, fSize,pFile);
if (result != fSize) {fprintf(stderr, "Error reading file"); exit(1);}

bfProg = (char*) malloc ((sizeof(char)*fSize));
int j;
j=0;
for (int i=0; i < fSize; i++){
if (buffer == 0x3E || buffer == 0x3C || buffer == 0x2B || buffer == 0x2D || buffer == 0x2E || buffer == 0x2C || buffer == 0x5B || buffer == 0x5D){
bfProg[j] = buffer;
j +=1;
}



}
return 0;
}
}

int interpret(char bfCommand){

switch (bfCommand) {
case 0x3E: // >
++p;

PC +=1;
break;

case 0x3C: // <
--p;

PC +=1;
break;

case 0x2B: // +
++*p;

PC +=1;
break;

case 0x2D: // -
--*p;

PC +=1;
break;

case 0x2E: // .
putchar(*p);

PC +=1;
break;

case 0x2C: // ,
*p = getchar ();

PC +=1;
break;

case 0x5B: // [

if(*p){
PC +=1;
}

else{
while (bfProg[PC] != 0x5D){
PC +=1;
}
PC +=1;


}

break;

case 0x5D: // ]

if(*p){
while (bfProg[PC] != 0x5B){
PC -=1;
}
}

else{
PC +=1;
}

break;

}
}



int main(int argc, char *argv[])
{

p = (unsigned char*) malloc ((sizeof(char)*30000));
if (p == NULL){ exit (1); fprintf(stderr, "Memory Error");}
memset (p,0x00,30000);

PC = 0;
loadFile("test.b");

while (bfProg[PC] == 0x3E || bfProg[PC] == 0x3C || bfProg[PC] == 0x2B || bfProg[PC] == 0x2D || bfProg[PC] == 0x2E || bfProg[PC] == 0x2C || bfProg[PC] == 0x5B || bfProg[PC] == 0x5D){
interpret(bfProg[PC]);
//putchar(bfProg[PC]);
}



//bfProg


return 0;
}



Cheers
 
Goobers said:
CODE
unsigned char PC;
This is the program instruction pointer, right? I suppose the other programs are larger than 256 bytes, if so, then change the char to int... I've quickly scanned through your code, couldn't find any large problems (I've written one or two bf interpreters, so I know the basics). Also, could it be that getchar() is acting up?

What exactly happens with the other programs, do they crash?

Btw, nice to see you're keeping it official, with the 30000 byte buffer and all :)

Edit: do the other programs, the ones that don't run, contain non-bf characters? Like spaces or normal letters?
 
Last edited by a moderator:
I attempted to sort the issue of programs containing other characters by stepping through each character of the loaded file and if it is a BF instruction, copying it to the bfProg pointer.

I'll check the PC thing now (how could I be so stupid :p)

nope, still screwy-

I was trying to run this:

CODE

>++++++++++[<++++++++++>-]<->>>>>+++[>+++>+++<<-]<<<<+<[>[>+
>+<<-]>>[-<<+>>]++++>+<[-<->]<[[-]>>-<<]>>[[-]<<+>>]<<[[-]>>
>>>>[[-]<++++++++++<->>]<-[>+>+<<-]>[<+>-]+>[[-]<->]<<<<<<<<
<->>]<[>+>+<<-]>>[-<<+>>]+>+<[-<->]<[[-]>>-<<]>>[[-]<<+>>]<<
<[>>+>+<<<-]>>>[-<<<+>>>]++>+<[-<->]<[[-]>>-<<]>>[[-]<<+>>]<
<[>+<[-]]<[>>+<<[-]]>>[<<+>>[-]]<<<[>>+>+<<<-]>>>[-<<<+>>>]+
+++>+<[-<->]<[[-]>>-<<]>>[[-]<<+>>]<<[>+<[-]]<[>>+<<[-]]>>[<
<+>>[-]]<<[[-]>>>++++++++[>>++++++<<-]>[<++++++++[>++++++<-]
>.<++++++++[>------<-]>[<<+>>-]]>.<<++++++++[>>------<<-]<[-
>>+<<]<++++++++[<++++>-]<.>+++++++[>+++++++++<-]>+++.<+++++[
>+++++++++<-]>.+++++..--------.-------.++++++++++++++>>[>>>+
>+<<<<-]>>>>[-<<<<+>>>>]>+<[-<->]<[[-]>>-<<]>>[[-]<<+>>]<<<<
[>>>+>+<<<<-]>>>>[-<<<<+>>>>]+>+<[-<->]<[[-]>>-<<]>>[[-]<<+>
>]<<<[>>+<<[-]]>[>+<[-]]++>>+<[-<->]<[[-]>>-<<]>>[[-]<<+>>]<
+<[[-]>-<]>[<<<<<<<.>>>>>>>[-]]<<<<<<<<<.>>----.---------.<<
.>>----.+++..+++++++++++++.[-]<<[-]]<[>+>+<<-]>>[-<<+>>]+>+<
[-<->]<[[-]>>-<<]>>[[-]<<+>>]<<<[>>+>+<<<-]>>>[-<<<+>>>]++++
>+<[-<->]<[[-]>>-<<]>>[[-]<<+>>]<<[>+<[-]]<[>>+<<[-]]>>[<<+>
>[-]]<<[[-]>++++++++[<++++>-]<.>++++++++++[>+++++++++++<-]>+
.-.<<.>>++++++.------------.---.<<.>++++++[>+++<-]>.<++++++[
>----<-]>++.+++++++++++..[-]<<[-]++++++++++.[-]]<[>+>+<<-]>>
[-<<+>>]+++>+<[-<->]<[[-]>>-<<]>>[[-]<<+>>]<<[[-]++++++++++.
>+++++++++[>+++++++++<-]>+++.+++++++++++++.++++++++++.------
.<++++++++[>>++++<<-]>>.<++++++++++.-.---------.>.<-.+++++++
++++.++++++++.---------.>.<-------------.+++++++++++++.-----
-----.>.<++++++++++++.---------------.<+++[>++++++<-]>..>.<-
---------.+++++++++++.>.<<+++[>------<-]>-.+++++++++++++++++
.---.++++++.-------.----------.[-]>[-]<<<.[-]]<[>+>+<<-]>>[-
<<+>>]++++>+<[-<->]<[[-]>>-<<]>>[[-]<<+>>]<<[[-]++++++++++.[
-]<[-]>]<+<]





(99 bottles of beer ;))

and all I get is:

"8B Bottle of beer on the wall

Take one down and pass it around"

hm....

(As I recall, I don't think that 99 bottles of beer was in Hex:p)
 
Dunny said:
I wrote one as a challenge in Sinclair BASIC - it works, so you could probably compare to see if you do anything different.

If you're interested, it's at http://homepage.ntlworld.com/paul.dunn4/bf.bas

D.




Thanks dude, but I know it sounds stupid after writing in C, but I can't really understand that syntax:p

Used to write in basic all the time as a kid too :s
 
Last edited by a moderator:
Well, I haven't been bothered to fix the interpreter yet, but I did come up with the most annoying BF program ever:

CODE

++++++++++[>+++++++>++++++>+<<<-]>++>+++++>---[.<<.>.>]



Basically just plasters the screen with HAHAHAHA and beeps in an endless loop.

I'm SO easily amused :p
 
I'm thinking nested loops now... like [++[>++++<]--] (silly example, but you know what I'm mean). I'll try to fix it.

Edit: it ain't exactly pretty, but it works:
CODE
case 0x5B: // [
{
int nestedcount = 1;

if(*p) {
PC++;
}

else {
while (nestedcount) {
if (bfProg[PC+1] == '[')
nestedcount++;
if (bfProg[PC+1] == ']')
nestedcount--;
PC++;
}
}

break;
}

case 0x5D: // ]
{
int nestedcount = 1;

if(*p) {
while (nestedcount){
if (bfProg[PC-1] == ']')
nestedcount++;
if (bfProg[PC-1] == '[')
nestedcount--;
PC--;
}
} else {
PC ++;
}

break;
}


Now it runs 99 bottles.

"Amusing" sidenote:
This CODE
++++[>+++[>+++<-]<-]>>.
should output "$". I spent 20 minutes figuring out why the above code didn't work, only to find out I had placed a semicolon where it shouldn't be...
 
Optimised the subroutines out of the interpreter now - uses GOTO instead, with quite a surprising speed boost (and less memory used too!). Who said GOTO was evil?

CODE

10 REM Brainfuck Interpreter
20 CLEAR PEEK 23675+256*PEEK 23676-30020
30 LET e=0
40 LET c$="++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>."
50 LET p=20+PEEK 23730+256*PEEK 23731: GO TO 500
100 LET e=e+1: IF e>LEN c$ THEN STOP
110 IF c$(e)="+" THEN POKE p,PEEK p+1-(255*(PEEK p=255)): GO TO 100
120 IF c$(e)=">" THEN LET p=p+1: GO TO 100
130 IF c$(e)="<" THEN LET p=p-1: GO TO 100
140 IF c$(e)="-" THEN POKE p,PEEK p-1+(255*(PEEK p=0)): GO TO 100
150 IF c$(e)="." THEN PRINT CHR$ PEEK p;: GO TO 100
160 IF c$(e)="," THEN INPUT b$: POKE p,CODE b$: GO TO 100
170 IF c$(e)="[" THEN IF PEEK p=0 THEN GO TO 200
180 IF c$(e)="]" THEN IF PEEK p<>0 THEN GO TO 300
190 GO TO 100
200 LET b=1
210 LET e=e+1: IF c$(e)="[" THEN LET b=b+1
220 IF c$(e)="]" THEN LET b=b-1: IF b=0 THEN GO TO 100
230 GO TO 210
300 LET b=1
310 LET e=e-1: IF c$(e)="]" THEN LET b=b+1
320 IF c$(e)="[" THEN LET b=b-1: IF b=0 THEN GO TO 110
330 GO TO 310
500 RESTORE 510: FOR b=p-20 TO p-2: READ e: POKE b,e: NEXT b: RANDOMIZE USR (p-20): LET e=0: GO TO 100
510 DATA 237,91,178,92,33,20,0,25,1,48,117,84,93,54,0,19,237,176,201



Amazing that I can do this in so few lines compared to your C equivalent. Of course, you'll need a sinclair spectrum to run it on...

D.
 
Nice one! I had to try it too.

CODE

// bf
int main(){
char c[]="++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.";

int i,f=0;
char *p;

memset((p=malloc(30000)),0,30000);
do
switch(c[f]){
case '+':++*p;break;
case '-':--*p;break;
case '>':++p;break;
case '<':--p;break;
case '.':putchar(*p);break;
case ',':getchar(*p);break;
case '[':
i=1;
if(!(*p))
while(i){
i=(c[f+1]=='[')?(i+1):i;
i=(c[++f]==']')?(i-1):i;
}
break;

case ']':
i=1;
if((*p))
while(i){
i=(c[f-1]==']')?(i+1):i;
i=(c[--f]=='[')?(i-1):i;
}
break;
}
while(c[f++]);
free(p);
}


This is, ofcourse, without obfuscation and with indents. It could probably be a bit shorter.
 
You could try parsing the code into an array of function pointers and then execute the list. I don't know if this is possible in C, just an idea I have been thinking about implementing in my VNS interpreter (which is written in Python).
 
Found this one written in C:

CODE

char m[9999],*n[99],*r=m,*p=m+5000,**s=n,d,c;main(){for(read(0,r,4000);c=*r;
r++)c-']'||(d>1||(r=*p?*s:(--s,r)),!d||d--),c-'['||d++||(*++s=r),d||(*p+=c==
'+',*p-=c=='-',p+=c=='>',p-=c=='<',c-'.'||write(2,p,1),c-','||read(2,p,1));}



Pretty small... not sure I could compete :p

and this:

CODE

/* Eric */main(s,i,j,k,c){char*p=malloc(s=1),*a=p+(*p=i=j=k=0)/* Bock */
;while(~(*a=getchar())&&(++a-p<s||(a=(p=realloc(p,s+s))+s)&&(s+=s))||(*a
=0));for(a=malloc(s=1),*a=0;(c=p)&&(c=='+'&&++a[j]||c=='-'&&--a[j]||c
=='>'&&(++j<s||(a=realloc(a,s+s))&&memset(a+s,0,s)&&(s+=s))||c=='<'&&j--
||c=='.'&&~putchar(a[j])||c==','&&~(a[j]=getchar()))|!strchr("><.,",c);i
++)while((c=='['&&!a[j]||c==']'&&a[j])&&(k+=(p=='[')-(p==']'))&&p[
i+=c/* Brainf*** */=='[']&&(/* worse than */i-=c==']'/* this sig! */));}
 
Back
Top