From 54c80b33198954f430c1bde47204e1775f236edf Mon Sep 17 00:00:00 2001 From: key-collector Date: Thu, 22 May 2025 17:12:32 +0200 Subject: [PATCH 1/8] error message for missing return statement in function body --- src/main/java/com/compiler/StmtParser.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/main/java/com/compiler/StmtParser.java b/src/main/java/com/compiler/StmtParser.java index 0e4c1d1..d8a1e4c 100644 --- a/src/main/java/com/compiler/StmtParser.java +++ b/src/main/java/com/compiler/StmtParser.java @@ -88,6 +88,13 @@ public ASTStmtNode parseStmt() throws Exception { } public ASTStmtNode parseFunctionStmt() throws Exception { + // functionDecl: FUNCTION IDENTIFIER RPAREN idList RPAREN LBRACE functionBody RBRACE SEMICOLON + // + // idList: IDENTIFIER idListPost | eps + // idListPost: eps | COMMA IDENFIER idListPost + // + //functionBody: RETURN expr | stmt functionBody + m_lexer.expect(Type.FUNCTION); String functionName = m_lexer.m_currentToken.m_value; m_lexer.expect(TokenIntf.Type.IDENT); @@ -107,6 +114,9 @@ public ASTStmtNode parseFunctionStmt() throws Exception { private List parseFunctionBody() throws Exception { List stmtList = new ArrayList<>(); while(m_lexer.m_currentToken.m_type != Type.RETURN){ + if(m_lexer.m_currentToken.m_type == Type.RBRACE){ + m_lexer.throwCompilerException("Invalid end of function body", "RETURN"); + } stmtList.add(parseStmt()); } stmtList.add(parseReturnStmt()); From ba004164b48a75c210fe0af81046f1d771719cec Mon Sep 17 00:00:00 2001 From: key-collector Date: Thu, 22 May 2025 17:23:06 +0200 Subject: [PATCH 2/8] minor optimization --- src/main/java/com/compiler/StmtParser.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/compiler/StmtParser.java b/src/main/java/com/compiler/StmtParser.java index d8a1e4c..98363a3 100644 --- a/src/main/java/com/compiler/StmtParser.java +++ b/src/main/java/com/compiler/StmtParser.java @@ -100,7 +100,7 @@ public ASTStmtNode parseFunctionStmt() throws Exception { m_lexer.expect(TokenIntf.Type.IDENT); m_lexer.expect(Type.LPAREN); List parameterList = parseParameterList(); - parameterList.forEach(e -> m_symbolTable.createSymbol(e)); + parameterList.forEach(m_symbolTable::createSymbol); m_lexer.expect(TokenIntf.Type.RPAREN); m_lexer.expect(TokenIntf.Type.LBRACE); From 1544c0ad97efd6ff7b8d42b4dfc98f3b2238fbfd Mon Sep 17 00:00:00 2001 From: key-collector Date: Thu, 22 May 2025 19:56:23 +0200 Subject: [PATCH 3/8] =?UTF-8?q?implement=20functions=20(finished)=20(not?= =?UTF-8?q?=20tested=20:P)=20--=20but=20min=C3=BC=C3=9F=20c:?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/InterpreterMain.java | 15 +++++++- src/main/java/com/StmtParserMain.java | 7 +++- .../com/compiler/ast/ASTCallExprNode.java | 36 +++++++++++++++++++ .../com/compiler/ast/ASTFunctionStmtNode.java | 34 +++++++++++++++--- .../com/compiler/ast/ASTReturnStmtNode.java | 12 +++++++ .../com/compiler/instr/InstrPopStack.java | 21 +++++++++++ .../compiler/instr/InstrPushCallStack.java | 19 ++++++++++ .../com/compiler/instr/InstrPushStack.java | 23 ++++++++++++ .../java/com/compiler/instr/InstrReturn.java | 19 ++++++++++ 9 files changed, 180 insertions(+), 6 deletions(-) create mode 100644 src/main/java/com/compiler/instr/InstrPopStack.java create mode 100644 src/main/java/com/compiler/instr/InstrPushCallStack.java create mode 100644 src/main/java/com/compiler/instr/InstrPushStack.java create mode 100644 src/main/java/com/compiler/instr/InstrReturn.java diff --git a/src/main/java/com/InterpreterMain.java b/src/main/java/com/InterpreterMain.java index 4b63dc6..4c9d2b3 100644 --- a/src/main/java/com/InterpreterMain.java +++ b/src/main/java/com/InterpreterMain.java @@ -7,7 +7,20 @@ public class InterpreterMain { public static void main(String[] args) throws Exception { String input = new String(""" { - PRINT 4 + 3 - 2; + + FUNCTION minüß(x){ + RETURN x - 1; + }; + + FUNCTION add(a,b){ + PRINT 42; + DECLARE c; + c = 2; + RETURN CALL minüß(CALL minüß(a+b + c)); + }; + + PRINT CALL add(1,2); + PRINT 1; } """); com.compiler.CompileEnv compileEnv = new com.compiler.CompileEnv(input, false); diff --git a/src/main/java/com/StmtParserMain.java b/src/main/java/com/StmtParserMain.java index 5dc6118..b0ac771 100644 --- a/src/main/java/com/StmtParserMain.java +++ b/src/main/java/com/StmtParserMain.java @@ -12,8 +12,13 @@ public static void main(String[] args) throws Exception { DECLARE b; a = 1 + 2; b = 5; + FUNCTION foo(c,d){ + RETURN 0; + }; + c = 1; + PRINT c; PRINT a ? b + 1 : -1; - PRINT 1 + 2; + PRINT CALL foo(a,b); PRINT 3 + 4; } """; diff --git a/src/main/java/com/compiler/ast/ASTCallExprNode.java b/src/main/java/com/compiler/ast/ASTCallExprNode.java index 864a8c8..8c03d41 100644 --- a/src/main/java/com/compiler/ast/ASTCallExprNode.java +++ b/src/main/java/com/compiler/ast/ASTCallExprNode.java @@ -1,5 +1,12 @@ package com.compiler.ast; +import com.compiler.InstrBlock; +import com.compiler.InstrIntf; +import com.compiler.instr.InstrJump; +import com.compiler.instr.InstrPopStack; +import com.compiler.instr.InstrPushCallStack; +import com.compiler.instr.InstrPushStack; + import java.io.OutputStreamWriter; import java.util.List; @@ -21,4 +28,33 @@ public int eval() { public void print(OutputStreamWriter outStream, String indent) throws Exception { } + + + /* + * 1. Argumente auf Stack pushen + * 2. Rücksprungadresse auf CallStack pushen + * 3. JumpInstr zum Function Body + * 4. Pop Instruction für Rückgabewert + */ + @Override + public InstrIntf codegen(com.compiler.CompileEnvIntf env) { + + // 1. + m_argumentList.stream() + .map(arg -> arg.codegen(env)) + .forEach(arg -> env.addInstr(new InstrPushStack(arg))); + + // 2. + env.addInstr(new InstrPushCallStack()); + + // 3. + InstrBlock functionBody = env.getFunctionTable().getFunction(m_funcName).m_body; + env.addInstr(new InstrJump(functionBody)); + + // 4. + InstrIntf popInstr = new InstrPopStack(); + env.addInstr(popInstr); + return popInstr; + } + } diff --git a/src/main/java/com/compiler/ast/ASTFunctionStmtNode.java b/src/main/java/com/compiler/ast/ASTFunctionStmtNode.java index 35c7d23..08a82d5 100644 --- a/src/main/java/com/compiler/ast/ASTFunctionStmtNode.java +++ b/src/main/java/com/compiler/ast/ASTFunctionStmtNode.java @@ -1,12 +1,13 @@ package com.compiler.ast; import java.io.OutputStreamWriter; +import java.util.Collections; import java.util.List; import com.compiler.CompileEnvIntf; -import com.compiler.FunctionInfo; -import com.compiler.FunctionTable; import com.compiler.InstrBlock; +import com.compiler.instr.InstrAssign; +import com.compiler.instr.InstrPopStack; public class ASTFunctionStmtNode extends ASTStmtNode { String m_functionName; @@ -25,11 +26,36 @@ public void execute(OutputStreamWriter out) { } + /* + * 1. momentanen Block speichern + * 2. Body Block der Function erstellen + * 3. Current Environment Block auf Body Block setzen + * 4. Assign Instructions der Variablen mit PopInstructions + * 5. Codegenerierung des Function Bodys + * 6. body Block in die FunctionTable eintragen + * 7. Current Environment Block zu ursprünglichen Block zuweisen + */ @Override public void codegen(CompileEnvIntf env) { - super.codegen(env); + InstrBlock exitBlock = env.getCurrentBlock(); + + InstrBlock bodyBlock = env.createBlock("function_"+m_functionName); + env.setCurrentBlock(bodyBlock); + Collections.reverse(m_parameterList); + for (String parameter : m_parameterList) { + InstrPopStack popInstr = new InstrPopStack(); + env.addInstr(popInstr); + env.addInstr(new InstrAssign(env.getSymbolTable().getSymbol(parameter), popInstr)); + } + m_functionBody.forEach(s -> s.codegen(env)); + + env.getFunctionTable().getFunction(m_functionName).m_body = bodyBlock; + + env.setCurrentBlock(exitBlock); } @Override - public void print(OutputStreamWriter outStream, String indent) throws Exception {} + public void print(OutputStreamWriter outStream, String indent) throws Exception { + + } } diff --git a/src/main/java/com/compiler/ast/ASTReturnStmtNode.java b/src/main/java/com/compiler/ast/ASTReturnStmtNode.java index a258aef..1eb695c 100644 --- a/src/main/java/com/compiler/ast/ASTReturnStmtNode.java +++ b/src/main/java/com/compiler/ast/ASTReturnStmtNode.java @@ -1,5 +1,11 @@ package com.compiler.ast; +import com.compiler.CompileEnvIntf; +import com.compiler.InstrIntf; +import com.compiler.instr.InstrJump; +import com.compiler.instr.InstrPushStack; +import com.compiler.instr.InstrReturn; + import java.io.OutputStreamWriter; public class ASTReturnStmtNode extends ASTStmtNode { @@ -18,4 +24,10 @@ public void execute(OutputStreamWriter out) { public void print(OutputStreamWriter outStream, String indent) throws Exception { } + @Override + public void codegen(CompileEnvIntf env) { + InstrIntf result = m_expr.codegen(env); + env.addInstr(new InstrPushStack(result)); + env.addInstr(new InstrReturn()); + } } diff --git a/src/main/java/com/compiler/instr/InstrPopStack.java b/src/main/java/com/compiler/instr/InstrPopStack.java new file mode 100644 index 0000000..cd59ea9 --- /dev/null +++ b/src/main/java/com/compiler/instr/InstrPopStack.java @@ -0,0 +1,21 @@ +package com.compiler.instr; + +import com.compiler.ExecutionEnvIntf; +import com.compiler.InstrIntf; + +import java.io.OutputStreamWriter; + +public class InstrPopStack extends InstrIntf { + + public InstrPopStack() {} + + @Override + public void execute(ExecutionEnvIntf env) throws Exception { + m_value = env.pop(); + } + + @Override + public void trace(OutputStreamWriter os) throws Exception { + os.write("POP_INTO " + m_value); + } +} diff --git a/src/main/java/com/compiler/instr/InstrPushCallStack.java b/src/main/java/com/compiler/instr/InstrPushCallStack.java new file mode 100644 index 0000000..bbed0c8 --- /dev/null +++ b/src/main/java/com/compiler/instr/InstrPushCallStack.java @@ -0,0 +1,19 @@ +package com.compiler.instr; + +import com.compiler.ExecutionEnvIntf; +import com.compiler.InstrIntf; + +import java.io.OutputStreamWriter; + +public class InstrPushCallStack extends InstrIntf { + @Override + public void execute(ExecutionEnvIntf env) throws Exception { + // maybe we need to advance by one iterator-thingy-stuff... + env.pushReturnAddr(env.getInstrIter()); + } + + @Override + public void trace(OutputStreamWriter os) throws Exception { + + } +} diff --git a/src/main/java/com/compiler/instr/InstrPushStack.java b/src/main/java/com/compiler/instr/InstrPushStack.java new file mode 100644 index 0000000..b42a292 --- /dev/null +++ b/src/main/java/com/compiler/instr/InstrPushStack.java @@ -0,0 +1,23 @@ +package com.compiler.instr; + +import com.compiler.ExecutionEnvIntf; +import com.compiler.InstrIntf; + +import java.io.OutputStreamWriter; + +public class InstrPushStack extends InstrIntf { + InstrIntf m_instruction; + public InstrPushStack(InstrIntf instruction) { + m_instruction = instruction; + } + + @Override + public void execute(ExecutionEnvIntf env) throws Exception { + env.push(m_instruction.getValue()); + } + + @Override + public void trace(OutputStreamWriter os) throws Exception { + os.write("PUSH %%"+m_instruction.getId()); + } +} diff --git a/src/main/java/com/compiler/instr/InstrReturn.java b/src/main/java/com/compiler/instr/InstrReturn.java new file mode 100644 index 0000000..94d9f98 --- /dev/null +++ b/src/main/java/com/compiler/instr/InstrReturn.java @@ -0,0 +1,19 @@ +package com.compiler.instr; + +import com.compiler.ExecutionEnvIntf; +import com.compiler.InstrIntf; + +import java.io.OutputStreamWriter; + +public class InstrReturn extends InstrIntf { + @Override + public void execute(ExecutionEnvIntf env) throws Exception { + env.setInstrIter(env.popReturnAddr()); + //env.getInstrIter().next(); + } + + @Override + public void trace(OutputStreamWriter os) throws Exception { + + } +} From bbc639af975cd9273c021db4f6110ef0b7c3e0b9 Mon Sep 17 00:00:00 2001 From: key-collector Date: Thu, 22 May 2025 20:31:37 +0200 Subject: [PATCH 4/8] Add trace for all instructions --- src/main/java/com/compiler/instr/InstrPopStack.java | 4 +++- src/main/java/com/compiler/instr/InstrPushCallStack.java | 1 + src/main/java/com/compiler/instr/InstrPushStack.java | 4 +++- src/main/java/com/compiler/instr/InstrReturn.java | 1 + 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/compiler/instr/InstrPopStack.java b/src/main/java/com/compiler/instr/InstrPopStack.java index cd59ea9..cc5eedd 100644 --- a/src/main/java/com/compiler/instr/InstrPopStack.java +++ b/src/main/java/com/compiler/instr/InstrPopStack.java @@ -16,6 +16,8 @@ public void execute(ExecutionEnvIntf env) throws Exception { @Override public void trace(OutputStreamWriter os) throws Exception { - os.write("POP_INTO " + m_value); + os.write(String.format("%%%d = POP\n", + m_id + )); } } diff --git a/src/main/java/com/compiler/instr/InstrPushCallStack.java b/src/main/java/com/compiler/instr/InstrPushCallStack.java index bbed0c8..23814ff 100644 --- a/src/main/java/com/compiler/instr/InstrPushCallStack.java +++ b/src/main/java/com/compiler/instr/InstrPushCallStack.java @@ -14,6 +14,7 @@ public void execute(ExecutionEnvIntf env) throws Exception { @Override public void trace(OutputStreamWriter os) throws Exception { + os.write("PUSH_RETURN_ADDR\n"); } } diff --git a/src/main/java/com/compiler/instr/InstrPushStack.java b/src/main/java/com/compiler/instr/InstrPushStack.java index b42a292..8fa0c61 100644 --- a/src/main/java/com/compiler/instr/InstrPushStack.java +++ b/src/main/java/com/compiler/instr/InstrPushStack.java @@ -18,6 +18,8 @@ public void execute(ExecutionEnvIntf env) throws Exception { @Override public void trace(OutputStreamWriter os) throws Exception { - os.write("PUSH %%"+m_instruction.getId()); + os.write(String.format("PUSH %%%d\n", + m_instruction.getId() + )); } } diff --git a/src/main/java/com/compiler/instr/InstrReturn.java b/src/main/java/com/compiler/instr/InstrReturn.java index 94d9f98..a644256 100644 --- a/src/main/java/com/compiler/instr/InstrReturn.java +++ b/src/main/java/com/compiler/instr/InstrReturn.java @@ -14,6 +14,7 @@ public void execute(ExecutionEnvIntf env) throws Exception { @Override public void trace(OutputStreamWriter os) throws Exception { + os.write("JUMP POP_RETURN_ADDR"); } } From 2ea4945a28cc0686b03de70ffc9206ea8d42cd16 Mon Sep 17 00:00:00 2001 From: key-collector Date: Thu, 22 May 2025 20:32:28 +0200 Subject: [PATCH 5/8] remove unneeded comments --- src/main/java/com/compiler/instr/InstrPushCallStack.java | 1 - src/main/java/com/compiler/instr/InstrReturn.java | 1 - 2 files changed, 2 deletions(-) diff --git a/src/main/java/com/compiler/instr/InstrPushCallStack.java b/src/main/java/com/compiler/instr/InstrPushCallStack.java index 23814ff..ecc3689 100644 --- a/src/main/java/com/compiler/instr/InstrPushCallStack.java +++ b/src/main/java/com/compiler/instr/InstrPushCallStack.java @@ -8,7 +8,6 @@ public class InstrPushCallStack extends InstrIntf { @Override public void execute(ExecutionEnvIntf env) throws Exception { - // maybe we need to advance by one iterator-thingy-stuff... env.pushReturnAddr(env.getInstrIter()); } diff --git a/src/main/java/com/compiler/instr/InstrReturn.java b/src/main/java/com/compiler/instr/InstrReturn.java index a644256..9935c09 100644 --- a/src/main/java/com/compiler/instr/InstrReturn.java +++ b/src/main/java/com/compiler/instr/InstrReturn.java @@ -9,7 +9,6 @@ public class InstrReturn extends InstrIntf { @Override public void execute(ExecutionEnvIntf env) throws Exception { env.setInstrIter(env.popReturnAddr()); - //env.getInstrIter().next(); } @Override From 2e96c390ff0722f16b6710b121c04f6a0d8d3ec3 Mon Sep 17 00:00:00 2001 From: Finn Hennemann Date: Fri, 23 May 2025 09:03:48 +0200 Subject: [PATCH 6/8] some reformatting and optimization --- .../java/com/compiler/ExpressionParser.java | 6 +- src/main/java/com/compiler/StmtParser.java | 22 ++++---- .../com/compiler/ast/ASTCallExprNode.java | 33 +++++------ .../com/compiler/ast/ASTFunctionStmtNode.java | 55 ++++++++++--------- .../com/compiler/ast/ASTReturnStmtNode.java | 14 ++--- ...rPopStack.java => InstrPopValueStack.java} | 4 +- ...ushStack.java => InstrPushValueStack.java} | 4 +- .../java/com/compiler/instr/InstrReturn.java | 1 - 8 files changed, 68 insertions(+), 71 deletions(-) rename src/main/java/com/compiler/instr/{InstrPopStack.java => InstrPopValueStack.java} (83%) rename src/main/java/com/compiler/instr/{InstrPushStack.java => InstrPushValueStack.java} (82%) diff --git a/src/main/java/com/compiler/ExpressionParser.java b/src/main/java/com/compiler/ExpressionParser.java index 3231250..a286432 100644 --- a/src/main/java/com/compiler/ExpressionParser.java +++ b/src/main/java/com/compiler/ExpressionParser.java @@ -227,17 +227,18 @@ ASTExprNode getAndOrExpr() throws Exception { } ASTExprNode getCallExpr() throws Exception { + // callExpr: CALL IDENTIFIER LPAREN argList RPAREN if(m_lexer.m_currentToken.m_type != TokenIntf.Type.CALL) { return getParantheseExpr(); }else { m_lexer.advance(); String funcName = m_lexer.m_currentToken.m_value; + m_lexer.expect(TokenIntf.Type.IDENT); FunctionInfo functionInfo = m_functionTable.getFunction(funcName); if(functionInfo == null) { m_lexer.throwCompilerException(String.format("%s not declared" , funcName), ""); } - m_lexer.expect(TokenIntf.Type.IDENT); m_lexer.expect(TokenIntf.Type.LPAREN); List argumentList = getArgumentList(); if(argumentList.size() != functionInfo.varNames.size()){ @@ -251,8 +252,9 @@ ASTExprNode getCallExpr() throws Exception { } private List getArgumentList() throws Exception { + // argList: expr argListPost | eps + // argListPost: eps | COMMA expr argListPost List argumentList = new ArrayList<>(); - if(m_lexer.m_currentToken.m_type == Type.RPAREN){ return argumentList; }else { diff --git a/src/main/java/com/compiler/StmtParser.java b/src/main/java/com/compiler/StmtParser.java index 98363a3..30d122e 100644 --- a/src/main/java/com/compiler/StmtParser.java +++ b/src/main/java/com/compiler/StmtParser.java @@ -88,30 +88,30 @@ public ASTStmtNode parseStmt() throws Exception { } public ASTStmtNode parseFunctionStmt() throws Exception { - // functionDecl: FUNCTION IDENTIFIER RPAREN idList RPAREN LBRACE functionBody RBRACE SEMICOLON - // - // idList: IDENTIFIER idListPost | eps - // idListPost: eps | COMMA IDENFIER idListPost - // - //functionBody: RETURN expr | stmt functionBody - + // functionDecl: FUNCTION IDENTIFIER RPAREN paramList RPAREN LBRACE functionBody RBRACE SEMICOLON m_lexer.expect(Type.FUNCTION); String functionName = m_lexer.m_currentToken.m_value; + m_lexer.expect(TokenIntf.Type.IDENT); m_lexer.expect(Type.LPAREN); + List parameterList = parseParameterList(); parameterList.forEach(m_symbolTable::createSymbol); - m_lexer.expect(TokenIntf.Type.RPAREN); + m_functionTable.createFunction(functionName, parameterList); + m_lexer.expect(TokenIntf.Type.RPAREN); m_lexer.expect(TokenIntf.Type.LBRACE); + List functionBody = parseFunctionBody(); + m_lexer.expect(TokenIntf.Type.RBRACE); m_lexer.expect(Type.SEMICOLON); - m_functionTable.createFunction(functionName, parameterList); + return new ASTFunctionStmtNode(functionName, parameterList, functionBody); } private List parseFunctionBody() throws Exception { + // functionBody: returnStmt | stmt functionBody List stmtList = new ArrayList<>(); while(m_lexer.m_currentToken.m_type != Type.RETURN){ if(m_lexer.m_currentToken.m_type == Type.RBRACE){ @@ -124,6 +124,7 @@ private List parseFunctionBody() throws Exception { } private ASTStmtNode parseReturnStmt() throws Exception { + // returnStmt: RETURN expr m_lexer.expect(Type.RETURN); ASTStmtNode returnStmtNode = new ASTReturnStmtNode(m_exprParser.getQuestionMarkExpr()); m_lexer.expect(Type.SEMICOLON); @@ -131,6 +132,8 @@ private ASTStmtNode parseReturnStmt() throws Exception { } private List parseParameterList() throws Exception { + // paramList: IDENTIFIER paramListPos | eps + // paramListPost: eps | COMMA IDENFIER paramListPost List parameterList = new ArrayList<>(); if(m_lexer.m_currentToken.m_type != Type.IDENT){ return parameterList; @@ -149,7 +152,6 @@ private List parseParameterList() throws Exception { public ASTStmtNode parsePrintStmt() throws Exception { m_lexer.expect(Type.PRINT); - ASTPrintStmtNode astPrintStmtNode = new ASTPrintStmtNode(m_exprParser.getQuestionMarkExpr()); m_lexer.expect(Type.SEMICOLON); return astPrintStmtNode; diff --git a/src/main/java/com/compiler/ast/ASTCallExprNode.java b/src/main/java/com/compiler/ast/ASTCallExprNode.java index 8c03d41..2076e55 100644 --- a/src/main/java/com/compiler/ast/ASTCallExprNode.java +++ b/src/main/java/com/compiler/ast/ASTCallExprNode.java @@ -3,9 +3,9 @@ import com.compiler.InstrBlock; import com.compiler.InstrIntf; import com.compiler.instr.InstrJump; -import com.compiler.instr.InstrPopStack; +import com.compiler.instr.InstrPopValueStack; import com.compiler.instr.InstrPushCallStack; -import com.compiler.instr.InstrPushStack; +import com.compiler.instr.InstrPushValueStack; import java.io.OutputStreamWriter; import java.util.List; @@ -21,38 +21,31 @@ public ASTCallExprNode(String funcName, List argumentList) { @Override public int eval() { - return 0; + return 0; // not implemented, as Call Expression only returns a value with prior function stmt } @Override public void print(OutputStreamWriter outStream, String indent) throws Exception { - + outStream.write(indent); + outStream.write("ASTCallExpressionNode "); + outStream.write("\n"); + for (ASTExprNode astExprNode : m_argumentList) { + astExprNode.print(outStream, indent + " "); + } } - - /* - * 1. Argumente auf Stack pushen - * 2. Rücksprungadresse auf CallStack pushen - * 3. JumpInstr zum Function Body - * 4. Pop Instruction für Rückgabewert - */ @Override public InstrIntf codegen(com.compiler.CompileEnvIntf env) { - - // 1. m_argumentList.stream() .map(arg -> arg.codegen(env)) - .forEach(arg -> env.addInstr(new InstrPushStack(arg))); + .forEach(argInstr -> env.addInstr(new InstrPushValueStack(argInstr))); - // 2. env.addInstr(new InstrPushCallStack()); - // 3. - InstrBlock functionBody = env.getFunctionTable().getFunction(m_funcName).m_body; - env.addInstr(new InstrJump(functionBody)); + InstrBlock functionBodyBlock = env.getFunctionTable().getFunction(m_funcName).m_body; + env.addInstr(new InstrJump(functionBodyBlock)); - // 4. - InstrIntf popInstr = new InstrPopStack(); + InstrIntf popInstr = new InstrPopValueStack(); env.addInstr(popInstr); return popInstr; } diff --git a/src/main/java/com/compiler/ast/ASTFunctionStmtNode.java b/src/main/java/com/compiler/ast/ASTFunctionStmtNode.java index 08a82d5..80e3140 100644 --- a/src/main/java/com/compiler/ast/ASTFunctionStmtNode.java +++ b/src/main/java/com/compiler/ast/ASTFunctionStmtNode.java @@ -7,7 +7,7 @@ import com.compiler.CompileEnvIntf; import com.compiler.InstrBlock; import com.compiler.instr.InstrAssign; -import com.compiler.instr.InstrPopStack; +import com.compiler.instr.InstrPopValueStack; public class ASTFunctionStmtNode extends ASTStmtNode { String m_functionName; @@ -23,39 +23,40 @@ public ASTFunctionStmtNode(String functionName, List parameterList, List @Override public void execute(OutputStreamWriter out) { - + // nothing to do at runtime } - /* - * 1. momentanen Block speichern - * 2. Body Block der Function erstellen - * 3. Current Environment Block auf Body Block setzen - * 4. Assign Instructions der Variablen mit PopInstructions - * 5. Codegenerierung des Function Bodys - * 6. body Block in die FunctionTable eintragen - * 7. Current Environment Block zu ursprünglichen Block zuweisen - */ @Override public void codegen(CompileEnvIntf env) { - InstrBlock exitBlock = env.getCurrentBlock(); - - InstrBlock bodyBlock = env.createBlock("function_"+m_functionName); - env.setCurrentBlock(bodyBlock); - Collections.reverse(m_parameterList); - for (String parameter : m_parameterList) { - InstrPopStack popInstr = new InstrPopStack(); - env.addInstr(popInstr); - env.addInstr(new InstrAssign(env.getSymbolTable().getSymbol(parameter), popInstr)); - } - m_functionBody.forEach(s -> s.codegen(env)); - - env.getFunctionTable().getFunction(m_functionName).m_body = bodyBlock; - - env.setCurrentBlock(exitBlock); + InstrBlock codegenEntryBlock = env.getCurrentBlock(); + + InstrBlock functionBodyBlock = env.createBlock("function_"+m_functionName); + env.setCurrentBlock(functionBodyBlock); + + m_parameterList.stream() + .sorted(Collections.reverseOrder()) + .map(env.getSymbolTable()::getSymbol) + .forEach(parameter -> { + InstrPopValueStack popStackInstr = new InstrPopValueStack(); + env.addInstr(popStackInstr); + InstrAssign assignInstr = new InstrAssign(parameter, popStackInstr); + env.addInstr(assignInstr); + }); + + m_functionBody.forEach(stmt -> stmt.codegen(env)); + + env.getFunctionTable().getFunction(m_functionName).m_body = functionBodyBlock; + + env.setCurrentBlock(codegenEntryBlock); } @Override public void print(OutputStreamWriter outStream, String indent) throws Exception { - + outStream.write(indent); + outStream.write("ASTFunctionStmtNode "); + outStream.write("\n"); + for (ASTStmtNode astStmtNode : m_functionBody) { + astStmtNode.print(outStream, indent + " "); + } } } diff --git a/src/main/java/com/compiler/ast/ASTReturnStmtNode.java b/src/main/java/com/compiler/ast/ASTReturnStmtNode.java index 1eb695c..39e6205 100644 --- a/src/main/java/com/compiler/ast/ASTReturnStmtNode.java +++ b/src/main/java/com/compiler/ast/ASTReturnStmtNode.java @@ -1,9 +1,7 @@ package com.compiler.ast; import com.compiler.CompileEnvIntf; -import com.compiler.InstrIntf; -import com.compiler.instr.InstrJump; -import com.compiler.instr.InstrPushStack; +import com.compiler.instr.InstrPushValueStack; import com.compiler.instr.InstrReturn; import java.io.OutputStreamWriter; @@ -17,17 +15,19 @@ public ASTReturnStmtNode(ASTExprNode questionMarkExpr) { @Override public void execute(OutputStreamWriter out) { - + // nothing to do } @Override public void print(OutputStreamWriter outStream, String indent) throws Exception { - + outStream.write(indent); + outStream.write("ASTReturnStmtNode "); + outStream.write("\n"); + m_expr.print(outStream, indent + " "); } @Override public void codegen(CompileEnvIntf env) { - InstrIntf result = m_expr.codegen(env); - env.addInstr(new InstrPushStack(result)); + env.addInstr(new InstrPushValueStack(m_expr.codegen(env))); env.addInstr(new InstrReturn()); } } diff --git a/src/main/java/com/compiler/instr/InstrPopStack.java b/src/main/java/com/compiler/instr/InstrPopValueStack.java similarity index 83% rename from src/main/java/com/compiler/instr/InstrPopStack.java rename to src/main/java/com/compiler/instr/InstrPopValueStack.java index cc5eedd..6ca190b 100644 --- a/src/main/java/com/compiler/instr/InstrPopStack.java +++ b/src/main/java/com/compiler/instr/InstrPopValueStack.java @@ -5,9 +5,9 @@ import java.io.OutputStreamWriter; -public class InstrPopStack extends InstrIntf { +public class InstrPopValueStack extends InstrIntf { - public InstrPopStack() {} + public InstrPopValueStack() {} @Override public void execute(ExecutionEnvIntf env) throws Exception { diff --git a/src/main/java/com/compiler/instr/InstrPushStack.java b/src/main/java/com/compiler/instr/InstrPushValueStack.java similarity index 82% rename from src/main/java/com/compiler/instr/InstrPushStack.java rename to src/main/java/com/compiler/instr/InstrPushValueStack.java index 8fa0c61..c117416 100644 --- a/src/main/java/com/compiler/instr/InstrPushStack.java +++ b/src/main/java/com/compiler/instr/InstrPushValueStack.java @@ -5,9 +5,9 @@ import java.io.OutputStreamWriter; -public class InstrPushStack extends InstrIntf { +public class InstrPushValueStack extends InstrIntf { InstrIntf m_instruction; - public InstrPushStack(InstrIntf instruction) { + public InstrPushValueStack(InstrIntf instruction) { m_instruction = instruction; } diff --git a/src/main/java/com/compiler/instr/InstrReturn.java b/src/main/java/com/compiler/instr/InstrReturn.java index 9935c09..31034c5 100644 --- a/src/main/java/com/compiler/instr/InstrReturn.java +++ b/src/main/java/com/compiler/instr/InstrReturn.java @@ -14,6 +14,5 @@ public void execute(ExecutionEnvIntf env) throws Exception { @Override public void trace(OutputStreamWriter os) throws Exception { os.write("JUMP POP_RETURN_ADDR"); - } } From acd252e61049bee543efcb576bdd352ddc295bcb Mon Sep 17 00:00:00 2001 From: Finn Hennemann Date: Fri, 23 May 2025 09:12:31 +0200 Subject: [PATCH 7/8] add tests for Function Stmts --- .../InterpreterTestFunctionStmts.java | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 src/test/java/com/compiler/InterpreterTestFunctionStmts.java diff --git a/src/test/java/com/compiler/InterpreterTestFunctionStmts.java b/src/test/java/com/compiler/InterpreterTestFunctionStmts.java new file mode 100644 index 0000000..8bd96b1 --- /dev/null +++ b/src/test/java/com/compiler/InterpreterTestFunctionStmts.java @@ -0,0 +1,99 @@ +package com.compiler; + +import org.junit.Test; + +public class InterpreterTestFunctionStmts extends InterpreterTestBase { + + @Test + public void testProgrammSimple() throws Exception { + String programm = """ + { + FUNCTION minüß3(x) { + EXECUTE 3 TIMES { + x = x - 1; + }; + RETURN x; + }; + PRINT CALL minüß3(45); + } + """; + String expectedOutput = """ + 42 + """; + testInterpreter(programm, expectedOutput); + } + + @Test + public void testFunction1NoParams() throws Exception { + String programm = """ + { + FUNCTION myFct() { + RETURN 1; + }; + PRINT CALL myFct(); + } + """; + String expectedOutput = """ + 1 + """; + testInterpreter(programm, expectedOutput); + } + + @Test + public void testFunction2WithParams() throws Exception { + String programm = """ + { + FUNCTION myFct(a, b) { + RETURN a + b; + }; + PRINT CALL myFct(1, 2); + } + """; + String expectedOutput = """ + 3 + """; + testInterpreter(programm, expectedOutput); + } + + @Test + public void testFunction3MultipleCalls() throws Exception { + String programm = """ + { + FUNCTION myFct1(a, b) { + DECLARE c; + c = a + 2 * b; + RETURN c; + }; + FUNCTION myFct2(d) { + RETURN d + 1; + }; + DECLARE e; + e = CALL myFct1(1, 2) + CALL myFct2(3); + PRINT e; + } + """; + String expectedOutput = """ + 9 + """; + testInterpreter(programm, expectedOutput); + } + + @Test + public void testFunction4CallInReturn() throws Exception { + String programm = """ + { + FUNCTION myFct1(a, b) { + RETURN a * b; + }; + FUNCTION myFct2(c) { + RETURN CALL myFct1(c, c + 1); + }; + PRINT CALL myFct2(5); + } + """; + String expectedOutput = """ + 30 + """; + testInterpreter(programm, expectedOutput); + } +} From 2f0c6235b7d7645485c353840b7c46c1802841e4 Mon Sep 17 00:00:00 2001 From: Finn Hennemann Date: Fri, 23 May 2025 23:16:31 +0200 Subject: [PATCH 8/8] reset Interpreter main --- src/main/java/com/InterpreterMain.java | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/InterpreterMain.java b/src/main/java/com/InterpreterMain.java index 4c9d2b3..08912f3 100644 --- a/src/main/java/com/InterpreterMain.java +++ b/src/main/java/com/InterpreterMain.java @@ -7,20 +7,7 @@ public class InterpreterMain { public static void main(String[] args) throws Exception { String input = new String(""" { - - FUNCTION minüß(x){ - RETURN x - 1; - }; - - FUNCTION add(a,b){ - PRINT 42; - DECLARE c; - c = 2; - RETURN CALL minüß(CALL minüß(a+b + c)); - }; - - PRINT CALL add(1,2); - PRINT 1; + PRINT 4 + 3 - 2; } """); com.compiler.CompileEnv compileEnv = new com.compiler.CompileEnv(input, false); @@ -36,4 +23,4 @@ FUNCTION add(a,b){ outStream.flush(); } -} +} \ No newline at end of file