From 2d1789ff5bba7da121d78a601c42f926894deb6d Mon Sep 17 00:00:00 2001 From: sandersirge Date: Sat, 9 May 2026 14:15:38 +0300 Subject: [PATCH 01/24] =?UTF-8?q?Funktsioonikutsed:=20Samm=201=20-=20Lisat?= =?UTF-8?q?ud=20ALLOC=20k=C3=A4sk=20ja=20pinu=20suuruse=20muutmise=20funkt?= =?UTF-8?q?sionaalsus,=20kaetud=20testidega?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/ee/ut/cs/sws/cma/CMaInterpreter.java | 1 + src/main/java/ee/ut/cs/sws/cma/CMaStack.java | 11 +++++++++++ .../sws/cma/instruction/CMaIntInstruction.java | 3 +++ .../ee/ut/cs/sws/cma/CMaInterpreterTest.java | 17 +++++++++++++++++ 4 files changed, 32 insertions(+) diff --git a/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java b/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java index 0730939..ce835ad 100644 --- a/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java +++ b/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java @@ -92,6 +92,7 @@ case CMaIntInstruction(CMaIntInstruction.Code code, int arg) -> { execute(new CMaIntInstruction(LOADC, arg)); execute(new CMaBasicInstruction(STORE)); } + case ALLOC -> stack.allocate(arg); } } diff --git a/src/main/java/ee/ut/cs/sws/cma/CMaStack.java b/src/main/java/ee/ut/cs/sws/cma/CMaStack.java index 32ff142..002e35e 100644 --- a/src/main/java/ee/ut/cs/sws/cma/CMaStack.java +++ b/src/main/java/ee/ut/cs/sws/cma/CMaStack.java @@ -53,6 +53,17 @@ public int size() { return data.size(); } + /** Kasvata stacki m nulliga algväärtustatud pesa võrra. SP += m */ + public void allocate(int m) { + for (int i = 0; i < m; i++) + data.add(0); + } + + /** Kärbi stack uuele suurusele. SP = newSize - 1 */ + public void truncate(int newSize) { + data.subList(newSize, data.size()).clear(); + } + @Override public boolean equals(Object o) { if (this == o) diff --git a/src/main/java/ee/ut/cs/sws/cma/instruction/CMaIntInstruction.java b/src/main/java/ee/ut/cs/sws/cma/instruction/CMaIntInstruction.java index 659c2e6..677a51d 100644 --- a/src/main/java/ee/ut/cs/sws/cma/instruction/CMaIntInstruction.java +++ b/src/main/java/ee/ut/cs/sws/cma/instruction/CMaIntInstruction.java @@ -12,6 +12,9 @@ public enum Code { /** salvesta väärtus indeksile */ STOREA, + + /** eralda m nulliga algväärtustatud pesa */ + ALLOC, //@formatter:on } diff --git a/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java b/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java index 4fc6223..55b6290 100644 --- a/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java +++ b/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java @@ -216,4 +216,21 @@ public void test_multiple_label() { pw.visit(JUMP, _label); pw.visit(_label); } + + // Funktsioonikutsed: Samm 1 — ALLOC käsu testimine + + @Test + public void test_alloc_empty() { + pw.visit(ALLOC, 3); + + assertInterpreted(new CMaStack(0, 0, 0)); + } + + @Test + public void test_alloc_after_loadc() { + pw.visit(LOADC, 5); + pw.visit(ALLOC, 2); + + assertInterpreted(new CMaStack(5, 0, 0)); + } } From 2541b112e470fb811cb0739d7c453362f2fb0ea5 Mon Sep 17 00:00:00 2001 From: sandersirge Date: Sat, 9 May 2026 14:24:23 +0300 Subject: [PATCH 02/24] Funktsioonikutsed: Samm 2 - Lisatud registrid viitadele FP, EP ja HP --- src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java b/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java index ce835ad..724d7e9 100644 --- a/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java +++ b/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java @@ -11,6 +11,9 @@ public class CMaInterpreter { private final CMaProgram program; private int pc = 0; private final CMaStack stack; + private int fp = 0; // Frame Pointer (raamiviit) + private int ep = 0; // Extreme Pointer (piiriviit) + private int hp = Integer.MAX_VALUE; // Heap Pointer (kuhjaviit) private CMaInterpreter(CMaProgram program, CMaStack initialStack) { this.program = program; From 2fb7129f7ad7e57bcfe77cb21bb4cbcffb287dca Mon Sep 17 00:00:00 2001 From: sandersirge Date: Sat, 9 May 2026 14:31:48 +0300 Subject: [PATCH 03/24] =?UTF-8?q?Funktsioonikutsed:=20Samm=203=20=E2=80=94?= =?UTF-8?q?=20Lisa=20LOADRC,=20LOADR=20ja=20STORER=20k=C3=A4sud,=20testide?= =?UTF-8?q?ga=20kaetud?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/ee/ut/cs/sws/cma/CMaInterpreter.java | 9 ++++++ .../cma/instruction/CMaIntInstruction.java | 9 ++++++ .../ee/ut/cs/sws/cma/CMaInterpreterTest.java | 29 +++++++++++++++++++ 3 files changed, 47 insertions(+) diff --git a/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java b/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java index 724d7e9..4312bab 100644 --- a/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java +++ b/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java @@ -96,6 +96,15 @@ case CMaIntInstruction(CMaIntInstruction.Code code, int arg) -> { execute(new CMaBasicInstruction(STORE)); } case ALLOC -> stack.allocate(arg); + case LOADRC -> stack.push(fp + arg); + case LOADR -> { + execute(new CMaIntInstruction(CMaIntInstruction.Code.LOADRC, arg)); + execute(new CMaBasicInstruction(LOAD)); + } + case STORER -> { + execute(new CMaIntInstruction(CMaIntInstruction.Code.LOADRC, arg)); + execute(new CMaBasicInstruction(STORE)); + } } } diff --git a/src/main/java/ee/ut/cs/sws/cma/instruction/CMaIntInstruction.java b/src/main/java/ee/ut/cs/sws/cma/instruction/CMaIntInstruction.java index 677a51d..22bcac6 100644 --- a/src/main/java/ee/ut/cs/sws/cma/instruction/CMaIntInstruction.java +++ b/src/main/java/ee/ut/cs/sws/cma/instruction/CMaIntInstruction.java @@ -15,6 +15,15 @@ public enum Code { /** eralda m nulliga algväärtustatud pesa */ ALLOC, + + /** lisa stackile FP + j (suhteline aadress) */ + LOADRC, + + /** loe väärtus FP-suhteliselt indeksilt */ + LOADR, + + /** salvesta väärtus FP-suhtelisele indeksile */ + STORER, //@formatter:on } diff --git a/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java b/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java index 55b6290..32d11f0 100644 --- a/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java +++ b/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java @@ -233,4 +233,33 @@ public void test_alloc_after_loadc() { assertInterpreted(new CMaStack(5, 0, 0)); } + + // Funktsioonikutsed: Samm 3 — LOADRC, LOADR ja STORER käskude testimine + + @Test + public void test_loadrc() { + // fp = 0 (vaikeväärtus), LOADRC 3 → push(0 + 3) = 3 + pw.visit(LOADRC, 3); + + assertInterpreted(new CMaStack(3)); + } + + @Test + public void test_loadr() { + // stack: [10, 20, 30], fp = 0 (vaikeväärtus) + // LOADR 2 → push(fp + 2) = push(2), LOAD → push(stack[2]) = 30 + pw.visit(LOADR, 2); + + assertInterpreted(new CMaStack(10, 20, 30, 30), new CMaStack(10, 20, 30)); + } + + @Test + public void test_storer() { + // stack: [10, 20, 30], fp = 0 (vaikeväärtus) + // LOADC 99; STORER 1 → push(fp + 1) = push(1), STORE → stack[1] = 99 + pw.visit(LOADC, 99); + pw.visit(STORER, 1); + + assertInterpreted(new CMaStack(10, 99, 30, 99), new CMaStack(10, 20, 30)); + } } From 4364474dec249c1395963366f130024301ef060f Mon Sep 17 00:00:00 2001 From: sandersirge Date: Sat, 9 May 2026 14:41:40 +0300 Subject: [PATCH 04/24] =?UTF-8?q?Funktsioonikutsed:=20Samm=204=20=E2=80=94?= =?UTF-8?q?=20Lisa=20MARK=20ja=20CALL=20k=C3=A4sud,=20testidega=20kaetud?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/ee/ut/cs/sws/cma/CMaInterpreter.java | 12 +++++++++ .../cma/instruction/CMaBasicInstruction.java | 6 +++++ .../ee/ut/cs/sws/cma/CMaInterpreterTest.java | 25 +++++++++++++++++++ 3 files changed, 43 insertions(+) diff --git a/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java b/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java index 4312bab..8d07fea 100644 --- a/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java +++ b/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java @@ -82,6 +82,18 @@ case CMaBasicInstruction(CMaBasicInstruction.Code code) -> { stack.set(arg, stack.peek()); } case HALT -> pc = -1; // out of range pc halts + case MARK -> { + // S[SP+1] = EP; S[SP+2] = FP; SP += 2 + stack.push(ep); + stack.push(fp); + } + case CALL -> { + // FP = SP; tmp = PC; PC = S[FP]; S[FP] = tmp + fp = stack.size() - 1; // SP = stack.size() - 1 + int tmp = pc; + pc = stack.get(fp); + stack.set(fp, tmp); + } } } case CMaIntInstruction(CMaIntInstruction.Code code, int arg) -> { diff --git a/src/main/java/ee/ut/cs/sws/cma/instruction/CMaBasicInstruction.java b/src/main/java/ee/ut/cs/sws/cma/instruction/CMaBasicInstruction.java index 6c9c32d..3d22fa9 100644 --- a/src/main/java/ee/ut/cs/sws/cma/instruction/CMaBasicInstruction.java +++ b/src/main/java/ee/ut/cs/sws/cma/instruction/CMaBasicInstruction.java @@ -37,6 +37,12 @@ public enum Code { /** seiska programm */ HALT, + + /** salvesta EP ja FP stackile (täitmisraami ettevalmistus) */ + MARK, + + /** kutsu funktsioon: FP=SP, vaheta PC ja S[FP] */ + CALL, //@formatter:on } diff --git a/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java b/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java index 32d11f0..63c1ebd 100644 --- a/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java +++ b/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java @@ -262,4 +262,29 @@ public void test_storer() { assertInterpreted(new CMaStack(10, 99, 30, 99), new CMaStack(10, 20, 30)); } + + // Funktsioonikutsed: Samm 4 — MARK ja CALL käskude testimine + + @Test + public void test_mark_call() { + // Stack enne: [] + // LOADC 42 → [42] (parameeter) + // MARK → [42, 0, 0] (push EP=0, push FP=0) + // LOADC 5 → [42, 0, 0, 5] (funktsiooni aadress) + // CALL → FP=3, PC=5, S[3]=4 → stack: [42, 0, 0, 4] + // indeks 4: HALT (tagastuspunkt, siia ei jõua) + // indeks 5: HALT (funktsioon peatub kohe) + CMaLabel _func = new CMaLabel(); + + pw.visit(LOADC, 42); // 0: parameeter + pw.visit(MARK); // 1: push EP(0), push FP(0) + pw.visit(LOADC, 5); // 2: funktsiooni aadress (indeks 5) + pw.visit(CALL); // 3: FP=3, PC=5, S[3]=4 (tagastusaadress) + pw.visit(HALT); // 4: tagastuspunkt + pw.visit(_func); // 5: funktsiooni algus + pw.visit(HALT); // 5: funktsioon peatub kohe + + // Stack pärast: [42, 0, 0, 4] — parameeter, salvestatud EP, FP, tagastusaadress + assertInterpreted(new CMaStack(42, 0, 0, 4)); + } } From 538db174d5cc9bae5e6d80c434c7e0a15d7746e6 Mon Sep 17 00:00:00 2001 From: sandersirge Date: Sat, 9 May 2026 14:50:59 +0300 Subject: [PATCH 05/24] =?UTF-8?q?Funktsioonikutsed:=20Samm=205=20=E2=80=94?= =?UTF-8?q?=20Lisa=20ENTER=20k=C3=A4sk,=20testidega=20kaetud?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/ee/ut/cs/sws/cma/CMaInterpreter.java | 8 ++++ .../cma/instruction/CMaIntInstruction.java | 3 ++ .../ee/ut/cs/sws/cma/CMaInterpreterTest.java | 40 +++++++++++++++++++ 3 files changed, 51 insertions(+) diff --git a/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java b/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java index 8d07fea..493ad1d 100644 --- a/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java +++ b/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java @@ -110,13 +110,21 @@ case CMaIntInstruction(CMaIntInstruction.Code code, int arg) -> { case ALLOC -> stack.allocate(arg); case LOADRC -> stack.push(fp + arg); case LOADR -> { + // LOADR j = LOADRC j; LOAD execute(new CMaIntInstruction(CMaIntInstruction.Code.LOADRC, arg)); execute(new CMaBasicInstruction(LOAD)); } case STORER -> { + // STORER j = LOADRC j; STORE execute(new CMaIntInstruction(CMaIntInstruction.Code.LOADRC, arg)); execute(new CMaBasicInstruction(STORE)); } + case ENTER -> { + // EP = SP + m; kui EP >= HP, siis viga + ep = stack.size() - 1 + arg; + if (ep >= hp) + throw new CMaException("Stack Overflow: EP(%d) >= HP(%d)".formatted(ep, hp)); + } } } diff --git a/src/main/java/ee/ut/cs/sws/cma/instruction/CMaIntInstruction.java b/src/main/java/ee/ut/cs/sws/cma/instruction/CMaIntInstruction.java index 22bcac6..69432b8 100644 --- a/src/main/java/ee/ut/cs/sws/cma/instruction/CMaIntInstruction.java +++ b/src/main/java/ee/ut/cs/sws/cma/instruction/CMaIntInstruction.java @@ -24,6 +24,9 @@ public enum Code { /** salvesta väärtus FP-suhtelisele indeksile */ STORER, + + /** sea piirviit EP = SP + m, kontrolli EP >= HP */ + ENTER, //@formatter:on } diff --git a/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java b/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java index 63c1ebd..f371847 100644 --- a/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java +++ b/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java @@ -287,4 +287,44 @@ public void test_mark_call() { // Stack pärast: [42, 0, 0, 4] — parameeter, salvestatud EP, FP, tagastusaadress assertInterpreted(new CMaStack(42, 0, 0, 4)); } + + // Funktsioonikutsed: Samm 5 — ENTER käsu testimine + + @Test + public void test_enter() { + // stack: [10, 20], ENTER 5 → EP = (2-1) + 5 = 6 + // MARK → push EP(6), push FP(0) → stack: [10, 20, 6, 0] + // Kontrollime EP väärtust läbi MARK käsu + pw.visit(ENTER, 5); + pw.visit(MARK); + + assertInterpreted(new CMaStack(10, 20, 6, 0), new CMaStack(10, 20)); + } + + @Test + public void test_enter_in_function() { + // MARK/CALL/ENTER tsükkel: funktsioon kutsutakse ja ENTER seab EP + // LOADC 42 → [42] + // MARK → [42, 0, 0] + // LOADC 5 → [42, 0, 0, 5] (funktsiooni aadress, _func label indeksil 5) + // CALL → FP=3, PC=5, S[3]=4 → [42, 0, 0, 4] + // HALT (tagastuspunkt, indeks 4) + // _func (indeks 5): ENTER 3 → EP = (4-1) + 3 = 6 + // MARK → push EP(6), push FP(3) → [42, 0, 0, 4, 6, 3] + // HALT + CMaLabel _func = new CMaLabel(); + + pw.visit(LOADC, 42); // 0: parameeter + pw.visit(MARK); // 1: push EP(0), push FP(0) + pw.visit(LOADC, 5); // 2: funktsiooni aadress (indeks 5) + pw.visit(CALL); // 3: FP=3, PC=5, S[3]=4 + pw.visit(HALT); // 4: tagastuspunkt + pw.visit(_func); // label indeksil 5 + pw.visit(ENTER, 3); // 5: EP = (4-1) + 3 = 6 + pw.visit(MARK); // 6: push EP(6), push FP(3) + pw.visit(HALT); // 7: funktsioon peatub + + // Stack pärast: [42, 0, 0, 4, 6, 3] + assertInterpreted(new CMaStack(42, 0, 0, 4, 6, 3)); + } } From 9022e1da5a426969c0a6c0efe7d0989a2296d3b9 Mon Sep 17 00:00:00 2001 From: sandersirge Date: Sat, 9 May 2026 14:59:51 +0300 Subject: [PATCH 06/24] =?UTF-8?q?Funktsioonikutsed:=20Samm=206=20=E2=80=94?= =?UTF-8?q?=20Lisa=20RETURN=20k=C3=A4sk,=20kaetud=20testiga?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/ee/ut/cs/sws/cma/CMaInterpreter.java | 12 ++++ .../cma/instruction/CMaIntInstruction.java | 3 + .../ee/ut/cs/sws/cma/CMaInterpreterTest.java | 69 +++++++++++++++++++ 3 files changed, 84 insertions(+) diff --git a/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java b/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java index 493ad1d..8d28474 100644 --- a/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java +++ b/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java @@ -125,6 +125,18 @@ case CMaIntInstruction(CMaIntInstruction.Code code, int arg) -> { if (ep >= hp) throw new CMaException("Stack Overflow: EP(%d) >= HP(%d)".formatted(ep, hp)); } + case RETURN -> { + // PC = S[FP]; EP = S[FP-2]; kontrolli EP >= HP; + // SP = FP - q (truncate(FP - q + 1)); FP = S[FP-1] + pc = stack.get(fp); // taasta tagastusaadress + ep = stack.get(fp - 2); // taasta vana EP + if (ep >= hp) + throw new CMaException("Stack Overflow: EP(%d) >= HP(%d)".formatted(ep, hp)); + int newSp = fp - arg; // SP = FP - q + int newFp = stack.get(fp - 1); // taasta vana FP + stack.truncate(newSp + 1); // kärbi stack: size = SP + 1 + fp = newFp; + } } } diff --git a/src/main/java/ee/ut/cs/sws/cma/instruction/CMaIntInstruction.java b/src/main/java/ee/ut/cs/sws/cma/instruction/CMaIntInstruction.java index 69432b8..71ab498 100644 --- a/src/main/java/ee/ut/cs/sws/cma/instruction/CMaIntInstruction.java +++ b/src/main/java/ee/ut/cs/sws/cma/instruction/CMaIntInstruction.java @@ -27,6 +27,9 @@ public enum Code { /** sea piirviit EP = SP + m, kontrolli EP >= HP */ ENTER, + + /** taasta registrid ja puhasta täitmisraam, q = org. pesade + parameetrite arv */ + RETURN, //@formatter:on } diff --git a/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java b/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java index f371847..f6a0312 100644 --- a/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java +++ b/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java @@ -327,4 +327,73 @@ public void test_enter_in_function() { // Stack pärast: [42, 0, 0, 4, 6, 3] assertInterpreted(new CMaStack(42, 0, 0, 4, 6, 3)); } + + // Funktsioonikutsed: Samm 6 — RETURN käsu testimine + + @Test + public void test_call_return() { + // Täielik kutse-tagastus tsükkel: + // Peaprogramm kutsub funktsiooni, mis kohe tagastab. + // + // 0: LOADC 42 → [42] (parameeter) + // 1: MARK → [42, 0, 0] (push EP=0, FP=0) + // 2: LOADC 6 → [42, 0, 0, 6] (funktsiooni aadress) + // 3: CALL → FP=3, PC=6, S[3]=4 → [42, 0, 0, 4] + // 4: HALT (tagastuspunkt) + // + // _func (indeks 5): + // 5: ENTER 0 → EP = (4-1)+0 = 3 + // 6: RETURN 3 → PC=S[3]=4, EP=S[1]=0, FP=S[2]=0 + // SP = 3-3 = 0, truncate(1) → [42] + // PC=4 → jõuab HALT-i + CMaLabel _func = new CMaLabel(); + + pw.visit(LOADC, 42); // 0: parameeter + pw.visit(MARK); // 1: push EP(0), push FP(0) + pw.visit(LOADC, 5); // 2: funktsiooni aadress + pw.visit(CALL); // 3: FP=3, PC=5, S[3]=4 + pw.visit(HALT); // 4: tagastuspunkt + pw.visit(_func); // label indeksil 5 + pw.visit(ENTER, 0); // 5: EP = 3 + pw.visit(RETURN, 3); // 6: taasta ja kärbi, q=3 (EP+FP+PC) + + // Pärast RETURN: stack = [42], PC=4 → HALT + assertInterpreted(new CMaStack(42)); + } + + @Test + public void test_call_return_with_locals() { + // Funktsioon eraldab lokaalse muutuja, kirjutab sinna ja tagastab. + // + // 0: LOADC 10 → [10] (parameeter) + // 1: MARK → [10, 0, 0] + // 2: LOADC 5 → [10, 0, 0, 5] + // 3: CALL → FP=3, PC=5, S[3]=4 → [10, 0, 0, 4] + // 4: HALT + // + // _func (indeks 5): + // 5: ENTER 1 → EP = (4-1)+1 = 4 + // 6: ALLOC 1 → [10, 0, 0, 4, 0] (lokaalne muutuja indeksil 4) + // 7: LOADC 99 + // 8: STORER 1 → stack[FP+1]=stack[4]=99 → [10, 0, 0, 4, 99, 99] + // 9: POP → [10, 0, 0, 4, 99] + // 10: RETURN 3 → PC=4, EP=0, SP=3-3=0, FP=0, truncate(1) → [10] + CMaLabel _func = new CMaLabel(); + + pw.visit(LOADC, 10); // 0: parameeter + pw.visit(MARK); // 1 + pw.visit(LOADC, 5); // 2: funktsiooni aadress + pw.visit(CALL); // 3 + pw.visit(HALT); // 4 + pw.visit(_func); // label indeksil 5 + pw.visit(ENTER, 1); // 5 + pw.visit(ALLOC, 1); // 6: lokaalne muutuja + pw.visit(LOADC, 99); // 7 + pw.visit(STORER, 1); // 8: kirjuta lokaalsesse muutujasse + pw.visit(POP); // 9 + pw.visit(RETURN, 3); // 10: tagasta, q=3 + + // Pärast RETURN: stack = [10], PC=4 → HALT + assertInterpreted(new CMaStack(10)); + } } From 7499783b902e89333993f9b8b6ee482db8374d74 Mon Sep 17 00:00:00 2001 From: sandersirge Date: Sun, 10 May 2026 11:22:37 +0300 Subject: [PATCH 07/24] =?UTF-8?q?Funktsioonikutsed:=20Samm=207=20=E2=80=94?= =?UTF-8?q?=20Lisatud=20SLIDE=20k=C3=A4sk=20ja=20uus=20record-klass=20CMaI?= =?UTF-8?q?ntIntInstruction,=20kaetud=20testidega?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/ee/ut/cs/sws/cma/CMaInterpreter.java | 12 ++++++ .../ee/ut/cs/sws/cma/CMaProgramWriter.java | 5 +++ .../sws/cma/instruction/CMaInstruction.java | 2 +- .../cma/instruction/CMaIntIntInstruction.java | 17 ++++++++ .../ee/ut/cs/sws/cma/CMaInterpreterTest.java | 42 +++++++++++++++++++ 5 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 src/main/java/ee/ut/cs/sws/cma/instruction/CMaIntIntInstruction.java diff --git a/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java b/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java index 8d28474..2ef6c39 100644 --- a/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java +++ b/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java @@ -140,6 +140,18 @@ case CMaIntInstruction(CMaIntInstruction.Code code, int arg) -> { } } + case CMaIntIntInstruction(CMaIntIntInstruction.Code code, int arg1, int arg2) -> { + switch (code) { + case SLIDE -> { + // SLIDE q m: kopeeri m väärtust q positsiooni allapoole, kärbi stack + // Book: for i=1 to m: S[SP-q-m+i] = S[SP-m+i]; SP = SP-q + int sp = stack.size() - 1; + for (int i = 1; i <= arg2; i++) + stack.set(sp - arg1 - arg2 + i, stack.get(sp - arg2 + i)); + stack.truncate(sp - arg1 + 1); // SP = SP - q, size = SP - q + 1 + } + } + } case CMaLabelInstruction(CMaLabelInstruction.Code code, CMaLabel label) -> { switch (code) { case JUMP -> pc = getLabelTarget(label); diff --git a/src/main/java/ee/ut/cs/sws/cma/CMaProgramWriter.java b/src/main/java/ee/ut/cs/sws/cma/CMaProgramWriter.java index c7b560a..30e842a 100644 --- a/src/main/java/ee/ut/cs/sws/cma/CMaProgramWriter.java +++ b/src/main/java/ee/ut/cs/sws/cma/CMaProgramWriter.java @@ -3,6 +3,7 @@ import ee.ut.cs.sws.cma.instruction.CMaBasicInstruction; import ee.ut.cs.sws.cma.instruction.CMaInstruction; import ee.ut.cs.sws.cma.instruction.CMaIntInstruction; +import ee.ut.cs.sws.cma.instruction.CMaIntIntInstruction; import ee.ut.cs.sws.cma.instruction.CMaLabelInstruction; import java.util.ArrayList; @@ -27,6 +28,10 @@ public void visit(CMaIntInstruction.Code code, int arg) { visit(new CMaIntInstruction(code, arg)); } + public void visit(CMaIntIntInstruction.Code code, int arg1, int arg2) { + visit(new CMaIntIntInstruction(code, arg1, arg2)); + } + public void visit(CMaLabelInstruction.Code code, CMaLabel label) { visit(new CMaLabelInstruction(code, label)); } diff --git a/src/main/java/ee/ut/cs/sws/cma/instruction/CMaInstruction.java b/src/main/java/ee/ut/cs/sws/cma/instruction/CMaInstruction.java index abaaf0c..7db0dc0 100644 --- a/src/main/java/ee/ut/cs/sws/cma/instruction/CMaInstruction.java +++ b/src/main/java/ee/ut/cs/sws/cma/instruction/CMaInstruction.java @@ -1,6 +1,6 @@ package ee.ut.cs.sws.cma.instruction; -public sealed interface CMaInstruction permits CMaBasicInstruction, CMaIntInstruction, CMaLabelInstruction { +public sealed interface CMaInstruction permits CMaBasicInstruction, CMaIntInstruction, CMaIntIntInstruction, CMaLabelInstruction { Code code(); diff --git a/src/main/java/ee/ut/cs/sws/cma/instruction/CMaIntIntInstruction.java b/src/main/java/ee/ut/cs/sws/cma/instruction/CMaIntIntInstruction.java new file mode 100644 index 0000000..fafe281 --- /dev/null +++ b/src/main/java/ee/ut/cs/sws/cma/instruction/CMaIntIntInstruction.java @@ -0,0 +1,17 @@ +package ee.ut.cs.sws.cma.instruction; + +public record CMaIntIntInstruction(Code code, int arg1, int arg2) implements CMaInstruction { + + public enum Code { + //@formatter:off + /** nihuta m väärtust q positsiooni võrra allapoole */ + SLIDE, + //@formatter:on + } + + @Override + public String toString() { + return code.name() + " " + arg1 + " " + arg2; + } +} + diff --git a/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java b/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java index f6a0312..a5e9745 100644 --- a/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java +++ b/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java @@ -7,6 +7,7 @@ import static ee.ut.cs.sws.cma.instruction.CMaBasicInstruction.Code.*; import static ee.ut.cs.sws.cma.instruction.CMaIntInstruction.Code.*; +import static ee.ut.cs.sws.cma.instruction.CMaIntIntInstruction.Code.*; import static ee.ut.cs.sws.cma.instruction.CMaLabelInstruction.Code.*; import static org.junit.Assert.*; @@ -396,4 +397,45 @@ public void test_call_return_with_locals() { // Pärast RETURN: stack = [10], PC=4 → HALT assertInterpreted(new CMaStack(10)); } + + // Funktsioonikutsed: Samm 7 — SLIDE käsu testimine + + @Test + public void test_slide() { + // stack: [10, 20, 30], SLIDE 2 1 → kopeeri 1 väärtus (30) 2 positsiooni allapoole + // S[SP-2-1+1] = S[SP-1+1] → S[0] = S[2] = 30 → stack: [30, 20, 30] + // truncate(SP-2+1) = truncate(1) → stack: [30] + pw.visit(LOADC, 10); + pw.visit(LOADC, 20); + pw.visit(LOADC, 30); + pw.visit(SLIDE, 2, 1); + + assertInterpreted(new CMaStack(30)); + } + + @Test + public void test_slide_multiple_values() { + // stack: [1, 2, 3, 4, 5], SLIDE 2 2 → kopeeri 2 väärtust (4, 5) 2 positsiooni allapoole + // S[SP-2-2+1] = S[SP-2+1] → S[1] = S[3] = 4 + // S[SP-2-2+2] = S[SP-2+2] → S[2] = S[4] = 5 + // truncate(SP-2+1) = truncate(3) → stack: [1, 4, 5] + pw.visit(LOADC, 1); + pw.visit(LOADC, 2); + pw.visit(LOADC, 3); + pw.visit(LOADC, 4); + pw.visit(LOADC, 5); + pw.visit(SLIDE, 2, 2); + + assertInterpreted(new CMaStack(1, 4, 5)); + } + + @Test + public void test_slide_zero() { + // stack: [10, 20], SLIDE 0 1 → q=0, nihkumist pole, truncate(SP+1) → muutumatu + pw.visit(LOADC, 10); + pw.visit(LOADC, 20); + pw.visit(SLIDE, 0, 1); + + assertInterpreted(new CMaStack(10, 20)); + } } From 2ae3b9dea9ae52244e246286f9c411384990edad Mon Sep 17 00:00:00 2001 From: sandersirge Date: Sun, 10 May 2026 11:28:09 +0300 Subject: [PATCH 08/24] =?UTF-8?q?Funktsioonikutsed:=20Samm=208=20=E2=80=94?= =?UTF-8?q?=20Lisa=20JUMPI=20k=C3=A4sk,=20kaetud=20testidega?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/ee/ut/cs/sws/cma/CMaInterpreter.java | 4 + .../cma/instruction/CMaLabelInstruction.java | 3 + .../ee/ut/cs/sws/cma/CMaInterpreterTest.java | 86 +++++++++++++++++++ 3 files changed, 93 insertions(+) diff --git a/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java b/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java index 2ef6c39..a30589a 100644 --- a/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java +++ b/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java @@ -159,6 +159,10 @@ case CMaLabelInstruction(CMaLabelInstruction.Code code, CMaLabel label) -> { if (!CMaUtils.int2bool(stack.pop())) pc = getLabelTarget(label); } + case JUMPI -> { + // PC = target(label) + S[SP]; SP-- + pc = getLabelTarget(label) + stack.pop(); + } } } } diff --git a/src/main/java/ee/ut/cs/sws/cma/instruction/CMaLabelInstruction.java b/src/main/java/ee/ut/cs/sws/cma/instruction/CMaLabelInstruction.java index 50f58bc..87d4678 100644 --- a/src/main/java/ee/ut/cs/sws/cma/instruction/CMaLabelInstruction.java +++ b/src/main/java/ee/ut/cs/sws/cma/instruction/CMaLabelInstruction.java @@ -11,6 +11,9 @@ public enum Code { /** hüppa labelile kui stackipealne väärtus on 0 */ JUMPZ, + + /** indekseeritud hüpe: PC = target(label) + S[SP]; SP-- */ + JUMPI, //@formatter:on } diff --git a/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java b/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java index a5e9745..3905e09 100644 --- a/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java +++ b/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java @@ -438,4 +438,90 @@ public void test_slide_zero() { assertInterpreted(new CMaStack(10, 20)); } + + // Funktsioonikutsed: Samm 8 — JUMPI käsu testimine + + @Test + public void test_jumpi() { + // Hüppetabel: väärtus 0 → case0, väärtus 1 → case1, väärtus 2 → case2 + // Iga case laeb oma väärtuse stackile ja peatub. + CMaLabel _table = new CMaLabel(); + CMaLabel _case0 = new CMaLabel(); + CMaLabel _case1 = new CMaLabel(); + CMaLabel _case2 = new CMaLabel(); + + // Programm: LOADC index; JUMPI _table; _table: JUMP _case0; JUMP _case1; JUMP _case2 + pw.visit(LOADC, 0); // 0: indeks + pw.visit(JUMPI, _table); // 1: PC = target(_table) + 0 = 2 + pw.visit(_table); // indeks 2 + pw.visit(JUMP, _case0); // 2: hüppa case0-le + pw.visit(JUMP, _case1); // 3: hüppa case1-le + pw.visit(JUMP, _case2); // 4: hüppa case2-le + pw.visit(_case0); + pw.visit(LOADC, 100); // 5 + pw.visit(HALT); // 6 + pw.visit(_case1); + pw.visit(LOADC, 200); // 7 + pw.visit(HALT); // 8 + pw.visit(_case2); + pw.visit(LOADC, 300); // 9 + pw.visit(HALT); // 10 + + // Indeks 0 → case0 → stack: [100] + assertInterpreted(new CMaStack(100)); + } + + @Test + public void test_jumpi_index1() { + CMaLabel _table = new CMaLabel(); + CMaLabel _case0 = new CMaLabel(); + CMaLabel _case1 = new CMaLabel(); + CMaLabel _case2 = new CMaLabel(); + + pw.visit(LOADC, 1); // 0: indeks + pw.visit(JUMPI, _table); // 1: PC = target(_table) + 1 = 3 + pw.visit(_table); + pw.visit(JUMP, _case0); // 2 + pw.visit(JUMP, _case1); // 3 + pw.visit(JUMP, _case2); // 4 + pw.visit(_case0); + pw.visit(LOADC, 100); + pw.visit(HALT); + pw.visit(_case1); + pw.visit(LOADC, 200); + pw.visit(HALT); + pw.visit(_case2); + pw.visit(LOADC, 300); + pw.visit(HALT); + + // Indeks 1 → case1 → stack: [200] + assertInterpreted(new CMaStack(200)); + } + + @Test + public void test_jumpi_index2() { + CMaLabel _table = new CMaLabel(); + CMaLabel _case0 = new CMaLabel(); + CMaLabel _case1 = new CMaLabel(); + CMaLabel _case2 = new CMaLabel(); + + pw.visit(LOADC, 2); // 0: indeks + pw.visit(JUMPI, _table); // 1: PC = target(_table) + 2 = 4 + pw.visit(_table); + pw.visit(JUMP, _case0); // 2 + pw.visit(JUMP, _case1); // 3 + pw.visit(JUMP, _case2); // 4 + pw.visit(_case0); + pw.visit(LOADC, 100); + pw.visit(HALT); + pw.visit(_case1); + pw.visit(LOADC, 200); + pw.visit(HALT); + pw.visit(_case2); + pw.visit(LOADC, 300); + pw.visit(HALT); + + // Indeks 2 → case2 → stack: [300] + assertInterpreted(new CMaStack(300)); + } } From aa234b143b8fb0017461a9861bf62b5b000116fe Mon Sep 17 00:00:00 2001 From: sandersirge Date: Sun, 10 May 2026 22:23:00 +0300 Subject: [PATCH 09/24] =?UTF-8?q?Funktsioonikutsed:=20Samm=209=20-=20Integ?= =?UTF-8?q?ratsioonitestid=20lisatud=20uusi=20k=C3=A4ske=20kasutavate=20t?= =?UTF-8?q?=C3=B6=C3=B6voogude=20testimiseks,=20dokumentatsioon=20parandat?= =?UTF-8?q?ud?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/ee/ut/cs/sws/cma/CMaInterpreter.java | 33 +- .../cma/instruction/CMaIntIntInstruction.java | 2 +- .../ee/ut/cs/sws/cma/CMaInterpreterTest.java | 650 ++++++++++++++---- 3 files changed, 543 insertions(+), 142 deletions(-) diff --git a/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java b/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java index a30589a..465fa53 100644 --- a/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java +++ b/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java @@ -128,12 +128,12 @@ case CMaIntInstruction(CMaIntInstruction.Code code, int arg) -> { case RETURN -> { // PC = S[FP]; EP = S[FP-2]; kontrolli EP >= HP; // SP = FP - q (truncate(FP - q + 1)); FP = S[FP-1] - pc = stack.get(fp); // taasta tagastusaadress - ep = stack.get(fp - 2); // taasta vana EP + pc = stack.get(fp); // taasta tagastusaadress + ep = stack.get(fp - 2); // taasta vana EP if (ep >= hp) throw new CMaException("Stack Overflow: EP(%d) >= HP(%d)".formatted(ep, hp)); - int newSp = fp - arg; // SP = FP - q - int newFp = stack.get(fp - 1); // taasta vana FP + int newSp = fp - arg; // SP = FP - q + int newFp = stack.get(fp - 1); // taasta vana FP stack.truncate(newSp + 1); // kärbi stack: size = SP + 1 fp = newFp; } @@ -143,12 +143,25 @@ case CMaIntInstruction(CMaIntInstruction.Code code, int arg) -> { case CMaIntIntInstruction(CMaIntIntInstruction.Code code, int arg1, int arg2) -> { switch (code) { case SLIDE -> { - // SLIDE q m: kopeeri m väärtust q positsiooni allapoole, kärbi stack - // Book: for i=1 to m: S[SP-q-m+i] = S[SP-m+i]; SP = SP-q - int sp = stack.size() - 1; - for (int i = 1; i <= arg2; i++) - stack.set(sp - arg1 - arg2 + i, stack.get(sp - arg2 + i)); - stack.truncate(sp - arg1 + 1); // SP = SP - q, size = SP - q + 1 + // SLIDE q m: nihuta m pealmist väärtust q positsiooni allapoole + // if (q > 0) + // if (m = 0) SP ← SP - q; + // else { SP ← SP-q-m; for (i←0; i 0) { + int sp = stack.size() - 1; + if (arg2 == 0) { + // m = 0: lihtsalt kärbi q pesa + stack.truncate(sp - arg1 + 1); // SP = SP - q, size = SP - q + 1 + } else { + // kopeeri m väärtust q positsiooni allapoole, siis kärbi + sp = sp - arg1 - arg2; + for (int i = 0; i < arg2; i++) { + sp++; + stack.set(sp, stack.get(sp + arg1)); // S[SP] ← S[SP+q] + } + stack.truncate(sp + 1); // SP = SP - q, size = SP - q + 1 + } + } } } } diff --git a/src/main/java/ee/ut/cs/sws/cma/instruction/CMaIntIntInstruction.java b/src/main/java/ee/ut/cs/sws/cma/instruction/CMaIntIntInstruction.java index fafe281..ab99aab 100644 --- a/src/main/java/ee/ut/cs/sws/cma/instruction/CMaIntIntInstruction.java +++ b/src/main/java/ee/ut/cs/sws/cma/instruction/CMaIntIntInstruction.java @@ -4,7 +4,7 @@ public record CMaIntIntInstruction(Code code, int arg1, int arg2) implements CMa public enum Code { //@formatter:off - /** nihuta m väärtust q positsiooni võrra allapoole */ + /** nihuta m pealmist väärtust q positsiooni võrra allapoole */ SLIDE, //@formatter:on } diff --git a/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java b/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java index 3905e09..5d6b755 100644 --- a/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java +++ b/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java @@ -239,7 +239,7 @@ public void test_alloc_after_loadc() { @Test public void test_loadrc() { - // fp = 0 (vaikeväärtus), LOADRC 3 → push(0 + 3) = 3 + /* fp = 0 (vaikeväärtus), LOADRC 3 → push(0 + 3) = 3 */ pw.visit(LOADRC, 3); assertInterpreted(new CMaStack(3)); @@ -247,8 +247,10 @@ public void test_loadrc() { @Test public void test_loadr() { - // stack: [10, 20, 30], fp = 0 (vaikeväärtus) - // LOADR 2 → push(fp + 2) = push(2), LOAD → push(stack[2]) = 30 + /* + * stack: [10, 20, 30], fp = 0 (vaikeväärtus) + * LOADR 2 → push(fp + 2) = push(2), LOAD → push(stack[2]) = 30 + */ pw.visit(LOADR, 2); assertInterpreted(new CMaStack(10, 20, 30, 30), new CMaStack(10, 20, 30)); @@ -256,8 +258,10 @@ public void test_loadr() { @Test public void test_storer() { - // stack: [10, 20, 30], fp = 0 (vaikeväärtus) - // LOADC 99; STORER 1 → push(fp + 1) = push(1), STORE → stack[1] = 99 + /* + * stack: [10, 20, 30], fp = 0 (vaikeväärtus) + * LOADC 99; STORER 1 → push(fp + 1) = push(1), STORE → stack[1] = 99 + */ pw.visit(LOADC, 99); pw.visit(STORER, 1); @@ -268,24 +272,26 @@ public void test_storer() { @Test public void test_mark_call() { - // Stack enne: [] - // LOADC 42 → [42] (parameeter) - // MARK → [42, 0, 0] (push EP=0, push FP=0) - // LOADC 5 → [42, 0, 0, 5] (funktsiooni aadress) - // CALL → FP=3, PC=5, S[3]=4 → stack: [42, 0, 0, 4] - // indeks 4: HALT (tagastuspunkt, siia ei jõua) - // indeks 5: HALT (funktsioon peatub kohe) + /* + * Stack enne: [] + * LOADC 42 → [42] (parameeter) + * MARK → [42, 0, 0] (push EP=0, push FP=0) + * LOADC 5 → [42, 0, 0, 5] (funktsiooni aadress) + * CALL → FP=3, PC=5, S[3]=4 → stack: [42, 0, 0, 4] + * indeks 4: HALT (tagastuspunkt, siia ei jõua) + * indeks 5: HALT (funktsioon peatub kohe) + */ CMaLabel _func = new CMaLabel(); - pw.visit(LOADC, 42); // 0: parameeter - pw.visit(MARK); // 1: push EP(0), push FP(0) - pw.visit(LOADC, 5); // 2: funktsiooni aadress (indeks 5) - pw.visit(CALL); // 3: FP=3, PC=5, S[3]=4 (tagastusaadress) - pw.visit(HALT); // 4: tagastuspunkt - pw.visit(_func); // 5: funktsiooni algus - pw.visit(HALT); // 5: funktsioon peatub kohe + pw.visit(LOADC, 42); // 0: parameeter + pw.visit(MARK); // 1: push EP(0), push FP(0) + pw.visit(LOADC, 5); // 2: funktsiooni aadress (indeks 5) + pw.visit(CALL); // 3: FP=3, PC=5, S[3]=4 (tagastusaadress) + pw.visit(HALT); // 4: tagastuspunkt + pw.visit(_func); // 5: funktsiooni algus + pw.visit(HALT); // 5: funktsioon peatub kohe - // Stack pärast: [42, 0, 0, 4] — parameeter, salvestatud EP, FP, tagastusaadress + /* Stack pärast: [42, 0, 0, 4] — parameeter, salv. EP, FP, tagastusaadress */ assertInterpreted(new CMaStack(42, 0, 0, 4)); } @@ -293,9 +299,11 @@ public void test_mark_call() { @Test public void test_enter() { - // stack: [10, 20], ENTER 5 → EP = (2-1) + 5 = 6 - // MARK → push EP(6), push FP(0) → stack: [10, 20, 6, 0] - // Kontrollime EP väärtust läbi MARK käsu + /* + * stack: [10, 20], ENTER 5 → EP = (2-1) + 5 = 6 + * MARK → push EP(6), push FP(0) → stack: [10, 20, 6, 0] + * Kontrollime EP väärtust läbi MARK käsu + */ pw.visit(ENTER, 5); pw.visit(MARK); @@ -304,28 +312,30 @@ public void test_enter() { @Test public void test_enter_in_function() { - // MARK/CALL/ENTER tsükkel: funktsioon kutsutakse ja ENTER seab EP - // LOADC 42 → [42] - // MARK → [42, 0, 0] - // LOADC 5 → [42, 0, 0, 5] (funktsiooni aadress, _func label indeksil 5) - // CALL → FP=3, PC=5, S[3]=4 → [42, 0, 0, 4] - // HALT (tagastuspunkt, indeks 4) - // _func (indeks 5): ENTER 3 → EP = (4-1) + 3 = 6 - // MARK → push EP(6), push FP(3) → [42, 0, 0, 4, 6, 3] - // HALT + /* + * MARK/CALL/ENTER tsükkel: funktsioon kutsub ja ENTER seab EP + * LOADC 42 → [42] + * MARK → [42, 0, 0] + * LOADC 5 → [42, 0, 0, 5] (funktsiooni aadress, _func label indeksil 5) + * CALL → FP=3, PC=5, S[3]=4 → [42, 0, 0, 4] + * HALT (tagastuspunkt, indeks 4) + * _func (indeks 5): ENTER 3 → EP = (4-1) + 3 = 6 + * MARK → push EP(6), push FP(3) → [42, 0, 0, 4, 6, 3] + * HALT + */ CMaLabel _func = new CMaLabel(); - pw.visit(LOADC, 42); // 0: parameeter - pw.visit(MARK); // 1: push EP(0), push FP(0) - pw.visit(LOADC, 5); // 2: funktsiooni aadress (indeks 5) - pw.visit(CALL); // 3: FP=3, PC=5, S[3]=4 - pw.visit(HALT); // 4: tagastuspunkt - pw.visit(_func); // label indeksil 5 - pw.visit(ENTER, 3); // 5: EP = (4-1) + 3 = 6 - pw.visit(MARK); // 6: push EP(6), push FP(3) - pw.visit(HALT); // 7: funktsioon peatub - - // Stack pärast: [42, 0, 0, 4, 6, 3] + pw.visit(LOADC, 42); // 0: parameeter + pw.visit(MARK); // 1: push EP(0), push FP(0) + pw.visit(LOADC, 5); // 2: funktsiooni aadress (indeks 5) + pw.visit(CALL); // 3: FP=3, PC=5, S[3]=4 + pw.visit(HALT); // 4: tagastuspunkt + pw.visit(_func); // label indeksil 5 + pw.visit(ENTER, 3); // 5: EP = (4-1) + 3 = 6 + pw.visit(MARK); // 6: push EP(6), push FP(3) + pw.visit(HALT); // 7: funktsioon peatub + + /* Stack pärast: [42, 0, 0, 4, 6, 3] */ assertInterpreted(new CMaStack(42, 0, 0, 4, 6, 3)); } @@ -333,68 +343,72 @@ public void test_enter_in_function() { @Test public void test_call_return() { - // Täielik kutse-tagastus tsükkel: - // Peaprogramm kutsub funktsiooni, mis kohe tagastab. - // - // 0: LOADC 42 → [42] (parameeter) - // 1: MARK → [42, 0, 0] (push EP=0, FP=0) - // 2: LOADC 6 → [42, 0, 0, 6] (funktsiooni aadress) - // 3: CALL → FP=3, PC=6, S[3]=4 → [42, 0, 0, 4] - // 4: HALT (tagastuspunkt) - // - // _func (indeks 5): - // 5: ENTER 0 → EP = (4-1)+0 = 3 - // 6: RETURN 3 → PC=S[3]=4, EP=S[1]=0, FP=S[2]=0 - // SP = 3-3 = 0, truncate(1) → [42] - // PC=4 → jõuab HALT-i + /* + * Täielik kutse-tagastus tsükkel: + * Peaprogramm kutsub funktsiooni, mis kohe tagastab. + * + * 0: LOADC 42 → [42] (parameeter) + * 1: MARK → [42, 0, 0] (push EP=0, FP=0) + * 2: LOADC 6 → [42, 0, 0, 6] (funktsiooni aadress) + * 3: CALL → FP=3, PC=6, S[3]=4 → [42, 0, 0, 4] + * 4: HALT (tagastuspunkt) + * + * _func (indeks 5): + * 5: ENTER 0 → EP = (4-1)+0 = 3 + * 6: RETURN 3 → PC=S[3]=4, EP=S[1]=0, FP=S[2]=0 + * SP = 3-3 = 0, truncate(1) → [42] + * PC=4 → jõuab HALT-i + */ CMaLabel _func = new CMaLabel(); - pw.visit(LOADC, 42); // 0: parameeter - pw.visit(MARK); // 1: push EP(0), push FP(0) - pw.visit(LOADC, 5); // 2: funktsiooni aadress - pw.visit(CALL); // 3: FP=3, PC=5, S[3]=4 - pw.visit(HALT); // 4: tagastuspunkt - pw.visit(_func); // label indeksil 5 - pw.visit(ENTER, 0); // 5: EP = 3 - pw.visit(RETURN, 3); // 6: taasta ja kärbi, q=3 (EP+FP+PC) + pw.visit(LOADC, 42); // 0: parameeter + pw.visit(MARK); // 1: push EP(0), push FP(0) + pw.visit(LOADC, 6); // 2: funktsiooni aadress + pw.visit(CALL); // 3: FP=3, PC=5, S[3]=4 + pw.visit(HALT); // 4: tagastuspunkt + pw.visit(_func); // label indeksil 5 + pw.visit(ENTER, 0); // 5: EP = 3 + pw.visit(RETURN, 3); // 6: taasta ja kärbi, q=3 (EP+FP+PC) - // Pärast RETURN: stack = [42], PC=4 → HALT + /* Pärast RETURN: stack = [42], PC=4 → HALT */ assertInterpreted(new CMaStack(42)); } @Test public void test_call_return_with_locals() { - // Funktsioon eraldab lokaalse muutuja, kirjutab sinna ja tagastab. - // - // 0: LOADC 10 → [10] (parameeter) - // 1: MARK → [10, 0, 0] - // 2: LOADC 5 → [10, 0, 0, 5] - // 3: CALL → FP=3, PC=5, S[3]=4 → [10, 0, 0, 4] - // 4: HALT - // - // _func (indeks 5): - // 5: ENTER 1 → EP = (4-1)+1 = 4 - // 6: ALLOC 1 → [10, 0, 0, 4, 0] (lokaalne muutuja indeksil 4) - // 7: LOADC 99 - // 8: STORER 1 → stack[FP+1]=stack[4]=99 → [10, 0, 0, 4, 99, 99] - // 9: POP → [10, 0, 0, 4, 99] - // 10: RETURN 3 → PC=4, EP=0, SP=3-3=0, FP=0, truncate(1) → [10] + /* + * Funktsioon eraldab lokaalse muutuja, kirjutab sinna ja tagastab. + * + * 0: LOADC 10 → [10] (parameeter) + * 1: MARK → [10, 0, 0] + * 2: LOADC 5 → [10, 0, 0, 5] + * 3: CALL → FP=3, PC=5, S[3]=4 → [10, 0, 0, 4] + * 4: HALT + * + * _func (indeks 5): + * 5: ENTER 1 → EP = (4-1)+1 = 4 + * 6: ALLOC 1 → [10, 0, 0, 4, 0] (lokaalne muutuja indeksil 4) + * 7: LOADC 99 + * 8: STORER 1 → stack[FP+1]=stack[4]=99 → [10, 0, 0, 4, 99, 99] + * 9: POP → [10, 0, 0, 4, 99] + * 10: RETURN 3 → PC=4, EP=0, SP=3-3=0, FP=0, truncate(1) → [10] + */ CMaLabel _func = new CMaLabel(); - pw.visit(LOADC, 10); // 0: parameeter - pw.visit(MARK); // 1 - pw.visit(LOADC, 5); // 2: funktsiooni aadress - pw.visit(CALL); // 3 - pw.visit(HALT); // 4 - pw.visit(_func); // label indeksil 5 - pw.visit(ENTER, 1); // 5 - pw.visit(ALLOC, 1); // 6: lokaalne muutuja - pw.visit(LOADC, 99); // 7 - pw.visit(STORER, 1); // 8: kirjuta lokaalsesse muutujasse - pw.visit(POP); // 9 - pw.visit(RETURN, 3); // 10: tagasta, q=3 - - // Pärast RETURN: stack = [10], PC=4 → HALT + pw.visit(LOADC, 10); // 0: parameeter + pw.visit(MARK); // 1 + pw.visit(LOADC, 5); // 2: funktsiooni aadress + pw.visit(CALL); // 3 + pw.visit(HALT); // 4 + pw.visit(_func); // label indeksil 5 + pw.visit(ENTER, 1); // 5 + pw.visit(ALLOC, 1); // 6: lokaalne muutuja + pw.visit(LOADC, 99); // 7 + pw.visit(STORER, 1); // 8: kirjuta lokaalsesse muutujasse + pw.visit(POP); // 9 + pw.visit(RETURN, 3); // 10: tagasta, q=3 + + /* Pärast RETURN: stack = [10], PC=4 → HALT */ assertInterpreted(new CMaStack(10)); } @@ -402,9 +416,11 @@ public void test_call_return_with_locals() { @Test public void test_slide() { - // stack: [10, 20, 30], SLIDE 2 1 → kopeeri 1 väärtus (30) 2 positsiooni allapoole - // S[SP-2-1+1] = S[SP-1+1] → S[0] = S[2] = 30 → stack: [30, 20, 30] - // truncate(SP-2+1) = truncate(1) → stack: [30] + /* + * stack: [10, 20, 30], SLIDE 2 1 → kopeeri 1 väärtus (30) 2 positsiooni allapoole + * S[SP-2-1+1] = S[SP-1+1] → S[0] = S[2] = 30 → stack: [30, 20, 30] + * truncate(SP-2+1) = truncate(1) → stack: [30] + */ pw.visit(LOADC, 10); pw.visit(LOADC, 20); pw.visit(LOADC, 30); @@ -415,10 +431,12 @@ public void test_slide() { @Test public void test_slide_multiple_values() { - // stack: [1, 2, 3, 4, 5], SLIDE 2 2 → kopeeri 2 väärtust (4, 5) 2 positsiooni allapoole - // S[SP-2-2+1] = S[SP-2+1] → S[1] = S[3] = 4 - // S[SP-2-2+2] = S[SP-2+2] → S[2] = S[4] = 5 - // truncate(SP-2+1) = truncate(3) → stack: [1, 4, 5] + /* + * stack: [1, 2, 3, 4, 5], SLIDE 2 2 → kopeeri 2 väärtust (4, 5) 2 positsiooni allapoole + * S[SP-2-2+1] = S[SP-2+1] → S[1] = S[3] = 4 + * S[SP-2-2+2] = S[SP-2+2] → S[2] = S[4] = 5 + * truncate(SP-2+1) = truncate(3) → stack: [1, 4, 5] + */ pw.visit(LOADC, 1); pw.visit(LOADC, 2); pw.visit(LOADC, 3); @@ -431,7 +449,7 @@ public void test_slide_multiple_values() { @Test public void test_slide_zero() { - // stack: [10, 20], SLIDE 0 1 → q=0, nihkumist pole, truncate(SP+1) → muutumatu + /* stack: [10, 20], SLIDE 0 1 → q=0, nihkumist pole, truncate(SP+1) → muutumatu */ pw.visit(LOADC, 10); pw.visit(LOADC, 20); pw.visit(SLIDE, 0, 1); @@ -439,35 +457,54 @@ public void test_slide_zero() { assertInterpreted(new CMaStack(10, 20)); } + @Test + public void test_slide_m_zero() { + /* + * stack: [10, 20, 30], SLIDE 2 0 → m=0, tagastusväärtust pole, kärbi q pesa + * SP = SP - q = 2 - 2 = 0 → truncate(1) → [10] + */ + pw.visit(LOADC, 10); + pw.visit(LOADC, 20); + pw.visit(LOADC, 30); + pw.visit(SLIDE, 2, 0); + + assertInterpreted(new CMaStack(10)); + } + // Funktsioonikutsed: Samm 8 — JUMPI käsu testimine @Test public void test_jumpi() { - // Hüppetabel: väärtus 0 → case0, väärtus 1 → case1, väärtus 2 → case2 - // Iga case laeb oma väärtuse stackile ja peatub. + /* + * Lülituslause harud: + * väärtus 0 → case0 + * väärtus 1 → case1 + * väärtus 2 → case2 + * Igale lülituslause harule vastavad väärtused laetakse stackile. + */ CMaLabel _table = new CMaLabel(); CMaLabel _case0 = new CMaLabel(); CMaLabel _case1 = new CMaLabel(); CMaLabel _case2 = new CMaLabel(); - // Programm: LOADC index; JUMPI _table; _table: JUMP _case0; JUMP _case1; JUMP _case2 - pw.visit(LOADC, 0); // 0: indeks - pw.visit(JUMPI, _table); // 1: PC = target(_table) + 0 = 2 - pw.visit(_table); // indeks 2 - pw.visit(JUMP, _case0); // 2: hüppa case0-le - pw.visit(JUMP, _case1); // 3: hüppa case1-le - pw.visit(JUMP, _case2); // 4: hüppa case2-le + /* Programm: LOADC index; JUMPI _table; _table: JUMP _case0; JUMP _case1; JUMP _case2 */ + pw.visit(LOADC, 0); // 0: indeks + pw.visit(JUMPI, _table); // 1: PC = target(_table) + 0 = 2 + pw.visit(_table); // indeks 2 + pw.visit(JUMP, _case0); // 2: hüppa case0-le + pw.visit(JUMP, _case1); // 3: hüppa case1-le + pw.visit(JUMP, _case2); // 4: hüppa case2-le pw.visit(_case0); - pw.visit(LOADC, 100); // 5 - pw.visit(HALT); // 6 + pw.visit(LOADC, 100); + pw.visit(HALT); pw.visit(_case1); - pw.visit(LOADC, 200); // 7 - pw.visit(HALT); // 8 + pw.visit(LOADC, 200); + pw.visit(HALT); pw.visit(_case2); - pw.visit(LOADC, 300); // 9 - pw.visit(HALT); // 10 + pw.visit(LOADC, 300); + pw.visit(HALT); - // Indeks 0 → case0 → stack: [100] + /* Indeks 0 → case0 → stack: [100] */ assertInterpreted(new CMaStack(100)); } @@ -478,12 +515,12 @@ public void test_jumpi_index1() { CMaLabel _case1 = new CMaLabel(); CMaLabel _case2 = new CMaLabel(); - pw.visit(LOADC, 1); // 0: indeks - pw.visit(JUMPI, _table); // 1: PC = target(_table) + 1 = 3 + pw.visit(LOADC, 1); // 0: indeks + pw.visit(JUMPI, _table); // 1: PC = target(_table) + 1 = 3 pw.visit(_table); - pw.visit(JUMP, _case0); // 2 - pw.visit(JUMP, _case1); // 3 - pw.visit(JUMP, _case2); // 4 + pw.visit(JUMP, _case0); // 2 + pw.visit(JUMP, _case1); // 3 + pw.visit(JUMP, _case2); // 4 pw.visit(_case0); pw.visit(LOADC, 100); pw.visit(HALT); @@ -494,7 +531,7 @@ public void test_jumpi_index1() { pw.visit(LOADC, 300); pw.visit(HALT); - // Indeks 1 → case1 → stack: [200] + /* Indeks 1 → case1 → stack: [200] */ assertInterpreted(new CMaStack(200)); } @@ -505,12 +542,12 @@ public void test_jumpi_index2() { CMaLabel _case1 = new CMaLabel(); CMaLabel _case2 = new CMaLabel(); - pw.visit(LOADC, 2); // 0: indeks - pw.visit(JUMPI, _table); // 1: PC = target(_table) + 2 = 4 + pw.visit(LOADC, 2); // 0: indeks + pw.visit(JUMPI, _table); // 1: PC = target(_table) + 2 = 4 pw.visit(_table); - pw.visit(JUMP, _case0); // 2 - pw.visit(JUMP, _case1); // 3 - pw.visit(JUMP, _case2); // 4 + pw.visit(JUMP, _case0); // 2 + pw.visit(JUMP, _case1); // 3 + pw.visit(JUMP, _case2); // 4 pw.visit(_case0); pw.visit(LOADC, 100); pw.visit(HALT); @@ -521,7 +558,358 @@ public void test_jumpi_index2() { pw.visit(LOADC, 300); pw.visit(HALT); - // Indeks 2 → case2 → stack: [300] + /* Indeks 2 → case2 → stack: [300] */ assertInterpreted(new CMaStack(300)); } + + // Funktsioonikutsed: Samm 9 — Integratsioonitestid kõikide käskude testimiseks erinevates töövoogudes + + /** + * Mitterekursiivne {@code inc(x)} funktsioon, mida kutsub {@code main(n)}. + * + *

C-kood:

+ *
{@code
+     * int inc(int x) { return x + 1; }
+     * int main(int n) {
+     *     int r = inc(n);
+     *     return r;
+     * }
+     * }
+ * + *

Täitmisraami paigutus (FP viitab salvestatud PC-le):

+ * + * + * + * + * + * + *
{@code FP-3}parameeter
{@code FP-2}salvestatud EP
{@code FP-1}salvestatud FP
{@code FP}salvestatud PC (tagastusaadress)
{@code FP+1} ja edasilokaalsed muutujad
+ */ + @Test + public void test_main_calls_non_recursive_function() { + CMaLabel _main = new CMaLabel(); + CMaLabel _inc = new CMaLabel(); + + /* === Peaprogramm (indeksid 0-5): kutsub main(41) === */ + pw.visit(LOADC, 41); // 0: main parameetriks antav väärtus + pw.visit(MARK); // 1: push EP, FP + pw.visit(LOADC, 6); // 2: _main aadress = 6 + pw.visit(CALL); // 3 + pw.visit(SLIDE, 0, 1); // 4: tõsta tulemus + pw.visit(HALT); // 5 + + /* + * === main(n) funktsioon (indeksid 6-17) === + * int main(int n) { int r = inc(n); return r; } + * Lokaalsed: r on FP+1 + */ + pw.visit(_main); // label indeksil 6 + pw.visit(ENTER, 1); // 6: EP = SP + 1 (1 lokaalne muutuja: r) + pw.visit(ALLOC, 1); // 7: eralda koht r-ile + + /* kutsu inc(n) */ + pw.visit(LOADR, -3); // 8: push n + pw.visit(MARK); // 9: push EP, FP + pw.visit(LOADC, 18); // 10: _inc aadress = 18 + pw.visit(CALL); // 11 + pw.visit(SLIDE, 0, 1); // 12: tõsta inc(n) tulemus + + pw.visit(STORER, 1); // 13: r = inc(n) + pw.visit(POP); // 14: eemalda STORER duplikaat + + /* return r */ + pw.visit(LOADR, 1); // 15: push r + pw.visit(STORER, -3); // 16: kirjuta tulemus parameetri pessa + pw.visit(RETURN, 3); // 17 + + /* + * === inc(x) funktsioon (indeksid 18-23) === + * int inc(int x) { return x + 1; } + */ + pw.visit(_inc); // label indeksil 18 + pw.visit(ENTER, 0); // 18: lokaalseid muutujaid pole + pw.visit(LOADR, -3); // 19: push x + pw.visit(LOADC, 1); // 20 + pw.visit(ADD); // 21: x + 1 + pw.visit(STORER, -3); // 22: tulemus → parameetri pessa + pw.visit(RETURN, 3); // 23 + + /* Oodatav tulemus: inc(41) = 42, main tagastab 42 */ + assertInterpreted(new CMaStack(42)); + } + + /** + * Rekursiivne {@code fac(n)} funktsioon. + * + *

C-kood:

+ *
{@code
+     * int fac(int n) {
+     *     if (n <= 0) return 1;
+     *     return n * fac(n - 1);
+     * }
+     * int main(int n) {
+     *     int r = fac(n);
+     *     return r;
+     * }
+     * }
+ * + *

Täitmisraami paigutus (FP viitab salvestatud PC-le):

+ * + * + * + * + * + * + *
{@code FP-3}parameeter
{@code FP-2}salvestatud EP
{@code FP-1}salvestatud FP
{@code FP}salvestatud PC (tagastusaadress)
{@code FP+1} ja edasilokaalsed muutujad
+ * + *

Tagastus: tulemus kirjutatakse parameetri pessa ({@code STORER -3}), + * seejärel {@code RETURN 3} kärbib täitmisraami ja kutsuja kasutab + * {@code SLIDE 0 1} tulemuse kättesaamiseks.

+ */ + private CMaStack runFac(int n) { + pw = new CMaProgramWriter(); + + CMaLabel _fac = new CMaLabel(); + CMaLabel _recurse = new CMaLabel(); + CMaLabel _main = new CMaLabel(); + + /* === Peaprogramm (indeksid 0-5): kutsub main() === */ + pw.visit(LOADC, n); // 0: main parameetriks antav n väärtus + pw.visit(MARK); // 1: push EP, FP + pw.visit(LOADC, 6); // 2: _main aadress = 6 + pw.visit(CALL); // 3: FP=3, PC=6, S[3]=4 + pw.visit(SLIDE, 0, 1); // 4: tõsta tulemus + pw.visit(HALT); // 5 + + /* + * === main() funktsioon (indeksid 6-17) === + * int main(int n) { int r = fac(n); return r; } + * Lokaalsed: r on FP+1 (indeks 1 täitmisraamist) + */ + pw.visit(_main); // label indeksil 6 + pw.visit(ENTER, 1); // 6: EP = SP + 1 (1 lokaalne muutuja: r) + pw.visit(ALLOC, 1); // 7: eralda koht r-ile + + /* kutsu fac(n): n on FP-3 */ + pw.visit(LOADR, -3); // 8: push n + pw.visit(MARK); // 9: push EP, FP + pw.visit(LOADC, 18); // 10: _fac aadress = 18 + pw.visit(CALL); // 11 + pw.visit(SLIDE, 0, 1); // 12: tõsta fac(n) tulemus + + pw.visit(STORER, 1); // 13: r = fac(n) + pw.visit(POP); // 14: eemalda STORER duplikaat + + /* return r: kopeeri r parameetri pessa */ + pw.visit(LOADR, 1); // 15: push r + pw.visit(STORER, -3); // 16: kirjuta tulemus parameetri pessa + pw.visit(RETURN, 3); // 17 + + /* === fac(n) funktsioon (indeksid 18-...) === */ + pw.visit(_fac); // label indeksil 18 + pw.visit(ENTER, 0); // 18: lokaalseid muutujaid pole + + /* if (n <= 0) return 1 */ + pw.visit(LOADR, -3); // 19: push n + pw.visit(LOADC, 0); // 20 + pw.visit(LEQ); // 21: n <= 0? + pw.visit(JUMPZ, _recurse); // 22: kui n > 0, hüppa rekursiivsesse harusse + pw.visit(LOADC, 1); // 23: baassjuht: tulemus = 1 + pw.visit(STORER, -3); // 24: tulemus → parameetri pessa + pw.visit(RETURN, 3); // 25 + + /* rekursiivne juht: return n * fac(n-1) */ + pw.visit(_recurse); // label indeksil 26 + pw.visit(LOADR, -3); // 26: push n (korrutamise jaoks) + pw.visit(LOADR, -3); // 27: push n (fac argumendi jaoks) + pw.visit(LOADC, 1); // 28 + pw.visit(SUB); // 29: n-1 + pw.visit(MARK); // 30: push EP, FP + pw.visit(LOADC, 18); // 31: _fac aadress = 18 + pw.visit(CALL); // 32 + pw.visit(SLIDE, 0, 1); // 33: tõsta fac(n-1) tulemus + pw.visit(MUL); // 34: n * fac(n-1) + pw.visit(STORER, -3); // 35: tulemus → parameetri pessa + pw.visit(RETURN, 3); // 36 + + return CMaInterpreter.run(pw.toProgram()); + } + + @Test + public void test_recursive_fac_0() { + CMaStack result = runFac(0); + assertEquals(new CMaStack(1), result); + } + + @Test + public void test_recursive_fac_1() { + CMaStack result = runFac(1); + assertEquals(new CMaStack(1), result); + } + + @Test + public void test_recursive_fac_5() { + CMaStack result = runFac(5); + assertEquals(new CMaStack(120), result); + } + + @Test + public void test_recursive_fac_10() { + CMaStack result = runFac(10); + assertEquals(new CMaStack(3628800), result); + } + + /** + * Ehitab ja käivitab programmi, mis kasutab kõiki uusi käske. + * + *

C-kood:

+ *
{@code
+     * int inc(int x, int step) { return x + step; }
+     * int main(int op) {
+     *     int n = 5;
+     *     int r;
+     *     switch (op) {
+     *         case 0: r = inc(n, 1); break;  // LOADRC, MARK, CALL, SLIDE 1 1
+     *         case 1: r = n * 2;     break;  // LOADR, MUL, STORER
+     *     }
+     *     return r;
+     * }
+     * }
+ * + *

Täitmisraami paigutus (FP viitab salvestatud PC-le):

+ * + * + * + * + * + * + * + * + *
{@code FP-3}parameeter (op / step)
{@code FP-2}salvestatud EP
{@code FP-1}salvestatud FP
{@code FP}salvestatud PC
{@code FP+1}lokaalne n (main)
{@code FP+2}lokaalne r (main)
{@code FP-4}esimene parameeter x (ainult inc-is)
+ * + *

{@code inc} kasutab {@code RETURN 3} (puhastab ainult org-pesad), jättes x-pesa alles. + * Kutsuja kasutab {@code SLIDE 1 1}, et x-pesa tulemusega üle kirjutada ja kärpida.

+ * + *

Programmi aadressid:

+ *
    + *
  • {@code 0–5}: peaprogramm
  • + *
  • {@code 6–11}: {@code inc(x, step)}
  • + *
  • {@code 12–18}: {@code main(op)}
  • + *
  • {@code 19–20}: lülituslause harud
  • + *
  • {@code 21–30}: case 0 (inc)
  • + *
  • {@code 31–35}: case 1 (n*2)
  • + *
  • {@code 36–38}: tagastus
  • + *
+ * + *

Oodatavad tulemused:

+ *
    + *
  • {@code op=0} → {@code inc(5, 1) = 6}
  • + *
  • {@code op=1} → {@code 5 * 2 = 10}
  • + *
+ */ + private CMaStack runDispatch(int op) { + pw = new CMaProgramWriter(); + + CMaLabel _inc = new CMaLabel(); + CMaLabel _main = new CMaLabel(); + CMaLabel _table = new CMaLabel(); + CMaLabel _case0 = new CMaLabel(); + CMaLabel _case1 = new CMaLabel(); + CMaLabel _end = new CMaLabel(); + + /* Peaprogramm (0–5): kutsub main(op). */ + pw.visit(LOADC, op); // 0: op → parameeter main-ile + pw.visit(MARK); // 1: push EP(0), FP(0) + pw.visit(LOADC, 12); // 2: _main aadress = 12 + pw.visit(CALL); // 3: FP=3, PC=12, S[3]=4 + pw.visit(SLIDE, 0, 1); // 4: tõsta tulemus parameetri kohalt + pw.visit(HALT); // 5: peaprogramm lõpeb + + /* + * inc(x, step) (6–11): tagastab x + step. + * FP-4=x (esimene arg), FP-3=step (teine arg). + * RETURN 3 puhastab ainult org-pesad — x-pesa jääb kutsujale. + * Käsud: ENTER, LOADR, ADD, STORER, RETURN. + */ + pw.visit(_inc); + pw.visit(ENTER, 0); // 6: lokaalseid muutujaid pole; EP = SP+0 + pw.visit(LOADR, -4); // 7: push x (FP-4, esimene arg) + pw.visit(LOADR, -3); // 8: push step (FP-3, teine arg) + pw.visit(ADD); // 9: x + step + pw.visit(STORER, -3); // 10: tulemus → step-pessa (FP-3) + pw.visit(RETURN, 3); // 11: q=3; x-pesa (FP-4) jääb kutsujale + + /* + * main(op) (12–18): eraldab n=5 ja r, valib haru JUMPI abil. + * Käsud: ENTER, ALLOC, STORER, LOADR, JUMPI. + */ + pw.visit(_main); + pw.visit(ENTER, 2); // 12: EP = SP+2 (2 lokaalset: n, r) + pw.visit(ALLOC, 2); // 13: eralda FP+1 (n) ja FP+2 (r) + pw.visit(LOADC, 5); // 14: push 5 + pw.visit(STORER, 1); // 15: n = 5 (FP+1) + pw.visit(POP); // 16: eemalda STORER duplikaat + pw.visit(LOADR, -3); // 17: push op (FP-3) — JUMPI indeks + pw.visit(JUMPI, _table); // 18: PC = target(_table) + op + + /* + * Lülituslause harud (19–20): JUMPI sihtmärgid. + * op=0 → _case0 (21), op=1 → _case1 (31). + */ + pw.visit(_table); + pw.visit(JUMP, _case0); // 19: op=0 → kutsu inc(n, 1) + pw.visit(JUMP, _case1); // 20: op=1 → arvuta n*2 + + /* + * case 0 (21–30): r = inc(n, 1). + * Push n (LOADRC+LOAD) ja step=1, kutsu inc. + * SLIDE 1 1 nihutab tulemuse x-pesa kohale ja kustutab x-pesa. + * Käsud: LOADRC, LOAD, LOADC, MARK, CALL, SLIDE 1 1, STORER. + */ + pw.visit(_case0); + pw.visit(LOADRC, 1); // 21: push FP+1 (n aadress) — LOADRC otse + pw.visit(LOAD); // 22: loe n väärtus aadressilt + pw.visit(LOADC, 1); // 23: push step=1 (teine argument inc-ile) + pw.visit(MARK); // 24: push EP, FP + pw.visit(LOADC, 6); // 25: _inc aadress = 6 + pw.visit(CALL); // 26: FP=10, PC=6, S[10]=27 + pw.visit(SLIDE, 1, 1); // 27: nihuta tulemus x-pesa kohale, kustuta x + pw.visit(STORER, 2); // 28: r = tulemus (FP+2) + pw.visit(POP); // 29: eemalda STORER duplikaat + pw.visit(JUMP, _end); // 30: hüppa tagastusele + + /* + * case 1 (31–35): r = n * 2. + * Käsud: LOADR, LOADC, MUL, STORER. + */ + pw.visit(_case1); + pw.visit(LOADR, 1); // 31: push n (FP+1) + pw.visit(LOADC, 2); // 32: push 2 + pw.visit(MUL); // 33: n * 2 = 10 + pw.visit(STORER, 2); // 34: r = n*2 (FP+2) + pw.visit(POP); // 35: eemalda STORER duplikaat + + /* + * Tagastus (36–38): return r. + * Käsud: LOADR, STORER, RETURN. + */ + pw.visit(_end); + pw.visit(LOADR, 2); // 36: push r (FP+2) + pw.visit(STORER, -3); // 37: tulemus → parameetri pessa (FP-3) + pw.visit(RETURN, 3); // 38: tagasta, q=3 + + return CMaInterpreter.run(pw.toProgram()); + } + + @Test + public void test_dispatch_inc() { + /* op=0 → inc(5, 1) = 6: kasutab LOADRC, MARK, CALL, SLIDE 1 1 */ + assertEquals(new CMaStack(6), runDispatch(0)); + } + + @Test + public void test_dispatch_double() { + /* op=1 → 5*2 = 10: kasutab LOADR, MUL, STORER */ + assertEquals(new CMaStack(10), runDispatch(1)); + } } From 5181da0be94f89ec5928ef294efd1deaa68312e7 Mon Sep 17 00:00:00 2001 From: sandersirge Date: Sat, 9 May 2026 14:31:48 +0300 Subject: [PATCH 10/24] =?UTF-8?q?Funktsioonikutsed:=20Samm=203=20=E2=80=94?= =?UTF-8?q?=20Lisatud=20LOADRC,=20LOADR=20ja=20STORER=20k=C3=A4sud,=20test?= =?UTF-8?q?idega=20kaetud?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/ee/ut/cs/sws/cma/CMaInterpreter.java | 9 ++++++ .../cma/instruction/CMaIntInstruction.java | 9 ++++++ .../ee/ut/cs/sws/cma/CMaInterpreterTest.java | 29 +++++++++++++++++++ 3 files changed, 47 insertions(+) diff --git a/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java b/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java index 724d7e9..4312bab 100644 --- a/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java +++ b/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java @@ -96,6 +96,15 @@ case CMaIntInstruction(CMaIntInstruction.Code code, int arg) -> { execute(new CMaBasicInstruction(STORE)); } case ALLOC -> stack.allocate(arg); + case LOADRC -> stack.push(fp + arg); + case LOADR -> { + execute(new CMaIntInstruction(CMaIntInstruction.Code.LOADRC, arg)); + execute(new CMaBasicInstruction(LOAD)); + } + case STORER -> { + execute(new CMaIntInstruction(CMaIntInstruction.Code.LOADRC, arg)); + execute(new CMaBasicInstruction(STORE)); + } } } diff --git a/src/main/java/ee/ut/cs/sws/cma/instruction/CMaIntInstruction.java b/src/main/java/ee/ut/cs/sws/cma/instruction/CMaIntInstruction.java index 677a51d..22bcac6 100644 --- a/src/main/java/ee/ut/cs/sws/cma/instruction/CMaIntInstruction.java +++ b/src/main/java/ee/ut/cs/sws/cma/instruction/CMaIntInstruction.java @@ -15,6 +15,15 @@ public enum Code { /** eralda m nulliga algväärtustatud pesa */ ALLOC, + + /** lisa stackile FP + j (suhteline aadress) */ + LOADRC, + + /** loe väärtus FP-suhteliselt indeksilt */ + LOADR, + + /** salvesta väärtus FP-suhtelisele indeksile */ + STORER, //@formatter:on } diff --git a/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java b/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java index 55b6290..32d11f0 100644 --- a/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java +++ b/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java @@ -233,4 +233,33 @@ public void test_alloc_after_loadc() { assertInterpreted(new CMaStack(5, 0, 0)); } + + // Funktsioonikutsed: Samm 3 — LOADRC, LOADR ja STORER käskude testimine + + @Test + public void test_loadrc() { + // fp = 0 (vaikeväärtus), LOADRC 3 → push(0 + 3) = 3 + pw.visit(LOADRC, 3); + + assertInterpreted(new CMaStack(3)); + } + + @Test + public void test_loadr() { + // stack: [10, 20, 30], fp = 0 (vaikeväärtus) + // LOADR 2 → push(fp + 2) = push(2), LOAD → push(stack[2]) = 30 + pw.visit(LOADR, 2); + + assertInterpreted(new CMaStack(10, 20, 30, 30), new CMaStack(10, 20, 30)); + } + + @Test + public void test_storer() { + // stack: [10, 20, 30], fp = 0 (vaikeväärtus) + // LOADC 99; STORER 1 → push(fp + 1) = push(1), STORE → stack[1] = 99 + pw.visit(LOADC, 99); + pw.visit(STORER, 1); + + assertInterpreted(new CMaStack(10, 99, 30, 99), new CMaStack(10, 20, 30)); + } } From 8eb5b19d6ed283acd701916a6dea4a907fc6a1e7 Mon Sep 17 00:00:00 2001 From: sandersirge Date: Sat, 9 May 2026 14:41:40 +0300 Subject: [PATCH 11/24] =?UTF-8?q?Funktsioonikutsed:=20Samm=204=20=E2=80=94?= =?UTF-8?q?=20Lisa=20MARK=20ja=20CALL=20k=C3=A4sud,=20testidega=20kaetud?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/ee/ut/cs/sws/cma/CMaInterpreter.java | 12 +++++++++ .../cma/instruction/CMaBasicInstruction.java | 6 +++++ .../ee/ut/cs/sws/cma/CMaInterpreterTest.java | 25 +++++++++++++++++++ 3 files changed, 43 insertions(+) diff --git a/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java b/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java index 4312bab..8d07fea 100644 --- a/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java +++ b/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java @@ -82,6 +82,18 @@ case CMaBasicInstruction(CMaBasicInstruction.Code code) -> { stack.set(arg, stack.peek()); } case HALT -> pc = -1; // out of range pc halts + case MARK -> { + // S[SP+1] = EP; S[SP+2] = FP; SP += 2 + stack.push(ep); + stack.push(fp); + } + case CALL -> { + // FP = SP; tmp = PC; PC = S[FP]; S[FP] = tmp + fp = stack.size() - 1; // SP = stack.size() - 1 + int tmp = pc; + pc = stack.get(fp); + stack.set(fp, tmp); + } } } case CMaIntInstruction(CMaIntInstruction.Code code, int arg) -> { diff --git a/src/main/java/ee/ut/cs/sws/cma/instruction/CMaBasicInstruction.java b/src/main/java/ee/ut/cs/sws/cma/instruction/CMaBasicInstruction.java index 6c9c32d..3d22fa9 100644 --- a/src/main/java/ee/ut/cs/sws/cma/instruction/CMaBasicInstruction.java +++ b/src/main/java/ee/ut/cs/sws/cma/instruction/CMaBasicInstruction.java @@ -37,6 +37,12 @@ public enum Code { /** seiska programm */ HALT, + + /** salvesta EP ja FP stackile (täitmisraami ettevalmistus) */ + MARK, + + /** kutsu funktsioon: FP=SP, vaheta PC ja S[FP] */ + CALL, //@formatter:on } diff --git a/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java b/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java index 32d11f0..63c1ebd 100644 --- a/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java +++ b/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java @@ -262,4 +262,29 @@ public void test_storer() { assertInterpreted(new CMaStack(10, 99, 30, 99), new CMaStack(10, 20, 30)); } + + // Funktsioonikutsed: Samm 4 — MARK ja CALL käskude testimine + + @Test + public void test_mark_call() { + // Stack enne: [] + // LOADC 42 → [42] (parameeter) + // MARK → [42, 0, 0] (push EP=0, push FP=0) + // LOADC 5 → [42, 0, 0, 5] (funktsiooni aadress) + // CALL → FP=3, PC=5, S[3]=4 → stack: [42, 0, 0, 4] + // indeks 4: HALT (tagastuspunkt, siia ei jõua) + // indeks 5: HALT (funktsioon peatub kohe) + CMaLabel _func = new CMaLabel(); + + pw.visit(LOADC, 42); // 0: parameeter + pw.visit(MARK); // 1: push EP(0), push FP(0) + pw.visit(LOADC, 5); // 2: funktsiooni aadress (indeks 5) + pw.visit(CALL); // 3: FP=3, PC=5, S[3]=4 (tagastusaadress) + pw.visit(HALT); // 4: tagastuspunkt + pw.visit(_func); // 5: funktsiooni algus + pw.visit(HALT); // 5: funktsioon peatub kohe + + // Stack pärast: [42, 0, 0, 4] — parameeter, salvestatud EP, FP, tagastusaadress + assertInterpreted(new CMaStack(42, 0, 0, 4)); + } } From d71bf871560fae68d4a9fff6ccbf78906a95906f Mon Sep 17 00:00:00 2001 From: sandersirge Date: Sat, 9 May 2026 14:50:59 +0300 Subject: [PATCH 12/24] =?UTF-8?q?Funktsioonikutsed:=20Samm=205=20=E2=80=94?= =?UTF-8?q?=20Lisa=20ENTER=20k=C3=A4sk,=20testidega=20kaetud?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/ee/ut/cs/sws/cma/CMaInterpreter.java | 8 ++++ .../cma/instruction/CMaIntInstruction.java | 3 ++ .../ee/ut/cs/sws/cma/CMaInterpreterTest.java | 40 +++++++++++++++++++ 3 files changed, 51 insertions(+) diff --git a/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java b/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java index 8d07fea..493ad1d 100644 --- a/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java +++ b/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java @@ -110,13 +110,21 @@ case CMaIntInstruction(CMaIntInstruction.Code code, int arg) -> { case ALLOC -> stack.allocate(arg); case LOADRC -> stack.push(fp + arg); case LOADR -> { + // LOADR j = LOADRC j; LOAD execute(new CMaIntInstruction(CMaIntInstruction.Code.LOADRC, arg)); execute(new CMaBasicInstruction(LOAD)); } case STORER -> { + // STORER j = LOADRC j; STORE execute(new CMaIntInstruction(CMaIntInstruction.Code.LOADRC, arg)); execute(new CMaBasicInstruction(STORE)); } + case ENTER -> { + // EP = SP + m; kui EP >= HP, siis viga + ep = stack.size() - 1 + arg; + if (ep >= hp) + throw new CMaException("Stack Overflow: EP(%d) >= HP(%d)".formatted(ep, hp)); + } } } diff --git a/src/main/java/ee/ut/cs/sws/cma/instruction/CMaIntInstruction.java b/src/main/java/ee/ut/cs/sws/cma/instruction/CMaIntInstruction.java index 22bcac6..69432b8 100644 --- a/src/main/java/ee/ut/cs/sws/cma/instruction/CMaIntInstruction.java +++ b/src/main/java/ee/ut/cs/sws/cma/instruction/CMaIntInstruction.java @@ -24,6 +24,9 @@ public enum Code { /** salvesta väärtus FP-suhtelisele indeksile */ STORER, + + /** sea piirviit EP = SP + m, kontrolli EP >= HP */ + ENTER, //@formatter:on } diff --git a/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java b/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java index 63c1ebd..f371847 100644 --- a/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java +++ b/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java @@ -287,4 +287,44 @@ public void test_mark_call() { // Stack pärast: [42, 0, 0, 4] — parameeter, salvestatud EP, FP, tagastusaadress assertInterpreted(new CMaStack(42, 0, 0, 4)); } + + // Funktsioonikutsed: Samm 5 — ENTER käsu testimine + + @Test + public void test_enter() { + // stack: [10, 20], ENTER 5 → EP = (2-1) + 5 = 6 + // MARK → push EP(6), push FP(0) → stack: [10, 20, 6, 0] + // Kontrollime EP väärtust läbi MARK käsu + pw.visit(ENTER, 5); + pw.visit(MARK); + + assertInterpreted(new CMaStack(10, 20, 6, 0), new CMaStack(10, 20)); + } + + @Test + public void test_enter_in_function() { + // MARK/CALL/ENTER tsükkel: funktsioon kutsutakse ja ENTER seab EP + // LOADC 42 → [42] + // MARK → [42, 0, 0] + // LOADC 5 → [42, 0, 0, 5] (funktsiooni aadress, _func label indeksil 5) + // CALL → FP=3, PC=5, S[3]=4 → [42, 0, 0, 4] + // HALT (tagastuspunkt, indeks 4) + // _func (indeks 5): ENTER 3 → EP = (4-1) + 3 = 6 + // MARK → push EP(6), push FP(3) → [42, 0, 0, 4, 6, 3] + // HALT + CMaLabel _func = new CMaLabel(); + + pw.visit(LOADC, 42); // 0: parameeter + pw.visit(MARK); // 1: push EP(0), push FP(0) + pw.visit(LOADC, 5); // 2: funktsiooni aadress (indeks 5) + pw.visit(CALL); // 3: FP=3, PC=5, S[3]=4 + pw.visit(HALT); // 4: tagastuspunkt + pw.visit(_func); // label indeksil 5 + pw.visit(ENTER, 3); // 5: EP = (4-1) + 3 = 6 + pw.visit(MARK); // 6: push EP(6), push FP(3) + pw.visit(HALT); // 7: funktsioon peatub + + // Stack pärast: [42, 0, 0, 4, 6, 3] + assertInterpreted(new CMaStack(42, 0, 0, 4, 6, 3)); + } } From 35e9ba10a209ceaed68fed3d4885e2c1c2e902b8 Mon Sep 17 00:00:00 2001 From: sandersirge Date: Sat, 9 May 2026 14:59:51 +0300 Subject: [PATCH 13/24] =?UTF-8?q?Funktsioonikutsed:=20Samm=206=20=E2=80=94?= =?UTF-8?q?=20Lisa=20RETURN=20k=C3=A4sk,=20kaetud=20testiga?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/ee/ut/cs/sws/cma/CMaInterpreter.java | 12 ++++ .../cma/instruction/CMaIntInstruction.java | 3 + .../ee/ut/cs/sws/cma/CMaInterpreterTest.java | 69 +++++++++++++++++++ 3 files changed, 84 insertions(+) diff --git a/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java b/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java index 493ad1d..8d28474 100644 --- a/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java +++ b/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java @@ -125,6 +125,18 @@ case CMaIntInstruction(CMaIntInstruction.Code code, int arg) -> { if (ep >= hp) throw new CMaException("Stack Overflow: EP(%d) >= HP(%d)".formatted(ep, hp)); } + case RETURN -> { + // PC = S[FP]; EP = S[FP-2]; kontrolli EP >= HP; + // SP = FP - q (truncate(FP - q + 1)); FP = S[FP-1] + pc = stack.get(fp); // taasta tagastusaadress + ep = stack.get(fp - 2); // taasta vana EP + if (ep >= hp) + throw new CMaException("Stack Overflow: EP(%d) >= HP(%d)".formatted(ep, hp)); + int newSp = fp - arg; // SP = FP - q + int newFp = stack.get(fp - 1); // taasta vana FP + stack.truncate(newSp + 1); // kärbi stack: size = SP + 1 + fp = newFp; + } } } diff --git a/src/main/java/ee/ut/cs/sws/cma/instruction/CMaIntInstruction.java b/src/main/java/ee/ut/cs/sws/cma/instruction/CMaIntInstruction.java index 69432b8..71ab498 100644 --- a/src/main/java/ee/ut/cs/sws/cma/instruction/CMaIntInstruction.java +++ b/src/main/java/ee/ut/cs/sws/cma/instruction/CMaIntInstruction.java @@ -27,6 +27,9 @@ public enum Code { /** sea piirviit EP = SP + m, kontrolli EP >= HP */ ENTER, + + /** taasta registrid ja puhasta täitmisraam, q = org. pesade + parameetrite arv */ + RETURN, //@formatter:on } diff --git a/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java b/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java index f371847..f6a0312 100644 --- a/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java +++ b/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java @@ -327,4 +327,73 @@ public void test_enter_in_function() { // Stack pärast: [42, 0, 0, 4, 6, 3] assertInterpreted(new CMaStack(42, 0, 0, 4, 6, 3)); } + + // Funktsioonikutsed: Samm 6 — RETURN käsu testimine + + @Test + public void test_call_return() { + // Täielik kutse-tagastus tsükkel: + // Peaprogramm kutsub funktsiooni, mis kohe tagastab. + // + // 0: LOADC 42 → [42] (parameeter) + // 1: MARK → [42, 0, 0] (push EP=0, FP=0) + // 2: LOADC 6 → [42, 0, 0, 6] (funktsiooni aadress) + // 3: CALL → FP=3, PC=6, S[3]=4 → [42, 0, 0, 4] + // 4: HALT (tagastuspunkt) + // + // _func (indeks 5): + // 5: ENTER 0 → EP = (4-1)+0 = 3 + // 6: RETURN 3 → PC=S[3]=4, EP=S[1]=0, FP=S[2]=0 + // SP = 3-3 = 0, truncate(1) → [42] + // PC=4 → jõuab HALT-i + CMaLabel _func = new CMaLabel(); + + pw.visit(LOADC, 42); // 0: parameeter + pw.visit(MARK); // 1: push EP(0), push FP(0) + pw.visit(LOADC, 5); // 2: funktsiooni aadress + pw.visit(CALL); // 3: FP=3, PC=5, S[3]=4 + pw.visit(HALT); // 4: tagastuspunkt + pw.visit(_func); // label indeksil 5 + pw.visit(ENTER, 0); // 5: EP = 3 + pw.visit(RETURN, 3); // 6: taasta ja kärbi, q=3 (EP+FP+PC) + + // Pärast RETURN: stack = [42], PC=4 → HALT + assertInterpreted(new CMaStack(42)); + } + + @Test + public void test_call_return_with_locals() { + // Funktsioon eraldab lokaalse muutuja, kirjutab sinna ja tagastab. + // + // 0: LOADC 10 → [10] (parameeter) + // 1: MARK → [10, 0, 0] + // 2: LOADC 5 → [10, 0, 0, 5] + // 3: CALL → FP=3, PC=5, S[3]=4 → [10, 0, 0, 4] + // 4: HALT + // + // _func (indeks 5): + // 5: ENTER 1 → EP = (4-1)+1 = 4 + // 6: ALLOC 1 → [10, 0, 0, 4, 0] (lokaalne muutuja indeksil 4) + // 7: LOADC 99 + // 8: STORER 1 → stack[FP+1]=stack[4]=99 → [10, 0, 0, 4, 99, 99] + // 9: POP → [10, 0, 0, 4, 99] + // 10: RETURN 3 → PC=4, EP=0, SP=3-3=0, FP=0, truncate(1) → [10] + CMaLabel _func = new CMaLabel(); + + pw.visit(LOADC, 10); // 0: parameeter + pw.visit(MARK); // 1 + pw.visit(LOADC, 5); // 2: funktsiooni aadress + pw.visit(CALL); // 3 + pw.visit(HALT); // 4 + pw.visit(_func); // label indeksil 5 + pw.visit(ENTER, 1); // 5 + pw.visit(ALLOC, 1); // 6: lokaalne muutuja + pw.visit(LOADC, 99); // 7 + pw.visit(STORER, 1); // 8: kirjuta lokaalsesse muutujasse + pw.visit(POP); // 9 + pw.visit(RETURN, 3); // 10: tagasta, q=3 + + // Pärast RETURN: stack = [10], PC=4 → HALT + assertInterpreted(new CMaStack(10)); + } } From 641e1a01627a861744ee761ba1bdf20291c1c3cf Mon Sep 17 00:00:00 2001 From: sandersirge Date: Sun, 10 May 2026 11:22:37 +0300 Subject: [PATCH 14/24] =?UTF-8?q?Funktsioonikutsed:=20Samm=207=20=E2=80=94?= =?UTF-8?q?=20Lisatud=20SLIDE=20k=C3=A4sk=20ja=20uus=20record-klass=20CMaI?= =?UTF-8?q?ntIntInstruction,=20kaetud=20testidega?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/ee/ut/cs/sws/cma/CMaInterpreter.java | 12 ++++++ .../ee/ut/cs/sws/cma/CMaProgramWriter.java | 5 +++ .../sws/cma/instruction/CMaInstruction.java | 2 +- .../cma/instruction/CMaIntIntInstruction.java | 17 ++++++++ .../ee/ut/cs/sws/cma/CMaInterpreterTest.java | 42 +++++++++++++++++++ 5 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 src/main/java/ee/ut/cs/sws/cma/instruction/CMaIntIntInstruction.java diff --git a/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java b/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java index 8d28474..2ef6c39 100644 --- a/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java +++ b/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java @@ -140,6 +140,18 @@ case CMaIntInstruction(CMaIntInstruction.Code code, int arg) -> { } } + case CMaIntIntInstruction(CMaIntIntInstruction.Code code, int arg1, int arg2) -> { + switch (code) { + case SLIDE -> { + // SLIDE q m: kopeeri m väärtust q positsiooni allapoole, kärbi stack + // Book: for i=1 to m: S[SP-q-m+i] = S[SP-m+i]; SP = SP-q + int sp = stack.size() - 1; + for (int i = 1; i <= arg2; i++) + stack.set(sp - arg1 - arg2 + i, stack.get(sp - arg2 + i)); + stack.truncate(sp - arg1 + 1); // SP = SP - q, size = SP - q + 1 + } + } + } case CMaLabelInstruction(CMaLabelInstruction.Code code, CMaLabel label) -> { switch (code) { case JUMP -> pc = getLabelTarget(label); diff --git a/src/main/java/ee/ut/cs/sws/cma/CMaProgramWriter.java b/src/main/java/ee/ut/cs/sws/cma/CMaProgramWriter.java index c7b560a..30e842a 100644 --- a/src/main/java/ee/ut/cs/sws/cma/CMaProgramWriter.java +++ b/src/main/java/ee/ut/cs/sws/cma/CMaProgramWriter.java @@ -3,6 +3,7 @@ import ee.ut.cs.sws.cma.instruction.CMaBasicInstruction; import ee.ut.cs.sws.cma.instruction.CMaInstruction; import ee.ut.cs.sws.cma.instruction.CMaIntInstruction; +import ee.ut.cs.sws.cma.instruction.CMaIntIntInstruction; import ee.ut.cs.sws.cma.instruction.CMaLabelInstruction; import java.util.ArrayList; @@ -27,6 +28,10 @@ public void visit(CMaIntInstruction.Code code, int arg) { visit(new CMaIntInstruction(code, arg)); } + public void visit(CMaIntIntInstruction.Code code, int arg1, int arg2) { + visit(new CMaIntIntInstruction(code, arg1, arg2)); + } + public void visit(CMaLabelInstruction.Code code, CMaLabel label) { visit(new CMaLabelInstruction(code, label)); } diff --git a/src/main/java/ee/ut/cs/sws/cma/instruction/CMaInstruction.java b/src/main/java/ee/ut/cs/sws/cma/instruction/CMaInstruction.java index abaaf0c..7db0dc0 100644 --- a/src/main/java/ee/ut/cs/sws/cma/instruction/CMaInstruction.java +++ b/src/main/java/ee/ut/cs/sws/cma/instruction/CMaInstruction.java @@ -1,6 +1,6 @@ package ee.ut.cs.sws.cma.instruction; -public sealed interface CMaInstruction permits CMaBasicInstruction, CMaIntInstruction, CMaLabelInstruction { +public sealed interface CMaInstruction permits CMaBasicInstruction, CMaIntInstruction, CMaIntIntInstruction, CMaLabelInstruction { Code code(); diff --git a/src/main/java/ee/ut/cs/sws/cma/instruction/CMaIntIntInstruction.java b/src/main/java/ee/ut/cs/sws/cma/instruction/CMaIntIntInstruction.java new file mode 100644 index 0000000..fafe281 --- /dev/null +++ b/src/main/java/ee/ut/cs/sws/cma/instruction/CMaIntIntInstruction.java @@ -0,0 +1,17 @@ +package ee.ut.cs.sws.cma.instruction; + +public record CMaIntIntInstruction(Code code, int arg1, int arg2) implements CMaInstruction { + + public enum Code { + //@formatter:off + /** nihuta m väärtust q positsiooni võrra allapoole */ + SLIDE, + //@formatter:on + } + + @Override + public String toString() { + return code.name() + " " + arg1 + " " + arg2; + } +} + diff --git a/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java b/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java index f6a0312..a5e9745 100644 --- a/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java +++ b/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java @@ -7,6 +7,7 @@ import static ee.ut.cs.sws.cma.instruction.CMaBasicInstruction.Code.*; import static ee.ut.cs.sws.cma.instruction.CMaIntInstruction.Code.*; +import static ee.ut.cs.sws.cma.instruction.CMaIntIntInstruction.Code.*; import static ee.ut.cs.sws.cma.instruction.CMaLabelInstruction.Code.*; import static org.junit.Assert.*; @@ -396,4 +397,45 @@ public void test_call_return_with_locals() { // Pärast RETURN: stack = [10], PC=4 → HALT assertInterpreted(new CMaStack(10)); } + + // Funktsioonikutsed: Samm 7 — SLIDE käsu testimine + + @Test + public void test_slide() { + // stack: [10, 20, 30], SLIDE 2 1 → kopeeri 1 väärtus (30) 2 positsiooni allapoole + // S[SP-2-1+1] = S[SP-1+1] → S[0] = S[2] = 30 → stack: [30, 20, 30] + // truncate(SP-2+1) = truncate(1) → stack: [30] + pw.visit(LOADC, 10); + pw.visit(LOADC, 20); + pw.visit(LOADC, 30); + pw.visit(SLIDE, 2, 1); + + assertInterpreted(new CMaStack(30)); + } + + @Test + public void test_slide_multiple_values() { + // stack: [1, 2, 3, 4, 5], SLIDE 2 2 → kopeeri 2 väärtust (4, 5) 2 positsiooni allapoole + // S[SP-2-2+1] = S[SP-2+1] → S[1] = S[3] = 4 + // S[SP-2-2+2] = S[SP-2+2] → S[2] = S[4] = 5 + // truncate(SP-2+1) = truncate(3) → stack: [1, 4, 5] + pw.visit(LOADC, 1); + pw.visit(LOADC, 2); + pw.visit(LOADC, 3); + pw.visit(LOADC, 4); + pw.visit(LOADC, 5); + pw.visit(SLIDE, 2, 2); + + assertInterpreted(new CMaStack(1, 4, 5)); + } + + @Test + public void test_slide_zero() { + // stack: [10, 20], SLIDE 0 1 → q=0, nihkumist pole, truncate(SP+1) → muutumatu + pw.visit(LOADC, 10); + pw.visit(LOADC, 20); + pw.visit(SLIDE, 0, 1); + + assertInterpreted(new CMaStack(10, 20)); + } } From 83ec4a946558802c7e96b078206fc475cd183e10 Mon Sep 17 00:00:00 2001 From: sandersirge Date: Sun, 10 May 2026 11:28:09 +0300 Subject: [PATCH 15/24] =?UTF-8?q?Funktsioonikutsed:=20Samm=208=20=E2=80=94?= =?UTF-8?q?=20Lisa=20JUMPI=20k=C3=A4sk,=20kaetud=20testidega?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/ee/ut/cs/sws/cma/CMaInterpreter.java | 4 + .../cma/instruction/CMaLabelInstruction.java | 3 + .../ee/ut/cs/sws/cma/CMaInterpreterTest.java | 86 +++++++++++++++++++ 3 files changed, 93 insertions(+) diff --git a/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java b/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java index 2ef6c39..a30589a 100644 --- a/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java +++ b/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java @@ -159,6 +159,10 @@ case CMaLabelInstruction(CMaLabelInstruction.Code code, CMaLabel label) -> { if (!CMaUtils.int2bool(stack.pop())) pc = getLabelTarget(label); } + case JUMPI -> { + // PC = target(label) + S[SP]; SP-- + pc = getLabelTarget(label) + stack.pop(); + } } } } diff --git a/src/main/java/ee/ut/cs/sws/cma/instruction/CMaLabelInstruction.java b/src/main/java/ee/ut/cs/sws/cma/instruction/CMaLabelInstruction.java index 50f58bc..87d4678 100644 --- a/src/main/java/ee/ut/cs/sws/cma/instruction/CMaLabelInstruction.java +++ b/src/main/java/ee/ut/cs/sws/cma/instruction/CMaLabelInstruction.java @@ -11,6 +11,9 @@ public enum Code { /** hüppa labelile kui stackipealne väärtus on 0 */ JUMPZ, + + /** indekseeritud hüpe: PC = target(label) + S[SP]; SP-- */ + JUMPI, //@formatter:on } diff --git a/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java b/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java index a5e9745..3905e09 100644 --- a/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java +++ b/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java @@ -438,4 +438,90 @@ public void test_slide_zero() { assertInterpreted(new CMaStack(10, 20)); } + + // Funktsioonikutsed: Samm 8 — JUMPI käsu testimine + + @Test + public void test_jumpi() { + // Hüppetabel: väärtus 0 → case0, väärtus 1 → case1, väärtus 2 → case2 + // Iga case laeb oma väärtuse stackile ja peatub. + CMaLabel _table = new CMaLabel(); + CMaLabel _case0 = new CMaLabel(); + CMaLabel _case1 = new CMaLabel(); + CMaLabel _case2 = new CMaLabel(); + + // Programm: LOADC index; JUMPI _table; _table: JUMP _case0; JUMP _case1; JUMP _case2 + pw.visit(LOADC, 0); // 0: indeks + pw.visit(JUMPI, _table); // 1: PC = target(_table) + 0 = 2 + pw.visit(_table); // indeks 2 + pw.visit(JUMP, _case0); // 2: hüppa case0-le + pw.visit(JUMP, _case1); // 3: hüppa case1-le + pw.visit(JUMP, _case2); // 4: hüppa case2-le + pw.visit(_case0); + pw.visit(LOADC, 100); // 5 + pw.visit(HALT); // 6 + pw.visit(_case1); + pw.visit(LOADC, 200); // 7 + pw.visit(HALT); // 8 + pw.visit(_case2); + pw.visit(LOADC, 300); // 9 + pw.visit(HALT); // 10 + + // Indeks 0 → case0 → stack: [100] + assertInterpreted(new CMaStack(100)); + } + + @Test + public void test_jumpi_index1() { + CMaLabel _table = new CMaLabel(); + CMaLabel _case0 = new CMaLabel(); + CMaLabel _case1 = new CMaLabel(); + CMaLabel _case2 = new CMaLabel(); + + pw.visit(LOADC, 1); // 0: indeks + pw.visit(JUMPI, _table); // 1: PC = target(_table) + 1 = 3 + pw.visit(_table); + pw.visit(JUMP, _case0); // 2 + pw.visit(JUMP, _case1); // 3 + pw.visit(JUMP, _case2); // 4 + pw.visit(_case0); + pw.visit(LOADC, 100); + pw.visit(HALT); + pw.visit(_case1); + pw.visit(LOADC, 200); + pw.visit(HALT); + pw.visit(_case2); + pw.visit(LOADC, 300); + pw.visit(HALT); + + // Indeks 1 → case1 → stack: [200] + assertInterpreted(new CMaStack(200)); + } + + @Test + public void test_jumpi_index2() { + CMaLabel _table = new CMaLabel(); + CMaLabel _case0 = new CMaLabel(); + CMaLabel _case1 = new CMaLabel(); + CMaLabel _case2 = new CMaLabel(); + + pw.visit(LOADC, 2); // 0: indeks + pw.visit(JUMPI, _table); // 1: PC = target(_table) + 2 = 4 + pw.visit(_table); + pw.visit(JUMP, _case0); // 2 + pw.visit(JUMP, _case1); // 3 + pw.visit(JUMP, _case2); // 4 + pw.visit(_case0); + pw.visit(LOADC, 100); + pw.visit(HALT); + pw.visit(_case1); + pw.visit(LOADC, 200); + pw.visit(HALT); + pw.visit(_case2); + pw.visit(LOADC, 300); + pw.visit(HALT); + + // Indeks 2 → case2 → stack: [300] + assertInterpreted(new CMaStack(300)); + } } From 50a9c75d00fe5bea0ae5d93d097a1dcfa671243d Mon Sep 17 00:00:00 2001 From: sandersirge Date: Sun, 10 May 2026 22:23:00 +0300 Subject: [PATCH 16/24] =?UTF-8?q?Funktsioonikutsed:=20Samm=209=20-=20Integ?= =?UTF-8?q?ratsioonitestid=20lisatud=20uusi=20k=C3=A4ske=20kasutavate=20t?= =?UTF-8?q?=C3=B6=C3=B6voogude=20testimiseks,=20dokumentatsioon=20parandat?= =?UTF-8?q?ud?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/ee/ut/cs/sws/cma/CMaInterpreter.java | 33 +- .../cma/instruction/CMaIntIntInstruction.java | 2 +- .../ee/ut/cs/sws/cma/CMaInterpreterTest.java | 650 ++++++++++++++---- 3 files changed, 543 insertions(+), 142 deletions(-) diff --git a/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java b/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java index a30589a..465fa53 100644 --- a/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java +++ b/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java @@ -128,12 +128,12 @@ case CMaIntInstruction(CMaIntInstruction.Code code, int arg) -> { case RETURN -> { // PC = S[FP]; EP = S[FP-2]; kontrolli EP >= HP; // SP = FP - q (truncate(FP - q + 1)); FP = S[FP-1] - pc = stack.get(fp); // taasta tagastusaadress - ep = stack.get(fp - 2); // taasta vana EP + pc = stack.get(fp); // taasta tagastusaadress + ep = stack.get(fp - 2); // taasta vana EP if (ep >= hp) throw new CMaException("Stack Overflow: EP(%d) >= HP(%d)".formatted(ep, hp)); - int newSp = fp - arg; // SP = FP - q - int newFp = stack.get(fp - 1); // taasta vana FP + int newSp = fp - arg; // SP = FP - q + int newFp = stack.get(fp - 1); // taasta vana FP stack.truncate(newSp + 1); // kärbi stack: size = SP + 1 fp = newFp; } @@ -143,12 +143,25 @@ case CMaIntInstruction(CMaIntInstruction.Code code, int arg) -> { case CMaIntIntInstruction(CMaIntIntInstruction.Code code, int arg1, int arg2) -> { switch (code) { case SLIDE -> { - // SLIDE q m: kopeeri m väärtust q positsiooni allapoole, kärbi stack - // Book: for i=1 to m: S[SP-q-m+i] = S[SP-m+i]; SP = SP-q - int sp = stack.size() - 1; - for (int i = 1; i <= arg2; i++) - stack.set(sp - arg1 - arg2 + i, stack.get(sp - arg2 + i)); - stack.truncate(sp - arg1 + 1); // SP = SP - q, size = SP - q + 1 + // SLIDE q m: nihuta m pealmist väärtust q positsiooni allapoole + // if (q > 0) + // if (m = 0) SP ← SP - q; + // else { SP ← SP-q-m; for (i←0; i 0) { + int sp = stack.size() - 1; + if (arg2 == 0) { + // m = 0: lihtsalt kärbi q pesa + stack.truncate(sp - arg1 + 1); // SP = SP - q, size = SP - q + 1 + } else { + // kopeeri m väärtust q positsiooni allapoole, siis kärbi + sp = sp - arg1 - arg2; + for (int i = 0; i < arg2; i++) { + sp++; + stack.set(sp, stack.get(sp + arg1)); // S[SP] ← S[SP+q] + } + stack.truncate(sp + 1); // SP = SP - q, size = SP - q + 1 + } + } } } } diff --git a/src/main/java/ee/ut/cs/sws/cma/instruction/CMaIntIntInstruction.java b/src/main/java/ee/ut/cs/sws/cma/instruction/CMaIntIntInstruction.java index fafe281..ab99aab 100644 --- a/src/main/java/ee/ut/cs/sws/cma/instruction/CMaIntIntInstruction.java +++ b/src/main/java/ee/ut/cs/sws/cma/instruction/CMaIntIntInstruction.java @@ -4,7 +4,7 @@ public record CMaIntIntInstruction(Code code, int arg1, int arg2) implements CMa public enum Code { //@formatter:off - /** nihuta m väärtust q positsiooni võrra allapoole */ + /** nihuta m pealmist väärtust q positsiooni võrra allapoole */ SLIDE, //@formatter:on } diff --git a/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java b/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java index 3905e09..5d6b755 100644 --- a/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java +++ b/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java @@ -239,7 +239,7 @@ public void test_alloc_after_loadc() { @Test public void test_loadrc() { - // fp = 0 (vaikeväärtus), LOADRC 3 → push(0 + 3) = 3 + /* fp = 0 (vaikeväärtus), LOADRC 3 → push(0 + 3) = 3 */ pw.visit(LOADRC, 3); assertInterpreted(new CMaStack(3)); @@ -247,8 +247,10 @@ public void test_loadrc() { @Test public void test_loadr() { - // stack: [10, 20, 30], fp = 0 (vaikeväärtus) - // LOADR 2 → push(fp + 2) = push(2), LOAD → push(stack[2]) = 30 + /* + * stack: [10, 20, 30], fp = 0 (vaikeväärtus) + * LOADR 2 → push(fp + 2) = push(2), LOAD → push(stack[2]) = 30 + */ pw.visit(LOADR, 2); assertInterpreted(new CMaStack(10, 20, 30, 30), new CMaStack(10, 20, 30)); @@ -256,8 +258,10 @@ public void test_loadr() { @Test public void test_storer() { - // stack: [10, 20, 30], fp = 0 (vaikeväärtus) - // LOADC 99; STORER 1 → push(fp + 1) = push(1), STORE → stack[1] = 99 + /* + * stack: [10, 20, 30], fp = 0 (vaikeväärtus) + * LOADC 99; STORER 1 → push(fp + 1) = push(1), STORE → stack[1] = 99 + */ pw.visit(LOADC, 99); pw.visit(STORER, 1); @@ -268,24 +272,26 @@ public void test_storer() { @Test public void test_mark_call() { - // Stack enne: [] - // LOADC 42 → [42] (parameeter) - // MARK → [42, 0, 0] (push EP=0, push FP=0) - // LOADC 5 → [42, 0, 0, 5] (funktsiooni aadress) - // CALL → FP=3, PC=5, S[3]=4 → stack: [42, 0, 0, 4] - // indeks 4: HALT (tagastuspunkt, siia ei jõua) - // indeks 5: HALT (funktsioon peatub kohe) + /* + * Stack enne: [] + * LOADC 42 → [42] (parameeter) + * MARK → [42, 0, 0] (push EP=0, push FP=0) + * LOADC 5 → [42, 0, 0, 5] (funktsiooni aadress) + * CALL → FP=3, PC=5, S[3]=4 → stack: [42, 0, 0, 4] + * indeks 4: HALT (tagastuspunkt, siia ei jõua) + * indeks 5: HALT (funktsioon peatub kohe) + */ CMaLabel _func = new CMaLabel(); - pw.visit(LOADC, 42); // 0: parameeter - pw.visit(MARK); // 1: push EP(0), push FP(0) - pw.visit(LOADC, 5); // 2: funktsiooni aadress (indeks 5) - pw.visit(CALL); // 3: FP=3, PC=5, S[3]=4 (tagastusaadress) - pw.visit(HALT); // 4: tagastuspunkt - pw.visit(_func); // 5: funktsiooni algus - pw.visit(HALT); // 5: funktsioon peatub kohe + pw.visit(LOADC, 42); // 0: parameeter + pw.visit(MARK); // 1: push EP(0), push FP(0) + pw.visit(LOADC, 5); // 2: funktsiooni aadress (indeks 5) + pw.visit(CALL); // 3: FP=3, PC=5, S[3]=4 (tagastusaadress) + pw.visit(HALT); // 4: tagastuspunkt + pw.visit(_func); // 5: funktsiooni algus + pw.visit(HALT); // 5: funktsioon peatub kohe - // Stack pärast: [42, 0, 0, 4] — parameeter, salvestatud EP, FP, tagastusaadress + /* Stack pärast: [42, 0, 0, 4] — parameeter, salv. EP, FP, tagastusaadress */ assertInterpreted(new CMaStack(42, 0, 0, 4)); } @@ -293,9 +299,11 @@ public void test_mark_call() { @Test public void test_enter() { - // stack: [10, 20], ENTER 5 → EP = (2-1) + 5 = 6 - // MARK → push EP(6), push FP(0) → stack: [10, 20, 6, 0] - // Kontrollime EP väärtust läbi MARK käsu + /* + * stack: [10, 20], ENTER 5 → EP = (2-1) + 5 = 6 + * MARK → push EP(6), push FP(0) → stack: [10, 20, 6, 0] + * Kontrollime EP väärtust läbi MARK käsu + */ pw.visit(ENTER, 5); pw.visit(MARK); @@ -304,28 +312,30 @@ public void test_enter() { @Test public void test_enter_in_function() { - // MARK/CALL/ENTER tsükkel: funktsioon kutsutakse ja ENTER seab EP - // LOADC 42 → [42] - // MARK → [42, 0, 0] - // LOADC 5 → [42, 0, 0, 5] (funktsiooni aadress, _func label indeksil 5) - // CALL → FP=3, PC=5, S[3]=4 → [42, 0, 0, 4] - // HALT (tagastuspunkt, indeks 4) - // _func (indeks 5): ENTER 3 → EP = (4-1) + 3 = 6 - // MARK → push EP(6), push FP(3) → [42, 0, 0, 4, 6, 3] - // HALT + /* + * MARK/CALL/ENTER tsükkel: funktsioon kutsub ja ENTER seab EP + * LOADC 42 → [42] + * MARK → [42, 0, 0] + * LOADC 5 → [42, 0, 0, 5] (funktsiooni aadress, _func label indeksil 5) + * CALL → FP=3, PC=5, S[3]=4 → [42, 0, 0, 4] + * HALT (tagastuspunkt, indeks 4) + * _func (indeks 5): ENTER 3 → EP = (4-1) + 3 = 6 + * MARK → push EP(6), push FP(3) → [42, 0, 0, 4, 6, 3] + * HALT + */ CMaLabel _func = new CMaLabel(); - pw.visit(LOADC, 42); // 0: parameeter - pw.visit(MARK); // 1: push EP(0), push FP(0) - pw.visit(LOADC, 5); // 2: funktsiooni aadress (indeks 5) - pw.visit(CALL); // 3: FP=3, PC=5, S[3]=4 - pw.visit(HALT); // 4: tagastuspunkt - pw.visit(_func); // label indeksil 5 - pw.visit(ENTER, 3); // 5: EP = (4-1) + 3 = 6 - pw.visit(MARK); // 6: push EP(6), push FP(3) - pw.visit(HALT); // 7: funktsioon peatub - - // Stack pärast: [42, 0, 0, 4, 6, 3] + pw.visit(LOADC, 42); // 0: parameeter + pw.visit(MARK); // 1: push EP(0), push FP(0) + pw.visit(LOADC, 5); // 2: funktsiooni aadress (indeks 5) + pw.visit(CALL); // 3: FP=3, PC=5, S[3]=4 + pw.visit(HALT); // 4: tagastuspunkt + pw.visit(_func); // label indeksil 5 + pw.visit(ENTER, 3); // 5: EP = (4-1) + 3 = 6 + pw.visit(MARK); // 6: push EP(6), push FP(3) + pw.visit(HALT); // 7: funktsioon peatub + + /* Stack pärast: [42, 0, 0, 4, 6, 3] */ assertInterpreted(new CMaStack(42, 0, 0, 4, 6, 3)); } @@ -333,68 +343,72 @@ public void test_enter_in_function() { @Test public void test_call_return() { - // Täielik kutse-tagastus tsükkel: - // Peaprogramm kutsub funktsiooni, mis kohe tagastab. - // - // 0: LOADC 42 → [42] (parameeter) - // 1: MARK → [42, 0, 0] (push EP=0, FP=0) - // 2: LOADC 6 → [42, 0, 0, 6] (funktsiooni aadress) - // 3: CALL → FP=3, PC=6, S[3]=4 → [42, 0, 0, 4] - // 4: HALT (tagastuspunkt) - // - // _func (indeks 5): - // 5: ENTER 0 → EP = (4-1)+0 = 3 - // 6: RETURN 3 → PC=S[3]=4, EP=S[1]=0, FP=S[2]=0 - // SP = 3-3 = 0, truncate(1) → [42] - // PC=4 → jõuab HALT-i + /* + * Täielik kutse-tagastus tsükkel: + * Peaprogramm kutsub funktsiooni, mis kohe tagastab. + * + * 0: LOADC 42 → [42] (parameeter) + * 1: MARK → [42, 0, 0] (push EP=0, FP=0) + * 2: LOADC 6 → [42, 0, 0, 6] (funktsiooni aadress) + * 3: CALL → FP=3, PC=6, S[3]=4 → [42, 0, 0, 4] + * 4: HALT (tagastuspunkt) + * + * _func (indeks 5): + * 5: ENTER 0 → EP = (4-1)+0 = 3 + * 6: RETURN 3 → PC=S[3]=4, EP=S[1]=0, FP=S[2]=0 + * SP = 3-3 = 0, truncate(1) → [42] + * PC=4 → jõuab HALT-i + */ CMaLabel _func = new CMaLabel(); - pw.visit(LOADC, 42); // 0: parameeter - pw.visit(MARK); // 1: push EP(0), push FP(0) - pw.visit(LOADC, 5); // 2: funktsiooni aadress - pw.visit(CALL); // 3: FP=3, PC=5, S[3]=4 - pw.visit(HALT); // 4: tagastuspunkt - pw.visit(_func); // label indeksil 5 - pw.visit(ENTER, 0); // 5: EP = 3 - pw.visit(RETURN, 3); // 6: taasta ja kärbi, q=3 (EP+FP+PC) + pw.visit(LOADC, 42); // 0: parameeter + pw.visit(MARK); // 1: push EP(0), push FP(0) + pw.visit(LOADC, 6); // 2: funktsiooni aadress + pw.visit(CALL); // 3: FP=3, PC=5, S[3]=4 + pw.visit(HALT); // 4: tagastuspunkt + pw.visit(_func); // label indeksil 5 + pw.visit(ENTER, 0); // 5: EP = 3 + pw.visit(RETURN, 3); // 6: taasta ja kärbi, q=3 (EP+FP+PC) - // Pärast RETURN: stack = [42], PC=4 → HALT + /* Pärast RETURN: stack = [42], PC=4 → HALT */ assertInterpreted(new CMaStack(42)); } @Test public void test_call_return_with_locals() { - // Funktsioon eraldab lokaalse muutuja, kirjutab sinna ja tagastab. - // - // 0: LOADC 10 → [10] (parameeter) - // 1: MARK → [10, 0, 0] - // 2: LOADC 5 → [10, 0, 0, 5] - // 3: CALL → FP=3, PC=5, S[3]=4 → [10, 0, 0, 4] - // 4: HALT - // - // _func (indeks 5): - // 5: ENTER 1 → EP = (4-1)+1 = 4 - // 6: ALLOC 1 → [10, 0, 0, 4, 0] (lokaalne muutuja indeksil 4) - // 7: LOADC 99 - // 8: STORER 1 → stack[FP+1]=stack[4]=99 → [10, 0, 0, 4, 99, 99] - // 9: POP → [10, 0, 0, 4, 99] - // 10: RETURN 3 → PC=4, EP=0, SP=3-3=0, FP=0, truncate(1) → [10] + /* + * Funktsioon eraldab lokaalse muutuja, kirjutab sinna ja tagastab. + * + * 0: LOADC 10 → [10] (parameeter) + * 1: MARK → [10, 0, 0] + * 2: LOADC 5 → [10, 0, 0, 5] + * 3: CALL → FP=3, PC=5, S[3]=4 → [10, 0, 0, 4] + * 4: HALT + * + * _func (indeks 5): + * 5: ENTER 1 → EP = (4-1)+1 = 4 + * 6: ALLOC 1 → [10, 0, 0, 4, 0] (lokaalne muutuja indeksil 4) + * 7: LOADC 99 + * 8: STORER 1 → stack[FP+1]=stack[4]=99 → [10, 0, 0, 4, 99, 99] + * 9: POP → [10, 0, 0, 4, 99] + * 10: RETURN 3 → PC=4, EP=0, SP=3-3=0, FP=0, truncate(1) → [10] + */ CMaLabel _func = new CMaLabel(); - pw.visit(LOADC, 10); // 0: parameeter - pw.visit(MARK); // 1 - pw.visit(LOADC, 5); // 2: funktsiooni aadress - pw.visit(CALL); // 3 - pw.visit(HALT); // 4 - pw.visit(_func); // label indeksil 5 - pw.visit(ENTER, 1); // 5 - pw.visit(ALLOC, 1); // 6: lokaalne muutuja - pw.visit(LOADC, 99); // 7 - pw.visit(STORER, 1); // 8: kirjuta lokaalsesse muutujasse - pw.visit(POP); // 9 - pw.visit(RETURN, 3); // 10: tagasta, q=3 - - // Pärast RETURN: stack = [10], PC=4 → HALT + pw.visit(LOADC, 10); // 0: parameeter + pw.visit(MARK); // 1 + pw.visit(LOADC, 5); // 2: funktsiooni aadress + pw.visit(CALL); // 3 + pw.visit(HALT); // 4 + pw.visit(_func); // label indeksil 5 + pw.visit(ENTER, 1); // 5 + pw.visit(ALLOC, 1); // 6: lokaalne muutuja + pw.visit(LOADC, 99); // 7 + pw.visit(STORER, 1); // 8: kirjuta lokaalsesse muutujasse + pw.visit(POP); // 9 + pw.visit(RETURN, 3); // 10: tagasta, q=3 + + /* Pärast RETURN: stack = [10], PC=4 → HALT */ assertInterpreted(new CMaStack(10)); } @@ -402,9 +416,11 @@ public void test_call_return_with_locals() { @Test public void test_slide() { - // stack: [10, 20, 30], SLIDE 2 1 → kopeeri 1 väärtus (30) 2 positsiooni allapoole - // S[SP-2-1+1] = S[SP-1+1] → S[0] = S[2] = 30 → stack: [30, 20, 30] - // truncate(SP-2+1) = truncate(1) → stack: [30] + /* + * stack: [10, 20, 30], SLIDE 2 1 → kopeeri 1 väärtus (30) 2 positsiooni allapoole + * S[SP-2-1+1] = S[SP-1+1] → S[0] = S[2] = 30 → stack: [30, 20, 30] + * truncate(SP-2+1) = truncate(1) → stack: [30] + */ pw.visit(LOADC, 10); pw.visit(LOADC, 20); pw.visit(LOADC, 30); @@ -415,10 +431,12 @@ public void test_slide() { @Test public void test_slide_multiple_values() { - // stack: [1, 2, 3, 4, 5], SLIDE 2 2 → kopeeri 2 väärtust (4, 5) 2 positsiooni allapoole - // S[SP-2-2+1] = S[SP-2+1] → S[1] = S[3] = 4 - // S[SP-2-2+2] = S[SP-2+2] → S[2] = S[4] = 5 - // truncate(SP-2+1) = truncate(3) → stack: [1, 4, 5] + /* + * stack: [1, 2, 3, 4, 5], SLIDE 2 2 → kopeeri 2 väärtust (4, 5) 2 positsiooni allapoole + * S[SP-2-2+1] = S[SP-2+1] → S[1] = S[3] = 4 + * S[SP-2-2+2] = S[SP-2+2] → S[2] = S[4] = 5 + * truncate(SP-2+1) = truncate(3) → stack: [1, 4, 5] + */ pw.visit(LOADC, 1); pw.visit(LOADC, 2); pw.visit(LOADC, 3); @@ -431,7 +449,7 @@ public void test_slide_multiple_values() { @Test public void test_slide_zero() { - // stack: [10, 20], SLIDE 0 1 → q=0, nihkumist pole, truncate(SP+1) → muutumatu + /* stack: [10, 20], SLIDE 0 1 → q=0, nihkumist pole, truncate(SP+1) → muutumatu */ pw.visit(LOADC, 10); pw.visit(LOADC, 20); pw.visit(SLIDE, 0, 1); @@ -439,35 +457,54 @@ public void test_slide_zero() { assertInterpreted(new CMaStack(10, 20)); } + @Test + public void test_slide_m_zero() { + /* + * stack: [10, 20, 30], SLIDE 2 0 → m=0, tagastusväärtust pole, kärbi q pesa + * SP = SP - q = 2 - 2 = 0 → truncate(1) → [10] + */ + pw.visit(LOADC, 10); + pw.visit(LOADC, 20); + pw.visit(LOADC, 30); + pw.visit(SLIDE, 2, 0); + + assertInterpreted(new CMaStack(10)); + } + // Funktsioonikutsed: Samm 8 — JUMPI käsu testimine @Test public void test_jumpi() { - // Hüppetabel: väärtus 0 → case0, väärtus 1 → case1, väärtus 2 → case2 - // Iga case laeb oma väärtuse stackile ja peatub. + /* + * Lülituslause harud: + * väärtus 0 → case0 + * väärtus 1 → case1 + * väärtus 2 → case2 + * Igale lülituslause harule vastavad väärtused laetakse stackile. + */ CMaLabel _table = new CMaLabel(); CMaLabel _case0 = new CMaLabel(); CMaLabel _case1 = new CMaLabel(); CMaLabel _case2 = new CMaLabel(); - // Programm: LOADC index; JUMPI _table; _table: JUMP _case0; JUMP _case1; JUMP _case2 - pw.visit(LOADC, 0); // 0: indeks - pw.visit(JUMPI, _table); // 1: PC = target(_table) + 0 = 2 - pw.visit(_table); // indeks 2 - pw.visit(JUMP, _case0); // 2: hüppa case0-le - pw.visit(JUMP, _case1); // 3: hüppa case1-le - pw.visit(JUMP, _case2); // 4: hüppa case2-le + /* Programm: LOADC index; JUMPI _table; _table: JUMP _case0; JUMP _case1; JUMP _case2 */ + pw.visit(LOADC, 0); // 0: indeks + pw.visit(JUMPI, _table); // 1: PC = target(_table) + 0 = 2 + pw.visit(_table); // indeks 2 + pw.visit(JUMP, _case0); // 2: hüppa case0-le + pw.visit(JUMP, _case1); // 3: hüppa case1-le + pw.visit(JUMP, _case2); // 4: hüppa case2-le pw.visit(_case0); - pw.visit(LOADC, 100); // 5 - pw.visit(HALT); // 6 + pw.visit(LOADC, 100); + pw.visit(HALT); pw.visit(_case1); - pw.visit(LOADC, 200); // 7 - pw.visit(HALT); // 8 + pw.visit(LOADC, 200); + pw.visit(HALT); pw.visit(_case2); - pw.visit(LOADC, 300); // 9 - pw.visit(HALT); // 10 + pw.visit(LOADC, 300); + pw.visit(HALT); - // Indeks 0 → case0 → stack: [100] + /* Indeks 0 → case0 → stack: [100] */ assertInterpreted(new CMaStack(100)); } @@ -478,12 +515,12 @@ public void test_jumpi_index1() { CMaLabel _case1 = new CMaLabel(); CMaLabel _case2 = new CMaLabel(); - pw.visit(LOADC, 1); // 0: indeks - pw.visit(JUMPI, _table); // 1: PC = target(_table) + 1 = 3 + pw.visit(LOADC, 1); // 0: indeks + pw.visit(JUMPI, _table); // 1: PC = target(_table) + 1 = 3 pw.visit(_table); - pw.visit(JUMP, _case0); // 2 - pw.visit(JUMP, _case1); // 3 - pw.visit(JUMP, _case2); // 4 + pw.visit(JUMP, _case0); // 2 + pw.visit(JUMP, _case1); // 3 + pw.visit(JUMP, _case2); // 4 pw.visit(_case0); pw.visit(LOADC, 100); pw.visit(HALT); @@ -494,7 +531,7 @@ public void test_jumpi_index1() { pw.visit(LOADC, 300); pw.visit(HALT); - // Indeks 1 → case1 → stack: [200] + /* Indeks 1 → case1 → stack: [200] */ assertInterpreted(new CMaStack(200)); } @@ -505,12 +542,12 @@ public void test_jumpi_index2() { CMaLabel _case1 = new CMaLabel(); CMaLabel _case2 = new CMaLabel(); - pw.visit(LOADC, 2); // 0: indeks - pw.visit(JUMPI, _table); // 1: PC = target(_table) + 2 = 4 + pw.visit(LOADC, 2); // 0: indeks + pw.visit(JUMPI, _table); // 1: PC = target(_table) + 2 = 4 pw.visit(_table); - pw.visit(JUMP, _case0); // 2 - pw.visit(JUMP, _case1); // 3 - pw.visit(JUMP, _case2); // 4 + pw.visit(JUMP, _case0); // 2 + pw.visit(JUMP, _case1); // 3 + pw.visit(JUMP, _case2); // 4 pw.visit(_case0); pw.visit(LOADC, 100); pw.visit(HALT); @@ -521,7 +558,358 @@ public void test_jumpi_index2() { pw.visit(LOADC, 300); pw.visit(HALT); - // Indeks 2 → case2 → stack: [300] + /* Indeks 2 → case2 → stack: [300] */ assertInterpreted(new CMaStack(300)); } + + // Funktsioonikutsed: Samm 9 — Integratsioonitestid kõikide käskude testimiseks erinevates töövoogudes + + /** + * Mitterekursiivne {@code inc(x)} funktsioon, mida kutsub {@code main(n)}. + * + *

C-kood:

+ *
{@code
+     * int inc(int x) { return x + 1; }
+     * int main(int n) {
+     *     int r = inc(n);
+     *     return r;
+     * }
+     * }
+ * + *

Täitmisraami paigutus (FP viitab salvestatud PC-le):

+ * + * + * + * + * + * + *
{@code FP-3}parameeter
{@code FP-2}salvestatud EP
{@code FP-1}salvestatud FP
{@code FP}salvestatud PC (tagastusaadress)
{@code FP+1} ja edasilokaalsed muutujad
+ */ + @Test + public void test_main_calls_non_recursive_function() { + CMaLabel _main = new CMaLabel(); + CMaLabel _inc = new CMaLabel(); + + /* === Peaprogramm (indeksid 0-5): kutsub main(41) === */ + pw.visit(LOADC, 41); // 0: main parameetriks antav väärtus + pw.visit(MARK); // 1: push EP, FP + pw.visit(LOADC, 6); // 2: _main aadress = 6 + pw.visit(CALL); // 3 + pw.visit(SLIDE, 0, 1); // 4: tõsta tulemus + pw.visit(HALT); // 5 + + /* + * === main(n) funktsioon (indeksid 6-17) === + * int main(int n) { int r = inc(n); return r; } + * Lokaalsed: r on FP+1 + */ + pw.visit(_main); // label indeksil 6 + pw.visit(ENTER, 1); // 6: EP = SP + 1 (1 lokaalne muutuja: r) + pw.visit(ALLOC, 1); // 7: eralda koht r-ile + + /* kutsu inc(n) */ + pw.visit(LOADR, -3); // 8: push n + pw.visit(MARK); // 9: push EP, FP + pw.visit(LOADC, 18); // 10: _inc aadress = 18 + pw.visit(CALL); // 11 + pw.visit(SLIDE, 0, 1); // 12: tõsta inc(n) tulemus + + pw.visit(STORER, 1); // 13: r = inc(n) + pw.visit(POP); // 14: eemalda STORER duplikaat + + /* return r */ + pw.visit(LOADR, 1); // 15: push r + pw.visit(STORER, -3); // 16: kirjuta tulemus parameetri pessa + pw.visit(RETURN, 3); // 17 + + /* + * === inc(x) funktsioon (indeksid 18-23) === + * int inc(int x) { return x + 1; } + */ + pw.visit(_inc); // label indeksil 18 + pw.visit(ENTER, 0); // 18: lokaalseid muutujaid pole + pw.visit(LOADR, -3); // 19: push x + pw.visit(LOADC, 1); // 20 + pw.visit(ADD); // 21: x + 1 + pw.visit(STORER, -3); // 22: tulemus → parameetri pessa + pw.visit(RETURN, 3); // 23 + + /* Oodatav tulemus: inc(41) = 42, main tagastab 42 */ + assertInterpreted(new CMaStack(42)); + } + + /** + * Rekursiivne {@code fac(n)} funktsioon. + * + *

C-kood:

+ *
{@code
+     * int fac(int n) {
+     *     if (n <= 0) return 1;
+     *     return n * fac(n - 1);
+     * }
+     * int main(int n) {
+     *     int r = fac(n);
+     *     return r;
+     * }
+     * }
+ * + *

Täitmisraami paigutus (FP viitab salvestatud PC-le):

+ * + * + * + * + * + * + *
{@code FP-3}parameeter
{@code FP-2}salvestatud EP
{@code FP-1}salvestatud FP
{@code FP}salvestatud PC (tagastusaadress)
{@code FP+1} ja edasilokaalsed muutujad
+ * + *

Tagastus: tulemus kirjutatakse parameetri pessa ({@code STORER -3}), + * seejärel {@code RETURN 3} kärbib täitmisraami ja kutsuja kasutab + * {@code SLIDE 0 1} tulemuse kättesaamiseks.

+ */ + private CMaStack runFac(int n) { + pw = new CMaProgramWriter(); + + CMaLabel _fac = new CMaLabel(); + CMaLabel _recurse = new CMaLabel(); + CMaLabel _main = new CMaLabel(); + + /* === Peaprogramm (indeksid 0-5): kutsub main() === */ + pw.visit(LOADC, n); // 0: main parameetriks antav n väärtus + pw.visit(MARK); // 1: push EP, FP + pw.visit(LOADC, 6); // 2: _main aadress = 6 + pw.visit(CALL); // 3: FP=3, PC=6, S[3]=4 + pw.visit(SLIDE, 0, 1); // 4: tõsta tulemus + pw.visit(HALT); // 5 + + /* + * === main() funktsioon (indeksid 6-17) === + * int main(int n) { int r = fac(n); return r; } + * Lokaalsed: r on FP+1 (indeks 1 täitmisraamist) + */ + pw.visit(_main); // label indeksil 6 + pw.visit(ENTER, 1); // 6: EP = SP + 1 (1 lokaalne muutuja: r) + pw.visit(ALLOC, 1); // 7: eralda koht r-ile + + /* kutsu fac(n): n on FP-3 */ + pw.visit(LOADR, -3); // 8: push n + pw.visit(MARK); // 9: push EP, FP + pw.visit(LOADC, 18); // 10: _fac aadress = 18 + pw.visit(CALL); // 11 + pw.visit(SLIDE, 0, 1); // 12: tõsta fac(n) tulemus + + pw.visit(STORER, 1); // 13: r = fac(n) + pw.visit(POP); // 14: eemalda STORER duplikaat + + /* return r: kopeeri r parameetri pessa */ + pw.visit(LOADR, 1); // 15: push r + pw.visit(STORER, -3); // 16: kirjuta tulemus parameetri pessa + pw.visit(RETURN, 3); // 17 + + /* === fac(n) funktsioon (indeksid 18-...) === */ + pw.visit(_fac); // label indeksil 18 + pw.visit(ENTER, 0); // 18: lokaalseid muutujaid pole + + /* if (n <= 0) return 1 */ + pw.visit(LOADR, -3); // 19: push n + pw.visit(LOADC, 0); // 20 + pw.visit(LEQ); // 21: n <= 0? + pw.visit(JUMPZ, _recurse); // 22: kui n > 0, hüppa rekursiivsesse harusse + pw.visit(LOADC, 1); // 23: baassjuht: tulemus = 1 + pw.visit(STORER, -3); // 24: tulemus → parameetri pessa + pw.visit(RETURN, 3); // 25 + + /* rekursiivne juht: return n * fac(n-1) */ + pw.visit(_recurse); // label indeksil 26 + pw.visit(LOADR, -3); // 26: push n (korrutamise jaoks) + pw.visit(LOADR, -3); // 27: push n (fac argumendi jaoks) + pw.visit(LOADC, 1); // 28 + pw.visit(SUB); // 29: n-1 + pw.visit(MARK); // 30: push EP, FP + pw.visit(LOADC, 18); // 31: _fac aadress = 18 + pw.visit(CALL); // 32 + pw.visit(SLIDE, 0, 1); // 33: tõsta fac(n-1) tulemus + pw.visit(MUL); // 34: n * fac(n-1) + pw.visit(STORER, -3); // 35: tulemus → parameetri pessa + pw.visit(RETURN, 3); // 36 + + return CMaInterpreter.run(pw.toProgram()); + } + + @Test + public void test_recursive_fac_0() { + CMaStack result = runFac(0); + assertEquals(new CMaStack(1), result); + } + + @Test + public void test_recursive_fac_1() { + CMaStack result = runFac(1); + assertEquals(new CMaStack(1), result); + } + + @Test + public void test_recursive_fac_5() { + CMaStack result = runFac(5); + assertEquals(new CMaStack(120), result); + } + + @Test + public void test_recursive_fac_10() { + CMaStack result = runFac(10); + assertEquals(new CMaStack(3628800), result); + } + + /** + * Ehitab ja käivitab programmi, mis kasutab kõiki uusi käske. + * + *

C-kood:

+ *
{@code
+     * int inc(int x, int step) { return x + step; }
+     * int main(int op) {
+     *     int n = 5;
+     *     int r;
+     *     switch (op) {
+     *         case 0: r = inc(n, 1); break;  // LOADRC, MARK, CALL, SLIDE 1 1
+     *         case 1: r = n * 2;     break;  // LOADR, MUL, STORER
+     *     }
+     *     return r;
+     * }
+     * }
+ * + *

Täitmisraami paigutus (FP viitab salvestatud PC-le):

+ * + * + * + * + * + * + * + * + *
{@code FP-3}parameeter (op / step)
{@code FP-2}salvestatud EP
{@code FP-1}salvestatud FP
{@code FP}salvestatud PC
{@code FP+1}lokaalne n (main)
{@code FP+2}lokaalne r (main)
{@code FP-4}esimene parameeter x (ainult inc-is)
+ * + *

{@code inc} kasutab {@code RETURN 3} (puhastab ainult org-pesad), jättes x-pesa alles. + * Kutsuja kasutab {@code SLIDE 1 1}, et x-pesa tulemusega üle kirjutada ja kärpida.

+ * + *

Programmi aadressid:

+ *
    + *
  • {@code 0–5}: peaprogramm
  • + *
  • {@code 6–11}: {@code inc(x, step)}
  • + *
  • {@code 12–18}: {@code main(op)}
  • + *
  • {@code 19–20}: lülituslause harud
  • + *
  • {@code 21–30}: case 0 (inc)
  • + *
  • {@code 31–35}: case 1 (n*2)
  • + *
  • {@code 36–38}: tagastus
  • + *
+ * + *

Oodatavad tulemused:

+ *
    + *
  • {@code op=0} → {@code inc(5, 1) = 6}
  • + *
  • {@code op=1} → {@code 5 * 2 = 10}
  • + *
+ */ + private CMaStack runDispatch(int op) { + pw = new CMaProgramWriter(); + + CMaLabel _inc = new CMaLabel(); + CMaLabel _main = new CMaLabel(); + CMaLabel _table = new CMaLabel(); + CMaLabel _case0 = new CMaLabel(); + CMaLabel _case1 = new CMaLabel(); + CMaLabel _end = new CMaLabel(); + + /* Peaprogramm (0–5): kutsub main(op). */ + pw.visit(LOADC, op); // 0: op → parameeter main-ile + pw.visit(MARK); // 1: push EP(0), FP(0) + pw.visit(LOADC, 12); // 2: _main aadress = 12 + pw.visit(CALL); // 3: FP=3, PC=12, S[3]=4 + pw.visit(SLIDE, 0, 1); // 4: tõsta tulemus parameetri kohalt + pw.visit(HALT); // 5: peaprogramm lõpeb + + /* + * inc(x, step) (6–11): tagastab x + step. + * FP-4=x (esimene arg), FP-3=step (teine arg). + * RETURN 3 puhastab ainult org-pesad — x-pesa jääb kutsujale. + * Käsud: ENTER, LOADR, ADD, STORER, RETURN. + */ + pw.visit(_inc); + pw.visit(ENTER, 0); // 6: lokaalseid muutujaid pole; EP = SP+0 + pw.visit(LOADR, -4); // 7: push x (FP-4, esimene arg) + pw.visit(LOADR, -3); // 8: push step (FP-3, teine arg) + pw.visit(ADD); // 9: x + step + pw.visit(STORER, -3); // 10: tulemus → step-pessa (FP-3) + pw.visit(RETURN, 3); // 11: q=3; x-pesa (FP-4) jääb kutsujale + + /* + * main(op) (12–18): eraldab n=5 ja r, valib haru JUMPI abil. + * Käsud: ENTER, ALLOC, STORER, LOADR, JUMPI. + */ + pw.visit(_main); + pw.visit(ENTER, 2); // 12: EP = SP+2 (2 lokaalset: n, r) + pw.visit(ALLOC, 2); // 13: eralda FP+1 (n) ja FP+2 (r) + pw.visit(LOADC, 5); // 14: push 5 + pw.visit(STORER, 1); // 15: n = 5 (FP+1) + pw.visit(POP); // 16: eemalda STORER duplikaat + pw.visit(LOADR, -3); // 17: push op (FP-3) — JUMPI indeks + pw.visit(JUMPI, _table); // 18: PC = target(_table) + op + + /* + * Lülituslause harud (19–20): JUMPI sihtmärgid. + * op=0 → _case0 (21), op=1 → _case1 (31). + */ + pw.visit(_table); + pw.visit(JUMP, _case0); // 19: op=0 → kutsu inc(n, 1) + pw.visit(JUMP, _case1); // 20: op=1 → arvuta n*2 + + /* + * case 0 (21–30): r = inc(n, 1). + * Push n (LOADRC+LOAD) ja step=1, kutsu inc. + * SLIDE 1 1 nihutab tulemuse x-pesa kohale ja kustutab x-pesa. + * Käsud: LOADRC, LOAD, LOADC, MARK, CALL, SLIDE 1 1, STORER. + */ + pw.visit(_case0); + pw.visit(LOADRC, 1); // 21: push FP+1 (n aadress) — LOADRC otse + pw.visit(LOAD); // 22: loe n väärtus aadressilt + pw.visit(LOADC, 1); // 23: push step=1 (teine argument inc-ile) + pw.visit(MARK); // 24: push EP, FP + pw.visit(LOADC, 6); // 25: _inc aadress = 6 + pw.visit(CALL); // 26: FP=10, PC=6, S[10]=27 + pw.visit(SLIDE, 1, 1); // 27: nihuta tulemus x-pesa kohale, kustuta x + pw.visit(STORER, 2); // 28: r = tulemus (FP+2) + pw.visit(POP); // 29: eemalda STORER duplikaat + pw.visit(JUMP, _end); // 30: hüppa tagastusele + + /* + * case 1 (31–35): r = n * 2. + * Käsud: LOADR, LOADC, MUL, STORER. + */ + pw.visit(_case1); + pw.visit(LOADR, 1); // 31: push n (FP+1) + pw.visit(LOADC, 2); // 32: push 2 + pw.visit(MUL); // 33: n * 2 = 10 + pw.visit(STORER, 2); // 34: r = n*2 (FP+2) + pw.visit(POP); // 35: eemalda STORER duplikaat + + /* + * Tagastus (36–38): return r. + * Käsud: LOADR, STORER, RETURN. + */ + pw.visit(_end); + pw.visit(LOADR, 2); // 36: push r (FP+2) + pw.visit(STORER, -3); // 37: tulemus → parameetri pessa (FP-3) + pw.visit(RETURN, 3); // 38: tagasta, q=3 + + return CMaInterpreter.run(pw.toProgram()); + } + + @Test + public void test_dispatch_inc() { + /* op=0 → inc(5, 1) = 6: kasutab LOADRC, MARK, CALL, SLIDE 1 1 */ + assertEquals(new CMaStack(6), runDispatch(0)); + } + + @Test + public void test_dispatch_double() { + /* op=1 → 5*2 = 10: kasutab LOADR, MUL, STORER */ + assertEquals(new CMaStack(10), runDispatch(1)); + } } From 9eb265b0853b00c6e4d147385b13adae13143ee2 Mon Sep 17 00:00:00 2001 From: sandersirge Date: Mon, 11 May 2026 15:05:50 +0300 Subject: [PATCH 17/24] =?UTF-8?q?Funktsioonikutsed:=20K=C3=A4skude=20paran?= =?UTF-8?q?dused=20tehtud,=20testid=20parandatud?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/ee/ut/cs/sws/cma/CMaInterpreter.java | 40 +++++-- .../cma/instruction/CMaIntInstruction.java | 8 +- .../cma/instruction/CMaIntIntInstruction.java | 6 + .../ee/ut/cs/sws/cma/CMaInterpreterTest.java | 103 ++++++++++++------ 4 files changed, 110 insertions(+), 47 deletions(-) diff --git a/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java b/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java index 465fa53..925d9b4 100644 --- a/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java +++ b/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java @@ -5,6 +5,9 @@ import static ee.ut.cs.sws.cma.instruction.CMaBasicInstruction.Code.LOAD; import static ee.ut.cs.sws.cma.instruction.CMaBasicInstruction.Code.STORE; import static ee.ut.cs.sws.cma.instruction.CMaIntInstruction.Code.LOADC; +import static ee.ut.cs.sws.cma.instruction.CMaIntInstruction.Code.LOADM; +import static ee.ut.cs.sws.cma.instruction.CMaIntInstruction.Code.STOREM; +import static ee.ut.cs.sws.cma.instruction.CMaIntInstruction.Code.LOADRC; public class CMaInterpreter { @@ -109,15 +112,22 @@ case CMaIntInstruction(CMaIntInstruction.Code code, int arg) -> { } case ALLOC -> stack.allocate(arg); case LOADRC -> stack.push(fp + arg); - case LOADR -> { - // LOADR j = LOADRC j; LOAD - execute(new CMaIntInstruction(CMaIntInstruction.Code.LOADRC, arg)); - execute(new CMaBasicInstruction(LOAD)); + case LOADM -> { + // LOADM m: S[SP+i] ← S[S[SP]+i] for i=m-1..0; SP ← SP + m - 1 + int sp = stack.size() - 1; + int target = stack.get(sp); // S[SP] = base address + stack.allocate(arg - 1); // expand: new SP = sp + arg - 1 + for (int i = arg - 1; i >= 0; i--) { + stack.set(sp + i, stack.get(target + i)); // S[SP+i] ← S[target+i] + } } - case STORER -> { - // STORER j = LOADRC j; STORE - execute(new CMaIntInstruction(CMaIntInstruction.Code.LOADRC, arg)); - execute(new CMaBasicInstruction(STORE)); + case STOREM -> { + // STOREM m: S[S[SP]+i] ← S[SP-m+i] for i=0..m-1; eemalda aadress + int sp = stack.size() - 1; + int target = stack.get(sp); // S[SP] = destination address + for (int i = 0; i < arg; i++) { + stack.set(target + i, stack.get(sp - arg + i)); // S[target+i] ← S[SP-m+i] + } } case ENTER -> { // EP = SP + m; kui EP >= HP, siis viga @@ -151,7 +161,7 @@ case CMaIntIntInstruction(CMaIntIntInstruction.Code code, int arg1, int arg2) -> int sp = stack.size() - 1; if (arg2 == 0) { // m = 0: lihtsalt kärbi q pesa - stack.truncate(sp - arg1 + 1); // SP = SP - q, size = SP - q + 1 + stack.truncate(sp - arg1 + 1); // SP = SP - q, size = SP - q + 1 } else { // kopeeri m väärtust q positsiooni allapoole, siis kärbi sp = sp - arg1 - arg2; @@ -159,10 +169,20 @@ case CMaIntIntInstruction(CMaIntIntInstruction.Code code, int arg1, int arg2) -> sp++; stack.set(sp, stack.get(sp + arg1)); // S[SP] ← S[SP+q] } - stack.truncate(sp + 1); // SP = SP - q, size = SP - q + 1 + stack.truncate(sp + 1); // SP = SP - q, size = SP - q + 1 } } } + case LOADR -> { + // LOADR j m = LOADRC j; LOADM m + execute(new CMaIntInstruction(LOADRC, arg1)); + execute(new CMaIntInstruction(LOADM, arg2)); + } + case STORER -> { + // STORER j m = LOADRC j; STOREM m + execute(new CMaIntInstruction(LOADRC, arg1)); + execute(new CMaIntInstruction(STOREM, arg2)); + } } } case CMaLabelInstruction(CMaLabelInstruction.Code code, CMaLabel label) -> { diff --git a/src/main/java/ee/ut/cs/sws/cma/instruction/CMaIntInstruction.java b/src/main/java/ee/ut/cs/sws/cma/instruction/CMaIntInstruction.java index 71ab498..0a1f469 100644 --- a/src/main/java/ee/ut/cs/sws/cma/instruction/CMaIntInstruction.java +++ b/src/main/java/ee/ut/cs/sws/cma/instruction/CMaIntInstruction.java @@ -19,11 +19,11 @@ public enum Code { /** lisa stackile FP + j (suhteline aadress) */ LOADRC, - /** loe väärtus FP-suhteliselt indeksilt */ - LOADR, + /** loe m väärtust mälust aadressil S[SP], laienda stack m-1 pesa võrra */ + LOADM, - /** salvesta väärtus FP-suhtelisele indeksile */ - STORER, + /** kirjuta m väärtust S[SP-m..SP-1] mällu aadressile S[SP], eemalda aadress */ + STOREM, /** sea piirviit EP = SP + m, kontrolli EP >= HP */ ENTER, diff --git a/src/main/java/ee/ut/cs/sws/cma/instruction/CMaIntIntInstruction.java b/src/main/java/ee/ut/cs/sws/cma/instruction/CMaIntIntInstruction.java index ab99aab..760fbb3 100644 --- a/src/main/java/ee/ut/cs/sws/cma/instruction/CMaIntIntInstruction.java +++ b/src/main/java/ee/ut/cs/sws/cma/instruction/CMaIntIntInstruction.java @@ -6,6 +6,12 @@ public enum Code { //@formatter:off /** nihuta m pealmist väärtust q positsiooni võrra allapoole */ SLIDE, + + /** loe m väärtust FP-suhteliselt aadressilt j: LOADRC j; LOADM m */ + LOADR, + + /** salvesta m väärtust FP-suhtelisele aadressile j: LOADRC j; STOREM m */ + STORER, //@formatter:on } diff --git a/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java b/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java index 5d6b755..3cf8309 100644 --- a/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java +++ b/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java @@ -235,7 +235,7 @@ public void test_alloc_after_loadc() { assertInterpreted(new CMaStack(5, 0, 0)); } - // Funktsioonikutsed: Samm 3 — LOADRC, LOADR ja STORER käskude testimine + // Funktsioonikutsed: Samm 3 — LOADRC, LOADR, STORER, LOADM ja STOREM käskude testimine @Test public void test_loadrc() { @@ -249,9 +249,9 @@ public void test_loadrc() { public void test_loadr() { /* * stack: [10, 20, 30], fp = 0 (vaikeväärtus) - * LOADR 2 → push(fp + 2) = push(2), LOAD → push(stack[2]) = 30 + * LOADR 2 1 → LOADRC 2; LOADM 1 → push(fp + 2) = push(2), load 1 väärtus: push(stack[2]) = 30 */ - pw.visit(LOADR, 2); + pw.visit(LOADR, 2, 1); assertInterpreted(new CMaStack(10, 20, 30, 30), new CMaStack(10, 20, 30)); } @@ -260,12 +260,49 @@ public void test_loadr() { public void test_storer() { /* * stack: [10, 20, 30], fp = 0 (vaikeväärtus) - * LOADC 99; STORER 1 → push(fp + 1) = push(1), STORE → stack[1] = 99 + * LOADC 99; STORER 1 1 → LOADRC 1; STOREM 1 + * LOADRC 1: push(fp + 1) = push(1) → [10, 20, 30, 99, 1] + * STOREM 1: stack[1] = stack[SP-1] = 99, SP ei muutu → [10, 99, 30, 99, 1] */ pw.visit(LOADC, 99); - pw.visit(STORER, 1); + pw.visit(STORER, 1, 1); - assertInterpreted(new CMaStack(10, 99, 30, 99), new CMaStack(10, 20, 30)); + assertInterpreted(new CMaStack(10, 99, 30, 99, 1), new CMaStack(10, 20, 30)); + } + + @Test + public void test_loadm() { + /* + * LOADM 2: lae 2 väärtust aadressilt S[SP] + * stack enne: [10, 20, 30, 1] (addr = 1, loeb stack[1] ja stack[2]) + * Tsükkel tagurpidi: + * i=1: S[SP+1] ← S[S[SP]+1] → S[4] ← S[2] = 30 (laiendab stacki) + * i=0: S[SP+0] ← S[S[SP]+0] → S[3] ← S[1] = 20 (kirjutab üle aadressi) + * SP ← SP + 2 - 1 = SP + 1 + * stack pärast: [10, 20, 30, 20, 30] + */ + pw.visit(LOADC, 10); + pw.visit(LOADC, 20); + pw.visit(LOADC, 30); + pw.visit(LOADC, 1); // aadress: stack[1..2] = [20, 30] + pw.visit(LOADM, 2); + + assertInterpreted(new CMaStack(10, 20, 30, 20, 30)); + } + + @Test + public void test_storem() { + /* + * STOREM 2: kirjuta 2 väärtust aadressile S[SP], SP ei muutu + * stack enne: [0, 0, 7, 8, 0] (addr = 0, kirjutab stack[2] ja stack[3] → stack[0] ja stack[1]) + * i=0: S[S[SP]+0] ← S[SP-2+0] → S[0] ← S[2] = 7 + * i=1: S[S[SP]+1] ← S[SP-2+1] → S[1] ← S[3] = 8 + * aadress (0) jääb pinule → SP ei muutu + * stack pärast: [7, 8, 7, 8, 0] + */ + pw.visit(STOREM, 2); + + assertInterpreted(new CMaStack(7, 8, 7, 8, 0), new CMaStack(0, 0, 7, 8, 0)); } // Funktsioonikutsed: Samm 4 — MARK ja CALL käskude testimine @@ -389,7 +426,7 @@ public void test_call_return_with_locals() { * 5: ENTER 1 → EP = (4-1)+1 = 4 * 6: ALLOC 1 → [10, 0, 0, 4, 0] (lokaalne muutuja indeksil 4) * 7: LOADC 99 - * 8: STORER 1 → stack[FP+1]=stack[4]=99 → [10, 0, 0, 4, 99, 99] + * 8: STORER 1 1 → stack[FP+1]=stack[4]=99 → [10, 0, 0, 4, 99, 99] * 9: POP → [10, 0, 0, 4, 99] * 10: RETURN 3 → PC=4, EP=0, SP=3-3=0, FP=0, truncate(1) → [10] */ @@ -404,7 +441,7 @@ public void test_call_return_with_locals() { pw.visit(ENTER, 1); // 5 pw.visit(ALLOC, 1); // 6: lokaalne muutuja pw.visit(LOADC, 99); // 7 - pw.visit(STORER, 1); // 8: kirjuta lokaalsesse muutujasse + pw.visit(STORER, 1, 1); // 8: kirjuta lokaalsesse muutujasse pw.visit(POP); // 9 pw.visit(RETURN, 3); // 10: tagasta, q=3 @@ -608,18 +645,18 @@ public void test_main_calls_non_recursive_function() { pw.visit(ALLOC, 1); // 7: eralda koht r-ile /* kutsu inc(n) */ - pw.visit(LOADR, -3); // 8: push n + pw.visit(LOADR, -3, 1); // 8: push n pw.visit(MARK); // 9: push EP, FP pw.visit(LOADC, 18); // 10: _inc aadress = 18 pw.visit(CALL); // 11 pw.visit(SLIDE, 0, 1); // 12: tõsta inc(n) tulemus - pw.visit(STORER, 1); // 13: r = inc(n) + pw.visit(STORER, 1, 1); // 13: r = inc(n) pw.visit(POP); // 14: eemalda STORER duplikaat /* return r */ - pw.visit(LOADR, 1); // 15: push r - pw.visit(STORER, -3); // 16: kirjuta tulemus parameetri pessa + pw.visit(LOADR, 1, 1); // 15: push r + pw.visit(STORER, -3, 1); // 16: kirjuta tulemus parameetri pessa pw.visit(RETURN, 3); // 17 /* @@ -628,10 +665,10 @@ public void test_main_calls_non_recursive_function() { */ pw.visit(_inc); // label indeksil 18 pw.visit(ENTER, 0); // 18: lokaalseid muutujaid pole - pw.visit(LOADR, -3); // 19: push x + pw.visit(LOADR, -3, 1); // 19: push x pw.visit(LOADC, 1); // 20 pw.visit(ADD); // 21: x + 1 - pw.visit(STORER, -3); // 22: tulemus → parameetri pessa + pw.visit(STORER, -3, 1); // 22: tulemus → parameetri pessa pw.visit(RETURN, 3); // 23 /* Oodatav tulemus: inc(41) = 42, main tagastab 42 */ @@ -691,18 +728,18 @@ private CMaStack runFac(int n) { pw.visit(ALLOC, 1); // 7: eralda koht r-ile /* kutsu fac(n): n on FP-3 */ - pw.visit(LOADR, -3); // 8: push n + pw.visit(LOADR, -3, 1); // 8: push n pw.visit(MARK); // 9: push EP, FP pw.visit(LOADC, 18); // 10: _fac aadress = 18 pw.visit(CALL); // 11 pw.visit(SLIDE, 0, 1); // 12: tõsta fac(n) tulemus - pw.visit(STORER, 1); // 13: r = fac(n) + pw.visit(STORER, 1, 1); // 13: r = fac(n) pw.visit(POP); // 14: eemalda STORER duplikaat /* return r: kopeeri r parameetri pessa */ - pw.visit(LOADR, 1); // 15: push r - pw.visit(STORER, -3); // 16: kirjuta tulemus parameetri pessa + pw.visit(LOADR, 1, 1); // 15: push r + pw.visit(STORER, -3, 1); // 16: kirjuta tulemus parameetri pessa pw.visit(RETURN, 3); // 17 /* === fac(n) funktsioon (indeksid 18-...) === */ @@ -710,18 +747,18 @@ private CMaStack runFac(int n) { pw.visit(ENTER, 0); // 18: lokaalseid muutujaid pole /* if (n <= 0) return 1 */ - pw.visit(LOADR, -3); // 19: push n + pw.visit(LOADR, -3, 1); // 19: push n pw.visit(LOADC, 0); // 20 pw.visit(LEQ); // 21: n <= 0? pw.visit(JUMPZ, _recurse); // 22: kui n > 0, hüppa rekursiivsesse harusse pw.visit(LOADC, 1); // 23: baassjuht: tulemus = 1 - pw.visit(STORER, -3); // 24: tulemus → parameetri pessa + pw.visit(STORER, -3, 1); // 24: tulemus → parameetri pessa pw.visit(RETURN, 3); // 25 /* rekursiivne juht: return n * fac(n-1) */ pw.visit(_recurse); // label indeksil 26 - pw.visit(LOADR, -3); // 26: push n (korrutamise jaoks) - pw.visit(LOADR, -3); // 27: push n (fac argumendi jaoks) + pw.visit(LOADR, -3, 1); // 26: push n (korrutamise jaoks) + pw.visit(LOADR, -3, 1); // 27: push n (fac argumendi jaoks) pw.visit(LOADC, 1); // 28 pw.visit(SUB); // 29: n-1 pw.visit(MARK); // 30: push EP, FP @@ -729,7 +766,7 @@ private CMaStack runFac(int n) { pw.visit(CALL); // 32 pw.visit(SLIDE, 0, 1); // 33: tõsta fac(n-1) tulemus pw.visit(MUL); // 34: n * fac(n-1) - pw.visit(STORER, -3); // 35: tulemus → parameetri pessa + pw.visit(STORER, -3, 1); // 35: tulemus → parameetri pessa pw.visit(RETURN, 3); // 36 return CMaInterpreter.run(pw.toProgram()); @@ -833,10 +870,10 @@ private CMaStack runDispatch(int op) { */ pw.visit(_inc); pw.visit(ENTER, 0); // 6: lokaalseid muutujaid pole; EP = SP+0 - pw.visit(LOADR, -4); // 7: push x (FP-4, esimene arg) - pw.visit(LOADR, -3); // 8: push step (FP-3, teine arg) + pw.visit(LOADR, -4, 1); // 7: push x (FP-4, esimene arg) + pw.visit(LOADR, -3, 1); // 8: push step (FP-3, teine arg) pw.visit(ADD); // 9: x + step - pw.visit(STORER, -3); // 10: tulemus → step-pessa (FP-3) + pw.visit(STORER, -3, 1); // 10: tulemus → step-pessa (FP-3) pw.visit(RETURN, 3); // 11: q=3; x-pesa (FP-4) jääb kutsujale /* @@ -847,9 +884,9 @@ private CMaStack runDispatch(int op) { pw.visit(ENTER, 2); // 12: EP = SP+2 (2 lokaalset: n, r) pw.visit(ALLOC, 2); // 13: eralda FP+1 (n) ja FP+2 (r) pw.visit(LOADC, 5); // 14: push 5 - pw.visit(STORER, 1); // 15: n = 5 (FP+1) + pw.visit(STORER, 1, 1); // 15: n = 5 (FP+1) pw.visit(POP); // 16: eemalda STORER duplikaat - pw.visit(LOADR, -3); // 17: push op (FP-3) — JUMPI indeks + pw.visit(LOADR, -3, 1); // 17: push op (FP-3) — JUMPI indeks pw.visit(JUMPI, _table); // 18: PC = target(_table) + op /* @@ -874,7 +911,7 @@ private CMaStack runDispatch(int op) { pw.visit(LOADC, 6); // 25: _inc aadress = 6 pw.visit(CALL); // 26: FP=10, PC=6, S[10]=27 pw.visit(SLIDE, 1, 1); // 27: nihuta tulemus x-pesa kohale, kustuta x - pw.visit(STORER, 2); // 28: r = tulemus (FP+2) + pw.visit(STORER, 2, 1); // 28: r = tulemus (FP+2) pw.visit(POP); // 29: eemalda STORER duplikaat pw.visit(JUMP, _end); // 30: hüppa tagastusele @@ -883,10 +920,10 @@ private CMaStack runDispatch(int op) { * Käsud: LOADR, LOADC, MUL, STORER. */ pw.visit(_case1); - pw.visit(LOADR, 1); // 31: push n (FP+1) + pw.visit(LOADR, 1, 1); // 31: push n (FP+1) pw.visit(LOADC, 2); // 32: push 2 pw.visit(MUL); // 33: n * 2 = 10 - pw.visit(STORER, 2); // 34: r = n*2 (FP+2) + pw.visit(STORER, 2, 1); // 34: r = n*2 (FP+2) pw.visit(POP); // 35: eemalda STORER duplikaat /* @@ -894,8 +931,8 @@ private CMaStack runDispatch(int op) { * Käsud: LOADR, STORER, RETURN. */ pw.visit(_end); - pw.visit(LOADR, 2); // 36: push r (FP+2) - pw.visit(STORER, -3); // 37: tulemus → parameetri pessa (FP-3) + pw.visit(LOADR, 2, 1); // 36: push r (FP+2) + pw.visit(STORER, -3, 1); // 37: tulemus → parameetri pessa (FP-3) pw.visit(RETURN, 3); // 38: tagasta, q=3 return CMaInterpreter.run(pw.toProgram()); From 341625f93178e7105d4b1b999fe4e79e668f331a Mon Sep 17 00:00:00 2001 From: Vesal Vojdani Date: Tue, 12 May 2026 17:15:30 +0300 Subject: [PATCH 18/24] Update build --- build.gradle | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 58c7532..816510f 100644 --- a/build.gradle +++ b/build.gradle @@ -1,9 +1,10 @@ plugins { - id 'java' + id 'java-library' + id 'maven-publish' } -group = 'ee.ut.cs.sws' -version = '1.0-SNAPSHOT' +group = 'com.github.sandersirge' +version = 'v0.0.1-pre_release' repositories { mavenCentral() @@ -17,6 +18,30 @@ dependencies { // testRuntimeOnly 'org.junit.platform:junit-platform-launcher' } +java { + sourceCompatibility = JavaVersion.toVersion(25) + targetCompatibility = JavaVersion.toVersion(25) + + withSourcesJar() +} + +tasks.withType(JavaCompile).configureEach { + options.encoding = 'UTF-8' + options.release = 25 +} + //test { // useJUnitPlatform() //} + +publishing { + publications { + mavenJava(MavenPublication) { + from components.java + + groupId = project.group + artifactId = 'java-cma-bachelor-thesis' + version = project.version + } + } +} From d88b0e591cd214e31c18fbf042aea953a9bb5b5d Mon Sep 17 00:00:00 2001 From: Vesal Vojdani Date: Tue, 12 May 2026 17:23:28 +0300 Subject: [PATCH 19/24] Configure JitPack Java 25 build --- build.gradle | 2 +- jitpack.yml | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 jitpack.yml diff --git a/build.gradle b/build.gradle index 816510f..85114e6 100644 --- a/build.gradle +++ b/build.gradle @@ -4,7 +4,7 @@ plugins { } group = 'com.github.sandersirge' -version = 'v0.0.1-pre_release' +version = 'v0.0.2-pre_release' repositories { mavenCentral() diff --git a/jitpack.yml b/jitpack.yml new file mode 100644 index 0000000..6cb9b16 --- /dev/null +++ b/jitpack.yml @@ -0,0 +1,3 @@ +before_install: + - sdk install java 25-tem + - sdk use java 25-tem From 2f851378e1404bcc577a3f283fd1905286e51af8 Mon Sep 17 00:00:00 2001 From: sandersirge Date: Wed, 13 May 2026 15:52:40 +0300 Subject: [PATCH 20/24] Funktsioonikutsed: Koodi- ja dokumentatsiooni parandused --- .../java/ee/ut/cs/sws/cma/CMaInterpreter.java | 8 +- .../cma/instruction/CMaIntIntInstruction.java | 1 - .../ee/ut/cs/sws/cma/CMaInterpreterTest.java | 198 +++++++++--------- 3 files changed, 104 insertions(+), 103 deletions(-) diff --git a/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java b/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java index 925d9b4..9941faa 100644 --- a/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java +++ b/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java @@ -12,11 +12,11 @@ public class CMaInterpreter { private final CMaProgram program; - private int pc = 0; private final CMaStack stack; - private int fp = 0; // Frame Pointer (raamiviit) - private int ep = 0; // Extreme Pointer (piiriviit) - private int hp = Integer.MAX_VALUE; // Heap Pointer (kuhjaviit) + private int pc = 0; + private int fp = 0; // Frame Pointer + private int ep = 0; // Extreme Pointer + private int hp = Integer.MAX_VALUE; // Heap Pointer private CMaInterpreter(CMaProgram program, CMaStack initialStack) { this.program = program; diff --git a/src/main/java/ee/ut/cs/sws/cma/instruction/CMaIntIntInstruction.java b/src/main/java/ee/ut/cs/sws/cma/instruction/CMaIntIntInstruction.java index 760fbb3..69dca5d 100644 --- a/src/main/java/ee/ut/cs/sws/cma/instruction/CMaIntIntInstruction.java +++ b/src/main/java/ee/ut/cs/sws/cma/instruction/CMaIntIntInstruction.java @@ -20,4 +20,3 @@ public String toString() { return code.name() + " " + arg1 + " " + arg2; } } - diff --git a/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java b/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java index 3cf8309..7b41cc8 100644 --- a/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java +++ b/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java @@ -602,12 +602,12 @@ public void test_jumpi_index2() { // Funktsioonikutsed: Samm 9 — Integratsioonitestid kõikide käskude testimiseks erinevates töövoogudes /** - * Mitterekursiivne {@code inc(x)} funktsioon, mida kutsub {@code main(n)}. + * Mitterekursiivne {@code inc(x)} funktsioon, mida kutsub {@code run(n)}. * *

C-kood:

*
{@code
      * int inc(int x) { return x + 1; }
-     * int main(int n) {
+     * int run(int n) {
      *     int r = inc(n);
      *     return r;
      * }
@@ -619,43 +619,43 @@ public void test_jumpi_index2() {
      *   {@code FP-2}salvestatud EP
      *   {@code FP-1}salvestatud FP
      *   {@code FP}salvestatud PC (tagastusaadress)
-     *   {@code FP+1} ja edasilokaalsed muutujad
+     *   {@code FP+1}lokaalne muutuja 'r' (ainult run-is)
      * 
      */
     @Test
     public void test_main_calls_non_recursive_function() {
-        CMaLabel _main = new CMaLabel();
+        CMaLabel _run = new CMaLabel();
         CMaLabel _inc = new CMaLabel();
 
-        /* === Peaprogramm (indeksid 0-5): kutsub main(41) === */
-        pw.visit(LOADC, 41);             // 0: main parameetriks antav väärtus
+        /* === Peaprogramm (indeksid 0-5): kutsub run(41) === */
+        pw.visit(LOADC, 41);             // 0: muutuja 'n' väärtus, run parameeter
         pw.visit(MARK);                       // 1: push EP, FP
-        pw.visit(LOADC, 6);              // 2: _main aadress = 6
+        pw.visit(LOADC, 6);              // 2: _run aadress = 6
         pw.visit(CALL);                       // 3
         pw.visit(SLIDE, 0, 1);    // 4: tõsta tulemus
         pw.visit(HALT);                       // 5
 
         /*
-         * === main(n) funktsioon (indeksid 6-17) ===
-         * int main(int n) { int r = inc(n); return r; }
-         * Lokaalsed: r on FP+1
+         * === run(n) funktsioon (indeksid 6-17) ===
+         * int run(int n) { int r = inc(n); return r; }
+         * Lokaalsed: muutuja 'r' on FP+1
          */
-        pw.visit(_main);                      // label indeksil 6
-        pw.visit(ENTER, 1);              // 6: EP = SP + 1 (1 lokaalne muutuja: r)
-        pw.visit(ALLOC, 1);              // 7: eralda koht r-ile
+        pw.visit(_run);                       // label indeksil 6
+        pw.visit(ENTER, 1);              // 6: EP = SP + 1 (lokaalne muutuja 'r')
+        pw.visit(ALLOC, 1);              // 7: eralda koht muutujale 'r'
 
-        /* kutsu inc(n) */
-        pw.visit(LOADR, -3, 1);   // 8: push n
+        /* kutsu inc(muutuja 'n') */
+        pw.visit(LOADR, -3, 1);   // 8: laadi muutuja 'n'
         pw.visit(MARK);                       // 9: push EP, FP
         pw.visit(LOADC, 18);             // 10: _inc aadress = 18
         pw.visit(CALL);                       // 11
-        pw.visit(SLIDE, 0, 1);    // 12: tõsta inc(n) tulemus
+        pw.visit(SLIDE, 0, 1);    // 12: tõsta inc tulemuse
 
-        pw.visit(STORER, 1, 1);   // 13: r = inc(n)
+        pw.visit(STORER, 1, 1);   // 13: muutuja 'r' = inc(muutuja 'n')
         pw.visit(POP);                        // 14: eemalda STORER duplikaat
 
-        /* return r */
-        pw.visit(LOADR, 1, 1);    // 15: push r
+        /* tagasta muutuja 'r' */
+        pw.visit(LOADR, 1, 1);    // 15: laadi muutuja 'r'
         pw.visit(STORER, -3, 1);  // 16: kirjuta tulemus parameetri pessa
         pw.visit(RETURN, 3);             // 17
 
@@ -665,18 +665,18 @@ public void test_main_calls_non_recursive_function() {
          */
         pw.visit(_inc);                       // label indeksil 18
         pw.visit(ENTER, 0);              // 18: lokaalseid muutujaid pole
-        pw.visit(LOADR, -3, 1);   // 19: push x
+        pw.visit(LOADR, -3, 1);   // 19: laadi muutuja 'x'
         pw.visit(LOADC, 1);              // 20
-        pw.visit(ADD);                        // 21: x + 1
+        pw.visit(ADD);                        // 21: muutuja 'x' + 1
         pw.visit(STORER, -3, 1);  // 22: tulemus → parameetri pessa
         pw.visit(RETURN, 3);             // 23
 
-        /* Oodatav tulemus: inc(41) = 42, main tagastab 42 */
+        /* Oodatav tulemus: inc(41) = 42, run tagastab 42 */
         assertInterpreted(new CMaStack(42));
     }
 
     /**
-     * Rekursiivne {@code fac(n)} funktsioon.
+     * Rekursiivne {@code fac(n)} funktsioon, mida kutsub {@code run(n)}.
      *
      * 

C-kood:

*
{@code
@@ -684,7 +684,7 @@ public void test_main_calls_non_recursive_function() {
      *     if (n <= 0) return 1;
      *     return n * fac(n - 1);
      * }
-     * int main(int n) {
+     * int run(int n) {
      *     int r = fac(n);
      *     return r;
      * }
@@ -696,49 +696,49 @@ public void test_main_calls_non_recursive_function() {
      *   {@code FP-2}salvestatud EP
      *   {@code FP-1}salvestatud FP
      *   {@code FP}salvestatud PC (tagastusaadress)
-     *   {@code FP+1} ja edasilokaalsed muutujad
+     *   {@code FP+1}lokaalne muutuja 'r' (ainult run-is)
      * 
      *
-     * 

Tagastus: tulemus kirjutatakse parameetri pessa ({@code STORER -3}), - * seejärel {@code RETURN 3} kärbib täitmisraami ja kutsuja kasutab - * {@code SLIDE 0 1} tulemuse kättesaamiseks.

+ *

Tulemus kirjutatakse parameetri pessa ({@code STORER -3}), + * seejärel {@code RETURN 3} kärbib täitmisraami. + * Kutsuja kasutab {@code SLIDE 0 1} (ei nihuta).

*/ private CMaStack runFac(int n) { pw = new CMaProgramWriter(); CMaLabel _fac = new CMaLabel(); CMaLabel _recurse = new CMaLabel(); - CMaLabel _main = new CMaLabel(); + CMaLabel _run = new CMaLabel(); - /* === Peaprogramm (indeksid 0-5): kutsub main() === */ - pw.visit(LOADC, n); // 0: main parameetriks antav n väärtus + /* === Peaprogramm (indeksid 0-5): kutsub run(n) === */ + pw.visit(LOADC, n); // 0: muutuja 'n' väärtus, run parameetriks pw.visit(MARK); // 1: push EP, FP - pw.visit(LOADC, 6); // 2: _main aadress = 6 + pw.visit(LOADC, 6); // 2: _run aadress = 6 pw.visit(CALL); // 3: FP=3, PC=6, S[3]=4 pw.visit(SLIDE, 0, 1); // 4: tõsta tulemus pw.visit(HALT); // 5 /* - * === main() funktsioon (indeksid 6-17) === - * int main(int n) { int r = fac(n); return r; } - * Lokaalsed: r on FP+1 (indeks 1 täitmisraamist) + * === run(n) funktsioon (indeksid 6-17) === + * int run(int n) { int r = fac(n); return r; } + * Lokaalsed: muutuja 'r' on FP+1 */ - pw.visit(_main); // label indeksil 6 - pw.visit(ENTER, 1); // 6: EP = SP + 1 (1 lokaalne muutuja: r) - pw.visit(ALLOC, 1); // 7: eralda koht r-ile + pw.visit(_run); // label indeksil 6 + pw.visit(ENTER, 1); // 6: EP = SP + 1 (lokaalne muutuja 'r') + pw.visit(ALLOC, 1); // 7: eralda koht muutujale 'r' - /* kutsu fac(n): n on FP-3 */ - pw.visit(LOADR, -3, 1); // 8: push n + /* kutsu fac(muutuja 'n'): muutuja 'n' asub FP-3 */ + pw.visit(LOADR, -3, 1); // 8: laadi muutuja 'n' pw.visit(MARK); // 9: push EP, FP pw.visit(LOADC, 18); // 10: _fac aadress = 18 pw.visit(CALL); // 11 - pw.visit(SLIDE, 0, 1); // 12: tõsta fac(n) tulemus + pw.visit(SLIDE, 0, 1); // 12: tõsta fac tulemuse - pw.visit(STORER, 1, 1); // 13: r = fac(n) + pw.visit(STORER, 1, 1); // 13: muutuja 'r' = fac(muutuja 'n') pw.visit(POP); // 14: eemalda STORER duplikaat - /* return r: kopeeri r parameetri pessa */ - pw.visit(LOADR, 1, 1); // 15: push r + /* tagasta muutuja 'r': kopeeri muutuja 'r' parameetri pessa */ + pw.visit(LOADR, 1, 1); // 15: laadi muutuja 'r' pw.visit(STORER, -3, 1); // 16: kirjuta tulemus parameetri pessa pw.visit(RETURN, 3); // 17 @@ -746,26 +746,26 @@ private CMaStack runFac(int n) { pw.visit(_fac); // label indeksil 18 pw.visit(ENTER, 0); // 18: lokaalseid muutujaid pole - /* if (n <= 0) return 1 */ - pw.visit(LOADR, -3, 1); // 19: push n + /* kui muutuja 'n' <= 0, tagasta 1 */ + pw.visit(LOADR, -3, 1); // 19: laadi muutuja 'n' pw.visit(LOADC, 0); // 20 - pw.visit(LEQ); // 21: n <= 0? + pw.visit(LEQ); // 21: muutuja 'n' <= 0? pw.visit(JUMPZ, _recurse); // 22: kui n > 0, hüppa rekursiivsesse harusse pw.visit(LOADC, 1); // 23: baassjuht: tulemus = 1 pw.visit(STORER, -3, 1); // 24: tulemus → parameetri pessa pw.visit(RETURN, 3); // 25 - /* rekursiivne juht: return n * fac(n-1) */ + /* rekursiivne juht: tagasta muutuja 'n' * fac(muutuja 'n' - 1) */ pw.visit(_recurse); // label indeksil 26 - pw.visit(LOADR, -3, 1); // 26: push n (korrutamise jaoks) - pw.visit(LOADR, -3, 1); // 27: push n (fac argumendi jaoks) + pw.visit(LOADR, -3, 1); // 26: laadi muutuja 'n' (korrutamiseks) + pw.visit(LOADR, -3, 1); // 27: laadi muutuja 'n' (fac argumendiks) pw.visit(LOADC, 1); // 28 - pw.visit(SUB); // 29: n-1 + pw.visit(SUB); // 29: muutuja 'n' - 1 pw.visit(MARK); // 30: push EP, FP pw.visit(LOADC, 18); // 31: _fac aadress = 18 pw.visit(CALL); // 32 - pw.visit(SLIDE, 0, 1); // 33: tõsta fac(n-1) tulemus - pw.visit(MUL); // 34: n * fac(n-1) + pw.visit(SLIDE, 0, 1); // 33: tõsta fac tulemuse + pw.visit(MUL); // 34: muutuja 'n' * fac(muutuja 'n' - 1) pw.visit(STORER, -3, 1); // 35: tulemus → parameetri pessa pw.visit(RETURN, 3); // 36 @@ -802,36 +802,38 @@ public void test_recursive_fac_10() { *

C-kood:

*
{@code
      * int inc(int x, int step) { return x + step; }
-     * int main(int op) {
+     * int run(int op) {
      *     int n = 5;
      *     int r;
      *     switch (op) {
-     *         case 0: r = inc(n, 1); break;  // LOADRC, MARK, CALL, SLIDE 1 1
+     *         case 0: r = inc(n, 1); break;  // LOADRC, MARK, CALL, SLIDE 0 1
      *         case 1: r = n * 2;     break;  // LOADR, MUL, STORER
      *     }
      *     return r;
      * }
      * }
* - *

Täitmisraami paigutus (FP viitab salvestatud PC-le):

+ *

Täitmisraami paigutus kahes funktsioonis (FP viitab salvestatud PC-le):

* - * + * + * * * * - * - * - * + * + * *
{@code FP-3}parameeter (op / step)
{@code FP-4}muutuja 'x' — esimene parameeter (ainult inc-is)
{@code FP-3}muutuja 'op' (run-is) / muutuja 'step' (inc-is)
{@code FP-2}salvestatud EP
{@code FP-1}salvestatud FP
{@code FP}salvestatud PC
{@code FP+1}lokaalne n (main)
{@code FP+2}lokaalne r (main)
{@code FP-4}esimene parameeter x (ainult inc-is)
{@code FP+1}lokaalne muutuja 'n' (ainult run-is)
{@code FP+2}lokaalne muutuja 'r' (ainult run-is)
* - *

{@code inc} kasutab {@code RETURN 3} (puhastab ainult org-pesad), jättes x-pesa alles. - * Kutsuja kasutab {@code SLIDE 1 1}, et x-pesa tulemusega üle kirjutada ja kärpida.

+ *

{@code inc} kasutab {@code RETURN 4}, mis puhastab muutuja 'step' pesa ja + * organisatsioonilised pesad (EP, FP, PC). Tulemus kirjutatakse muutuja 'x' pessa + * ({@code STORER -4}). Kutsuja kasutab {@code SLIDE 0 1} — tulemus on pärast + * tagastust juba pinul.

* *

Programmi aadressid:

*
    *
  • {@code 0–5}: peaprogramm
  • *
  • {@code 6–11}: {@code inc(x, step)}
  • - *
  • {@code 12–18}: {@code main(op)}
  • + *
  • {@code 12–18}: {@code run(op)}
  • *
  • {@code 19–20}: lülituslause harud
  • *
  • {@code 21–30}: case 0 (inc)
  • *
  • {@code 31–35}: case 1 (n*2)
  • @@ -848,82 +850,82 @@ private CMaStack runDispatch(int op) { pw = new CMaProgramWriter(); CMaLabel _inc = new CMaLabel(); - CMaLabel _main = new CMaLabel(); + CMaLabel _run = new CMaLabel(); CMaLabel _table = new CMaLabel(); CMaLabel _case0 = new CMaLabel(); CMaLabel _case1 = new CMaLabel(); CMaLabel _end = new CMaLabel(); - /* Peaprogramm (0–5): kutsub main(op). */ - pw.visit(LOADC, op); // 0: op → parameeter main-ile + /* Peaprogramm (0–5): kutsub run(op). */ + pw.visit(LOADC, op); // 0: muutuja 'op' → parameeter run-ile pw.visit(MARK); // 1: push EP(0), FP(0) - pw.visit(LOADC, 12); // 2: _main aadress = 12 + pw.visit(LOADC, 12); // 2: _run aadress = 12 pw.visit(CALL); // 3: FP=3, PC=12, S[3]=4 pw.visit(SLIDE, 0, 1); // 4: tõsta tulemus parameetri kohalt pw.visit(HALT); // 5: peaprogramm lõpeb /* - * inc(x, step) (6–11): tagastab x + step. - * FP-4=x (esimene arg), FP-3=step (teine arg). - * RETURN 3 puhastab ainult org-pesad — x-pesa jääb kutsujale. + * inc(muutuja 'x', muutuja 'step') (6–11): tagastab muutuja 'x' + muutuja 'step'. + * FP-4: muutuja 'x' (esimene arg), FP-3: muutuja 'step' (teine arg). + * RETURN 4 eemaldab muutuja 'step' pesa ja org-pesad (EP, FP, PC). * Käsud: ENTER, LOADR, ADD, STORER, RETURN. */ pw.visit(_inc); pw.visit(ENTER, 0); // 6: lokaalseid muutujaid pole; EP = SP+0 - pw.visit(LOADR, -4, 1); // 7: push x (FP-4, esimene arg) - pw.visit(LOADR, -3, 1); // 8: push step (FP-3, teine arg) - pw.visit(ADD); // 9: x + step - pw.visit(STORER, -3, 1); // 10: tulemus → step-pessa (FP-3) - pw.visit(RETURN, 3); // 11: q=3; x-pesa (FP-4) jääb kutsujale + pw.visit(LOADR, -4, 1); // 7: laadi muutuja 'x' (FP-4, esimene arg) + pw.visit(LOADR, -3, 1); // 8: laadi muutuja 'step' (FP-3, teine arg) + pw.visit(ADD); // 9: muutuja 'x' + muutuja 'step' + pw.visit(STORER, -4, 1); // 10: tulemus → muutuja 'x' pessa (FP-4) + pw.visit(RETURN, 4); // 11: eemaldab muutuja 'step' ja org-pesad /* - * main(op) (12–18): eraldab n=5 ja r, valib haru JUMPI abil. + * run(muutuja 'op') (12–18): eraldab muutuja 'n'=5 ja muutuja 'r', valib haru JUMPI abil. * Käsud: ENTER, ALLOC, STORER, LOADR, JUMPI. */ - pw.visit(_main); + pw.visit(_run); pw.visit(ENTER, 2); // 12: EP = SP+2 (2 lokaalset: n, r) - pw.visit(ALLOC, 2); // 13: eralda FP+1 (n) ja FP+2 (r) + pw.visit(ALLOC, 2); // 13: eralda koht muutujatele 'n' ja 'r' pw.visit(LOADC, 5); // 14: push 5 - pw.visit(STORER, 1, 1); // 15: n = 5 (FP+1) + pw.visit(STORER, 1, 1); // 15: muutuja 'n' = 5 (FP+1) pw.visit(POP); // 16: eemalda STORER duplikaat - pw.visit(LOADR, -3, 1); // 17: push op (FP-3) — JUMPI indeks + pw.visit(LOADR, -3, 1); // 17: laadi muutuja 'op' (FP-3) — JUMPI indeks pw.visit(JUMPI, _table); // 18: PC = target(_table) + op /* * Lülituslause harud (19–20): JUMPI sihtmärgid. - * op=0 → _case0 (21), op=1 → _case1 (31). + * muutuja 'op'=0 → _case0 (21), muutuja 'op'=1 → _case1 (31). */ pw.visit(_table); pw.visit(JUMP, _case0); // 19: op=0 → kutsu inc(n, 1) pw.visit(JUMP, _case1); // 20: op=1 → arvuta n*2 /* - * case 0 (21–30): r = inc(n, 1). - * Push n (LOADRC+LOAD) ja step=1, kutsu inc. - * SLIDE 1 1 nihutab tulemuse x-pesa kohale ja kustutab x-pesa. - * Käsud: LOADRC, LOAD, LOADC, MARK, CALL, SLIDE 1 1, STORER. + * case 0 (21–30): muutuja 'r' = inc(muutuja 'n', 1). + * Laadi muutuja 'n' (LOADRC+LOAD) ja muutuja 'step'=1, kutsu inc. + * SLIDE 0 1 on no-op — tulemus on pärast RETURN 4 juba pinul. + * Käsud: LOADRC, LOAD, LOADC, MARK, CALL, SLIDE 0 1, STORER. */ pw.visit(_case0); - pw.visit(LOADRC, 1); // 21: push FP+1 (n aadress) — LOADRC otse - pw.visit(LOAD); // 22: loe n väärtus aadressilt - pw.visit(LOADC, 1); // 23: push step=1 (teine argument inc-ile) + pw.visit(LOADRC, 1); // 21: laadi muutuja 'n' aadress (FP+1) — LOADRC otse + pw.visit(LOAD); // 22: loe muutuja 'n' väärtus + pw.visit(LOADC, 1); // 23: muutuja 'step'=1 (teine arg inc-ile) pw.visit(MARK); // 24: push EP, FP pw.visit(LOADC, 6); // 25: _inc aadress = 6 pw.visit(CALL); // 26: FP=10, PC=6, S[10]=27 - pw.visit(SLIDE, 1, 1); // 27: nihuta tulemus x-pesa kohale, kustuta x - pw.visit(STORER, 2, 1); // 28: r = tulemus (FP+2) + pw.visit(SLIDE, 0, 1); // 27: tulemus juba pinul (no-op) + pw.visit(STORER, 2, 1); // 28: muutuja 'r' = tulemus (FP+2) pw.visit(POP); // 29: eemalda STORER duplikaat pw.visit(JUMP, _end); // 30: hüppa tagastusele /* - * case 1 (31–35): r = n * 2. + * case 1 (31–35): muutuja 'r' = muutuja 'n' * 2. * Käsud: LOADR, LOADC, MUL, STORER. */ pw.visit(_case1); - pw.visit(LOADR, 1, 1); // 31: push n (FP+1) + pw.visit(LOADR, 1, 1); // 31: laadi muutuja 'n' (FP+1) pw.visit(LOADC, 2); // 32: push 2 - pw.visit(MUL); // 33: n * 2 = 10 - pw.visit(STORER, 2, 1); // 34: r = n*2 (FP+2) + pw.visit(MUL); // 33: muutuja 'n' * 2 = 10 + pw.visit(STORER, 2, 1); // 34: muutuja 'r' = muutuja 'n'*2 (FP+2) pw.visit(POP); // 35: eemalda STORER duplikaat /* @@ -931,22 +933,22 @@ private CMaStack runDispatch(int op) { * Käsud: LOADR, STORER, RETURN. */ pw.visit(_end); - pw.visit(LOADR, 2, 1); // 36: push r (FP+2) + pw.visit(LOADR, 2, 1); // 36: laadi muutuja 'r' (FP+2) pw.visit(STORER, -3, 1); // 37: tulemus → parameetri pessa (FP-3) - pw.visit(RETURN, 3); // 38: tagasta, q=3 + pw.visit(RETURN, 3); // 38: tagasta return CMaInterpreter.run(pw.toProgram()); } @Test public void test_dispatch_inc() { - /* op=0 → inc(5, 1) = 6: kasutab LOADRC, MARK, CALL, SLIDE 1 1 */ + /* muutuja 'op'=0 → inc(5, 1) = 6: kasutab LOADRC, MARK, CALL, SLIDE 0 1 */ assertEquals(new CMaStack(6), runDispatch(0)); } @Test public void test_dispatch_double() { - /* op=1 → 5*2 = 10: kasutab LOADR, MUL, STORER */ + /* muutuja 'op'=1 → 5*2 = 10: kasutab LOADR, MUL, STORER */ assertEquals(new CMaStack(10), runDispatch(1)); } } From 01e0958331de8efb50c91641c3141290db2125ed Mon Sep 17 00:00:00 2001 From: sandersirge Date: Thu, 14 May 2026 00:17:33 +0300 Subject: [PATCH 21/24] =?UTF-8?q?Funktsioonikutsed:=20Lisatud=20viimased?= =?UTF-8?q?=20testid,=20t=C3=B6=C3=B6voogude=20testid=20eraldi=20failis,?= =?UTF-8?q?=20dokumentatsioon=20parandatud?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cma/CMaInterpreterIntegrationTest.java | 674 ++++++++++++++++++ .../ee/ut/cs/sws/cma/CMaInterpreterTest.java | 356 +-------- 2 files changed, 677 insertions(+), 353 deletions(-) create mode 100644 src/test/java/ee/ut/cs/sws/cma/CMaInterpreterIntegrationTest.java diff --git a/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterIntegrationTest.java b/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterIntegrationTest.java new file mode 100644 index 0000000..78dfa92 --- /dev/null +++ b/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterIntegrationTest.java @@ -0,0 +1,674 @@ +package ee.ut.cs.sws.cma; + +import org.junit.Before; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; + +import static ee.ut.cs.sws.cma.instruction.CMaBasicInstruction.Code.*; +import static ee.ut.cs.sws.cma.instruction.CMaIntInstruction.Code.*; +import static ee.ut.cs.sws.cma.instruction.CMaIntIntInstruction.Code.*; +import static ee.ut.cs.sws.cma.instruction.CMaLabelInstruction.Code.*; +import static org.junit.Assert.*; + +@FixMethodOrder(MethodSorters.JVM) +public class CMaInterpreterIntegrationTest { + + private CMaProgramWriter pw; + + @Before + public void setUp() { + pw = new CMaProgramWriter(); + } + + private void assertInterpreted(CMaStack expected) { + assertInterpreted(expected, new CMaStack()); + } + + private void assertInterpreted(CMaStack expected, CMaStack initial) { + CMaStack actual = CMaInterpreter.run(pw.toProgram(), initial); + assertEquals(expected, actual); + } + + // Funktsioonikutsed: Samm 9 — Integratsioonitestid kõikide käskude testimiseks erinevates töövoogudes + + /** + * Ehitab ja käivitab programmi, kus {@code run(n)} kutsub mitterekursiivset {@code inc(x)}. + * + *

    C-kood:

    + *
    {@code
    +     * int inc(int x) { return x + 1; }
    +     * int run(int n) {
    +     *     int r = inc(n);
    +     *     return r;
    +     * }
    +     * run() //  väärtustatakse igas testis erinevalt
    +     * }
    + * + *

    Oodatavad tulemused:

    + *
      + *
    • {@code n = 0} → {@code inc(0) = 1}
    • + *
    • {@code n = 9} → {@code inc(9) = 10}
    • + *
    • {@code n = 41} → {@code inc(41) = 42}
    • + *
    • {@code n = -1} → {@code inc(-1) = 0}
    • + *
    + */ + private void runNonRecursive(int n) { + pw = new CMaProgramWriter(); + + CMaLabel _run = new CMaLabel(); + CMaLabel _inc = new CMaLabel(); + + /* === Peaprogramm (indeksid 0-5): kutsub run(n) === */ + pw.visit(LOADC, n); // 0: muutuja 'n' väärtus, run parameeter + pw.visit(MARK); // 1: push EP, FP + pw.visit(LOADC, 6); // 2: _run aadress = 6 + pw.visit(CALL); // 3 + pw.visit(SLIDE, 0, 1); // 4: tõsta tulemus + pw.visit(HALT); // 5 + + /* + * === run(n) funktsioon (indeksid 6-17) === + * int run(int n) { int r = inc(n); return r; } + * Lokaalsed: muutuja 'r' on FP+1 + */ + pw.visit(_run); // label indeksil 6 + pw.visit(ENTER, 1); // 6: EP = SP + 1 (lokaalne muutuja 'r') + pw.visit(ALLOC, 1); // 7: eralda koht muutujale 'r' + + /* kutsu inc(muutuja 'n') */ + pw.visit(LOADR, -3, 1); // 8: laadi muutuja 'n' + pw.visit(MARK); // 9: push EP, FP + pw.visit(LOADC, 18); // 10: _inc aadress = 18 + pw.visit(CALL); // 11 + pw.visit(SLIDE, 0, 1); // 12: tõsta inc tulemus + + pw.visit(STORER, 1, 1); // 13: muutuja 'r' = inc(muutuja 'n') + pw.visit(POP); // 14: eemalda STORER duplikaat + + /* tagasta muutuja 'r' */ + pw.visit(LOADR, 1, 1); // 15: laadi muutuja 'r' + pw.visit(STORER, -3, 1); // 16: kirjuta tulemus parameetri pessa + pw.visit(RETURN, 3); // 17 + + /* + * === inc(x) funktsioon (indeksid 18-23) === + * int inc(int x) { return x + 1; } + */ + pw.visit(_inc); // label indeksil 18 + pw.visit(ENTER, 0); // 18: lokaalseid muutujaid pole + pw.visit(LOADR, -3, 1); // 19: laadi muutuja 'x' + pw.visit(LOADC, 1); // 20 + pw.visit(ADD); // 21: muutuja 'x' + 1 + pw.visit(STORER, -3, 1); // 22: tulemus → parameetri pessa + pw.visit(RETURN, 3); // 23 + + assertInterpreted(new CMaStack(n + 1)); + } + + @Test + public void test_non_recursive_inc_0() { + /* run(0): inc(0) = 1 */ + runNonRecursive(0); + } + + @Test + public void test_non_recursive_inc_9() { + /* run(9): inc(9) = 10 */ + runNonRecursive(9); + } + + @Test + public void test_non_recursive_inc_41() { + /* run(41): inc(41) = 42 */ + runNonRecursive(41); + } + + @Test + public void test_non_recursive_inc_neg() { + /* run(-1): inc(-1) = 0 */ + runNonRecursive(-1); + } + + /** + * Rekursiivne {@code fac(n)} funktsioon, mida kutsub {@code run(n)}. + * + *

    C-kood:

    + *
    {@code
    +     * int fac(int n) {
    +     *     if (n <= 0) return 1;
    +     *     return n * fac(n - 1);
    +     * }
    +     * int run(int n) {
    +     *     int r = fac(n);
    +     *     return r;
    +     * }
    +     * run() //  väärtustatakse igas testis erinevalt
    +     * }
    + * + *

    Oodatavad tulemused:

    + *
      + *
    • {@code n = 0} → {@code fac(0) = 1}
    • + *
    • {@code n = 1} → {@code fac(1) = 1}
    • + *
    • {@code n = 5} → {@code fac(5) = 120}
    • + *
    • {@code n = 10} → {@code fac(10) = 3628800}
    • + *
    + */ + private CMaStack runFac(int n) { + pw = new CMaProgramWriter(); + + CMaLabel _fac = new CMaLabel(); + CMaLabel _recurse = new CMaLabel(); + CMaLabel _run = new CMaLabel(); + + /* === Peaprogramm (indeksid 0-5): kutsub run(n) === */ + pw.visit(LOADC, n); // 0: muutuja 'n' väärtus, run parameetriks + pw.visit(MARK); // 1: push EP, FP + pw.visit(LOADC, 6); // 2: _run aadress = 6 + pw.visit(CALL); // 3: FP=3, PC=6, S[3]=4 + pw.visit(SLIDE, 0, 1); // 4: tõsta tulemus + pw.visit(HALT); // 5 + + /* + * === run(n) funktsioon (indeksid 6-17) === + * int run(int n) { int r = fac(n); return r; } + * Lokaalsed: muutuja 'r' on FP+1 + */ + pw.visit(_run); // label indeksil 6 + pw.visit(ENTER, 1); // 6: EP = SP + 1 (lokaalne muutuja 'r') + pw.visit(ALLOC, 1); // 7: eralda koht muutujale 'r' + + /* kutsu fac(muutuja 'n'): muutuja 'n' asub FP-3 */ + pw.visit(LOADR, -3, 1); // 8: laadi muutuja 'n' + pw.visit(MARK); // 9: push EP, FP + pw.visit(LOADC, 18); // 10: _fac aadress = 18 + pw.visit(CALL); // 11 + pw.visit(SLIDE, 0, 1); // 12: tõsta fac tulemus + + pw.visit(STORER, 1, 1); // 13: muutuja 'r' = fac(muutuja 'n') + pw.visit(POP); // 14: eemalda STORER duplikaat + + /* tagasta muutuja 'r': kopeeri muutuja 'r' parameetri pessa */ + pw.visit(LOADR, 1, 1); // 15: laadi muutuja 'r' + pw.visit(STORER, -3, 1); // 16: kirjuta tulemus parameetri pessa + pw.visit(RETURN, 3); // 17 + + /* === fac(n) funktsioon (indeksid 18-...) === */ + pw.visit(_fac); // label indeksil 18 + pw.visit(ENTER, 0); // 18: lokaalseid muutujaid pole + + /* kui muutuja 'n' <= 0, tagasta 1 */ + pw.visit(LOADR, -3, 1); // 19: laadi muutuja 'n' + pw.visit(LOADC, 0); // 20 + pw.visit(LEQ); // 21: muutuja 'n' <= 0? + pw.visit(JUMPZ, _recurse); // 22: kui n > 0, hüppa rekursiivsesse harusse + pw.visit(LOADC, 1); // 23: baassjuht: tulemus = 1 + pw.visit(STORER, -3, 1); // 24: tulemus → parameetri pessa + pw.visit(RETURN, 3); // 25 + + /* rekursiivne juht: tagasta muutuja 'n' * fac(muutuja 'n' - 1) */ + pw.visit(_recurse); // label indeksil 26 + pw.visit(LOADR, -3, 1); // 26: laadi muutuja 'n' (korrutamiseks) + pw.visit(LOADR, -3, 1); // 27: laadi muutuja 'n' (fac argumendiks) + pw.visit(LOADC, 1); // 28 + pw.visit(SUB); // 29: muutuja 'n' - 1 + pw.visit(MARK); // 30: push EP, FP + pw.visit(LOADC, 18); // 31: _fac aadress = 18 + pw.visit(CALL); // 32 + pw.visit(SLIDE, 0, 1); // 33: tõsta fac tulemus + pw.visit(MUL); // 34: muutuja 'n' * fac(muutuja 'n' - 1) + pw.visit(STORER, -3, 1); // 35: tulemus → parameetri pessa + pw.visit(RETURN, 3); // 36 + + return CMaInterpreter.run(pw.toProgram()); + } + + @Test + public void test_recursive_fac_0() { + /* run(0): fac(0) = 1 */ + assertEquals(new CMaStack(1), runFac(0)); + } + + @Test + public void test_recursive_fac_1() { + /* run(1): fac(1) = 1 */ + assertEquals(new CMaStack(1), runFac(1)); + } + + @Test + public void test_recursive_fac_5() { + /* run(5): fac(5) = 120 */ + assertEquals(new CMaStack(120), runFac(5)); + } + + @Test + public void test_recursive_fac_10() { + /* run(10): fac(10) = 3628800 */ + assertEquals(new CMaStack(3628800), runFac(10)); + } + + /** + * {@code inc(x, step)} funktsioon, mida kutsub lülituslausega {@code run(op)}. + * + *

    C-kood:

    + *
    {@code
    +     * int inc(int x, int step) { return x + step; }
    +     * int run(int op) {
    +     *     int n = 5;
    +     *     int r;
    +     *     switch (op) {
    +     *         case 0: r = inc(n, 1); break;  // LOADRC, MARK, CALL, SLIDE 0 1
    +     *         case 1: r = n * 2;     break;  // LOADR, MUL, STORER
    +     *     }
    +     *     return r;
    +     * }
    +     * run() //  väärtustatakse igas testis erinevalt
    +     * }
    + * + *

    Oodatavad tulemused:

    + *
      + *
    • {@code op=0} → {@code inc(5, 1) = 6}
    • + *
    • {@code op=1} → {@code 5 * 2 = 10}
    • + *
    + */ + private CMaStack runDispatch(int op) { + pw = new CMaProgramWriter(); + + CMaLabel _inc = new CMaLabel(); + CMaLabel _run = new CMaLabel(); + CMaLabel _table = new CMaLabel(); + CMaLabel _case0 = new CMaLabel(); + CMaLabel _case1 = new CMaLabel(); + CMaLabel _end = new CMaLabel(); + + /* Peaprogramm (0–5): kutsub run(op). */ + pw.visit(LOADC, op); // 0: muutuja 'op' → parameeter run-ile + pw.visit(MARK); // 1: push EP(0), FP(0) + pw.visit(LOADC, 12); // 2: _run aadress = 12 + pw.visit(CALL); // 3: FP=3, PC=12, S[3]=4 + pw.visit(SLIDE, 0, 1); // 4: tõsta tulemus parameetri kohalt + pw.visit(HALT); // 5: peaprogramm lõpeb + + /* + * inc(muutuja 'x', muutuja 'step') (6–11): tagastab muutuja 'x' + muutuja 'step'. + * FP-4: muutuja 'x' (esimene arg), FP-3: muutuja 'step' (teine arg). + * RETURN 4 eemaldab muutuja 'step' pesa ja org-pesad (EP, FP, PC). + * Käsud: ENTER, LOADR, ADD, STORER, RETURN. + */ + pw.visit(_inc); + pw.visit(ENTER, 0); // 6: lokaalseid muutujaid pole; EP = SP+0 + pw.visit(LOADR, -4, 1); // 7: laadi muutuja 'x' (FP-4, esimene arg) + pw.visit(LOADR, -3, 1); // 8: laadi muutuja 'step' (FP-3, teine arg) + pw.visit(ADD); // 9: muutuja 'x' + muutuja 'step' + pw.visit(STORER, -4, 1); // 10: tulemus → muutuja 'x' pessa (FP-4) + pw.visit(RETURN, 4); // 11: eemaldab muutuja 'step' ja org-pesad + + /* + * run(muutuja 'op') (12–18): eraldab muutuja 'n'=5 ja muutuja 'r', valib haru JUMPI abil. + * Käsud: ENTER, ALLOC, STORER, LOADR, JUMPI. + */ + pw.visit(_run); + pw.visit(ENTER, 2); // 12: EP = SP+2 (2 lokaalset: n, r) + pw.visit(ALLOC, 2); // 13: eralda koht muutujatele 'n' ja 'r' + pw.visit(LOADC, 5); // 14: push 5 + pw.visit(STORER, 1, 1); // 15: muutuja 'n' = 5 (FP+1) + pw.visit(POP); // 16: eemalda STORER duplikaat + pw.visit(LOADR, -3, 1); // 17: laadi muutuja 'op' (FP-3) — JUMPI indeks + pw.visit(JUMPI, _table); // 18: PC = target(_table) + op + + /* + * Lülituslause harud (19–20): JUMPI sihtmärgid. + * muutuja 'op'=0 → _case0 (21), muutuja 'op'=1 → _case1 (31). + */ + pw.visit(_table); + pw.visit(JUMP, _case0); // 19: op=0 → kutsu inc(n, 1) + pw.visit(JUMP, _case1); // 20: op=1 → arvuta n*2 + + /* + * case 0 (21–30): muutuja 'r' = inc(muutuja 'n', 1). + * Laadi muutuja 'n' (LOADRC+LOAD) ja muutuja 'step'=1, kutsu inc. + * SLIDE 0 1 on no-op — tulemus on pärast RETURN 4 juba pinul. + * Käsud: LOADRC, LOAD, LOADC, MARK, CALL, SLIDE 0 1, STORER. + */ + pw.visit(_case0); + pw.visit(LOADRC, 1); // 21: laadi muutuja 'n' aadress (FP+1) — LOADRC otse + pw.visit(LOAD); // 22: loe muutuja 'n' väärtus + pw.visit(LOADC, 1); // 23: muutuja 'step'=1 (teine arg inc-ile) + pw.visit(MARK); // 24: push EP, FP + pw.visit(LOADC, 6); // 25: _inc aadress = 6 + pw.visit(CALL); // 26: FP=10, PC=6, S[10]=27 + pw.visit(SLIDE, 0, 1); // 27: tulemus juba pinul (no-op) + pw.visit(STORER, 2, 1); // 28: muutuja 'r' = tulemus (FP+2) + pw.visit(POP); // 29: eemalda STORER duplikaat + pw.visit(JUMP, _end); // 30: hüppa tagastusele + + /* + * case 1 (31–35): muutuja 'r' = muutuja 'n' * 2. + * Käsud: LOADR, LOADC, MUL, STORER. + */ + pw.visit(_case1); + pw.visit(LOADR, 1, 1); // 31: laadi muutuja 'n' (FP+1) + pw.visit(LOADC, 2); // 32: push 2 + pw.visit(MUL); // 33: muutuja 'n' * 2 = 10 + pw.visit(STORER, 2, 1); // 34: muutuja 'r' = muutuja 'n'*2 (FP+2) + pw.visit(POP); // 35: eemalda STORER duplikaat + + /* + * Tagastus (36–38): return r. + * Käsud: LOADR, STORER, RETURN. + */ + pw.visit(_end); + pw.visit(LOADR, 2, 1); // 36: laadi muutuja 'r' (FP+2) + pw.visit(STORER, -3, 1); // 37: tulemus → parameetri pessa (FP-3) + pw.visit(RETURN, 3); // 38: tagasta + + return CMaInterpreter.run(pw.toProgram()); + } + + @Test + public void test_dispatch_inc() { + /* run(0): inc(5, 1) = 6 — kasutab LOADRC, MARK, CALL, SLIDE 0 1 */ + assertEquals(new CMaStack(6), runDispatch(0)); + } + + @Test + public void test_dispatch_double() { + /* run(1): 5 * 2 = 10 — kasutab LOADR, MUL, STORER */ + assertEquals(new CMaStack(10), runDispatch(1)); + } + + /** + * {@code void compute(x)} funktsioon lokaalsete muutujatega, mida kutsub {@code run(n)}. + * + *

    C-kood:

    + *
    {@code
    +     * void compute(int x) {
    +     *     int a = x * 2;
    +     *     int b = a + 1;
    +     *     return;
    +     * }
    +     * int run(int n) {
    +     *     compute(n);
    +     *     return n * 2;
    +     * }
    +     * run() //  väärtustatakse igas testis erinevalt
    +     * }
    + * + *

    Oodatavad tulemused:

    + *
      + *
    • {@code n = 0} → {@code 0 * 2 = 0}
    • + *
    • {@code n = 3} → {@code 3 * 2 = 6}
    • + *
    • {@code n = -4} → {@code -4 * 2 = -8}
    • + *
    + * + *

    Programmi aadressid:

    + *
      + *
    • {@code 0–5}: peaprogramm
    • + *
    • {@code 6–18}: {@code compute(x)}
    • + *
    • {@code 19–28}: {@code run(n)}
    • + *
    + */ + private void runVoidReturn(int n) { + pw = new CMaProgramWriter(); + + CMaLabel _compute = new CMaLabel(); + CMaLabel _run = new CMaLabel(); + + /* === Peaprogramm (indeksid 0-5): kutsub run(n) === */ + pw.visit(LOADC, n); // 0: muutuja 'n' väärtus, run parameeter + pw.visit(MARK); // 1: push EP, FP + pw.visit(LOADC, 19); // 2: _run aadress = 19 + pw.visit(CALL); // 3 + pw.visit(SLIDE, 0, 1); // 4: tõsta tulemus + pw.visit(HALT); // 5 + + /* + * === compute(x) funktsioon (indeksid 6-18) === + * void compute(int x) { + * int a = x * 2; + * int b = a + 1; + * return; + * } + * Lokaalsed: muutuja 'a' on FP+1, muutuja 'b' on FP+2. + * Tagastustüüp void: RETURN 4 (q = 1 + 3 - 0 = 4). + */ + pw.visit(_compute); // label indeksil 6 + pw.visit(ENTER, 2); // 6: EP = SP + 2 (2 lokaalset: a, b) + pw.visit(ALLOC, 2); // 7: eralda koht muutujatele 'a' ja 'b' + + /* muutuja 'a' = muutuja 'x' * 2 */ + pw.visit(LOADR, -3, 1); // 8: laadi muutuja 'x' (FP-3) + pw.visit(LOADC, 2); // 9 + pw.visit(MUL); // 10: muutuja 'x' * 2 + pw.visit(STORER, 1, 1); // 11: muutuja 'a' = muutuja 'x' * 2 (FP+1) + pw.visit(POP); // 12: eemalda STORER duplikaat + + /* muutuja 'b' = muutuja 'a' + 1 */ + pw.visit(LOADR, 1, 1); // 13: laadi muutuja 'a' (FP+1) + pw.visit(LOADC, 1); // 14 + pw.visit(ADD); // 15: muutuja 'a' + 1 + pw.visit(STORER, 2, 1); // 16: muutuja 'b' = muutuja 'a' + 1 (FP+2) + pw.visit(POP); // 17: eemalda STORER duplikaat + + pw.visit(RETURN, 4); // 18: void tagastus, eemaldab param + lokaalsed + org-pesad + + /* + * === run(n) funktsioon (indeksid 19-28) === + * int run(int n) { compute(n); return n * 2; } + * Lokaalseid muutujaid pole. + */ + pw.visit(_run); // label indeksil 19 + pw.visit(ENTER, 0); // 19: lokaalseid muutujaid pole + + /* kutsu compute(muutuja 'n') */ + pw.visit(LOADR, -3, 1); // 20: laadi muutuja 'n' + pw.visit(MARK); // 21: push EP, FP + pw.visit(LOADC, 6); // 22: _compute aadress = 6 + pw.visit(CALL); // 23 + /* void tagastus: pinu on taastatud, SLIDE pole vaja */ + + /* tagasta muutuja 'n' * 2 */ + pw.visit(LOADR, -3, 1); // 24: laadi muutuja 'n' + pw.visit(LOADC, 2); // 25 + pw.visit(MUL); // 26: muutuja 'n' * 2 + pw.visit(STORER, -3, 1); // 27: tulemus → parameetri pessa + pw.visit(RETURN, 3); // 28 + + assertInterpreted(new CMaStack(n * 2)); + } + + @Test + public void test_void_return_0() { + /* run(0): compute(0); return 0*2 = 0 */ + runVoidReturn(0); + } + + @Test + public void test_void_return_3() { + /* run(3): compute(3); return 3*2 = 6 */ + runVoidReturn(3); + } + + @Test + public void test_void_return_neg() { + /* run(-4): compute(-4); return -4*2 = -8 */ + runVoidReturn(-4); + } + + private static int fibExpected(int n) { + if (n < 0) return -1; + if (n <= 1) return n; + int a = 0, b = 1; + for (int i = 2; i <= n; i++) { int c = a + b; a = b; b = c; } + return b; + } + + /** + * Rekursiivne {@code fibo(n)} funktsioon koos lülituslausega, mida kutsub {@code run(n)}. + * + *

    C-kood (vt joonis 2.x):

    + *
    {@code
    +     * int fibo(int n) {
    +     *     if (n < 0) return -1;
    +     *     switch (n) {
    +     *         case 0:  return 0; break;
    +     *         case 1:  return 1; break;
    +     *         default: return fibo(n - 1) + fibo(n - 2);
    +     *     }
    +     * }
    +     * int run(int n) {
    +     *     int r = fibo(n);
    +     *     return r;
    +     * }
    +     * run() //  väärtustatakse igas testis erinevalt
    +     * }
    + * + *

    Oodatavad tulemused:

    + *
      + *
    • {@code n < 0} → {@code -1}
    • + *
    • {@code n = 0} → {@code 0}
    • + *
    • {@code n = 1} → {@code 1}
    • + *
    • {@code n = 5} → {@code 5}
    • + *
    • {@code n = 7} → {@code 13}
    • + *
    + */ + private void runFibo(int n) { + pw = new CMaProgramWriter(); + + CMaLabel _fibo = new CMaLabel(); + CMaLabel _run = new CMaLabel(); + CMaLabel _non_neg = new CMaLabel(); + CMaLabel _table = new CMaLabel(); + CMaLabel _case0 = new CMaLabel(); + CMaLabel _case1 = new CMaLabel(); + CMaLabel _recurse = new CMaLabel(); + + /* === Peaprogramm (indeksid 0-5): kutsub run(n) === */ + pw.visit(LOADC, n); // 0: muutuja 'n' väärtus, run parameeter + pw.visit(MARK); // 1: push EP, FP + pw.visit(LOADC, 6); // 2: _run aadress = 6 + pw.visit(CALL); // 3 + pw.visit(SLIDE, 0, 1); // 4: tõsta tulemus + pw.visit(HALT); // 5 + + /* + * === run(n) funktsioon (indeksid 6-17) === + * int run(int n) { int r = fibo(n); return r; } + * Lokaalsed: muutuja 'r' on FP+1 + */ + pw.visit(_run); // label indeksil 6 + pw.visit(ENTER, 1); // 6: EP = SP + 1 (lokaalne muutuja 'r') + pw.visit(ALLOC, 1); // 7: eralda koht muutujale 'r' + + /* kutsu fibo(muutuja 'n') */ + pw.visit(LOADR, -3, 1); // 8: laadi muutuja 'n' + pw.visit(MARK); // 9: push EP, FP + pw.visit(LOADC, 18); // 10: _fibo aadress = 18 + pw.visit(CALL); // 11 + pw.visit(SLIDE, 0, 1); // 12: tõsta fibo tulemus + + pw.visit(STORER, 1, 1); // 13: muutuja 'r' = fibo(muutuja 'n') + pw.visit(POP); // 14: eemalda STORER duplikaat + + /* tagasta muutuja 'r' */ + pw.visit(LOADR, 1, 1); // 15: laadi muutuja 'r' + pw.visit(STORER, -3, 1); // 16: kirjuta tulemus parameetri pessa + pw.visit(RETURN, 3); // 17 + + /* + * === fibo(n) funktsioon (indeksid 18-56) === + * Baassjuhud n<0, n=0, n=1 — rekursiivne juht: fibo(n-1) + fibo(n-2). + */ + pw.visit(_fibo); // label indeksil 18 + pw.visit(ENTER, 0); // 18: lokaalseid muutujaid pole + + /* kui n < 0, tagasta -1 */ + pw.visit(LOADC, 0); // 19: push 0 + pw.visit(LOADR, -3, 1); // 20: laadi muutuja 'n' + pw.visit(GR); // 21: 0 > n, ehk n < 0? + pw.visit(JUMPZ, _non_neg); // 22: kui n >= 0, hüppa edasi + pw.visit(LOADC, -1); // 23: tulemus = -1 + pw.visit(STORER, -3, 1); // 24: tulemus → parameetri pessa + pw.visit(RETURN, 3); // 25 + + /* lülituslause: n=0, n=1 → baassjuhud; n>1 → rekursiivne juht */ + pw.visit(_non_neg); // label indeksil 26 + pw.visit(LOADR, -3, 1); // 26: laadi muutuja 'n' + pw.visit(LOADC, 1); // 27 + pw.visit(LEQ); // 28: n <= 1? + pw.visit(JUMPZ, _recurse); // 29: kui n > 1, hüppa rekursiivsesse harusse + + /* JUMPI lülituslause harud: n=0 → _case0, n=1 → _case1 */ + pw.visit(LOADR, -3, 1); // 30: laadi muutuja 'n' (JUMPI indeks) + pw.visit(JUMPI, _table); // 31: PC = target(_table) + n + + pw.visit(_table); // label indeksil 32 + pw.visit(JUMP, _case0); // 32: n=0 → tagasta 0 + pw.visit(JUMP, _case1); // 33: n=1 → tagasta 1 + + pw.visit(_case0); // label indeksil 34 + pw.visit(LOADC, 0); // 34: tulemus = 0 + pw.visit(STORER, -3, 1); // 35: tulemus → parameetri pessa + pw.visit(RETURN, 3); // 36 + + pw.visit(_case1); // label indeksil 37 + pw.visit(LOADC, 1); // 37: tulemus = 1 + pw.visit(STORER, -3, 1); // 38: tulemus → parameetri pessa + pw.visit(RETURN, 3); // 39 + + /* rekursiivne juht: fibo(n-1) + fibo(n-2) */ + pw.visit(_recurse); // label indeksil 40 + pw.visit(LOADR, -3, 1); // 40: laadi muutuja 'n' (fibo(n-1) argumendiks) + pw.visit(LOADC, 1); // 41 + pw.visit(SUB); // 42: muutuja 'n' - 1 + pw.visit(MARK); // 43: push EP, FP + pw.visit(LOADC, 18); // 44: _fibo aadress = 18 + pw.visit(CALL); // 45 + pw.visit(SLIDE, 0, 1); // 46: fibo(n-1) tulemus pinul + + /* fibo(n-1) on pinul — arvuta fibo(n-2) */ + pw.visit(LOADR, -3, 1); // 47: laadi muutuja 'n' (FP taastatud) + pw.visit(LOADC, 2); // 48 + pw.visit(SUB); // 49: muutuja 'n' - 2 + pw.visit(MARK); // 50: push EP, FP + pw.visit(LOADC, 18); // 51: _fibo aadress = 18 + pw.visit(CALL); // 52 + pw.visit(SLIDE, 0, 1); // 53: fibo(n-2) tulemus pinul + + pw.visit(ADD); // 54: fibo(n-1) + fibo(n-2) + pw.visit(STORER, -3, 1); // 55: tulemus → parameetri pessa + pw.visit(RETURN, 3); // 56 + + assertInterpreted(new CMaStack(fibExpected(n))); + } + + @Test + public void test_fibo_neg() { + /* run(-1): fibo(-1) = -1 */ + runFibo(-1); + } + + @Test + public void test_fibo_0() { + /* run(0): fibo(0) = 0 */ + runFibo(0); + } + + @Test + public void test_fibo_1() { + /* run(1): fibo(1) = 1 */ + runFibo(1); + } + + @Test + public void test_fibo_5() { + /* run(5): fibo(5) = 5 */ + runFibo(5); + } + + @Test + public void test_fibo_7() { + /* run(7): fibo(7) = 13 */ + runFibo(7); + } +} diff --git a/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java b/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java index 7b41cc8..7e5e22e 100644 --- a/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java +++ b/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java @@ -367,6 +367,7 @@ public void test_enter_in_function() { pw.visit(LOADC, 5); // 2: funktsiooni aadress (indeks 5) pw.visit(CALL); // 3: FP=3, PC=5, S[3]=4 pw.visit(HALT); // 4: tagastuspunkt + pw.visit(_func); // label indeksil 5 pw.visit(ENTER, 3); // 5: EP = (4-1) + 3 = 6 pw.visit(MARK); // 6: push EP(6), push FP(3) @@ -403,6 +404,7 @@ public void test_call_return() { pw.visit(LOADC, 6); // 2: funktsiooni aadress pw.visit(CALL); // 3: FP=3, PC=5, S[3]=4 pw.visit(HALT); // 4: tagastuspunkt + pw.visit(_func); // label indeksil 5 pw.visit(ENTER, 0); // 5: EP = 3 pw.visit(RETURN, 3); // 6: taasta ja kärbi, q=3 (EP+FP+PC) @@ -437,6 +439,7 @@ public void test_call_return_with_locals() { pw.visit(LOADC, 5); // 2: funktsiooni aadress pw.visit(CALL); // 3 pw.visit(HALT); // 4 + pw.visit(_func); // label indeksil 5 pw.visit(ENTER, 1); // 5 pw.visit(ALLOC, 1); // 6: lokaalne muutuja @@ -598,357 +601,4 @@ public void test_jumpi_index2() { /* Indeks 2 → case2 → stack: [300] */ assertInterpreted(new CMaStack(300)); } - - // Funktsioonikutsed: Samm 9 — Integratsioonitestid kõikide käskude testimiseks erinevates töövoogudes - - /** - * Mitterekursiivne {@code inc(x)} funktsioon, mida kutsub {@code run(n)}. - * - *

    C-kood:

    - *
    {@code
    -     * int inc(int x) { return x + 1; }
    -     * int run(int n) {
    -     *     int r = inc(n);
    -     *     return r;
    -     * }
    -     * }
    - * - *

    Täitmisraami paigutus (FP viitab salvestatud PC-le):

    - * - * - * - * - * - * - *
    {@code FP-3}parameeter
    {@code FP-2}salvestatud EP
    {@code FP-1}salvestatud FP
    {@code FP}salvestatud PC (tagastusaadress)
    {@code FP+1}lokaalne muutuja 'r' (ainult run-is)
    - */ - @Test - public void test_main_calls_non_recursive_function() { - CMaLabel _run = new CMaLabel(); - CMaLabel _inc = new CMaLabel(); - - /* === Peaprogramm (indeksid 0-5): kutsub run(41) === */ - pw.visit(LOADC, 41); // 0: muutuja 'n' väärtus, run parameeter - pw.visit(MARK); // 1: push EP, FP - pw.visit(LOADC, 6); // 2: _run aadress = 6 - pw.visit(CALL); // 3 - pw.visit(SLIDE, 0, 1); // 4: tõsta tulemus - pw.visit(HALT); // 5 - - /* - * === run(n) funktsioon (indeksid 6-17) === - * int run(int n) { int r = inc(n); return r; } - * Lokaalsed: muutuja 'r' on FP+1 - */ - pw.visit(_run); // label indeksil 6 - pw.visit(ENTER, 1); // 6: EP = SP + 1 (lokaalne muutuja 'r') - pw.visit(ALLOC, 1); // 7: eralda koht muutujale 'r' - - /* kutsu inc(muutuja 'n') */ - pw.visit(LOADR, -3, 1); // 8: laadi muutuja 'n' - pw.visit(MARK); // 9: push EP, FP - pw.visit(LOADC, 18); // 10: _inc aadress = 18 - pw.visit(CALL); // 11 - pw.visit(SLIDE, 0, 1); // 12: tõsta inc tulemuse - - pw.visit(STORER, 1, 1); // 13: muutuja 'r' = inc(muutuja 'n') - pw.visit(POP); // 14: eemalda STORER duplikaat - - /* tagasta muutuja 'r' */ - pw.visit(LOADR, 1, 1); // 15: laadi muutuja 'r' - pw.visit(STORER, -3, 1); // 16: kirjuta tulemus parameetri pessa - pw.visit(RETURN, 3); // 17 - - /* - * === inc(x) funktsioon (indeksid 18-23) === - * int inc(int x) { return x + 1; } - */ - pw.visit(_inc); // label indeksil 18 - pw.visit(ENTER, 0); // 18: lokaalseid muutujaid pole - pw.visit(LOADR, -3, 1); // 19: laadi muutuja 'x' - pw.visit(LOADC, 1); // 20 - pw.visit(ADD); // 21: muutuja 'x' + 1 - pw.visit(STORER, -3, 1); // 22: tulemus → parameetri pessa - pw.visit(RETURN, 3); // 23 - - /* Oodatav tulemus: inc(41) = 42, run tagastab 42 */ - assertInterpreted(new CMaStack(42)); - } - - /** - * Rekursiivne {@code fac(n)} funktsioon, mida kutsub {@code run(n)}. - * - *

    C-kood:

    - *
    {@code
    -     * int fac(int n) {
    -     *     if (n <= 0) return 1;
    -     *     return n * fac(n - 1);
    -     * }
    -     * int run(int n) {
    -     *     int r = fac(n);
    -     *     return r;
    -     * }
    -     * }
    - * - *

    Täitmisraami paigutus (FP viitab salvestatud PC-le):

    - * - * - * - * - * - * - *
    {@code FP-3}parameeter
    {@code FP-2}salvestatud EP
    {@code FP-1}salvestatud FP
    {@code FP}salvestatud PC (tagastusaadress)
    {@code FP+1}lokaalne muutuja 'r' (ainult run-is)
    - * - *

    Tulemus kirjutatakse parameetri pessa ({@code STORER -3}), - * seejärel {@code RETURN 3} kärbib täitmisraami. - * Kutsuja kasutab {@code SLIDE 0 1} (ei nihuta).

    - */ - private CMaStack runFac(int n) { - pw = new CMaProgramWriter(); - - CMaLabel _fac = new CMaLabel(); - CMaLabel _recurse = new CMaLabel(); - CMaLabel _run = new CMaLabel(); - - /* === Peaprogramm (indeksid 0-5): kutsub run(n) === */ - pw.visit(LOADC, n); // 0: muutuja 'n' väärtus, run parameetriks - pw.visit(MARK); // 1: push EP, FP - pw.visit(LOADC, 6); // 2: _run aadress = 6 - pw.visit(CALL); // 3: FP=3, PC=6, S[3]=4 - pw.visit(SLIDE, 0, 1); // 4: tõsta tulemus - pw.visit(HALT); // 5 - - /* - * === run(n) funktsioon (indeksid 6-17) === - * int run(int n) { int r = fac(n); return r; } - * Lokaalsed: muutuja 'r' on FP+1 - */ - pw.visit(_run); // label indeksil 6 - pw.visit(ENTER, 1); // 6: EP = SP + 1 (lokaalne muutuja 'r') - pw.visit(ALLOC, 1); // 7: eralda koht muutujale 'r' - - /* kutsu fac(muutuja 'n'): muutuja 'n' asub FP-3 */ - pw.visit(LOADR, -3, 1); // 8: laadi muutuja 'n' - pw.visit(MARK); // 9: push EP, FP - pw.visit(LOADC, 18); // 10: _fac aadress = 18 - pw.visit(CALL); // 11 - pw.visit(SLIDE, 0, 1); // 12: tõsta fac tulemuse - - pw.visit(STORER, 1, 1); // 13: muutuja 'r' = fac(muutuja 'n') - pw.visit(POP); // 14: eemalda STORER duplikaat - - /* tagasta muutuja 'r': kopeeri muutuja 'r' parameetri pessa */ - pw.visit(LOADR, 1, 1); // 15: laadi muutuja 'r' - pw.visit(STORER, -3, 1); // 16: kirjuta tulemus parameetri pessa - pw.visit(RETURN, 3); // 17 - - /* === fac(n) funktsioon (indeksid 18-...) === */ - pw.visit(_fac); // label indeksil 18 - pw.visit(ENTER, 0); // 18: lokaalseid muutujaid pole - - /* kui muutuja 'n' <= 0, tagasta 1 */ - pw.visit(LOADR, -3, 1); // 19: laadi muutuja 'n' - pw.visit(LOADC, 0); // 20 - pw.visit(LEQ); // 21: muutuja 'n' <= 0? - pw.visit(JUMPZ, _recurse); // 22: kui n > 0, hüppa rekursiivsesse harusse - pw.visit(LOADC, 1); // 23: baassjuht: tulemus = 1 - pw.visit(STORER, -3, 1); // 24: tulemus → parameetri pessa - pw.visit(RETURN, 3); // 25 - - /* rekursiivne juht: tagasta muutuja 'n' * fac(muutuja 'n' - 1) */ - pw.visit(_recurse); // label indeksil 26 - pw.visit(LOADR, -3, 1); // 26: laadi muutuja 'n' (korrutamiseks) - pw.visit(LOADR, -3, 1); // 27: laadi muutuja 'n' (fac argumendiks) - pw.visit(LOADC, 1); // 28 - pw.visit(SUB); // 29: muutuja 'n' - 1 - pw.visit(MARK); // 30: push EP, FP - pw.visit(LOADC, 18); // 31: _fac aadress = 18 - pw.visit(CALL); // 32 - pw.visit(SLIDE, 0, 1); // 33: tõsta fac tulemuse - pw.visit(MUL); // 34: muutuja 'n' * fac(muutuja 'n' - 1) - pw.visit(STORER, -3, 1); // 35: tulemus → parameetri pessa - pw.visit(RETURN, 3); // 36 - - return CMaInterpreter.run(pw.toProgram()); - } - - @Test - public void test_recursive_fac_0() { - CMaStack result = runFac(0); - assertEquals(new CMaStack(1), result); - } - - @Test - public void test_recursive_fac_1() { - CMaStack result = runFac(1); - assertEquals(new CMaStack(1), result); - } - - @Test - public void test_recursive_fac_5() { - CMaStack result = runFac(5); - assertEquals(new CMaStack(120), result); - } - - @Test - public void test_recursive_fac_10() { - CMaStack result = runFac(10); - assertEquals(new CMaStack(3628800), result); - } - - /** - * Ehitab ja käivitab programmi, mis kasutab kõiki uusi käske. - * - *

    C-kood:

    - *
    {@code
    -     * int inc(int x, int step) { return x + step; }
    -     * int run(int op) {
    -     *     int n = 5;
    -     *     int r;
    -     *     switch (op) {
    -     *         case 0: r = inc(n, 1); break;  // LOADRC, MARK, CALL, SLIDE 0 1
    -     *         case 1: r = n * 2;     break;  // LOADR, MUL, STORER
    -     *     }
    -     *     return r;
    -     * }
    -     * }
    - * - *

    Täitmisraami paigutus kahes funktsioonis (FP viitab salvestatud PC-le):

    - * - * - * - * - * - * - * - * - *
    {@code FP-4}muutuja 'x' — esimene parameeter (ainult inc-is)
    {@code FP-3}muutuja 'op' (run-is) / muutuja 'step' (inc-is)
    {@code FP-2}salvestatud EP
    {@code FP-1}salvestatud FP
    {@code FP}salvestatud PC
    {@code FP+1}lokaalne muutuja 'n' (ainult run-is)
    {@code FP+2}lokaalne muutuja 'r' (ainult run-is)
    - * - *

    {@code inc} kasutab {@code RETURN 4}, mis puhastab muutuja 'step' pesa ja - * organisatsioonilised pesad (EP, FP, PC). Tulemus kirjutatakse muutuja 'x' pessa - * ({@code STORER -4}). Kutsuja kasutab {@code SLIDE 0 1} — tulemus on pärast - * tagastust juba pinul.

    - * - *

    Programmi aadressid:

    - *
      - *
    • {@code 0–5}: peaprogramm
    • - *
    • {@code 6–11}: {@code inc(x, step)}
    • - *
    • {@code 12–18}: {@code run(op)}
    • - *
    • {@code 19–20}: lülituslause harud
    • - *
    • {@code 21–30}: case 0 (inc)
    • - *
    • {@code 31–35}: case 1 (n*2)
    • - *
    • {@code 36–38}: tagastus
    • - *
    - * - *

    Oodatavad tulemused:

    - *
      - *
    • {@code op=0} → {@code inc(5, 1) = 6}
    • - *
    • {@code op=1} → {@code 5 * 2 = 10}
    • - *
    - */ - private CMaStack runDispatch(int op) { - pw = new CMaProgramWriter(); - - CMaLabel _inc = new CMaLabel(); - CMaLabel _run = new CMaLabel(); - CMaLabel _table = new CMaLabel(); - CMaLabel _case0 = new CMaLabel(); - CMaLabel _case1 = new CMaLabel(); - CMaLabel _end = new CMaLabel(); - - /* Peaprogramm (0–5): kutsub run(op). */ - pw.visit(LOADC, op); // 0: muutuja 'op' → parameeter run-ile - pw.visit(MARK); // 1: push EP(0), FP(0) - pw.visit(LOADC, 12); // 2: _run aadress = 12 - pw.visit(CALL); // 3: FP=3, PC=12, S[3]=4 - pw.visit(SLIDE, 0, 1); // 4: tõsta tulemus parameetri kohalt - pw.visit(HALT); // 5: peaprogramm lõpeb - - /* - * inc(muutuja 'x', muutuja 'step') (6–11): tagastab muutuja 'x' + muutuja 'step'. - * FP-4: muutuja 'x' (esimene arg), FP-3: muutuja 'step' (teine arg). - * RETURN 4 eemaldab muutuja 'step' pesa ja org-pesad (EP, FP, PC). - * Käsud: ENTER, LOADR, ADD, STORER, RETURN. - */ - pw.visit(_inc); - pw.visit(ENTER, 0); // 6: lokaalseid muutujaid pole; EP = SP+0 - pw.visit(LOADR, -4, 1); // 7: laadi muutuja 'x' (FP-4, esimene arg) - pw.visit(LOADR, -3, 1); // 8: laadi muutuja 'step' (FP-3, teine arg) - pw.visit(ADD); // 9: muutuja 'x' + muutuja 'step' - pw.visit(STORER, -4, 1); // 10: tulemus → muutuja 'x' pessa (FP-4) - pw.visit(RETURN, 4); // 11: eemaldab muutuja 'step' ja org-pesad - - /* - * run(muutuja 'op') (12–18): eraldab muutuja 'n'=5 ja muutuja 'r', valib haru JUMPI abil. - * Käsud: ENTER, ALLOC, STORER, LOADR, JUMPI. - */ - pw.visit(_run); - pw.visit(ENTER, 2); // 12: EP = SP+2 (2 lokaalset: n, r) - pw.visit(ALLOC, 2); // 13: eralda koht muutujatele 'n' ja 'r' - pw.visit(LOADC, 5); // 14: push 5 - pw.visit(STORER, 1, 1); // 15: muutuja 'n' = 5 (FP+1) - pw.visit(POP); // 16: eemalda STORER duplikaat - pw.visit(LOADR, -3, 1); // 17: laadi muutuja 'op' (FP-3) — JUMPI indeks - pw.visit(JUMPI, _table); // 18: PC = target(_table) + op - - /* - * Lülituslause harud (19–20): JUMPI sihtmärgid. - * muutuja 'op'=0 → _case0 (21), muutuja 'op'=1 → _case1 (31). - */ - pw.visit(_table); - pw.visit(JUMP, _case0); // 19: op=0 → kutsu inc(n, 1) - pw.visit(JUMP, _case1); // 20: op=1 → arvuta n*2 - - /* - * case 0 (21–30): muutuja 'r' = inc(muutuja 'n', 1). - * Laadi muutuja 'n' (LOADRC+LOAD) ja muutuja 'step'=1, kutsu inc. - * SLIDE 0 1 on no-op — tulemus on pärast RETURN 4 juba pinul. - * Käsud: LOADRC, LOAD, LOADC, MARK, CALL, SLIDE 0 1, STORER. - */ - pw.visit(_case0); - pw.visit(LOADRC, 1); // 21: laadi muutuja 'n' aadress (FP+1) — LOADRC otse - pw.visit(LOAD); // 22: loe muutuja 'n' väärtus - pw.visit(LOADC, 1); // 23: muutuja 'step'=1 (teine arg inc-ile) - pw.visit(MARK); // 24: push EP, FP - pw.visit(LOADC, 6); // 25: _inc aadress = 6 - pw.visit(CALL); // 26: FP=10, PC=6, S[10]=27 - pw.visit(SLIDE, 0, 1); // 27: tulemus juba pinul (no-op) - pw.visit(STORER, 2, 1); // 28: muutuja 'r' = tulemus (FP+2) - pw.visit(POP); // 29: eemalda STORER duplikaat - pw.visit(JUMP, _end); // 30: hüppa tagastusele - - /* - * case 1 (31–35): muutuja 'r' = muutuja 'n' * 2. - * Käsud: LOADR, LOADC, MUL, STORER. - */ - pw.visit(_case1); - pw.visit(LOADR, 1, 1); // 31: laadi muutuja 'n' (FP+1) - pw.visit(LOADC, 2); // 32: push 2 - pw.visit(MUL); // 33: muutuja 'n' * 2 = 10 - pw.visit(STORER, 2, 1); // 34: muutuja 'r' = muutuja 'n'*2 (FP+2) - pw.visit(POP); // 35: eemalda STORER duplikaat - - /* - * Tagastus (36–38): return r. - * Käsud: LOADR, STORER, RETURN. - */ - pw.visit(_end); - pw.visit(LOADR, 2, 1); // 36: laadi muutuja 'r' (FP+2) - pw.visit(STORER, -3, 1); // 37: tulemus → parameetri pessa (FP-3) - pw.visit(RETURN, 3); // 38: tagasta - - return CMaInterpreter.run(pw.toProgram()); - } - - @Test - public void test_dispatch_inc() { - /* muutuja 'op'=0 → inc(5, 1) = 6: kasutab LOADRC, MARK, CALL, SLIDE 0 1 */ - assertEquals(new CMaStack(6), runDispatch(0)); - } - - @Test - public void test_dispatch_double() { - /* muutuja 'op'=1 → 5*2 = 10: kasutab LOADR, MUL, STORER */ - assertEquals(new CMaStack(10), runDispatch(1)); - } } From fbbdae31ca3751fc1cd1bf2ca987d7e813b2d4f5 Mon Sep 17 00:00:00 2001 From: sandersirge Date: Thu, 14 May 2026 00:19:58 +0300 Subject: [PATCH 22/24] Funktsioonikutsed: Dokumentatsioon parandatud --- .../java/ee/ut/cs/sws/cma/CMaInterpreterTest.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java b/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java index 7e5e22e..c4c946d 100644 --- a/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java +++ b/src/test/java/ee/ut/cs/sws/cma/CMaInterpreterTest.java @@ -558,9 +558,9 @@ public void test_jumpi_index1() { pw.visit(LOADC, 1); // 0: indeks pw.visit(JUMPI, _table); // 1: PC = target(_table) + 1 = 3 pw.visit(_table); - pw.visit(JUMP, _case0); // 2 - pw.visit(JUMP, _case1); // 3 - pw.visit(JUMP, _case2); // 4 + pw.visit(JUMP, _case0); // 2: hüppa case0-le + pw.visit(JUMP, _case1); // 3: hüppa case1-le + pw.visit(JUMP, _case2); // 4: hüppa case2-le pw.visit(_case0); pw.visit(LOADC, 100); pw.visit(HALT); @@ -585,9 +585,9 @@ public void test_jumpi_index2() { pw.visit(LOADC, 2); // 0: indeks pw.visit(JUMPI, _table); // 1: PC = target(_table) + 2 = 4 pw.visit(_table); - pw.visit(JUMP, _case0); // 2 - pw.visit(JUMP, _case1); // 3 - pw.visit(JUMP, _case2); // 4 + pw.visit(JUMP, _case0); // 2: hüppa case0-le + pw.visit(JUMP, _case1); // 3: hüppa case1-le + pw.visit(JUMP, _case2); // 4: hüppa case2-le pw.visit(_case0); pw.visit(LOADC, 100); pw.visit(HALT); From 9cd7fe1fa60a00dc6c046c0d05387c0bc656b8b5 Mon Sep 17 00:00:00 2001 From: sandersirge Date: Thu, 14 May 2026 18:27:58 +0300 Subject: [PATCH 23/24] =?UTF-8?q?T=C3=A4iendused:=20Lisa=20LOADLC=20k?= =?UTF-8?q?=C3=A4sk=20sildi=20j=C3=A4rjekorranumbri=20pinule=20laadimiseks?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java | 1 + .../java/ee/ut/cs/sws/cma/instruction/CMaLabelInstruction.java | 3 +++ 2 files changed, 4 insertions(+) diff --git a/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java b/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java index 9941faa..f6e6617 100644 --- a/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java +++ b/src/main/java/ee/ut/cs/sws/cma/CMaInterpreter.java @@ -187,6 +187,7 @@ case CMaIntIntInstruction(CMaIntIntInstruction.Code code, int arg1, int arg2) -> } case CMaLabelInstruction(CMaLabelInstruction.Code code, CMaLabel label) -> { switch (code) { + case LOADLC -> stack.push(getLabelTarget(label)); case JUMP -> pc = getLabelTarget(label); case JUMPZ -> { if (!CMaUtils.int2bool(stack.pop())) diff --git a/src/main/java/ee/ut/cs/sws/cma/instruction/CMaLabelInstruction.java b/src/main/java/ee/ut/cs/sws/cma/instruction/CMaLabelInstruction.java index 87d4678..9a37879 100644 --- a/src/main/java/ee/ut/cs/sws/cma/instruction/CMaLabelInstruction.java +++ b/src/main/java/ee/ut/cs/sws/cma/instruction/CMaLabelInstruction.java @@ -6,6 +6,9 @@ public record CMaLabelInstruction(Code code, CMaLabel label) implements CMaInstr public enum Code { //@formatter:off + /** lae label väärtus pinule */ + LOADLC, + /** hüppa labelile */ JUMP, From b5fd218201afa94ce57f89ae514b70e8365b343a Mon Sep 17 00:00:00 2001 From: Vesal Vojdani Date: Wed, 20 May 2026 15:43:17 +0300 Subject: [PATCH 24/24] Update JDK version and checkout step in workflow --- .github/workflows/gradle.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 00b6d20..96d6674 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -14,17 +14,17 @@ jobs: contents: read steps: - - uses: actions/checkout@v4 - - name: Set up JDK 21 + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up JDK 25 uses: actions/setup-java@v4 with: - java-version: '21' + java-version: '25' distribution: 'temurin' - # Configure Gradle for optimal use in GitHub Actions, including caching of downloaded dependencies. - # See: https://github.com/gradle/actions/blob/main/setup-gradle/README.md - name: Setup Gradle - uses: gradle/actions/setup-gradle@af1da67850ed9a4cedd57bfd976089dd991e2582 # v4.0.0 + uses: gradle/actions/setup-gradle@v4 - name: Build with Gradle Wrapper run: ./gradlew build