Last active
February 15, 2019 02:31
-
-
Save BenjaminUrquhart/0aee5c1ea878d3b071e4170206a5b785 to your computer and use it in GitHub Desktop.
BrainF interpreter in Java
This file contains hidden or 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
package net.benjaminurquhart.bfj; | |
import java.io.IOException; | |
import java.util.ArrayList; | |
import java.util.HashMap; | |
import javax.script.ScriptException; | |
public class BFJ { | |
public static String stripComments(String code){ | |
return code.chars().mapToObj((c) -> ((char)c)+"").filter((c)->",.+-<>[]".contains(c)).reduce("",(x,y)->x+y); | |
} | |
public static void execute(String code) throws ScriptException{ | |
execute(code, 30000); | |
} | |
public static void execute(String code, int cellAmount) throws ScriptException{ | |
int[] buff = new int[cellAmount < 30000 ? 30000 : cellAmount]; | |
ArrayList<BracketPair> bracketsQueue = new ArrayList<>(), brackets = new ArrayList<>(); | |
int instruction = 0, data = 0, codeLen = code.length(); | |
for(int i = 0; i < codeLen; i++){ | |
try{ | |
if(code.charAt(i) == '[') bracketsQueue.add(0, new BracketPair(i, 0)); | |
if(code.charAt(i) == ']') brackets.add(bracketsQueue.remove(0).setB(i)); | |
} | |
catch(IndexOutOfBoundsException e){ | |
throw new ScriptException("Unmatched jump instruction at character " + i); | |
} | |
} | |
if(!bracketsQueue.isEmpty()){ | |
throw new ScriptException("Unmatched jump instruction at character " + bracketsQueue.get(0).getF()); | |
} | |
HashMap<Integer, Integer> forward = new HashMap<>(), backward = new HashMap<>(); | |
for(BracketPair pair : brackets){ | |
if(pair.getB() == pair.getF()){ | |
throw new ScriptException("Invalid jump instruction at character " + pair.getB()); | |
} | |
backward.put(pair.getF(), pair.getB()); | |
forward.put(pair.getB(), pair.getF()); | |
} | |
try{ | |
while(instruction < codeLen){ | |
switch(code.charAt(instruction)){ | |
case ',': buff[data] = System.in.read(); break; | |
case '.': System.out.print((char)buff[data]); break; | |
case '+': buff[data]++; break; | |
case '-': buff[data]--; break; | |
case '>' : data++; break; | |
case '<' : data--; break; | |
case '[': instruction = (buff[data] == 0 ? backward.get(instruction) : instruction); break; | |
case ']': instruction = (buff[data] != 0 ? forward.get(instruction) : instruction); break; | |
} | |
if(data >= buff.length || data < 0){ | |
throw new ScriptException(String.format("Out-of-bounds buffer access at character %d. Index: %d, Size: %d", instruction, data, buff.length)); | |
} | |
instruction++; | |
} | |
} | |
catch(IOException e){ | |
throw new ScriptException("Failed to read from standard input: " + e.getMessage()); | |
} | |
} | |
} | |
class BracketPair{ | |
private int f,b; | |
protected BracketPair(int f, int b){ | |
this.f = f; | |
this.b = b; | |
} | |
protected BracketPair setF(int f){ | |
this.f = f; | |
return this; | |
} | |
protected BracketPair setB(int b){ | |
this.b = b; | |
return this; | |
} | |
protected int getF(){ | |
return f; | |
} | |
protected int getB(){ | |
return b; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment