/* interpretes Brainfuck programs (see also http://en.wikipedia.org/wiki/Brainfuck for syntax) 05/2007 help: just execute without arguments compile: dmd bf.d tested under dmd version 1.014 Bugs: getch() behaviour not tested under linux, winXP works fine (reads single char without echo) */ module bf; import std.cstream: dout; // for dout.flush import std.file: read; import std.path: getBaseName; import std.stdio; void bfInterpreteProgram(char[] program) { byte[] memory; memory.length = 10_000; // extended dynamically when .length is reached - as if... uint pointer; uint programindex; char command; while (programindex < program.length) { command = program[programindex]; switch(command) { case '>': pointer++; if (pointer == memory.length) memory.length = memory.length + 100; break; case '<': if (pointer == 0) // first check, then decrease b/c pointer is a uint pointer += memory.length; // treat as a ring pointer--; break; case '+': memory[pointer]++; break; case '-': memory[pointer]--; break; case '.': writef(cast(char)memory[pointer]); dout.flush(); // flush() for cs like: bf "+[>+++++++.]" break; case ',': memory[pointer] = getch(); break; case '[': if (memory[pointer] == 0) // conditional jump { int depth = 1; while (depth > 0) // process possibly nested brackets { programindex++; if (programindex >= program.length) throw new Exception("invalid Brainfuck program, couldn't find matching ]"); if (program[programindex] == '[') depth++; if (program[programindex] == ']') depth--; } } break; case ']': if (memory[pointer] != 0) // conditional jump { int depth = 1; while (depth > 0) // process possibly nested brackets { programindex--; if (programindex < 0) throw new Exception("invalid Brainfuck program, couldn't find matching ["); if (program[programindex] == '[') depth--; if (program[programindex] == ']') depth++; } } break; default: break; // all other characters are treated as comments } // switch(command) programindex++; } // while (programindex < program.length) } // void bfInterpreteProgram(char[] program) void main(char[][] args) { char[] program; if (args.length == 1) // no argument, print help { char[] help; help ~= "Brainfuck interpreter, see also http://en.wikipedia.org/wiki/Brainfuck\n" ~ "Usage:\n" ~ " " ~ getBaseName(args[0]) ~ " prints this help\n" ~ " " ~ getBaseName(args[0]) ~ " helloworld Hello World Example\n" ~ " " ~ getBaseName(args[0]) ~ " file intepretes \"file\" if it exists\n" ~ " " ~ getBaseName(args[0]) ~ " \"+++++++.\" interpretes parameters as a program (note the \"\")\n"; writef(help); return; } else if ((args.length == 2) && (args[1] == "helloworld")) // hello world example { writefln("Entering Mode: default helloworld"); program = "++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>."; } else if ((args.length == 2) && (std.file.exists(args[1]))) // load program from file { writefln("Entering Mode: load program from file given as argument"); program = cast(char[])std.file.read(args[1]); } else // parse arguments as program { writefln("Entering Mode: program given as argument(s)"); for (int i=1; i