Created
December 12, 2014 04:58
-
-
Save steveash/10de12a2c085215b66d8 to your computer and use it in GitHub Desktop.
Simple Brainfuck interpreter for a friend
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.io.IOException; | |
import java.util.HashMap; | |
import java.util.Map; | |
import java.util.Scanner; | |
public class Brainfuck { | |
public static void main(String[] args) throws IOException { | |
int maxTapeSize = 10000; | |
Scanner s = new Scanner(System.in); | |
char[] program = s.nextLine().toCharArray(); | |
short[] tape = new short[maxTapeSize]; | |
Map<Integer, Integer> jumpTable = new HashMap<>(); | |
int p = 0; // pointer to the current program instruction | |
int t = 0; // pointer to the current tape location | |
int allowedCommands = 10000; | |
int doneCommands = 0; | |
while (p < program.length && doneCommands < allowedCommands) { | |
char cmd = program[p]; | |
if (cmd == '>') { | |
if (t == tape.length - 1) { | |
t = 0; // go to first location in the buffer (i.e wrap around) | |
} else { | |
t += 1; | |
} | |
p += 1; // program goes to next instruction | |
} else if (cmd == '<') { | |
if (t == 0) { | |
t = tape.length - 1; // go to the last location in the buffer (i.e. wrap around) | |
} else { | |
t -= 1; // tape moves one location to the left | |
} | |
p += 1; // program moves to the next character | |
} else if (cmd == '+') { | |
short cell = tape[t]; | |
if (cell == 255) { | |
tape[t] = 0; | |
} else { | |
tape[t] += 1; | |
} | |
p += 1; // program moves to the next character | |
} else if (cmd == '-') { | |
short cell = tape[t]; | |
if (cell == 0) { | |
tape[t] = 255; | |
} else { | |
tape[t] -= 1; | |
} | |
p += 1; // program moves to the next character | |
} else if (cmd == '.') { | |
short cell = tape[t]; | |
System.out.println(cell); | |
p += 1; // program moves to the next character | |
} else if (cmd == ',') { | |
short valueToWrite = 0; // if there's no more then write zero | |
if (s.hasNextShort()) { | |
valueToWrite = s.nextShort(); | |
} | |
tape[t] = valueToWrite; | |
p += 1; | |
} else if (cmd == '[') { | |
short cell = tape[t]; | |
if (cell != 0) { | |
p += 1; // if its != zero then just move to the next program position | |
} else { | |
// we need to _find_ the next program position | |
Integer jump = jumpTable.get(p); | |
if (jump == null) { | |
// we've never hit this bracket and needed to jump before so find the pair | |
jump = findClosingBracket(program, p + 1); | |
// save it so next time we dont have to look it up | |
jumpTable.put(p, jump); | |
jumpTable.put(jump, p); | |
} | |
p = 1 + jump; | |
} | |
} else if (cmd == ']') { | |
short cell = tape[t]; | |
if (cell == 0) { | |
p += 1; // if its zero then move to the next, otherwise go back to the opening bracket | |
} else { | |
Integer jump = jumpTable.get(p); | |
if (jump == null) { | |
// we've never hit this bracket and needed to jump before so find the pair | |
jump = findOpeningBracket(program, p - 1); | |
// save it so next time we dont have to look it up | |
jumpTable.put(p, jump); | |
jumpTable.put(jump, p); | |
} | |
p = 1 + jump; | |
} | |
} | |
// we already dealt with p above (because sometimes it increments by one sometimes it jumps around) | |
doneCommands += 1; | |
} | |
} | |
// finds the next closing bracket starting at p; returns -1 if it can't find anything because the brainfuck | |
// program was not specified correctly (i.e. a starting bracket with no closing) | |
private static int findClosingBracket(char[] program, int i) { | |
int nestedCount = 0; | |
while (true) { | |
if (i >= program.length) { | |
// we ran out of program and couldnt find a closing bracket so the program mustve been entered incorrectly | |
throw new IllegalStateException("Bad program input cant find closing bracket from " + i); | |
} | |
if (program[i] == '[') { | |
// uh oh we were looking for a closing bracket but we found a nested opening bracket that means we need | |
// to find this nested brackets closing bracket before we can get ours; let's keep track of how many | |
// nested brackets we're looking for | |
nestedCount += 1; | |
} | |
if (program[i] == ']') { | |
// we found _a_ closing bracket but we're not sure if its _ours_ or one of the nested ones we're looking for | |
if (nestedCount == 0) { | |
// we found _our_ bracket! | |
return i; | |
} else { | |
// this is someone else's so just _decrement_ the nestedCount, when we finally hit the closing bracket | |
// with nestedCount = 0 then we know we've found ours | |
nestedCount -= 1; | |
} | |
} | |
// didn't find it this time, try the next spot | |
i += 1; | |
} | |
} | |
private static int findOpeningBracket(char[] program, int i) { | |
int nestedCount = 0; | |
while (true) { | |
if (i < 0) { | |
throw new IllegalStateException("Bad program input cant find opening bracket from " + i); | |
} | |
if (program[i] == ']') { | |
nestedCount += 1; | |
} | |
if (program[i] == '[') { | |
if (nestedCount == 0) { | |
return i; | |
} else { | |
nestedCount -= 1; | |
} | |
} | |
i -= 1; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment