Execute Brain****/C: Difference between revisions
Content deleted Content added
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. */
- 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;
}</lang>
This Brain**** interpreter is released into the Public domain or if your prefer the Creative commons CC0 license.