|
import java.util.HashMap; |
|
import java.util.Scanner; |
|
import java.util.regex.Matcher; |
|
import java.util.regex.Pattern; |
|
|
|
public class CPU { |
|
public String[] ram; |
|
private HashMap<String, Instruction> rom; |
|
private double accumulator; |
|
private int instructionPointer; |
|
|
|
public CPU () { |
|
rom = new HashMap<String, Instruction>(); |
|
rom.put("READ", new Read()); |
|
rom.put("LOAD", new Load()); |
|
rom.put("LOAD#", new LoadDirect()); |
|
rom.put("LOAD@", new LoadIndirect()); |
|
rom.put("STORE", new Store()); |
|
rom.put("ADD", new Add()); |
|
rom.put("ADD#", new AddDirect()); |
|
rom.put("SUB", new Sub()); |
|
rom.put("SUB#", new SubDirect()); |
|
rom.put("MUL", new Mul()); |
|
rom.put("DIV", new Div()); |
|
rom.put("MOD", new Mod()); |
|
rom.put("POW", new Pow()); |
|
rom.put("SHL", new ShiftLeft()); |
|
rom.put("SHR", new ShiftRight()); |
|
rom.put("AND", new And()); |
|
rom.put("OR", new Or()); |
|
rom.put("NOT", new Not()); |
|
rom.put("XOR", new Xor()); |
|
rom.put("JZ", new JumpIfZero()); |
|
rom.put("JNZ", new JumpIfNotZero()); |
|
rom.put("JUMP", new Jump()); |
|
rom.put("JGZ", new JumpIfGreaterThanZero()); |
|
rom.put("JGEZ", new JumpIfGreaterOrEqualsThanZero()); |
|
rom.put("JLZ", new JumpIfLessThanZero()); |
|
rom.put("JLEZ", new JumpIfLessOrEqualsThanZero()); |
|
rom.put("PRINT", new Print()); |
|
rom.put("ECHO", new Echo()); |
|
rom.put("HALT", new Halt()); |
|
} |
|
|
|
public void start() { |
|
while(instructionPointer >= 0) { |
|
fetch(ram[instructionPointer]); |
|
} |
|
} |
|
|
|
public void load(String[] ram) { |
|
this.ram = ram; |
|
} |
|
|
|
public void dump() { |
|
for (int i = 0; i < ram.length; i++) |
|
if (ram[i] != null) |
|
System.out.println(String.format("%d.\t%s", i, ram[i])); |
|
} |
|
|
|
public void fetch(String instruction) { |
|
try { |
|
Pattern pattern = Pattern.compile("([^\\s]+)"); |
|
Matcher match = pattern.matcher(instruction); |
|
String executor = nextToken(match).toUpperCase(); |
|
if (rom.containsKey(executor)) { |
|
Instruction cmd = rom.get(executor); |
|
cmd.execute(match); |
|
} else { |
|
throw new RuntimeException("Unknow Instruction"); |
|
} |
|
} |
|
catch (Exception e) { |
|
System.out.println("Address: " + instructionPointer + "\tInterrupt: "); |
|
e.printStackTrace(); |
|
fetch("HALT"); |
|
} |
|
} |
|
|
|
private String nextToken(Matcher match) { |
|
if (!match.find()) throw new RuntimeException("Command malformed"); |
|
return match.group(); |
|
} |
|
|
|
private class Load implements Instruction { |
|
@Override |
|
public void execute(Matcher matcher) { |
|
accumulator = Double.parseDouble(ram[(int)Double.parseDouble(nextToken(matcher))]); |
|
instructionPointer++; |
|
} |
|
} |
|
|
|
private class LoadDirect implements Instruction { |
|
@Override |
|
public void execute(Matcher matcher) { |
|
accumulator = Double.parseDouble(nextToken(matcher)); |
|
instructionPointer++; |
|
} |
|
} |
|
|
|
private class LoadIndirect implements Instruction { |
|
public void execute(Matcher matcher) { |
|
accumulator = Double.parseDouble(ram[(int)Double.parseDouble(ram[(int)Double.parseDouble(nextToken(matcher))])]); |
|
instructionPointer++; |
|
} |
|
} |
|
|
|
private class Store implements Instruction { |
|
@Override |
|
public void execute(Matcher matcher) { |
|
ram[(int)Double.parseDouble(nextToken(matcher))] = Double.toString(accumulator); |
|
instructionPointer++; |
|
} |
|
} |
|
|
|
private class Add implements Instruction { |
|
@Override |
|
public void execute(Matcher matcher) { |
|
accumulator += Double.parseDouble(ram[(int)Double.parseDouble(nextToken(matcher))]); |
|
instructionPointer++; |
|
} |
|
} |
|
|
|
private class AddDirect implements Instruction { |
|
@Override |
|
public void execute(Matcher matcher) { |
|
accumulator += Double.parseDouble(nextToken(matcher)); |
|
instructionPointer++; |
|
} |
|
} |
|
|
|
private class JumpIfZero implements Instruction { |
|
@Override |
|
public void execute(Matcher matcher) { |
|
if(accumulator == 0) { |
|
instructionPointer = (int)Double.parseDouble(nextToken(matcher)); |
|
return; |
|
} |
|
instructionPointer++; |
|
} |
|
} |
|
|
|
private class JumpIfNotZero implements Instruction { |
|
@Override |
|
public void execute(Matcher matcher) { |
|
if(accumulator != 0) { |
|
instructionPointer = (int)Double.parseDouble(nextToken(matcher)); |
|
return; |
|
} |
|
instructionPointer++; |
|
} |
|
} |
|
|
|
private class Jump implements Instruction { |
|
@Override |
|
public void execute(Matcher matcher) { |
|
instructionPointer = (int)Double.parseDouble(nextToken(matcher)); |
|
} |
|
} |
|
|
|
private class Print implements Instruction { |
|
@Override |
|
public void execute(Matcher matcher) { |
|
System.out.println(accumulator); |
|
instructionPointer++; |
|
} |
|
} |
|
|
|
private class Halt implements Instruction { |
|
@Override |
|
public void execute(Matcher matcher) { |
|
instructionPointer = -1; |
|
} |
|
} |
|
|
|
private class JumpIfGreaterThanZero implements Instruction { |
|
@Override |
|
public void execute(Matcher matcher) { |
|
if(accumulator > 0) { |
|
instructionPointer = (int)Double.parseDouble(nextToken(matcher)); |
|
return; |
|
} |
|
instructionPointer++; |
|
} |
|
} |
|
|
|
private class JumpIfGreaterOrEqualsThanZero implements Instruction { |
|
@Override |
|
public void execute(Matcher matcher) { |
|
if(accumulator >= 0) { |
|
instructionPointer = (int)Double.parseDouble(nextToken(matcher)); |
|
return; |
|
} |
|
instructionPointer++; |
|
} |
|
} |
|
|
|
private class JumpIfLessThanZero implements Instruction { |
|
@Override |
|
public void execute(Matcher matcher) { |
|
if(accumulator < 0) { |
|
instructionPointer = (int)Double.parseDouble(nextToken(matcher)); |
|
return; |
|
} |
|
instructionPointer++; |
|
} |
|
} |
|
|
|
private class JumpIfLessOrEqualsThanZero implements Instruction { |
|
@Override |
|
public void execute(Matcher matcher) { |
|
if(accumulator <= 0) { |
|
instructionPointer = (int)Double.parseDouble(nextToken(matcher)); |
|
return; |
|
} |
|
instructionPointer++; |
|
} |
|
} |
|
|
|
private class Sub implements Instruction { |
|
@Override |
|
public void execute(Matcher matcher) { |
|
accumulator -= Double.parseDouble(ram[(int)Double.parseDouble(nextToken(matcher))]); |
|
instructionPointer++; |
|
} |
|
} |
|
|
|
private class SubDirect implements Instruction { |
|
@Override |
|
public void execute(Matcher matcher) { |
|
accumulator -= Double.parseDouble(nextToken(matcher)); |
|
instructionPointer++; |
|
} |
|
} |
|
|
|
private class Mul implements Instruction { |
|
@Override |
|
public void execute(Matcher matcher) { |
|
accumulator *= Double.parseDouble(ram[(int)Double.parseDouble(nextToken(matcher))]); |
|
instructionPointer++; |
|
} |
|
} |
|
|
|
private class Div implements Instruction { |
|
@Override |
|
public void execute(Matcher matcher) { |
|
double d = Double.parseDouble(ram[(int)Double.parseDouble(nextToken(matcher))]); |
|
if(d == 0) throw new RuntimeException("Division by Zero"); |
|
accumulator /= d; |
|
instructionPointer++; |
|
} |
|
} |
|
|
|
private class Mod implements Instruction { |
|
@Override |
|
public void execute(Matcher matcher) { |
|
accumulator %= Double.parseDouble(ram[(int)Double.parseDouble(nextToken(matcher))]); |
|
instructionPointer++; |
|
} |
|
} |
|
|
|
/* base = accumulator; exponent = param */ |
|
private class Pow implements Instruction { |
|
@Override |
|
public void execute(Matcher matcher) { |
|
accumulator = Math.pow(accumulator, Double.parseDouble(ram[(int)Double.parseDouble(nextToken(matcher))])); |
|
instructionPointer++; |
|
} |
|
} |
|
|
|
private class ShiftLeft implements Instruction { |
|
@Override |
|
public void execute(Matcher matcher) { |
|
accumulator = (int) accumulator << Integer.parseInt(ram[(int)Double.parseDouble(nextToken(matcher))]); |
|
instructionPointer++; |
|
} |
|
} |
|
|
|
private class ShiftRight implements Instruction { |
|
@Override |
|
public void execute(Matcher matcher) { |
|
accumulator = (int) accumulator >> Integer.parseInt(ram[(int)Double.parseDouble(nextToken(matcher))]); |
|
instructionPointer++; |
|
} |
|
} |
|
|
|
private class And implements Instruction { |
|
@Override |
|
public void execute(Matcher matcher) { |
|
accumulator = (int) accumulator & Integer.parseInt(ram[(int)Double.parseDouble(nextToken(matcher))]); |
|
instructionPointer++; |
|
} |
|
} |
|
|
|
private class Or implements Instruction { |
|
@Override |
|
public void execute(Matcher matcher) { |
|
accumulator = (int) accumulator | Integer.parseInt(ram[(int)Double.parseDouble(nextToken(matcher))]); |
|
instructionPointer++; |
|
} |
|
} |
|
|
|
|
|
private class Not implements Instruction { |
|
@Override |
|
public void execute(Matcher matcher) { |
|
accumulator = ~ (int) accumulator; |
|
instructionPointer++; |
|
} |
|
} |
|
|
|
private class Xor implements Instruction { |
|
@Override |
|
public void execute(Matcher matcher) { |
|
accumulator = (int) accumulator ^ Integer.parseInt(ram[(int)Double.parseDouble(nextToken(matcher))]); |
|
instructionPointer++; |
|
} |
|
} |
|
|
|
private class Read implements Instruction { |
|
@Override |
|
public void execute(Matcher matcher) { |
|
Scanner sc = new Scanner(System.in); |
|
accumulator = sc.nextDouble(); |
|
instructionPointer++; |
|
} |
|
} |
|
|
|
private class Echo implements Instruction { |
|
@Override |
|
public void execute(Matcher matcher) { |
|
String message = ""; |
|
while (matcher.find()) { |
|
message += matcher.group(); |
|
message += " "; |
|
} |
|
if(message.charAt(0) == '"' && message.charAt(message.length()-2) == '"') { |
|
System.out.println(message.substring(1, message.length()-2)); |
|
instructionPointer++; |
|
return; |
|
} |
|
throw new IllegalArgumentException("Instruction Malformed"); |
|
} |
|
} |
|
} |