Execute Brain****/D: Difference between revisions
Content added Content deleted
(Updated D entry) |
(Removed first D entry, faster second entry) |
||
Line 1: | Line 1: | ||
{{implementation|Brainf***}}{{collection|RCBF}} |
{{implementation|Brainf***}}{{collection|RCBF}} |
||
===Version 1=== |
===Version 1=== |
||
An implementation of Rosetta Code [[Brainfuck|BrainF*ck]] interpreter in [[D]]. |
|||
Implement notes: |
|||
*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>import core.stdc.stdio, core.stdc.stdlib, std.file; |
|||
alias void delegate() Act; |
|||
__gshared char[int] mem; // memory |
|||
__gshared int ptr; // mem pointer |
|||
__gshared Act[char] cmd; // bf command except loop-control |
|||
static this() { |
|||
cmd['>'] = { if (!(++ptr in mem)) mem[ptr] = 0; }; |
|||
cmd['<'] = { if (!(--ptr in mem)) mem[ptr] = 0; }; |
|||
cmd['+'] = { mem[ptr]++; }; |
|||
cmd['-'] = { mem[ptr]--; }; |
|||
cmd['.'] = { putchar(mem[ptr]); }; |
|||
cmd[','] = { |
|||
int c = getc(stdin); |
|||
if (c == EOF) |
|||
exit(1); |
|||
mem[ptr] = cast(char)c; |
|||
}; |
|||
} |
|||
void bf(in 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) { |
|||
// cc get next command and code pointer cp is advanced |
|||
cc = code[cp]; |
|||
cp++; |
|||
switch (cc) { |
|||
case '[': |
|||
nested++; |
|||
acts ~= bfAct(); // begin inner loop |
|||
break; |
|||
case ']': |
|||
nested--; |
|||
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(); |
|||
}; |
|||
} |
|||
// reset memory |
|||
mem = null; |
|||
mem[0] = 0; |
|||
ptr = 0; |
|||
Act run = bfAct(); |
|||
if (nested != 0) |
|||
throw new Exception("Unmatched Loops"); |
|||
run(); // execute the whole bf program |
|||
printf("\n"); |
|||
} |
|||
void main(in string[] args) { |
|||
// if no argument, demo code will be run, else the first |
|||
// argument is treated as filename of bf source and executed. |
|||
if (args.length > 1) { |
|||
bf(readText(args[1])); |
|||
} else { |
|||
bf(">+++++++++[<+++++++++>-]<+.>+++[<----->-] |
|||
<.-.++++.>++++++[<------>-]<--.>++++++++[ |
|||
<+++++++++>-]<+.>++[<++>-]<+.>++++++++[<- |
|||
-------->-]<------.>++++++[<++++++>-]<.>+ |
|||
++++[<------->-]<."); |
|||
} |
|||
}</lang> |
|||
===Version 2=== |
|||
Simpler and faster: |
|||
<lang d>import core.stdc.stdio, core.stdc.stdlib, std.conv; |
<lang d>import core.stdc.stdio, core.stdc.stdlib, std.conv; |
||
void brainfuckRun(in |
void brainfuckRun(in dstring code) nothrow { |
||
static int[int] matchBraces(in |
static int[int] matchBraces(in dstring code) pure nothrow |
||
out(result) { |
out(result) { |
||
foreach (immutable k, immutable v; result) { |
foreach (immutable k, immutable v; result) { |
||
assert(k >=0 && k < code.length); |
assert(k >=0 && k < code.length); |
||
assert(v >=0 && v < code.length); |
assert(v >=0 && v < code.length); |
||
assert(v in result); |
|||
} |
} |
||
} body { |
} body { |
||
Line 119: | Line 18: | ||
loopStack ~= i; |
loopStack ~= i; |
||
else if (instruction == ']') { |
else if (instruction == ']') { |
||
loops[loopStack[$ - 1]] = i; |
|||
loops[i] = loopStack[$ - 1]; |
|||
loopStack.length -= 1; |
loopStack.length -= 1; |
||
loops[loops[i]] = i; |
|||
} |
} |
||
} |
} |
||
Line 130: | Line 27: | ||
} |
} |
||
static void runCode(in |
static void runCode(in dstring code, in int[int] loops) nothrow { |
||
enum char empty = '\0'; |
enum char empty = '\0'; |
||
char[30_000] tape = empty; |
char[30_000] tape = empty; |
||
int cell, index; |
int cell, index; |
||
int[10_000] stack; // Bracket stack |
|||
size_t stack_pos = 0; // Bracket stack position |
|||
while (index < code.length.signed) { |
while (index < code.length.signed) { |
||
Line 153: | Line 52: | ||
if (tape[cell] == empty) |
if (tape[cell] == empty) |
||
index = loops[index]; |
index = loops[index]; |
||
else { |
|||
stack[stack_pos] = index; |
|||
stack_pos++; |
|||
} |
|||
break; |
break; |
||
case ']': |
case ']': |
||
immutable matching = stack[stack_pos - 1]; |
|||
stack_pos -= 1; |
|||
if (tape[cell] != empty) |
if (tape[cell] != empty) |
||
index = |
index = matching - 1; |
||
break; |
break; |
||
default: |
default: |
||
Line 170: | Line 75: | ||
} |
} |
||
void main() { |
void main(in string[] args) { |
||
import std.file; |
|||
brainfuckRun("++++++++++[>+++++++>++++++++++>+++>+<<<<-] |
|||
>++.>+.+++++++..+++.>++.<<+++++++++++++++.>. |
|||
// if no argument, demo code will be run, else the first |
|||
+++.------.--------.>+.>."); |
|||
// argument is treated as filename of bf source and executed. |
|||
if (args.length > 1) { |
|||
args[1].readText.dtext.brainfuckRun; |
|||
} else { |
|||
brainfuckRun("++++++++++[>+++++++>++++++++++>+++>+<<<<-] |
|||
>++.>+.+++++++..+++.>++.<<+++++++++++++++.>. |
|||
+++.------.--------.>+.>."); |
|||
} |
|||
}</lang> |
}</lang> |
||
===Version |
===Version 2=== |
||
Much faster version, code generated at compile-time, run at run-time: |
|||
<lang d>string ctbf(in string code) pure nothrow { |
<lang d>string ctbf(in string code) pure nothrow { |
||
string r; |
string r; |
Revision as of 10:16, 27 November 2015
Execute Brain****/D is an implementation of Brainf***.
Other implementations of Brainf***.
Execute Brain****/D is part of RCBF. You may find other members of RCBF at Category:RCBF.
Version 1
<lang d>import core.stdc.stdio, core.stdc.stdlib, std.conv;
void brainfuckRun(in dstring code) nothrow {
static int[int] matchBraces(in dstring code) pure nothrow out(result) { foreach (immutable k, immutable v; result) { assert(k >=0 && k < code.length); assert(v >=0 && v < code.length); } } body { int[int] loops; int[] loopStack;
foreach (immutable i, immutable instruction; code) { if (instruction == '[') loopStack ~= i; else if (instruction == ']') { loops[loopStack[$ - 1]] = i; loopStack.length -= 1; } }
assert(!loopStack.length); return loops; }
static void runCode(in dstring code, in int[int] loops) nothrow { enum char empty = '\0'; char[30_000] tape = empty; int cell, index; int[10_000] stack; // Bracket stack size_t stack_pos = 0; // Bracket stack position
while (index < code.length.signed) { 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 ',': immutable int c = getchar; if (c == EOF) exit(1); tape[cell] = cast(char)c; break; case '[': if (tape[cell] == empty) index = loops[index]; else { stack[stack_pos] = index; stack_pos++; } break; case ']': immutable matching = stack[stack_pos - 1]; stack_pos -= 1; if (tape[cell] != empty) index = matching - 1; break; default: break; }
index++; } }
int[int] loops = matchBraces(code); runCode(code, loops);
}
void main(in string[] args) {
import std.file;
// if no argument, demo code will be run, else the first // argument is treated as filename of bf source and executed. if (args.length > 1) { args[1].readText.dtext.brainfuckRun; } else { brainfuckRun("++++++++++[>+++++++>++++++++++>+++>+<<<<-] >++.>+.+++++++..+++.>++.<<+++++++++++++++.>. +++.------.--------.>+.>."); }
}</lang>
Version 2
Much faster version, code generated at compile-time, run at run-time: <lang d>string ctbf(in string code) pure nothrow {
string r; foreach (immutable 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 ~= "m[i].putchar;"; break; case ',': r ~= "{ int d = getchar; if (d == EOF) exit(1); m[i] = cast(char)d; }"; break; default: break; } return r;
}
void main() {
import core.stdc.stdio, core.stdc.stdlib;
char[30_000] m = '\0'; size_t i; mixin(ctbf("++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++ ++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>."));
}</lang>