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

From Rosetta Code
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 string code) nothrow {
void brainfuckRun(in dstring code) nothrow {
static int[int] matchBraces(in string code) pure nothrow
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 == ']') {
assert(loopStack.length);
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 string code, in int[int] loops) nothrow {
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 = loops[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 3===
===Version 2===
Faster version, code generated at compile-time, run at run-time:
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>