From 3533f1fe2b0a387501bad47e69b9bb59b6497dc6 Mon Sep 17 00:00:00 2001 From: Nicola Pfister Date: Thu, 6 Oct 2016 14:13:42 +0200 Subject: [PATCH] Implemented jump points --- src/JohnnyScript.java | 87 +++++++++++++++++++++++++++++++++++-------- test/RamCodeTest.java | 68 ++++++++++++++++++++++++++++++++- 2 files changed, 137 insertions(+), 18 deletions(-) diff --git a/src/JohnnyScript.java b/src/JohnnyScript.java index fcea1a5..8c030b0 100644 --- a/src/JohnnyScript.java +++ b/src/JohnnyScript.java @@ -1,5 +1,3 @@ -import com.sun.org.apache.bcel.internal.classfile.Code; - import java.io.IOException; import java.nio.file.FileSystems; import java.nio.file.Path; @@ -68,8 +66,7 @@ private static String compile(String line) throws InvalidScriptException { if (!nonComment.equals("")) return encode(nonComment); else return null; - } - else + } else return encode(line); } @@ -163,17 +160,22 @@ public String getCode() { class RamCode { private static final int MAX_LINES = 999; + private static final String JUMP_POINT_DELIMITER = ":"; private static int writeIndex; private ArrayList code; private Map variables; private Map varLoc; + private Map jumpPoints; + private Map> jumps; RamCode() { code = new ArrayList<>(); variables = new LinkedHashMap<>(); varLoc = new LinkedHashMap<>(); + jumpPoints = new LinkedHashMap<>(); + jumps = new LinkedHashMap<>(); } void addCode(String input) { @@ -189,17 +191,38 @@ void addVar(String name, int value) throws DuplicateVariableException { } } - void addVarRef(String input) throws VariableNotInitializedException { - String[] parts = input.split(" "); + void addCodeWithVar(String input) throws VariableNotInitializedException { + assert input.contains("#"); + String[] parts = input.split("#"); assert parts.length == 2; - assert parts[1].contains("#"); - String var = parts[1].replace("#",""); + String var = parts[1]; if (!variables.containsKey(var)) { throw new VariableNotInitializedException("Variable has not been initialized: " + var); } else { int line = varLoc.get(var); - code.add(parts[0] + String.format("%03d",line)); + code.add(parts[0].trim() + String.format("%03d", line)); + } + } + + void addJumpPoint(String jpName) throws DuplicateJumpPointException { + if (jumpPoints.containsKey(jpName)) { + throw new DuplicateJumpPointException("Same jump point can't be set twice: " + jpName); + } else { + jumpPoints.put(jpName, code.size()); + } + } + + void addJump(String jpName) { + List jumpLines; + if (jumps.containsKey(jpName)) { + jumpLines = jumps.get(jpName); + } else { + jumpLines = new ArrayList<>(); } + jumpLines.add(code.size()); + jumps.put(jpName,jumpLines); + + code.add(jpName + ":"); } private List initializeZeros(List code) { @@ -209,7 +232,7 @@ private List initializeZeros(List code) { return code; } - List getCode() { + List getCode() throws InvalidJumpsException { List output = new ArrayList<>(); initializeZeros(output); @@ -218,24 +241,42 @@ List getCode() { output.set(writeIndex, generateLineZero()); writeIndex++; - variables.forEach((k,v) -> { - output.set(writeIndex, String.format("%03d",v)); + variables.forEach((k, v) -> { + output.set(writeIndex, String.format("%03d", v)); writeIndex++; }); - for (String loc: code - ) { + for (String loc : code + ) { output.add(writeIndex, loc); writeIndex++; } + List invalid = new ArrayList<>(); + + jumps.forEach((jpName,jumpList) -> { + if(!jumpPoints.containsKey(jpName)) { + invalid.add(jpName); + } else { + for (int line:jumpList) { + line = 1 + variables.size() + line; + assert output.get(line).equals(jpName + ":"); + output.set(line, JohnnyScript.Codes.JMP.codeOrdinal + String.format("%03d", line)); + } + } + }); + + if (!invalid.isEmpty()) { + throw new InvalidJumpsException("Jumps to inexistent jump points: " + invalid.toString()); + } + assert writeIndex == 1 + variables.size() + code.size(); return output; } private String generateLineZero() { - String firstLocAdress = String.format("%03d",variables.size()+1); + String firstLocAdress = String.format("%03d", variables.size() + 1); return JohnnyScript.Codes.JMP.codeOrdinal + firstLocAdress; } } @@ -256,7 +297,9 @@ class CompilerHaltException extends RuntimeException { class DuplicateVariableException extends Exception { - DuplicateVariableException(String message) {super(message);} + DuplicateVariableException(String message) { + super(message); + } } class VariableNotInitializedException extends Exception { @@ -265,3 +308,15 @@ class VariableNotInitializedException extends Exception { super(message); } } + +class DuplicateJumpPointException extends Exception { + DuplicateJumpPointException(String message) { + super(message); + } +} + +class InvalidJumpsException extends Exception { + InvalidJumpsException(String message) { + super(message); + } +} diff --git a/test/RamCodeTest.java b/test/RamCodeTest.java index 001c864..c320934 100644 --- a/test/RamCodeTest.java +++ b/test/RamCodeTest.java @@ -53,7 +53,7 @@ public void testAddVar() throws Exception { @Test(expected = VariableNotInitializedException.class) public void testAddVarRefWithoutInit() throws Exception { RamCode code = new RamCode(); - code.addVarRef(JohnnyScript.Codes.ADD.codeOrdinal+" #tst"); + code.addCodeWithVar(JohnnyScript.Codes.ADD.codeOrdinal+" #tst"); } @Test(expected = DuplicateVariableException.class) @@ -67,7 +67,7 @@ public void testAddDuplicateVar() throws Exception { public void testAddVarRef() throws Exception { RamCode code = new RamCode(); code.addVar("tst",5); - code.addVarRef(JohnnyScript.Codes.ADD.codeOrdinal+" #tst"); + code.addCodeWithVar(JohnnyScript.Codes.ADD.codeOrdinal+" #tst"); List codeList = code.getCode(); @@ -79,4 +79,68 @@ public void testAddVarRef() throws Exception { assertEquals("000",codeList.get(i)); } } + + @Test + public void testAddJumpAfterJumpPoint() throws Exception { + RamCode code = new RamCode(); + code.addJumpPoint("tst"); + code.addJump("tst"); + + List codeList = code.getCode(); + + assertEquals(JohnnyScript.Codes.JMP.codeOrdinal + "001",codeList.get(0)); + assertEquals(JohnnyScript.Codes.JMP.codeOrdinal + "001",codeList.get(1)); + + for (int i = 2; i < 1000; i++) { + assertEquals("000",codeList.get(i)); + } + } + + @Test + public void testAddJumpBeforeJumpPoint() throws Exception { + RamCode code = new RamCode(); + code.addJump("tst"); + code.addJumpPoint("tst"); + + List codeList = code.getCode(); + + assertEquals(JohnnyScript.Codes.JMP.codeOrdinal + "001",codeList.get(0)); + assertEquals(JohnnyScript.Codes.JMP.codeOrdinal + "001",codeList.get(1)); + + for (int i = 2; i < 1000; i++) { + assertEquals("000",codeList.get(i)); + } + } + + @Test(expected = DuplicateJumpPointException.class) + public void testAddDuplicateJumpPoint() throws Exception { + RamCode code = new RamCode(); + code.addJumpPoint("tst"); + code.addJumpPoint("tst"); + } + + @Test(expected = InvalidJumpsException.class) + public void testInvalidJump() throws Exception { + RamCode code = new RamCode(); + code.addJump(JohnnyScript.Codes.JMP.codeOrdinal + " tst"); + + code.getCode(); + } + + @Test + public void testProgram() throws Exception { + RamCode code = new RamCode(); + code.addVar("z3", 0); + code.addCodeWithVar(JohnnyScript.Codes.NULL.codeOrdinal + "#z3"); + code.addJumpPoint("start"); + code.addCodeWithVar(JohnnyScript.Codes.TAKE.codeOrdinal + "#z3"); + code.addVar("z1", 5); + code.addCodeWithVar(JohnnyScript.Codes.ADD.codeOrdinal + "#z1"); + code.addVar("z2", 3); + code.addCodeWithVar(JohnnyScript.Codes.SAVE.codeOrdinal + "#z2"); + code.addCodeWithVar(JohnnyScript.Codes.DEC.codeOrdinal + "#z1"); + code.addCodeWithVar(JohnnyScript.Codes.TST.codeOrdinal + "#z1"); + code.addJump("start"); + code.addCode(JohnnyScript.Codes.HLT.codeOrdinal + "0"); + } } \ No newline at end of file