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

From Rosetta Code
Content added Content deleted
(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}}


== Implementation 1 ==
===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 ; // memory
__gshared char[int] mem; // memory
__gshared int ptr; // mem pointer
Act[char] cmd ; // bf command except loop-control
__gshared Act[char] cmd; // bf command except loop-control
int ptr ; // mem pointer


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] += 1 ; } ;
cmd['+'] = { mem[ptr]++; };
cmd['-'] = { mem[ptr] -= 1 ; } ;
cmd['-'] = { mem[ptr]--; };
cmd['.'] = { printf("%c", mem[ptr]) ; } ;
cmd['.'] = { putchar(mem[ptr]); };
cmd[','] = { printf("%c", mem[ptr] = getch()) ; flushall ; } ;
cmd[','] = {
int c = getc(stdin);
if (c == EOF)
exit(1);
mem[ptr] = cast(char)c;
};
}
}


void bf(string code) {
void bf(in string code) {
int cp = 0 ; // code pointer
int cp = 0; // code pointer
int nested = 0 ; // nested loop level
int nested = 0; // nested loop level


Act bfAct() {
Act bfAct() {
Act[] acts ; // store commands of current nesting level
Act[] acts; // store commands of current nesting level
char cc ;
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") ;
}


while (cp < code.length) {
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
// cc get next command and code pointer cp is advanced
foreach(f ; args[1..$]) // and executed one by one.
cc = code[cp];
try bf(cast(string)read(f)) ;
cp++;
catch (Exception e) printf("%*s",e.msg) ;
switch (cc) {
case '[':
else
nested++;
bf(">+++++++++[<+++++++++>-]<+.>+++[<----->-]"
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");
}
}

</lang>

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 ==
== Implementation 2 ==

Revision as of 23:51, 24 March 2012

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

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>