Execute Brain****/C: Difference between revisions

From Rosetta Code
Content added Content deleted
(And Jesus wept! The test was right there!)
(As none of the previous versions were correct I've replaced them completely.)
Line 1: Line 1:
{{implementation|Brainf***}}{{collection|RCBF}}
{{implementation|Brainf***}}{{collection|RCBF}}
==Version 1==
{{incorrect|C|This version is not standard C; C does not allow nested functions}}
Simple BF engine with infinite tape support.
<lang c>#include <stdio.h>
#include <stdlib.h>
#include <string.h>


This Brain**** interpreter has an eight bit cell size with the tape length bounded only by available memory. The normal [http://esolangs.org/wiki/Brainfuck_bitwidth_conversions cell expansion techniques] work for brain**** programs that require a larger cell size (or you can just change the tape cell type).
void bf_run(char *s) {
int len = 1, d = 0;
char *tape = calloc(len, 1);


It is a fairly slow interpreter which is probably able to run [http://esoteric.sange.fi/brainfuck/utils/mandelbrot/mandelbrot.b mandelbrot.b] in about a minute on your machine.
int run(int skip) {
for (; d >= 0 && *s; s++) {
if (d >= len) {
tape = realloc(tape, len * 2);
memset(tape + len, 0, len);
len = len * 2;
}


<lang c>/* This is the Neutron brainfuck interpreter.
if (*s == ']') return tape[d];
* It's rather small and dense, but still readable, more or less.
if (*s == '[') {
*
char *p = ++s;
* Robert de Bath -- 2013.
while (run(!tape[d])) s = p;
*/
continue;
#include <stdio.h>
}
#include <stdlib.h>

if (skip) continue;

#define CASE(a, b) if (*s == a) { b; continue; }
CASE('+', tape[d]++);
CASE('-', tape[d]--);
CASE('>', d++);
CASE('<', d--);
CASE('.', putchar(tape[d]));
CASE(',', tape[d] = getchar());
}
return 0;
}

run(0);
free(tape);
}

int main(void) {
bf_run( "++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++.."
"+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.");

return 0;
}</lang>

This is a simple function that will run Brain**** code.
The code can be fed from a file or anything else. Here it's entered directly (it reverses a string you type).

==Version 2==
{{incorrect}}
The below Hello World fails.
<pre>
>++++++++[<+++++++++>-]<.>>+>+>++>[-]+<[>[->+<<++++>]<<]>.+++++++..+++.>
>+++++++.<<<[[-]<[-]>]<+++++++++++++++.>>.+++.------.--------.>>+.>++++.
</pre>
<lang c>#include <stdio.h>
#include <string.h>
#include <string.h>
#include <stdlib.h>

//Making it easier to understand. All for you guys <3
enum retval_enum{INIT_ERROR_VALUES, INIT_ERROR_MEMORY, RUN_ERROR_BOUNDARIES, ENDLOOP_MISSING, STARTLOOP_MISSING, FINISHED};

//The function to execute the Brainf*** code
enum retval_enum runCode(char *code, int cellnum);


struct bfi { char cmd; struct bfi *next, *jmp; };
struct mem { char val; struct mem *next, *prev; };


int main(int argc, char **argv)
int main(int argc, char **argv)
{
{
FILE * ifd;
printf("Running code\n\n");
int ch;
struct bfi *p=0, *n=0, *j=0, *pgm = 0;
struct mem *m = calloc(1,sizeof*m);
setbuf(stdout, NULL);


/* Open the file from the command line or stdin */
//Run some code to test. I think this is a Hello World program. The code can be read from a file or whatever else is wanted
if (argc < 2 || strcmp(argv[1], "-") == 0) ifd = stdin;
else if ((ifd = fopen(argv[1], "r")) == 0) { perror(argv[1]); exit(1); }


/*
unsigned int stat = runCode(",----------[++++++++++>,----------]<[.<]+++++++++++++.---.", 1000);
* For each character, if it's a valid BF command add it onto the
printf("\n\nDone running code\n");
* end of the program. If the input is stdin use the '!' character
switch(stat)
* to mark the end of the program and the start of the data, but
{
* only if we have a complete program. The 'j' variable points
case INIT_ERROR_VALUES:
* at the list of currently open '[' commands, one is matched off
printf("Error initializing values.\n");
* by each ']'. A ']' without a matching '[' is not a legal BF
//Some jerk set the number of cells to 0
* command and so is ignored. If there are any '[' commands left
break;
* over at the end they are not valid BF commands and so are ignored.
*/
while((ch = getc(ifd)) != EOF && (ifd!=stdin || ch != '!' || j || !pgm)) {
if (ch == '<' || ch == '>' || ch == '+' || ch == '-' ||
ch == ',' || ch == '.' || ch == '[' || (ch == ']' && j)) {
if ((n = calloc(1, sizeof*n)) == 0) {
perror(argv[0]); exit(1);
}
if (p) p->next = n; else pgm = n;
n->cmd = ch; p = n;
if (n->cmd == '[') { n->jmp=j; j = n; }
else if (n->cmd == ']') {
n->jmp = j; j = j->jmp; n->jmp->jmp = n;
}
}
}


/* Ignore any left over '[' commands */
case INIT_ERROR_MEMORY:
while(j) { p = j; j = j->jmp; p->jmp = 0; p->cmd = ' '; }
printf("Not enough memory.\n");
//Not enough memory to allocate an array of chars with length cellnum
break;


if (ifd!=stdin) fclose(ifd);
case RUN_ERROR_BOUNDARIES:
printf("Boundary error in BF prog\n");
//Whilst running, the cell iterator got below 0 or over cellnum. ie. not enough cells
break;


/* Execute the loaded BF program */
case STARTLOOP_MISSING:
for(n=pgm; n; n=n->next)
printf("Error in code. Start loop missing\n");
switch(n->cmd)
//An endloop was found without a startloop
{
break;
case '+': m->val++; break;
case '-': m->val--; break;
case '.': putchar(m->val); break;
case ',': if((ch=getchar())!=EOF) m->val=ch; break;
case '[': if (m->val == 0) n=n->jmp; break;
case ']': if (m->val != 0) n=n->jmp; break;
case '<':
if (!(m=m->prev)) {
fprintf(stderr, "%s: Hit start of tape\n", argv[0]);
exit(1);
}
break;
case '>':
if (m->next == 0) {
if ((m->next = calloc(1,sizeof*m)) == 0) {
perror(argv[0]); exit(1);
}
m->next->prev = m;
}
m=m->next;
break;
}


return 0;
case ENDLOOP_MISSING:
}</lang>
printf("Error in code. End loop missing\n");
//A Startloop was found without an endloop
break;

case FINISHED:
printf("Finished with no problems\n");
//Code finished without any probs
break;
};

return 0;
}

enum retval_enum runCode(char *code, int cellnum)
{
//Returns with enum on failure
if(cellnum==0)
return INIT_ERROR_VALUES;

//Allocate memory for cells
unsigned char *p_cells = 0;
p_cells = (unsigned char*) malloc(cellnum);
if(p_cells == 0)
return INIT_ERROR_MEMORY;

int cell_iter = 0;
int code_len = strlen(code);
int code_iter = 0;

//iter is changed according to code
while(code_iter < code_len)
{
switch(code[code_iter])
{
case '+':
//Just increase. If it overflows, it'll become 0
p_cells[cell_iter]++;
break;

case '-':
//"Underflowing" will cause it to be max(int)
p_cells[cell_iter]--;
break;

case '>':
//Move pointer and check boundaries
cell_iter++;
if(cell_iter == cellnum)
{
free(p_cells);
return RUN_ERROR_BOUNDARIES;
}
break;

case '<':
//Move pointer and check boundaries
cell_iter--;
if(cell_iter<0)
{
free(p_cells);
return RUN_ERROR_BOUNDARIES;
}
break;

case '.':
//Output current cell
putchar(p_cells[cell_iter]);
break;

case ',':
//Grab 1 char input
p_cells[cell_iter]=getchar();
break;

case '[':
//If current cell is 0, run to the next ']'
if(p_cells[cell_iter]==0)
while(code[code_iter]!=']')
{
code_iter++;
if(code_iter>=code_len)
{
free(p_cells);
return ENDLOOP_MISSING;
}
}
break;

case ']':
//Run all the way back before the last '['
while(code[code_iter]!='[')
{
code_iter--;
if(code_iter<0)
{
free(p_cells);
return STARTLOOP_MISSING;
}
}
code_iter--;
break;

default:
//It's not a relevant char, ignore it.
break;
};
code_iter++;
};

//Just clean up
free(p_cells);

//We are done. Give an awesome goodness signal back!
return FINISHED;
}
</lang>

==Version 3==
{{incorrect}}
The below Hello World fails.
<pre>
>++++++++[<+++++++++>-]<.>>+>+>++>[-]+<[>[->+<<++++>]<<]>.+++++++..+++.>
>+++++++.<<<[[-]<[-]>]<+++++++++++++++.>>.+++.------.--------.>>+.>++++.
</pre>
This is a modified code of Version 1. It happens to be Standard C.

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

char *nested_loop (char *s, char *tape, int d) {
char *p = ++s;
while(*p != ']') {
int c = *p;
switch(c) {
case '+': tape[d]++; break;
case '-': tape[d]--; break;
case '>': d++; break;
case '<': d--; break;
case '.': putchar(tape[d]); break;
case ',': tape[d] = getchar(); break;
case '[': p = nested_loop(p, tape, d); break;
default: break;
}
p++;
if(*p == ']' && tape[d] != 0) p = s;
}
return p;
}

void bf_run(char *s) {
int len = strlen(s), d = 0;
char *tape = calloc(len, sizeof(char));
int brack = 0;
for (; d >= 0 && *s; s++) {
if (*s == '[') {
char *p = ++s;
while(*p != ']') {
int c = *p;
switch(c) {
case '+': tape[d]++; break;
case '-': tape[d]--; break;
case '>': d++; break;
case '<': d--; break;
case '.': putchar(tape[d]); break;
case ',': tape[d] = getchar(); break;
case '[': p = nested_loop(p, tape, d); break;
default: break;
}

p++;
if(*p == ']' && tape[d] != 0) p = s;
}
s = p + 1;
}
#define CASE(a, b) if (*s == a) { b; continue; }
CASE('+', tape[d]++);
CASE('-', tape[d]--);
CASE('>', d++);
CASE('<', d--);
CASE('.', putchar(tape[d]));
CASE(',', tape[d] = getchar());
}
free(tape);
}


This Brain**** interpreter is released into the Public domain or if your prefer the Creative commons CC0 license.
int main(void) {
bf_run("--------[-->+++<]>.------------.---.--[--->+<]>-.----[->++++<]>+.++++."
"------------.------.++++++++.-[++>---<]>+.[->+++<]>++.[--->+<]>----.---."
"++++++++.---------.-[->+++++<]>-.++[->+++<]>.+++++++++.+++++++++.[---->+<]"
">++.-[--->++<]>.+++++++++++.--------.+++.+++.+[---->+<]>+++.+++++[->+++<]>"
".+++++++.+[->+++<]>.+++++++++++++.[-->+++++<]>+++.---[->++++<]>.----------"
"--.---.--[--->+<]>-.++[--->++<]>.-----------.+[----->+<]>.-.-[---->+<]>++."
"+[->+++<]>+.+++++++++++.--------.--[->+++<]>-.,"); //the quick brown fox jumps over the lazy dog.
return 0;
}
</lang>

Revision as of 00:57, 20 June 2015

Execute Brain****/C is an implementation of Brainf***. Other implementations of Brainf***.
Execute Brain****/C is part of RCBF. You may find other members of RCBF at Category:RCBF.

This Brain**** interpreter has an eight bit cell size with the tape length bounded only by available memory. The normal cell expansion techniques work for brain**** programs that require a larger cell size (or you can just change the tape cell type).

It is a fairly slow interpreter which is probably able to run mandelbrot.b in about a minute on your machine.

<lang c>/* This is the Neutron brainfuck interpreter.

* It's rather small and dense, but still readable, more or less.
*
* Robert de Bath -- 2013.
*/
  1. include <stdio.h>
  2. include <stdlib.h>
  3. include <string.h>

struct bfi { char cmd; struct bfi *next, *jmp; }; struct mem { char val; struct mem *next, *prev; };

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

   FILE * ifd;
   int ch;
   struct bfi *p=0, *n=0, *j=0, *pgm = 0;
   struct mem *m = calloc(1,sizeof*m);
   setbuf(stdout, NULL);
   /* Open the file from the command line or stdin */
   if (argc < 2 || strcmp(argv[1], "-") == 0) ifd = stdin;
   else if ((ifd = fopen(argv[1], "r")) == 0) { perror(argv[1]); exit(1); }
   /*
    *  For each character, if it's a valid BF command add it onto the
    *  end of the program. If the input is stdin use the '!' character
    *  to mark the end of the program and the start of the data, but
    *  only if we have a complete program.  The 'j' variable points
    *  at the list of currently open '[' commands, one is matched off
    *  by each ']'.  A ']' without a matching '[' is not a legal BF
    *  command and so is ignored.  If there are any '[' commands left
    *  over at the end they are not valid BF commands and so are ignored.
    */
   while((ch = getc(ifd)) != EOF && (ifd!=stdin || ch != '!' || j || !pgm)) {
       if (ch == '<' || ch == '>' || ch == '+' || ch == '-' ||
           ch == ',' || ch == '.' || ch == '[' || (ch == ']' && j)) {
           if ((n = calloc(1, sizeof*n)) == 0) {
               perror(argv[0]); exit(1);
           }
           if (p) p->next = n; else pgm = n;
           n->cmd = ch; p = n;
           if (n->cmd == '[') { n->jmp=j; j = n; }
           else if (n->cmd == ']') {
               n->jmp = j; j = j->jmp; n->jmp->jmp = n;
           }
       }
   }
   /* Ignore any left over '[' commands */
   while(j) { p = j; j = j->jmp; p->jmp = 0; p->cmd = ' '; }
   if (ifd!=stdin) fclose(ifd);
   /* Execute the loaded BF program */
   for(n=pgm; n; n=n->next)
       switch(n->cmd)
       {
           case '+': m->val++; break;
           case '-': m->val--; break;
           case '.': putchar(m->val); break;
           case ',': if((ch=getchar())!=EOF) m->val=ch; break;
           case '[': if (m->val == 0) n=n->jmp; break;
           case ']': if (m->val != 0) n=n->jmp; break;
           case '<':
               if (!(m=m->prev)) {
                   fprintf(stderr, "%s: Hit start of tape\n", argv[0]);
                   exit(1);
               }
               break;
           case '>':
               if (m->next == 0) {
                   if ((m->next = calloc(1,sizeof*m)) == 0) {
                       perror(argv[0]); exit(1);
                   }
                   m->next->prev = m;
               }
               m=m->next;
               break;
       }
   return 0;

}</lang>

This Brain**** interpreter is released into the Public domain or if your prefer the Creative commons CC0 license.