1 module brainfuck; 2 3 import std.conv; 4 import std.array; 5 import std.stdio; 6 import std.format; 7 8 class VM { 9 uint pointer = 0; 10 ubyte[] tape; 11 12 this() { 13 tape.length = 30000; 14 } 15 } 16 17 class BrainfuckInstruction { 18 abstract void run(VM); 19 abstract string compile(uint); 20 abstract string to_string(uint); 21 22 string compile() { 23 return compile(0); 24 } 25 26 string to_string() { 27 return to_string(0); 28 } 29 } 30 31 class Modify : BrainfuckInstruction { 32 int amt; 33 34 this(int amt) { 35 this.amt = amt; 36 } 37 38 override void run(VM vm) { 39 vm.tape[vm.pointer] += amt; 40 } 41 42 override string compile(uint depth) { 43 return "%s*p += %s;".format(" ".replicate(depth), amt); 44 } 45 46 override string to_string(uint depth) { 47 return "%sModify(%s)".format(" ".replicate(depth), amt.to!string); 48 } 49 } 50 51 class Select : BrainfuckInstruction { 52 int amt; 53 54 this(int amt) { 55 this.amt = amt; 56 } 57 58 override void run(VM vm) { 59 vm.pointer += amt; 60 } 61 62 override string compile(uint depth) { 63 return "%sp += %s;".format(" ".replicate(depth), amt); 64 } 65 66 override string to_string(uint depth) { 67 return "%sSelect(%s)".format(" ".replicate(depth), amt.to!string); 68 } 69 } 70 71 class Loop : BrainfuckInstruction { 72 BrainfuckInstruction[] insts; 73 74 this(BrainfuckInstruction[] insts) { 75 this.insts = insts; 76 } 77 78 override void run(VM vm) { 79 while(vm.tape[vm.pointer] != 0) { 80 foreach(inst; insts) { 81 inst.run(vm); 82 } 83 } 84 } 85 86 override string compile(uint depth) { 87 char[] s; 88 s ~= "%swhile(*p) {\n".format(" ".replicate(depth)); 89 90 foreach(inst; insts) { 91 s ~= "%s\n".format(inst.compile(depth + 1)); 92 } 93 94 s ~= "%s}".format(" ".replicate(depth)); 95 return cast(string) s; 96 } 97 98 override string to_string(uint depth) { 99 char[] s; 100 s ~= "%sLoop {\n".format(" ".replicate(depth)); 101 102 foreach(inst; insts) { 103 s ~= "%s\n".format(inst.to_string(depth + 1)); 104 } 105 106 s ~= "%s}".format(" ".replicate(depth)); 107 return cast(string) s; 108 } 109 } 110 111 class Input : BrainfuckInstruction { 112 override void run(VM vm) { 113 char c; 114 readf("%s", &c); 115 vm.tape[vm.pointer] = c; 116 } 117 118 override string compile(uint depth) { 119 return "%s*p = getchar();".format(" ".replicate(depth)); 120 } 121 122 override string to_string(uint depth) { 123 return "%sInput".format(" ".replicate(depth)); 124 } 125 } 126 127 class Output : BrainfuckInstruction { 128 override void run(VM vm) { 129 write(cast(char) vm.tape[vm.pointer]); 130 stdout.flush; 131 } 132 133 override string compile(uint depth) { 134 return "%sputchar(*p); fflush(stdout);".format(" ".replicate(depth)); 135 } 136 137 override string to_string(uint depth) { 138 return "%sOutput".format(" ".replicate(depth)); 139 } 140 } 141 142 class Clear : BrainfuckInstruction { 143 override void run(VM vm) { 144 vm.tape[vm.pointer] = 0; 145 } 146 147 override string compile(uint depth) { 148 return "%s*p = 0;".format(" ".replicate(depth)); 149 } 150 151 override string to_string(uint depth) { 152 return "%sClear".format(" ".replicate(depth)); 153 } 154 } 155 156 class MoveLoop : BrainfuckInstruction { 157 int[int] modifications; 158 159 this(int[int] modifications) { 160 this.modifications = modifications; 161 } 162 163 override void run(VM vm) { 164 auto src = vm.tape[vm.pointer]; 165 if(src == 0) return; 166 167 foreach(pointer, modify; modifications) { 168 vm.tape[vm.pointer + pointer] += modify * src; 169 } 170 171 vm.tape[vm.pointer] = 0; 172 } 173 174 override string compile(uint depth) { 175 char[] s; 176 s ~= "%sif(*p) {\n".format(" ".replicate(depth)); 177 178 foreach(pointer, modify; modifications) { 179 s ~= "%s*(p + %s) += %s * (*p);\n".format(" ".replicate(depth + 1), pointer, modify); 180 } 181 182 s ~= "%s*p = 0;\n".format(" ".replicate(depth + 1)); 183 s ~= "%s}".format(" ".replicate(depth)); 184 return cast(string) s; 185 } 186 187 override string to_string(uint depth) { 188 return "%sMoveLoop %s".format(" ".replicate(depth), modifications.to!string); 189 } 190 } 191 192 class If : BrainfuckInstruction { 193 BrainfuckInstruction[] insts; 194 195 this(BrainfuckInstruction[] insts) { 196 this.insts = insts; 197 } 198 199 override void run(VM vm) { 200 if(vm.tape[vm.pointer] != 0) { 201 foreach(inst; insts) { 202 inst.run(vm); 203 } 204 } 205 } 206 207 override string compile(uint depth) { 208 char[] s; 209 s ~= "%sif(*p) {\n".format(" ".replicate(depth)); 210 211 foreach(inst; insts) { 212 s ~= "%s\n".format(inst.compile(depth + 1)); 213 } 214 215 s ~= "%s}".format(" ".replicate(depth)); 216 return cast(string) s; 217 } 218 219 override string to_string(uint depth) { 220 char[] s; 221 s ~= "%sIf {\n".format(" ".replicate(depth)); 222 223 foreach(inst; insts) { 224 s ~= "%s\n".format(inst.to_string(depth + 1)); 225 } 226 227 s ~= "%s}".format(" ".replicate(depth)); 228 return cast(string) s; 229 } 230 } 231 232 class UnrolledLoop : BrainfuckInstruction { 233 uint count; 234 BrainfuckInstruction[] insts; 235 236 this(uint count, BrainfuckInstruction[] insts) { 237 this.count = count; 238 this.insts = insts; 239 } 240 241 override void run(VM vm) { 242 for(uint i = 0; i < count; i++) { 243 foreach(inst; insts) { 244 inst.run(vm); 245 } 246 } 247 } 248 249 override string compile(uint depth) { 250 char[] s; 251 252 for(uint i = 0; i < count; i++) { 253 foreach(inst; insts) { 254 s ~= "%s\n".format(inst.compile(depth)); 255 } 256 } 257 258 return cast(string) s; 259 } 260 261 override string to_string(uint depth) { 262 char[] s; 263 s ~= "%sUnrolledLoop(%s) {\n".format(" ".replicate(depth), count); 264 265 foreach(inst; insts) { 266 s ~= "%s\n".format(inst.to_string(depth + 1)); 267 } 268 269 s ~= "%s}".format(" ".replicate(depth)); 270 return cast(string) s; 271 } 272 }