Execute Brain****/D

From Rosetta Code
Revision as of 23:52, 24 March 2012 by rosettacode>Bearophile (Version 2 D updated)
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>

Version 2

Simpler and faster: <lang d>import core.stdc.stdio, core.stdc.stdlib;

void brainfuckRun(in string code) nothrow {

   static int[int] matchBraces(in string code) pure nothrow
   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(in string code, in int[int] loops) nothrow {
       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 ',':
                   immutable 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>