Execute Brain****/D: Difference between revisions
(Move 2 alternate implementations from Execute Brain****. http://rosettacode.org/mw/index.php?title=Execute_Brain****&action=history) |
(Version 1 updated) |
||
Line 1: | Line 1: | ||
{{implementation|Brainf***}}{{collection|RCBF}} |
{{implementation|Brainf***}}{{collection|RCBF}} |
||
== |
===Version 1=== |
||
{{works with|D|2.007+}} |
|||
An implementation of Rosetta Code [[Brainfuck|BrainF*ck]] interpreter in [[D]]. |
An implementation of Rosetta Code [[Brainfuck|BrainF*ck]] interpreter in [[D]]. |
||
Implement notes: |
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. |
*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. |
*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. |
*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; |
|||
<lang d>module rcbf ; |
|||
import std.file, std.c.stdio ; |
|||
alias void delegate() Act |
alias void delegate() Act; |
||
char[int] mem |
__gshared char[int] mem; // memory |
||
⚫ | |||
Act[char] cmd |
__gshared Act[char] cmd; // bf command except loop-control |
||
⚫ | |||
static this() { |
static this() { |
||
cmd['>'] = { if(!(++ptr in mem)) mem[ptr] = 0 |
cmd['>'] = { if (!(++ptr in mem)) mem[ptr] = 0; }; |
||
cmd['<'] = { if(!(--ptr in mem)) mem[ptr] = 0 |
cmd['<'] = { if (!(--ptr in mem)) mem[ptr] = 0; }; |
||
cmd['+'] = { mem[ptr] |
cmd['+'] = { mem[ptr]++; }; |
||
cmd['-'] = { mem[ptr] |
cmd['-'] = { mem[ptr]--; }; |
||
cmd['.'] = { |
cmd['.'] = { putchar(mem[ptr]); }; |
||
cmd[','] = { |
cmd[','] = { |
||
int c = getc(stdin); |
|||
⚫ | |||
⚫ | |||
mem[ptr] = cast(char)c; |
|||
⚫ | |||
} |
} |
||
void bf(string code) { |
void bf(in string code) { |
||
int cp = 0 |
int cp = 0; // code pointer |
||
int nested = 0 |
int nested = 0; // nested loop level |
||
Act bfAct() { |
Act bfAct() { |
||
Act[] acts |
Act[] acts; // store commands of current nesting level |
||
char cc; |
|||
⚫ | |||
switch(cc = code[cp++]) { // cc get next command and code pointer cp is advanced |
|||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
return { while(mem[ptr]) { foreach(x ; acts){x();} } } ; |
|||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
mem = null ; mem[0] = 0 ; ptr = 0 ; // reset memory |
|||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
} |
|||
⚫ | |||
⚫ | |||
// cc get next command and code pointer cp is advanced |
|||
cc = code[cp]; |
|||
cp++; |
|||
switch (cc) { |
|||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
break; |
|||
⚫ | |||
⚫ | |||
case ']': |
|||
nested--; |
|||
if (nested < 0) |
|||
⚫ | |||
return { |
|||
while (mem[ptr]) { |
|||
foreach (x; acts) |
|||
x(); |
|||
⚫ | |||
}; |
|||
⚫ | |||
if (cc in cmd) |
|||
⚫ | |||
⚫ | |||
} |
|||
} |
|||
return { |
|||
⚫ | |||
x(); |
|||
}; |
|||
⚫ | |||
// reset memory |
|||
mem = null; |
|||
mem[0] = 0; |
|||
ptr = 0; |
|||
⚫ | |||
if (nested != 0) |
|||
⚫ | |||
⚫ | |||
⚫ | |||
} |
} |
||
⚫ | |||
void main(in string[] args) { |
|||
⚫ | |||
// argument is treated as filename of bf source and executed. |
|||
if (args.length > 1) { |
|||
bf(readText(args[1])); |
|||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
++++[<------->-]<."); |
|||
} |
|||
⚫ | |||
== Implementation 2 == |
== Implementation 2 == |
Revision as of 23:51, 24 March 2012
Version 1
An implementation of Rosetta Code 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>
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>