diff --git a/src/main/java/com/InterpreterMain.java b/src/main/java/com/InterpreterMain.java index 4b63dc6..08912f3 100644 --- a/src/main/java/com/InterpreterMain.java +++ b/src/main/java/com/InterpreterMain.java @@ -23,4 +23,4 @@ public static void main(String[] args) throws Exception { outStream.flush(); } -} +} \ No newline at end of file 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 a08d528..aef6a4c 100644 --- a/src/main/java/com/compiler/StmtParser.java +++ b/src/main/java/com/compiler/StmtParser.java @@ -74,7 +74,11 @@ 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(); } @@ -166,6 +170,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); ASTPrintStmtNode astPrintStmtNode = new ASTPrintStmtNode(m_exprParser.getQuestionMarkExpr()); @@ -331,7 +354,7 @@ private ASTStmtNode parseBreakNode() throws Exception { m_lexer.expect(Type.BREAK); return new ASTBreakStmtNode(); } - + ASTStmtNode parseExecuteNTimesStmt() throws Exception { // EXECUTE integer|identifier TIMES LBRACE stmtList RBRACE SEMICOLON m_lexer.expect(Type.EXECUTE); @@ -389,4 +412,4 @@ private ASTCaseNode parseCaseStmt() throws Exception { ASTStmtListNode stmtList = parseStmtlist(); return new ASTCaseNode(value, stmtList); } -} \ No newline at end of file +} diff --git a/src/test/java/com/compiler/ConstFoldUnaryExprTest.java b/src/test/java/com/compiler/ConstFoldUnaryExprTest.java index f4bcc7c..62e7e93 100644 --- a/src/test/java/com/compiler/ConstFoldUnaryExprTest.java +++ b/src/test/java/com/compiler/ConstFoldUnaryExprTest.java @@ -33,7 +33,6 @@ public void testNotZero() throws Exception { """; testInterpreter(input, expected); - } } 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"); + } +}