Execute Brain****/D: Difference between revisions
m (moved RCBF/D to Execute Brain****/D) |
(Move 2 alternate implementations from Execute Brain****. http://rosettacode.org/mw/index.php?title=Execute_Brain****&action=history) |
||
Line 1:
{{implementation|Brainf***}}{{collection|RCBF}}
== Implementation 1 ==
{{works with|D|2.007+}}
An implementation of Rosetta Code [[Brainfuck|BrainF*ck]] interpreter in [[D]].
Line 70 ⟶ 72:
}
</lang>
== Implementation 2 ==
Alternative version, simpler and faster:
<lang d>import core.stdc.stdio: getchar, putchar, EOF;
import core.stdc.stdlib: exit;
void brainfuckRun(const string code) {
static pure int[int] matchBraces(const string code)
out(result) {
foreach (k, v; result) {
assert(k >=0 && k < code.length);
assert(v >=0 && v < code.length);
assert(v in result);
}
} body {
int[int] loops;
int[] loopStack;
foreach (i, instruction; code) {
if (instruction == '[')
loopStack ~= i;
else if (instruction == ']') {
assert(loopStack.length);
loops[i] = loopStack[$ - 1];
loopStack.length -= 1;
loops[loops[i]] = i;
}
}
assert(!loopStack.length);
return loops;
}
static void runCode(const string code, const int[int] loops) {
enum char empty = '\0';
char[30_000] tape = empty;
int cell, index;
while (index < cast(int)code.length) {
immutable int instruction = code[index];
switch (instruction) {
case '>': cell++; assert(cell < tape.length); break;
case '<': cell--; assert(cell >= 0); break;
case '+': tape[cell]++; break;
case '-': tape[cell]--; break;
case '.': putchar(tape[cell]); break;
case ',':
int c = getchar();
if (c == EOF)
exit(1);
tape[cell] = cast(char)c;
break;
case '[':
if (tape[cell] == empty)
index = loops[index];
break;
case ']':
if (tape[cell] != empty)
index = loops[index];
break;
default: break;
}
index++;
}
}
int[int] loops = matchBraces(code);
runCode(code, loops);
}
void main() {
brainfuckRun("++++++++++[>+++++++>++++++++++>+++>+<<<<-]
>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.");
}</lang>
== Implementation 3 ==
Faster partially compile-time version (code generated at compile-time, run at run time):
<lang d>import core.stdc.stdio, core.stdc.stdlib;
pure string ctbf(in string code) {
string r;
foreach (c; code)
switch (c) {
case '>': r ~= "i++; assert(i < m.length);"; break;
case '<': r ~= "i--; assert(i >= 0);"; break;
case '+': r ~= "m[i]++;"; break;
case '-': r ~= "m[i]--;"; break;
case '[': r ~= "while (m[i]) {"; break;
case ']': r ~= "}"; break;
case '.': r ~= "putchar(m[i]);"; break;
case ',': r ~= "int d = getchar();
if (d == EOF) exit(1);
m[i] = cast(char)d;"; break;
default: break;
}
return r;
}
void main() {
char[30_000] m = '\0';
size_t i;
mixin(ctbf("++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++
++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>."));
}</lang>
|
Revision as of 17:51, 29 September 2011
Implementation 1
An implementation of Rosetta Code BrainF*ck interpreter in D.
Implement notes:
- Needs D version 2.007+, because closure support is required (it should compile in D1, but will run abnormally if brackets/loop-commands are in the BF source).
- Memory is represented by an associative array, so that negative addresses are allowed, though it is not efficient.
- Input and output are in character mode, rather than in numerical.
- Nesting level is checked during parsing, and if loops/brackets are not matched, an error is thrown before executing the code.
<lang d>module rcbf ; import std.file, std.c.stdio ;
alias void delegate() Act ;
char[int] mem ; // memory Act[char] cmd ; // bf command except loop-control int ptr ; // mem pointer
static this() {
cmd['>'] = { if(!(++ptr in mem)) mem[ptr] = 0 ; } ; cmd['<'] = { if(!(--ptr in mem)) mem[ptr] = 0 ; } ; cmd['+'] = { mem[ptr] += 1 ; } ; cmd['-'] = { mem[ptr] -= 1 ; } ; cmd['.'] = { printf("%c", mem[ptr]) ; } ; cmd[','] = { printf("%c", mem[ptr] = getch()) ; flushall ; } ;
}
void bf(string code) {
int cp = 0 ; // code pointer int nested = 0 ; // nested loop level
Act bfAct() { Act[] acts ; // store commands of current nesting level char cc ; while(cp < code.length) switch(cc = code[cp++]) { // cc get next command and code pointer cp is advanced case '[': nested++ ; acts ~= bfAct() ; // begin inner loop break ; case ']': if(--nested < 0) throw new Exception("Unmatched Loops") ; return { while(mem[ptr]) { foreach(x ; acts){x();} } } ; default: if(cc in cmd) acts ~= cmd[cc] ; //else ignore other non-command char } return { foreach(x ; acts){x();} } ; } mem = null ; mem[0] = 0 ; ptr = 0 ; // reset memory Act run = bfAct() ; if(nested != 0) throw new Exception("Unmatched Loops") ; run() ; // execute the whole bf program printf("\n") ;
}
void main(string[] args) { // if no argument, demo code will be run, else
if(args.length > 1) // the arguments are treated as filenames of bf source foreach(f ; args[1..$]) // and executed one by one. try bf(cast(string)read(f)) ; catch (Exception e) printf("%*s",e.msg) ; else bf(">+++++++++[<+++++++++>-]<+.>+++[<----->-]" "<.-.++++.>++++++[<------>-]<--.>++++++++[" "<+++++++++>-]<+.>++[<++>-]<+.>++++++++[<-" "-------->-]<------.>++++++[<++++++>-]<.>+" "++++[<------->-]<.") ;
} </lang>
Implementation 2
Alternative version, simpler and faster: <lang d>import core.stdc.stdio: getchar, putchar, EOF; import core.stdc.stdlib: exit;
void brainfuckRun(const string code) {
static pure int[int] matchBraces(const string code) out(result) { foreach (k, v; result) { assert(k >=0 && k < code.length); assert(v >=0 && v < code.length); assert(v in result); } } body { int[int] loops; int[] loopStack;
foreach (i, instruction; code) { if (instruction == '[') loopStack ~= i; else if (instruction == ']') { assert(loopStack.length); loops[i] = loopStack[$ - 1]; loopStack.length -= 1; loops[loops[i]] = i; } }
assert(!loopStack.length); return loops; }
static void runCode(const string code, const int[int] loops) { enum char empty = '\0'; char[30_000] tape = empty; int cell, index;
while (index < cast(int)code.length) { immutable int instruction = code[index];
switch (instruction) { case '>': cell++; assert(cell < tape.length); break; case '<': cell--; assert(cell >= 0); break; case '+': tape[cell]++; break; case '-': tape[cell]--; break; case '.': putchar(tape[cell]); break; case ',': int c = getchar(); if (c == EOF) exit(1); tape[cell] = cast(char)c; break; case '[': if (tape[cell] == empty) index = loops[index]; break; case ']': if (tape[cell] != empty) index = loops[index]; break; default: break; }
index++; } }
int[int] loops = matchBraces(code); runCode(code, loops);
}
void main() {
brainfuckRun("++++++++++[>+++++++>++++++++++>+++>+<<<<-] >++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.");
}</lang>
Implementation 3
Faster partially compile-time version (code generated at compile-time, run at run time): <lang d>import core.stdc.stdio, core.stdc.stdlib;
pure string ctbf(in string code) {
string r; foreach (c; code) switch (c) { case '>': r ~= "i++; assert(i < m.length);"; break; case '<': r ~= "i--; assert(i >= 0);"; break; case '+': r ~= "m[i]++;"; break; case '-': r ~= "m[i]--;"; break; case '[': r ~= "while (m[i]) {"; break; case ']': r ~= "}"; break; case '.': r ~= "putchar(m[i]);"; break; case ',': r ~= "int d = getchar(); if (d == EOF) exit(1); m[i] = cast(char)d;"; break; default: break; } return r;
}
void main() {
char[30_000] m = '\0'; size_t i; mixin(ctbf("++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++ ++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>."));
}</lang>