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

Removed first D entry, faster second entry
(Updated D entry)
(Removed first D entry, faster second entry)
Line 1:
{{implementation|Brainf***}}{{collection|RCBF}}
 
===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;
 
void brainfuckRun(in stringdstring code) nothrow {
static int[int] matchBraces(in stringdstring code) pure nothrow
out(result) {
foreach (immutable k, immutable v; result) {
assert(k >=0 && k < code.length);
assert(v >=0 && v < code.length);
assert(v in result);
}
} body {
Line 119 ⟶ 18:
loopStack ~= i;
else if (instruction == ']') {
assert(loops[loopStack.length)[$ - 1]] = i;
loops[i] = loopStack[$ - 1];
loopStack.length -= 1;
loops[loops[i]] = i;
}
}
Line 130 ⟶ 27:
}
 
static void runCode(in stringdstring 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) {
Line 153 ⟶ 52:
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 = loops[index]matching - 1;
break;
default:
Line 170 ⟶ 75:
}
 
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>
 
===Version 32===
FasterMuch faster version, code generated at compile-time, run at run-time:
<lang d>string ctbf(in string code) pure nothrow {
string r;