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

From Rosetta Code
Content added Content deleted
No edit summary
m (Fixed syntax highlighting.)
 
(7 intermediate revisions by 3 users not shown)
Line 1: Line 1:
{{implementation|Brainf***}}{{collection|RCBF}}
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).


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).
<lang c>#include <stdio.h>
#include <string.h>
#include <stdlib.h>


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.
//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};


<syntaxhighlight lang="c">/* This is the Neutron brainfuck interpreter.
//The function to execute the Brainf*** code
* It's rather small and dense, but still readable, more or less.
enum retval_enum runCode(char *code, int cellnum);
*
* Robert de Bath -- 2013.
*/
#include <stdio.h>
#include <stdlib.h>
#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)
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;
//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
struct mem *m = calloc(1,sizeof*m);

setbuf(stdout, NULL);
unsigned int stat = runCode(",----------[++++++++++>,----------]<[.<]+++++++++++++.---.", 1000);
printf("\n\nDone running code\n");
switch(stat)
{
case INIT_ERROR_VALUES:
printf("Error initializing values.\n");
//Some jerk set the number of cells to 0
break;

case INIT_ERROR_MEMORY:
printf("Not enough memory.\n");
//Not enough memory to allocate an array of chars with length cellnum
break;

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;

case STARTLOOP_MISSING:
printf("Error in code. Start loop missing\n");
//An endloop was found without a startloop
break;

case ENDLOOP_MISSING:
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;


/* Open the file from the command line or stdin */
case '.':
if (argc < 2 || strcmp(argv[1], "-") == 0) ifd = stdin;
//Output current cell
else if ((ifd = fopen(argv[1], "r")) == 0) { perror(argv[1]); exit(1); }
putchar(p_cells[cell_iter]);
break;


/*
case ',':
* For each character, if it's a valid BF command add it onto the
//Grab 1 char input
* end of the program. If the input is stdin use the '!' character
p_cells[cell_iter]=getchar();
* to mark the end of the program and the start of the data, but
break;
* 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 */
case '[':
while(j) { p = j; j = j->jmp; p->jmp = 0; p->cmd = ' '; }
//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;


if (ifd!=stdin) fclose(ifd);
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;


/* Execute the loaded BF program */
default:
for(n=pgm; n; n=n->next)
//It's not a relevant char, ignore it.
switch(n->cmd)
break;
{
};
case '+': m->val++; break;
code_iter++;
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;
//Just clean up
}</syntaxhighlight>
free(p_cells);


This Brain**** interpreter is released into the Public domain or if your prefer the Creative commons CC0 license.
//We are done. Give an awesome goodness signal back!
return FINISHED;
}
</lang>

Latest revision as of 11:05, 1 September 2022

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.

/* This is the Neutron brainfuck interpreter.
 * It's rather small and dense, but still readable, more or less.
 *
 * Robert de Bath -- 2013.
 */
#include <stdio.h>
#include <stdlib.h>
#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;
}

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