Fix ggt and write tests
This commit is contained in:
Binary file not shown.
@@ -35,7 +35,6 @@ public class AbstractMachine {
|
|||||||
// Executes single step and returns configuration
|
// Executes single step and returns configuration
|
||||||
public void executeStep() {
|
public void executeStep() {
|
||||||
try {
|
try {
|
||||||
ensureCapacity(this.TOP);
|
|
||||||
Instruction inst = this.prog.get(this.PC);
|
Instruction inst = this.prog.get(this.PC);
|
||||||
|
|
||||||
int arg1 = inst.getArg1() != null ? inst.getArg1() : 0;
|
int arg1 = inst.getArg1() != null ? inst.getArg1() : 0;
|
||||||
@@ -45,96 +44,96 @@ public class AbstractMachine {
|
|||||||
switch (inst.getOpcode()) {
|
switch (inst.getOpcode()) {
|
||||||
case Instruction.CONST:
|
case Instruction.CONST:
|
||||||
// Pg. 9
|
// Pg. 9
|
||||||
this.stack.set(this.TOP + 1, arg1);
|
write(this.TOP + 1, arg1);
|
||||||
this.TOP += 1;
|
this.TOP += 1;
|
||||||
this.PC += 1;
|
this.PC += 1;
|
||||||
break;
|
break;
|
||||||
case Instruction.LOAD:
|
case Instruction.LOAD:
|
||||||
// Pg. 25
|
// Pg. 25
|
||||||
int loadSpp = spp(arg2, this.PP, this.FP);
|
int loadSpp = spp(arg2, this.PP, this.FP);
|
||||||
this.stack.set(this.TOP + 1, this.stack.get(loadSpp + arg1));
|
write(this.TOP + 1, read(loadSpp + arg1));
|
||||||
this.TOP += 1;
|
this.TOP += 1;
|
||||||
this.PC += 1;
|
this.PC += 1;
|
||||||
break;
|
break;
|
||||||
case Instruction.STORE:
|
case Instruction.STORE:
|
||||||
// Pg. 25
|
// Pg. 25
|
||||||
int storeSpp = spp(arg2, this.PP, this.FP);
|
int storeSpp = spp(arg2, this.PP, this.FP);
|
||||||
this.stack.set(storeSpp + arg1, this.stack.get(this.TOP));
|
write(storeSpp + arg1, read(this.TOP));
|
||||||
this.TOP -= 1;
|
this.TOP -= 1;
|
||||||
this.PC += 1;
|
this.PC += 1;
|
||||||
break;
|
break;
|
||||||
case Instruction.ADD:
|
case Instruction.ADD:
|
||||||
// Pg. 9
|
// Pg. 9
|
||||||
int addA = stack.get(this.TOP - 1);
|
int addA = read(this.TOP - 1);
|
||||||
int addB = stack.get(this.TOP);
|
int addB = read(this.TOP);
|
||||||
this.stack.set(this.TOP - 1, addA + addB);
|
write(this.TOP - 1, addA + addB);
|
||||||
this.TOP -= 1;
|
this.TOP -= 1;
|
||||||
this.PC += 1;
|
this.PC += 1;
|
||||||
break;
|
break;
|
||||||
case Instruction.SUB:
|
case Instruction.SUB:
|
||||||
// Pg. 9
|
// Pg. 9
|
||||||
int subA = stack.get(this.TOP - 1);
|
int subA = read(this.TOP - 1);
|
||||||
int subB = stack.get(this.TOP);
|
int subB = read(this.TOP);
|
||||||
this.stack.set(this.TOP - 1, subA - subB);
|
write(this.TOP - 1, subA - subB);
|
||||||
this.TOP -= 1;
|
this.TOP -= 1;
|
||||||
this.PC += 1;
|
this.PC += 1;
|
||||||
break;
|
break;
|
||||||
case Instruction.MUL:
|
case Instruction.MUL:
|
||||||
// Pg. 9
|
// Pg. 9
|
||||||
int mulA = stack.get(this.TOP - 1);
|
int mulA = read(this.TOP - 1);
|
||||||
int mulB = stack.get(this.TOP);
|
int mulB = read(this.TOP);
|
||||||
this.stack.set(this.TOP - 1, mulA * mulB);
|
write(this.TOP - 1, mulA * mulB);
|
||||||
this.TOP -= 1;
|
this.TOP -= 1;
|
||||||
this.PC += 1;
|
this.PC += 1;
|
||||||
break;
|
break;
|
||||||
case Instruction.DIV:
|
case Instruction.DIV:
|
||||||
// Pg. 9
|
// Pg. 9
|
||||||
int divA = stack.get(this.TOP - 1);
|
int divA = read(this.TOP - 1);
|
||||||
int divB = stack.get(this.TOP);
|
int divB = read(this.TOP);
|
||||||
|
|
||||||
if (divB == 0) {
|
if (divB == 0) {
|
||||||
throw new ArithmeticException("Division by zero");
|
throw new ArithmeticException("Division by zero");
|
||||||
}
|
}
|
||||||
|
|
||||||
this.stack.set(this.TOP - 1, divA / divB);
|
write(this.TOP - 1, Math.floorDiv(divA, divB));
|
||||||
this.TOP -= 1;
|
this.TOP -= 1;
|
||||||
this.PC += 1;
|
this.PC += 1;
|
||||||
break;
|
break;
|
||||||
case Instruction.LT:
|
case Instruction.LT:
|
||||||
// Pg. 12
|
// Pg. 12
|
||||||
int ltA = stack.get(this.TOP - 1);
|
int ltA = read(this.TOP - 1);
|
||||||
int ltB = stack.get(this.TOP);
|
int ltB = read(this.TOP);
|
||||||
this.stack.set(this.TOP - 1, ltA < ltB ? 1 : 0);
|
write(this.TOP - 1, ltA < ltB ? 1 : 0);
|
||||||
this.TOP -= 1;
|
this.TOP -= 1;
|
||||||
this.PC += 1;
|
this.PC += 1;
|
||||||
break;
|
break;
|
||||||
case Instruction.GT:
|
case Instruction.GT:
|
||||||
// Pg. 12
|
// Pg. 12
|
||||||
int gtA = stack.get(this.TOP - 1);
|
int gtA = read(this.TOP - 1);
|
||||||
int gtB = stack.get(this.TOP);
|
int gtB = read(this.TOP);
|
||||||
this.stack.set(this.TOP - 1, gtA > gtB ? 1 : 0);
|
write(this.TOP - 1, gtA > gtB ? 1 : 0);
|
||||||
this.TOP -= 1;
|
this.TOP -= 1;
|
||||||
this.PC += 1;
|
this.PC += 1;
|
||||||
break;
|
break;
|
||||||
case Instruction.EQ:
|
case Instruction.EQ:
|
||||||
// Pg. 12
|
// Pg. 12
|
||||||
int eqA = stack.get(this.TOP - 1);
|
int eqA = read(this.TOP - 1);
|
||||||
int eqB = stack.get(this.TOP);
|
int eqB = read(this.TOP);
|
||||||
this.stack.set(this.TOP - 1, eqA == eqB ? 1 : 0);
|
write(this.TOP - 1, eqA == eqB ? 1 : 0);
|
||||||
this.TOP -= 1;
|
this.TOP -= 1;
|
||||||
this.PC += 1;
|
this.PC += 1;
|
||||||
break;
|
break;
|
||||||
case Instruction.NEQ:
|
case Instruction.NEQ:
|
||||||
// Pg. 12
|
// Pg. 12
|
||||||
int neqA = stack.get(this.TOP - 1);
|
int neqA = read(this.TOP - 1);
|
||||||
int neqB = stack.get(this.TOP);
|
int neqB = read(this.TOP);
|
||||||
this.stack.set(this.TOP - 1, neqA != neqB ? 1 : 0);
|
write(this.TOP - 1, neqA != neqB ? 1 : 0);
|
||||||
this.TOP -= 1;
|
this.TOP -= 1;
|
||||||
this.PC += 1;
|
this.PC += 1;
|
||||||
break;
|
break;
|
||||||
case Instruction.IFZERO:
|
case Instruction.IFZERO:
|
||||||
// Pg. 13
|
// Pg. 13
|
||||||
if (this.stack.get(this.TOP) == 0) {
|
if (read(this.TOP) == 0) {
|
||||||
this.PC = arg1;
|
this.PC = arg1;
|
||||||
} else {
|
} else {
|
||||||
this.PC += 1;
|
this.PC += 1;
|
||||||
@@ -155,11 +154,11 @@ public class AbstractMachine {
|
|||||||
break;
|
break;
|
||||||
case Instruction.INVOKE:
|
case Instruction.INVOKE:
|
||||||
// Pg. 23
|
// Pg. 23
|
||||||
this.stack.set(this.TOP + 1, this.PC + 1);
|
write(this.TOP + 1, this.PC + 1);
|
||||||
this.stack.set(this.TOP + 2, this.PP);
|
write(this.TOP + 2, this.PP);
|
||||||
this.stack.set(this.TOP + 3, this.FP);
|
write(this.TOP + 3, this.FP);
|
||||||
this.stack.set(this.TOP + 4, spp(arg3, this.PP, this.FP));
|
write(this.TOP + 4, spp(arg3, this.PP, this.FP));
|
||||||
this.stack.set(this.TOP + 5, sfp(arg3, this.PP, this.FP));
|
write(this.TOP + 5, sfp(arg3, this.PP, this.FP));
|
||||||
this.PP = this.TOP - arg1 + 1;
|
this.PP = this.TOP - arg1 + 1;
|
||||||
this.FP = this.TOP + 1;
|
this.FP = this.TOP + 1;
|
||||||
this.TOP += 5;
|
this.TOP += 5;
|
||||||
@@ -167,12 +166,12 @@ public class AbstractMachine {
|
|||||||
break;
|
break;
|
||||||
case Instruction.RETURN:
|
case Instruction.RETURN:
|
||||||
// Pg. 24
|
// Pg. 24
|
||||||
int res = this.stack.get(this.TOP);
|
int res = read(this.TOP);
|
||||||
this.TOP = this.PP;
|
this.TOP = this.PP;
|
||||||
this.PC = this.stack.get(this.FP);
|
this.PC = read(this.FP);
|
||||||
this.PP = this.stack.get(this.FP + 1);
|
this.PP = read(this.FP + 1);
|
||||||
this.FP = this.stack.get(this.FP + 2);
|
this.FP = read(this.FP + 2);
|
||||||
this.stack.set(this.TOP, res);
|
write(this.TOP, res);
|
||||||
break;
|
break;
|
||||||
case Instruction.POP:
|
case Instruction.POP:
|
||||||
// Not in docs, see MaMa
|
// Not in docs, see MaMa
|
||||||
@@ -211,23 +210,6 @@ public class AbstractMachine {
|
|||||||
return sfp(d-1, this.stack.get(fp+3), this.stack.get(fp+4));
|
return sfp(d-1, this.stack.get(fp+3), this.stack.get(fp+4));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called before each instruction
|
|
||||||
protected void ensureCapacity(int currSize) {
|
|
||||||
int size = stack.size();
|
|
||||||
|
|
||||||
// Always ensure a minimum working capacity of 16
|
|
||||||
if (size < 16) {
|
|
||||||
for (int i = size; i < 16; i++) stack.add(0);
|
|
||||||
size = 16;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Double list capacity when fewer than 8 free slots remain
|
|
||||||
if (currSize >= size - 8) {
|
|
||||||
int newSize = size * 2;
|
|
||||||
for (int i = size; i < newSize; i++) stack.add(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the machine's current configuration as string
|
// Returns the machine's current configuration as string
|
||||||
public String confStr() {
|
public String confStr() {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
@@ -266,4 +248,13 @@ public class AbstractMachine {
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void write(int index, int value) {
|
||||||
|
while (stack.size() <= index) stack.add(0);
|
||||||
|
stack.set(index, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int read(int index) {
|
||||||
|
return stack.get(index);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,6 @@ package de.unitrier.st.uap.w25.tram;
|
|||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
public class AbstractMachineTests {
|
public class AbstractMachineTests {
|
||||||
@@ -75,29 +73,7 @@ public class AbstractMachineTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testGGTx48y18() {
|
void testMODx5y2() {
|
||||||
Instruction[] code = Assembler.readTRAMCode("tramcode/ggt.tram");
|
|
||||||
AbstractMachine tram = new AbstractMachine(code, new Integer[]{48, 18});
|
|
||||||
tram.execute();
|
|
||||||
|
|
||||||
assertTrue(tram.isHalted(), "Machine should halt.");
|
|
||||||
int result = tram.result();
|
|
||||||
assertEquals(6, result, "Expected ggt(48,18) = 6.");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testGGTx270y192() {
|
|
||||||
Instruction[] code = Assembler.readTRAMCode("tramcode/ggt.tram");
|
|
||||||
AbstractMachine tram = new AbstractMachine(code, new Integer[]{270, 192});
|
|
||||||
tram.execute();
|
|
||||||
|
|
||||||
assertTrue(tram.isHalted(), "Machine should halt.");
|
|
||||||
int result = tram.result();
|
|
||||||
assertEquals(6, result, "Expected ggt(270,192) = 6.");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testModPositive() {
|
|
||||||
Instruction[] code = Assembler.readTRAMCode("tramcode/mod.tram");
|
Instruction[] code = Assembler.readTRAMCode("tramcode/mod.tram");
|
||||||
AbstractMachine tram = new AbstractMachine(code, new Integer[]{17, 5});
|
AbstractMachine tram = new AbstractMachine(code, new Integer[]{17, 5});
|
||||||
tram.execute();
|
tram.execute();
|
||||||
@@ -108,7 +84,7 @@ public class AbstractMachineTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testModExactDivision() {
|
void testMODx20y5() {
|
||||||
Instruction[] code = Assembler.readTRAMCode("tramcode/mod.tram");
|
Instruction[] code = Assembler.readTRAMCode("tramcode/mod.tram");
|
||||||
AbstractMachine tram = new AbstractMachine(code, new Integer[]{20, 5});
|
AbstractMachine tram = new AbstractMachine(code, new Integer[]{20, 5});
|
||||||
tram.execute();
|
tram.execute();
|
||||||
@@ -119,7 +95,7 @@ public class AbstractMachineTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testModSmallerDividend() {
|
void testMODx3y10() {
|
||||||
Instruction[] code = Assembler.readTRAMCode("tramcode/mod.tram");
|
Instruction[] code = Assembler.readTRAMCode("tramcode/mod.tram");
|
||||||
AbstractMachine tram = new AbstractMachine(code, new Integer[]{3, 10});
|
AbstractMachine tram = new AbstractMachine(code, new Integer[]{3, 10});
|
||||||
tram.execute();
|
tram.execute();
|
||||||
@@ -129,6 +105,16 @@ public class AbstractMachineTests {
|
|||||||
assertEquals(3, result, "Expected 3 mod 10 = 3.");
|
assertEquals(3, result, "Expected 3 mod 10 = 3.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testMODx37y16() {
|
||||||
|
Instruction[] code = Assembler.readTRAMCode("tramcode/mod.tram");
|
||||||
|
AbstractMachine tram = new AbstractMachine(code, new Integer[]{37,16});
|
||||||
|
tram.execute();
|
||||||
|
|
||||||
|
assertTrue(tram.isHalted(), "Machine should halt.");
|
||||||
|
int result = tram.result();
|
||||||
|
assertEquals(5, result, "Expected 37 mod 16 = 5.");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testGGTx17y5() {
|
void testGGTx17y5() {
|
||||||
@@ -163,4 +149,80 @@ public class AbstractMachineTests {
|
|||||||
assertEquals(25, result, "Expected ggt(0,25) = 25.");
|
assertEquals(25, result, "Expected ggt(0,25) = 25.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testGGTx270y192() {
|
||||||
|
Instruction[] code = Assembler.readTRAMCode("tramcode/ggt.tram");
|
||||||
|
AbstractMachine tram = new AbstractMachine(code, new Integer[]{270, 192});
|
||||||
|
tram.execute();
|
||||||
|
|
||||||
|
assertTrue(tram.isHalted(), "Machine should halt.");
|
||||||
|
int result = tram.result();
|
||||||
|
assertEquals(6, result, "Expected ggt(270,192) = 6.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testGGTx48y18() {
|
||||||
|
Instruction[] code = Assembler.readTRAMCode("tramcode/ggt.tram");
|
||||||
|
AbstractMachine tram = new AbstractMachine(code, new Integer[]{48, 18});
|
||||||
|
tram.execute();
|
||||||
|
|
||||||
|
assertTrue(tram.isHalted(), "Machine should halt.");
|
||||||
|
int result = tram.result();
|
||||||
|
assertEquals(6, result, "Expected ggt(48,18) = 6.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testGGTx3y9() {
|
||||||
|
Instruction[] code = Assembler.readTRAMCode("tramcode/ggt.tram");
|
||||||
|
AbstractMachine tram = new AbstractMachine(code, new Integer[]{3,9});
|
||||||
|
tram.execute();
|
||||||
|
|
||||||
|
assertTrue(tram.isHalted(), "Machine should halt.");
|
||||||
|
int result = tram.result();
|
||||||
|
assertEquals(3, result, "Expected ggt(48,18) = 6.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testGGTx9y3() {
|
||||||
|
Instruction[] code = Assembler.readTRAMCode("tramcode/ggt.tram");
|
||||||
|
AbstractMachine tram = new AbstractMachine(code, new Integer[]{9,3});
|
||||||
|
tram.execute();
|
||||||
|
|
||||||
|
assertTrue(tram.isHalted(), "Machine should halt.");
|
||||||
|
int result = tram.result();
|
||||||
|
assertEquals(3, result, "Expected ggt(48,18) = 6.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testGGTx24y4() {
|
||||||
|
Instruction[] code = Assembler.readTRAMCode("tramcode/ggt.tram");
|
||||||
|
AbstractMachine tram = new AbstractMachine(code, new Integer[]{24,4});
|
||||||
|
tram.execute();
|
||||||
|
|
||||||
|
assertTrue(tram.isHalted(), "Machine should halt.");
|
||||||
|
int result = tram.result();
|
||||||
|
assertEquals(4, result, "Expected ggt(48,18) = 6.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testGGTx16y37() {
|
||||||
|
Instruction[] code = Assembler.readTRAMCode("tramcode/ggt.tram");
|
||||||
|
AbstractMachine tram = new AbstractMachine(code, new Integer[]{16,37});
|
||||||
|
tram.execute();
|
||||||
|
|
||||||
|
assertTrue(tram.isHalted(), "Machine should halt.");
|
||||||
|
int result = tram.result();
|
||||||
|
assertEquals(1, result, "Expected ggt(16,37) = 1.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testGGTx37y16() {
|
||||||
|
Instruction[] code = Assembler.readTRAMCode("tramcode/ggt.tram");
|
||||||
|
AbstractMachine tram = new AbstractMachine(code, new Integer[]{37,16});
|
||||||
|
tram.execute();
|
||||||
|
|
||||||
|
assertTrue(tram.isHalted(), "Machine should halt.");
|
||||||
|
int result = tram.result();
|
||||||
|
assertEquals(1, result, "Expected ggt(37,16) = 1.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,26 @@
|
|||||||
// Quellkode: ggt(a,b) { if (b==0) then a else ggt(b, a mod b) }
|
// Quellkode: ggt(a,b) { if (b==0) then a else ggt(b, a mod b) }
|
||||||
// Annahmen: Die Argumente a und b werden durch Kellerzellen 0 und 1 repräsentiert,
|
// Annahmen: Die Argumente a und b werden durch Kellerzellen 0 und 1 repräsentiert,
|
||||||
// sowie PP=0, FP=0 und TOP=-1
|
// sowie PP=0, FP=0 und TOP=-1
|
||||||
INVOKE 2 LGGT 0
|
INVOKE 2 GGT 0
|
||||||
POP
|
|
||||||
HALT
|
HALT
|
||||||
|
|
||||||
LGGT:
|
GGT: LOAD 1 0
|
||||||
// b
|
IFZERO RET
|
||||||
LOAD 1 0
|
LOAD 1 0
|
||||||
// if b != 0 -> 1
|
|
||||||
IFZERO 1
|
|
||||||
// return a
|
|
||||||
LOAD 0 0
|
|
||||||
RETURN
|
|
||||||
L1:
|
|
||||||
LOAD 1 0 // b
|
|
||||||
LOAD 0 0
|
LOAD 0 0
|
||||||
LOAD 1 0
|
LOAD 1 0
|
||||||
MOD // a mod b
|
INVOKE 2 MOD 1
|
||||||
INVOKE 2 LGGT 0 // ggt(b, a mod b)
|
INVOKE 2 GGT 0
|
||||||
RETURN
|
RETURN
|
||||||
|
|
||||||
|
RET: LOAD 0 0
|
||||||
|
RETURN
|
||||||
|
|
||||||
|
MOD: LOAD 0 0
|
||||||
|
LOAD 1 0
|
||||||
|
LOAD 0 0
|
||||||
|
LOAD 1 0
|
||||||
|
DIV
|
||||||
|
MUL
|
||||||
|
SUB
|
||||||
|
RETURN
|
||||||
@@ -3,10 +3,11 @@
|
|||||||
INVOKE 2 MOD 0
|
INVOKE 2 MOD 0
|
||||||
HALT
|
HALT
|
||||||
|
|
||||||
MOD: LOAD 1 0
|
MOD: LOAD 0 0
|
||||||
|
LOAD 1 0
|
||||||
|
LOAD 0 0
|
||||||
LOAD 1 0
|
LOAD 1 0
|
||||||
DIV
|
DIV
|
||||||
LOAD 2 0
|
|
||||||
MUL
|
MUL
|
||||||
SUB
|
SUB
|
||||||
RETURN
|
RETURN
|
||||||
|
|||||||
Reference in New Issue
Block a user