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

m
Fixed syntax highlighting.
(And Jesus wept! The test was right there!)
m (Fixed syntax highlighting.)
 
(One intermediate revision by one other user not shown)
Line 1:
{{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;
}
 
<syntaxhighlight 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 <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)
{
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;
 
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;
 
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>
 
if (ifd!=stdin) fclose(ifd);
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;
}
 
/* Execute the loaded BF program */
void bf_run(char *s) {
for(n=pgm; n; n=n->next)
int len = strlen(s), d = 0;
switch(n->cmd)
char *tape = calloc(len, sizeof(char));
{
int brack = 0;
case '+': m->val++; break;
case '-': m->val--; break;
for (; d >= 0 && *s; s++) {
case '.': putchar(m->val); break;
if (*s == '[') {
case ',': if((ch=getchar())!=EOF) m->val=ch; break;
char *p = ++s;
case '[': if (m->val == 0) n=n->jmp; break;
case ']': if (m->val != 0) n=n->jmp; break;
while(*p != ']') {
case '<':
int c = *p;
if (!(m=m->prev)) {
switch(c) {
fprintf(stderr, "%s: Hit start of tape\n", argv[0]);
case '+': tape[d]++; break;
exit(1);
case '-': tape[d]--; break;
}
case '>': d++; break;
case '<': d--; break;
case '>':
case '.': putchar(tape[d]); break;
if (m->next == 0) {
case ',': tape[d] = getchar(); break;
if ((m->next = calloc(1,sizeof*m)) == 0) {
case '[': p = nested_loop(p, tape, d); break;
perror(argv[0]); exit(1);
default: break;
}
}
m->next->prev = m;
}
m=m->next;
break;
}
 
return 0;
p++;
}</syntaxhighlight>
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>
9,476

edits