From 886ccad0c77223693c5847c65071e3b0ff59b603 Mon Sep 17 00:00:00 2001 From: Sebastian Heinzenburger Date: Thu, 22 May 2025 14:52:23 +0200 Subject: [PATCH 1/9] feat: add ASTForLoopStmtNode implementation and corresponding parser and tests --- src/main/java/com/InterpreterMain.java | 6 +- .../java/com/compiler/ASTForLoopStmtNode.java | 82 +++++++++++++++++++ src/main/java/com/compiler/StmtParser.java | 26 +++++- .../com/compiler/ast/ASTAssignStmtNode.java | 6 +- src/test/java/com/compiler/TestForLoop.java | 57 +++++++++++++ 5 files changed, 174 insertions(+), 3 deletions(-) create mode 100644 src/main/java/com/compiler/ASTForLoopStmtNode.java create mode 100644 src/test/java/com/compiler/TestForLoop.java diff --git a/src/main/java/com/InterpreterMain.java b/src/main/java/com/InterpreterMain.java index 4b63dc6..4e74946 100644 --- a/src/main/java/com/InterpreterMain.java +++ b/src/main/java/com/InterpreterMain.java @@ -7,7 +7,11 @@ public class InterpreterMain { public static void main(String[] args) throws Exception { String input = new String(""" { - PRINT 4 + 3 - 2; + DECLARE i; + FOR (i = 0; i < 10; i = i + 1;) { + PRINT(i); + }; + PRINT 187; } """); com.compiler.CompileEnv compileEnv = new com.compiler.CompileEnv(input, false); diff --git a/src/main/java/com/compiler/ASTForLoopStmtNode.java b/src/main/java/com/compiler/ASTForLoopStmtNode.java new file mode 100644 index 0000000..e2b9790 --- /dev/null +++ b/src/main/java/com/compiler/ASTForLoopStmtNode.java @@ -0,0 +1,82 @@ +package com.compiler; + +import com.compiler.ast.ASTExprNode; +import com.compiler.ast.ASTStmtNode; +import com.compiler.instr.InstrCondJump; +import com.compiler.instr.InstrJump; + +import java.io.OutputStreamWriter; + +public class ASTForLoopStmtNode extends ASTStmtNode { + private ASTStmtNode m_initStmt; + private ASTExprNode m_predicate; + private ASTStmtNode m_updateStmt; + private ASTStmtNode m_body; + + public ASTForLoopStmtNode(ASTStmtNode initStmt, ASTExprNode predicate, ASTStmtNode updateStmt, ASTStmtNode body) { + m_initStmt = initStmt; + m_predicate = predicate; + m_updateStmt = updateStmt; + m_body = body; + } + + @Override + public void execute(OutputStreamWriter out) { + m_initStmt.execute(out); + while (m_predicate.eval() != 0) { + m_body.execute(out); + m_updateStmt.execute(out); + } + } + + @Override + public void codegen(CompileEnvIntf env) { + InstrBlock initBlock = env.createBlock("for_init"); + InstrBlock predicateBlock = env.createBlock("for_predicate"); + InstrBlock bodyBlock = env.createBlock("for_body"); + InstrBlock updateBlock = env.createBlock("for_update"); + InstrBlock exitBlock = env.createBlock("for_exit"); + + env.addInstr(new InstrJump(initBlock)); + env.setCurrentBlock(initBlock); + m_initStmt.codegen(env); + env.addInstr(new InstrJump(predicateBlock)); + + env.setCurrentBlock(predicateBlock); + InstrIntf predicateInstr = m_predicate.codegen(env); + env.addInstr(predicateInstr); + env.addInstr(new InstrCondJump(predicateInstr, bodyBlock, exitBlock)); + + env.setCurrentBlock(bodyBlock); + m_body.codegen(env); + env.addInstr(new InstrJump(updateBlock)); + + env.setCurrentBlock(updateBlock); + m_updateStmt.codegen(env); + env.addInstr(new InstrJump(predicateBlock)); + + env.setCurrentBlock(exitBlock); + + } + + @Override + public void print(OutputStreamWriter outStream, String indent) throws Exception { + outStream.write(indent + "FOR:\n" ); + + outStream.write(indent + "\t" + "initStmt: \n"); + m_initStmt.print(outStream, indent + "\t\t"); + outStream.write("\n"); + + outStream.write(indent + "\t" + "predicate: \n"); + m_predicate.print(outStream, indent + "\t\t"); + outStream.write("\n"); + + outStream.write(indent + "\t" + "updateStmt: \n"); + m_updateStmt.print(outStream, indent + "\t\t"); + outStream.write("\n"); + + outStream.write(indent + "\t" + "body: \n"); + m_body.print(outStream, indent + "\t\t"); + outStream.write("\n"); + } +} diff --git a/src/main/java/com/compiler/StmtParser.java b/src/main/java/com/compiler/StmtParser.java index 0e4c1d1..8075911 100644 --- a/src/main/java/com/compiler/StmtParser.java +++ b/src/main/java/com/compiler/StmtParser.java @@ -74,6 +74,10 @@ public ASTStmtNode parseStmt() throws Exception { if (type == TokenIntf.Type.DO) { return parseDoWhileLoopStmt(); } + + if (type == TokenIntf.Type.FOR) { + return parseForLoopStmt(); + } if (type == TokenIntf.Type.EXECUTE) { return parseExecuteNTimesStmt(); @@ -87,6 +91,7 @@ public ASTStmtNode parseStmt() throws Exception { return null; // unreachable } +<<<<<<< HEAD public ASTStmtNode parseFunctionStmt() throws Exception { m_lexer.expect(Type.FUNCTION); String functionName = m_lexer.m_currentToken.m_value; @@ -137,6 +142,25 @@ private List parseParameterList() throws Exception { } } + private ASTStmtNode parseForLoopStmt() throws Exception { + // forStmt: FOR LPAREN stmt questionMarkExpr SEMICOLON stmt RPAREN blockStmt SEMICOLON + m_lexer.expect(TokenIntf.Type.FOR); + m_lexer.expect(TokenIntf.Type.LPAREN); + + ASTStmtNode initStmt = parseStmt(); + + ASTExprNode predicate = this.m_exprParser.getQuestionMarkExpr(); + m_lexer.expect(TokenIntf.Type.SEMICOLON); + + ASTStmtNode updateStmt = parseStmt(); + + m_lexer.expect(TokenIntf.Type.RPAREN); + ASTStmtNode body = parseBlockStmt(); + m_lexer.expect(TokenIntf.Type.SEMICOLON); + + return new ASTForLoopStmtNode(initStmt, predicate, updateStmt, body); + } + public ASTStmtNode parsePrintStmt() throws Exception { m_lexer.expect(Type.PRINT); @@ -282,4 +306,4 @@ ASTStmtNode parseExecuteNTimesStmt() throws Exception { return new ASTExecuteNTimesNode(count, stmtlistNode); } -} \ No newline at end of file +} diff --git a/src/main/java/com/compiler/ast/ASTAssignStmtNode.java b/src/main/java/com/compiler/ast/ASTAssignStmtNode.java index d7440e5..454f26e 100644 --- a/src/main/java/com/compiler/ast/ASTAssignStmtNode.java +++ b/src/main/java/com/compiler/ast/ASTAssignStmtNode.java @@ -31,6 +31,10 @@ public void codegen(com.compiler.CompileEnvIntf env) { } @Override - public void print(OutputStreamWriter outStream, String indent) throws Exception {} + public void print(OutputStreamWriter outStream, String indent) throws Exception { + outStream.write(indent + "ASSIGN: " + identifier.m_name + "\n"); + outStream.write(indent + "\t" + "expr: \n"); + expr.print(outStream, indent + "\t\t"); + } } diff --git a/src/test/java/com/compiler/TestForLoop.java b/src/test/java/com/compiler/TestForLoop.java new file mode 100644 index 0000000..a8b23a7 --- /dev/null +++ b/src/test/java/com/compiler/TestForLoop.java @@ -0,0 +1,57 @@ +package com.compiler; + +import org.junit.Test; + +public class TestForLoop extends InterpreterTestBase { + + @Test + public void testForLoop1() throws Exception { + String code = """ + { + DECLARE index; + DECLARE sum; + index = 0; + sum = 0; + FOR(index = 10; index; index = index - 1;) { + sum = sum + index; + }; + PRINT sum; + } + """; + testInterpreter(code, "55\n"); + } + + @Test + public void testForLoop2() throws Exception { + String code = """ + { + DECLARE index; + DECLARE sum; + index = 64; + sum = 0; + FOR(index = index * 2; index; index = index / 2;) { + sum = sum + index; + }; + PRINT sum; + } + """; + testInterpreter(code, "255\n"); + } + + @Test + public void testForLoop3() throws Exception { + String code = """ + { + DECLARE index; + DECLARE sum; + index = 10 - 20; + sum = 0; + FOR(PRINT index; index; index = index + 2;) { + sum = sum + index; + }; + PRINT sum; + } + """; + testInterpreter(code, "-10\n-30\n"); + } +} From 6212d0463a8f3664e57c953458a871c9ff850155 Mon Sep 17 00:00:00 2001 From: Sebastian Heinzenburger Date: Fri, 23 May 2025 10:59:42 +0200 Subject: [PATCH 2/9] fix: remove merge conflict markers from StmtParser.java --- src/main/java/com/compiler/StmtParser.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/compiler/StmtParser.java b/src/main/java/com/compiler/StmtParser.java index 8075911..136454a 100644 --- a/src/main/java/com/compiler/StmtParser.java +++ b/src/main/java/com/compiler/StmtParser.java @@ -91,7 +91,6 @@ public ASTStmtNode parseStmt() throws Exception { return null; // unreachable } -<<<<<<< HEAD public ASTStmtNode parseFunctionStmt() throws Exception { m_lexer.expect(Type.FUNCTION); String functionName = m_lexer.m_currentToken.m_value; From 2c5c2ecdecd3ea071efda8ccdc1d858f73ec11ed Mon Sep 17 00:00:00 2001 From: Sebastian <67160355+Sebastian-Heinzenburger@users.noreply.github.com> Date: Fri, 23 May 2025 11:05:41 +0200 Subject: [PATCH 3/9] Update ci.yml --- .github/workflows/ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2d38106..2ee59ab 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,4 +21,5 @@ jobs: run: mvn -B package --file pom.xml - name: Test with Maven - run: mvn -B test --file pom.xml \ No newline at end of file + run: mvn -B test --file pom.xml + From 3883dfd112ca6e3054102cbf6f57e7e1d9e399f3 Mon Sep 17 00:00:00 2001 From: Sebastian Heinzenburger Date: Wed, 4 Jun 2025 16:39:17 +0200 Subject: [PATCH 4/9] Revert "Update ci.yml" This reverts commit 2c5c2ecdecd3ea071efda8ccdc1d858f73ec11ed. --- .github/workflows/ci.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2ee59ab..2d38106 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,5 +21,4 @@ jobs: run: mvn -B package --file pom.xml - name: Test with Maven - run: mvn -B test --file pom.xml - + run: mvn -B test --file pom.xml \ No newline at end of file From 8d88b0951db9093c5510201d65c5052df9bd3a1c Mon Sep 17 00:00:00 2001 From: Sebastian Heinzenburger Date: Wed, 4 Jun 2025 17:04:33 +0200 Subject: [PATCH 5/9] fix: update interpreter tests to use regex for expected output --- .../com/compiler/ConstFoldUnaryExprTest.java | 16 ++++++---------- .../com/compiler/InterpreterDumpTestBase.java | 6 ++++-- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/test/java/com/compiler/ConstFoldUnaryExprTest.java b/src/test/java/com/compiler/ConstFoldUnaryExprTest.java index d70a23a..87d9ff8 100644 --- a/src/test/java/com/compiler/ConstFoldUnaryExprTest.java +++ b/src/test/java/com/compiler/ConstFoldUnaryExprTest.java @@ -10,13 +10,8 @@ public void testUnaryMinus() throws Exception { PRINT -5; } """; - String expected = """ -entry: -%0 = LITERAL -5 -PRINT %0 - -"""; - testInterpreter(input, expected); + String expectedRegex = "entry:\n%(\\d) = LITERAL -5\nPRINT %\\1\n\n"; + testInterpreter(input, expectedRegex); } @Test @@ -28,11 +23,12 @@ public void testNotZero() throws Exception { """; String expected = """ entry: -%2 = LITERAL 1 -PRINT %2 +%%%d = LITERAL 1 +PRINT %%%d """; - testInterpreter(input, expected); + String expectedRegex = "entry:\n%(\\d) = LITERAL 1\nPRINT %\\1\n\n"; + testInterpreter(input, expectedRegex); } diff --git a/src/test/java/com/compiler/InterpreterDumpTestBase.java b/src/test/java/com/compiler/InterpreterDumpTestBase.java index 6d13ee2..bff3dba 100644 --- a/src/test/java/com/compiler/InterpreterDumpTestBase.java +++ b/src/test/java/com/compiler/InterpreterDumpTestBase.java @@ -5,7 +5,7 @@ import static org.junit.Assert.assertEquals; public class InterpreterDumpTestBase { - protected void testInterpreter(String program, String expectedOutput) throws Exception { + protected void testInterpreter(String program, String expectedOutputRegex) throws Exception { // create out stream ByteArrayOutputStream os = new ByteArrayOutputStream(); // compile program @@ -15,7 +15,9 @@ protected void testInterpreter(String program, String expectedOutput) throws Exc compileEnv.dump(os); // check result String output = os.toString(); - assertEquals(expectedOutput, output); + System.out.println("Output: >" + output + "<"); + // assert that the regex matches the output + assert(output.matches(expectedOutputRegex)); } } From 963ba082785bad31b630e0036eb12eeffd5eb646 Mon Sep 17 00:00:00 2001 From: Sebastian Heinzenburger Date: Thu, 5 Jun 2025 04:50:56 +0200 Subject: [PATCH 6/9] fix: update regex in interpreter tests for expected output --- src/test/java/com/compiler/ConstFoldUnaryExprTest.java | 10 ++-------- .../java/com/compiler/InterpreterDumpTestBase.java | 1 - 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/test/java/com/compiler/ConstFoldUnaryExprTest.java b/src/test/java/com/compiler/ConstFoldUnaryExprTest.java index 87d9ff8..864daca 100644 --- a/src/test/java/com/compiler/ConstFoldUnaryExprTest.java +++ b/src/test/java/com/compiler/ConstFoldUnaryExprTest.java @@ -10,7 +10,7 @@ public void testUnaryMinus() throws Exception { PRINT -5; } """; - String expectedRegex = "entry:\n%(\\d) = LITERAL -5\nPRINT %\\1\n\n"; + String expectedRegex = "entry:\n%(\\d+) = LITERAL -5\nPRINT %\\1\n\n"; testInterpreter(input, expectedRegex); } @@ -21,13 +21,7 @@ public void testNotZero() throws Exception { PRINT !0; } """; - String expected = """ -entry: -%%%d = LITERAL 1 -PRINT %%%d - -"""; - String expectedRegex = "entry:\n%(\\d) = LITERAL 1\nPRINT %\\1\n\n"; + String expectedRegex = "entry:\n%(\\d+) = LITERAL 1\nPRINT %\\1\n\n"; testInterpreter(input, expectedRegex); } diff --git a/src/test/java/com/compiler/InterpreterDumpTestBase.java b/src/test/java/com/compiler/InterpreterDumpTestBase.java index bff3dba..914cf88 100644 --- a/src/test/java/com/compiler/InterpreterDumpTestBase.java +++ b/src/test/java/com/compiler/InterpreterDumpTestBase.java @@ -15,7 +15,6 @@ protected void testInterpreter(String program, String expectedOutputRegex) throw compileEnv.dump(os); // check result String output = os.toString(); - System.out.println("Output: >" + output + "<"); // assert that the regex matches the output assert(output.matches(expectedOutputRegex)); } From b6ab00600c4edae12997898c8c4b027c412550fe Mon Sep 17 00:00:00 2001 From: Sebastian Heinzenburger Date: Thu, 5 Jun 2025 05:00:38 +0200 Subject: [PATCH 7/9] fix: revert InterpreterMain --- src/main/java/com/InterpreterMain.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/InterpreterMain.java b/src/main/java/com/InterpreterMain.java index 4e74946..08912f3 100644 --- a/src/main/java/com/InterpreterMain.java +++ b/src/main/java/com/InterpreterMain.java @@ -7,11 +7,7 @@ public class InterpreterMain { public static void main(String[] args) throws Exception { String input = new String(""" { - DECLARE i; - FOR (i = 0; i < 10; i = i + 1;) { - PRINT(i); - }; - PRINT 187; + PRINT 4 + 3 - 2; } """); com.compiler.CompileEnv compileEnv = new com.compiler.CompileEnv(input, false); @@ -27,4 +23,4 @@ public static void main(String[] args) throws Exception { outStream.flush(); } -} +} \ No newline at end of file From 3f69bb6e0099aa7c6ee1bf1140d7f0b5fad30c6a Mon Sep 17 00:00:00 2001 From: Sebastian Heinzenburger Date: Thu, 5 Jun 2025 05:12:46 +0200 Subject: [PATCH 8/9] fix: revert the changes to InterpreterDumpTestBase and the ConstFoldUnaryExprTest as they are not needed anymore after 16a422a --- .../com/compiler/ConstFoldUnaryExprTest.java | 17 +++++++++++++---- .../com/compiler/InterpreterDumpTestBase.java | 4 ++-- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/test/java/com/compiler/ConstFoldUnaryExprTest.java b/src/test/java/com/compiler/ConstFoldUnaryExprTest.java index 864daca..62e7e93 100644 --- a/src/test/java/com/compiler/ConstFoldUnaryExprTest.java +++ b/src/test/java/com/compiler/ConstFoldUnaryExprTest.java @@ -10,8 +10,13 @@ public void testUnaryMinus() throws Exception { PRINT -5; } """; - String expectedRegex = "entry:\n%(\\d+) = LITERAL -5\nPRINT %\\1\n\n"; - testInterpreter(input, expectedRegex); + String expected = """ +entry: +%0 = LITERAL -5 +PRINT %0 + +"""; + testInterpreter(input, expected); } @Test @@ -21,9 +26,13 @@ public void testNotZero() throws Exception { PRINT !0; } """; - String expectedRegex = "entry:\n%(\\d+) = LITERAL 1\nPRINT %\\1\n\n"; - testInterpreter(input, expectedRegex); + String expected = """ +entry: +%0 = LITERAL 1 +PRINT %0 +"""; + testInterpreter(input, expected); } } diff --git a/src/test/java/com/compiler/InterpreterDumpTestBase.java b/src/test/java/com/compiler/InterpreterDumpTestBase.java index 914cf88..e3ac4a4 100644 --- a/src/test/java/com/compiler/InterpreterDumpTestBase.java +++ b/src/test/java/com/compiler/InterpreterDumpTestBase.java @@ -5,7 +5,7 @@ import static org.junit.Assert.assertEquals; public class InterpreterDumpTestBase { - protected void testInterpreter(String program, String expectedOutputRegex) throws Exception { + protected void testInterpreter(String program, String expectedOutput) throws Exception { // create out stream ByteArrayOutputStream os = new ByteArrayOutputStream(); // compile program @@ -16,7 +16,7 @@ protected void testInterpreter(String program, String expectedOutputRegex) throw // check result String output = os.toString(); // assert that the regex matches the output - assert(output.matches(expectedOutputRegex)); + assertEquals(expectedOutput, output); } } From 73427d84024818a60379c6b82d1a092717663b14 Mon Sep 17 00:00:00 2001 From: Sebastian Heinzenburger Date: Thu, 5 Jun 2025 05:13:28 +0200 Subject: [PATCH 9/9] fix: revert the changes to InterpreterDumpTestBase and the ConstFoldUnaryExprTest as they are not needed anymore after 16a422a --- src/test/java/com/compiler/InterpreterDumpTestBase.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/java/com/compiler/InterpreterDumpTestBase.java b/src/test/java/com/compiler/InterpreterDumpTestBase.java index e3ac4a4..6d13ee2 100644 --- a/src/test/java/com/compiler/InterpreterDumpTestBase.java +++ b/src/test/java/com/compiler/InterpreterDumpTestBase.java @@ -15,7 +15,6 @@ protected void testInterpreter(String program, String expectedOutput) throws Exc compileEnv.dump(os); // check result String output = os.toString(); - // assert that the regex matches the output assertEquals(expectedOutput, output); }