From 13caee066751673b8dc46cca316e869c00577c8f Mon Sep 17 00:00:00 2001 From: Marvin Kaiser Date: Mon, 18 Nov 2019 16:39:12 +0100 Subject: [PATCH] Added function call and function definition --- .../antlr4/de/hsrm/compiler/Klang/Klang.g4 | 29 +++- .../hsrm/compiler/Klang/ContextAnalysis.java | 41 ++++-- .../Klang/nodes/FunctionDefinition.java | 22 +++ .../de/hsrm/compiler/Klang/nodes/Program.java | 20 +++ .../Klang/nodes/expressions/FunctionCall.java | 19 +++ .../compiler/Klang/visitors/EvalVisitor.java | 135 ++++++++++-------- .../Klang/visitors/PrettyPrintVisitor.java | 47 ++++++ .../hsrm/compiler/Klang/visitors/Visitor.java | 5 + 8 files changed, 242 insertions(+), 76 deletions(-) create mode 100644 src/main/java/de/hsrm/compiler/Klang/nodes/FunctionDefinition.java create mode 100644 src/main/java/de/hsrm/compiler/Klang/nodes/Program.java create mode 100644 src/main/java/de/hsrm/compiler/Klang/nodes/expressions/FunctionCall.java diff --git a/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 b/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 index d4249ea..9d76fbe 100644 --- a/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 +++ b/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 @@ -1,11 +1,19 @@ grammar Klang; parse - : block + : program ; -block - : statement+ +program + : functionDef* expression + ; + +functionDef + : FUNC funcName=IDENT OPAR parameters CPAR braced_block + ; + +parameters + : (IDENT (COMMA IDENT)*)? ; braced_block @@ -31,6 +39,15 @@ expression | atom MOD atom #moduloExpression | SUB atom #unaryNegateExpression | atom #atomExpression + | functionCall #functionCallExpression + ; + +functionCall + : IDENT OPAR arguments CPAR SCOL + ; + +arguments + : (expression (COMMA expression)*)? ; atom @@ -40,12 +57,14 @@ atom PRINT: 'print'; IF: 'if'; ELSE: 'else'; +FUNC: 'function'; SCOL: ';'; OBRK: '{'; CBRK: '}'; OPAR: '('; CPAR: ')'; +COMMA: ','; MULT: '*'; ADD: '+'; @@ -56,6 +75,10 @@ INTEGER_LITERAL : [0-9]+ ; +IDENT + : [a-zA-Z][a-zA-Z0-9]* + ; + WS : [ \t\r\n] -> skip ; diff --git a/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java b/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java index 328ff76..7efd07f 100644 --- a/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java +++ b/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java @@ -7,17 +7,13 @@ import de.hsrm.compiler.Klang.types.Type; public class ContextAnalysis extends KlangBaseVisitor { @Override - public Node visitBlock(KlangParser.BlockContext ctx) { - Statement[] statements = new Statement[ctx.statement().size()]; - - for (int i = 0; i < ctx.statement().size(); i++) { - Node currentStatement = this.visit(ctx.statement(i)); - statements[i] = (Statement) currentStatement; + public Node visitProgram(KlangParser.ProgramContext ctx) { + FunctionDefinition[] funcs = new FunctionDefinition[ctx.functionDef().size()]; + for (int i = 0; i < ctx.functionDef().size(); i++) { + funcs[i] = (FunctionDefinition) this.visit(ctx.functionDef(i)); } - - Block result = new Block(statements); - result.type = null; - return result; + Expression expression = (Expression) this.visit(ctx.expression()); + return new Program(funcs, expression); } @Override @@ -28,7 +24,7 @@ public class ContextAnalysis extends KlangBaseVisitor { Node currentStatement = this.visit(ctx.statement(i)); statements[i] = (Statement) currentStatement; } - + Block result = new Block(statements); result.type = null; return result; @@ -48,7 +44,7 @@ public class ContextAnalysis extends KlangBaseVisitor { if (ctx.alt != null) { Node elseBlock = this.visit(ctx.alt); return new IfStatement((Expression) condition, (Block) thenBlock, (Block) elseBlock); - } else if(ctx.elif != null) { + } else if (ctx.elif != null) { Node elif = this.visit(ctx.elif); return new IfStatement((Expression) condition, (Block) thenBlock, (IfStatement) elif); } else { @@ -102,4 +98,25 @@ public class ContextAnalysis extends KlangBaseVisitor { n.type = Type.getIntegerType(); return n; } + + @Override + public Node visitFunctionDef(KlangParser.FunctionDefContext ctx) { + String name = ctx.funcName.getText(); + String[] params = new String[ctx.parameters().IDENT().size()]; + for (int i = 0; i < ctx.parameters().IDENT().size(); i++) { + params[i] = ctx.parameters().IDENT(i).getText(); + } + Node block = this.visit(ctx.braced_block()); + return new FunctionDefinition(name, params, (Block) block); + } + + @Override + public Node visitFunctionCallExpression(KlangParser.FunctionCallExpressionContext ctx) { + String name = ctx.functionCall().IDENT().getText(); + Expression[] args = new Expression[ctx.functionCall().arguments().expression().size()]; + for (int i = 0; i < ctx.functionCall().arguments().expression().size(); i++) { + args[i] = (Expression) this.visit(ctx.functionCall().arguments().expression(i)); + } + return new FunctionCall(name, args); + } } \ No newline at end of file diff --git a/src/main/java/de/hsrm/compiler/Klang/nodes/FunctionDefinition.java b/src/main/java/de/hsrm/compiler/Klang/nodes/FunctionDefinition.java new file mode 100644 index 0000000..afc2af6 --- /dev/null +++ b/src/main/java/de/hsrm/compiler/Klang/nodes/FunctionDefinition.java @@ -0,0 +1,22 @@ +package de.hsrm.compiler.Klang.nodes; + +import de.hsrm.compiler.Klang.visitors.Visitor; + +public class FunctionDefinition extends Node { + + public String name; + public String[] parameters; + public Block block; + + public FunctionDefinition(String name, String[] parameters, Block block) { + this.name = name; + this.parameters = parameters; + this.block = block; + } + + + @Override + public R welcome(Visitor v) { + return v.visit(this); + } +} \ No newline at end of file diff --git a/src/main/java/de/hsrm/compiler/Klang/nodes/Program.java b/src/main/java/de/hsrm/compiler/Klang/nodes/Program.java new file mode 100644 index 0000000..e02d893 --- /dev/null +++ b/src/main/java/de/hsrm/compiler/Klang/nodes/Program.java @@ -0,0 +1,20 @@ +package de.hsrm.compiler.Klang.nodes; + +import de.hsrm.compiler.Klang.nodes.expressions.Expression; +import de.hsrm.compiler.Klang.visitors.Visitor; + +public class Program extends Node { + + public FunctionDefinition[] funcs; + public Expression expression; + + public Program(FunctionDefinition[] funcs, Expression expression) { + this.funcs = funcs; + this.expression = expression; + } + + @Override + public R welcome(Visitor v) { + return v.visit(this); + } +} \ No newline at end of file diff --git a/src/main/java/de/hsrm/compiler/Klang/nodes/expressions/FunctionCall.java b/src/main/java/de/hsrm/compiler/Klang/nodes/expressions/FunctionCall.java new file mode 100644 index 0000000..feec2af --- /dev/null +++ b/src/main/java/de/hsrm/compiler/Klang/nodes/expressions/FunctionCall.java @@ -0,0 +1,19 @@ +package de.hsrm.compiler.Klang.nodes.expressions; + +import de.hsrm.compiler.Klang.visitors.Visitor; + +public class FunctionCall extends Expression { + + public String name; + public Expression[] arguments; + + public FunctionCall(String name, Expression[] arguments) { + this.name = name; + this.arguments = arguments; + } + + @Override + public R welcome(Visitor v) { + return v.visit(this); + } +} \ No newline at end of file diff --git a/src/main/java/de/hsrm/compiler/Klang/visitors/EvalVisitor.java b/src/main/java/de/hsrm/compiler/Klang/visitors/EvalVisitor.java index 52fca42..fedb689 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/EvalVisitor.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/EvalVisitor.java @@ -2,76 +2,89 @@ package de.hsrm.compiler.Klang.visitors; import de.hsrm.compiler.Klang.Value; import de.hsrm.compiler.Klang.nodes.Block; +import de.hsrm.compiler.Klang.nodes.FunctionDefinition; import de.hsrm.compiler.Klang.nodes.expressions.*; import de.hsrm.compiler.Klang.nodes.statements.*; public class EvalVisitor implements Visitor { - @Override - public Value visit(IntegerExpression e) { - return new Value(e.value); + @Override + public Value visit(IntegerExpression e) { + return new Value(e.value); + } + + @Override + public Value visit(MultiplicativeExpression e) { + Value a = e.lhs.welcome(this); + Value b = e.rhs.welcome(this); + return new Value(a.asInteger() * b.asInteger()); + } + + @Override + public Value visit(AdditiveExpression e) { + Value a = e.lhs.welcome(this); + Value b = e.rhs.welcome(this); + return new Value(a.asInteger() + b.asInteger()); + } + + @Override + public Value visit(ModuloExpression e) { + Value a = e.lhs.welcome(this); + Value b = e.rhs.welcome(this); + return new Value(a.asInteger() % b.asInteger()); + } + + @Override + public Value visit(NegateExpression e) { + Value a = e.lhs.welcome(this); + return new Value(-a.asInteger()); + } + + @Override + public Value visit(IfStatement e) { + // In the future we have to make sure that the + // value is actually a type that we can use as boolean + Value condition = e.cond.welcome(this); + + if (condition.asInteger() != 0) { + e.then.welcome(this); + } else if (e.alt != null) { + e.alt.welcome(this); + } else if (e.elif != null) { + e.elif.welcome(this); } - @Override - public Value visit(MultiplicativeExpression e) { - Value a = e.lhs.welcome(this); - Value b = e.rhs.welcome(this); - return new Value(a.asInteger() * b.asInteger()); + return null; + } + + @Override + public Value visit(PrintStatement e) { + Value value = e.expression.welcome(this); + + // In the future we have to determine of which type the value is + // before calling an "asX()" method + System.out.println(value.asInteger()); + return null; + } + + @Override + public Value visit(Block e) { + for (var stmt : e.statements) { + stmt.welcome(this); } + return null; + } - @Override - public Value visit(AdditiveExpression e) { - Value a = e.lhs.welcome(this); - Value b = e.rhs.welcome(this); - return new Value(a.asInteger() + b.asInteger()); - } + @Override + public Value visit(FunctionDefinition e) { + // TODO Auto-generated method stub + return null; + } - @Override - public Value visit(ModuloExpression e) { - Value a = e.lhs.welcome(this); - Value b = e.rhs.welcome(this); - return new Value(a.asInteger() % b.asInteger()); - } - - @Override - public Value visit(NegateExpression e) { - Value a = e.lhs.welcome(this); - return new Value(-a.asInteger()); - } - - @Override - public Value visit(IfStatement e) { - // In the future we have to make sure that the - // value is actually a type that we can use as boolean - Value condition = e.cond.welcome(this); - - if (condition.asInteger() != 0) { - e.then.welcome(this); - } else if (e.alt != null) { - e.alt.welcome(this); - } else if (e.elif != null) { - e.elif.welcome(this); - } - - return null; - } - - @Override - public Value visit(PrintStatement e) { - Value value = e.expression.welcome(this); - - // In the future we have to determine of which type the value is - // before calling an "asX()" method - System.out.println(value.asInteger()); - return null; - } - - @Override - public Value visit(Block e) { - for (var stmt: e.statements) { - stmt.welcome(this); - } - return null; - } + @Override + public Value visit(FunctionCall e) { + // TODO Auto-generated method stub + return null; + } } \ No newline at end of file diff --git a/src/main/java/de/hsrm/compiler/Klang/visitors/PrettyPrintVisitor.java b/src/main/java/de/hsrm/compiler/Klang/visitors/PrettyPrintVisitor.java index ada0573..8fd2849 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/PrettyPrintVisitor.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/PrettyPrintVisitor.java @@ -53,6 +53,17 @@ public class PrettyPrintVisitor implements Visitor { this.ex = ex; } + @Override + public Void visit(Program e) { + for (var funcDef : e.funcs) { + funcDef.welcome(this); + ex.nl(); + ex.nl(); + } + e.expression.welcome(this); + return null; + } + @Override public Void visit(IntegerExpression e) { ex.write(e.value); @@ -128,4 +139,40 @@ public class PrettyPrintVisitor implements Visitor { return null; } + @Override + public Void visit(FunctionDefinition e) { + ex.write("function "); + ex.write(e.name); + ex.write(" ("); + boolean first = true; + for (String param : e.parameters) { + if (!first) { + ex.write(", "); + } else { + first = false; + } + ex.write(param); + } + ex.write(") "); + e.block.welcome(this); + return null; + } + + @Override + public Void visit(FunctionCall e) { + ex.write(e.name); + ex.write("("); + boolean first = true; + for (Expression arg : e.arguments) { + if (!first) { + ex.write(", "); + } else { + first = false; + } + arg.welcome(this); + } + ex.write(");"); + return null; + } + } \ No newline at end of file diff --git a/src/main/java/de/hsrm/compiler/Klang/visitors/Visitor.java b/src/main/java/de/hsrm/compiler/Klang/visitors/Visitor.java index 56e317e..29017d2 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/Visitor.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/Visitor.java @@ -1,6 +1,8 @@ package de.hsrm.compiler.Klang.visitors; import de.hsrm.compiler.Klang.nodes.Block; +import de.hsrm.compiler.Klang.nodes.FunctionDefinition; +import de.hsrm.compiler.Klang.nodes.Program; import de.hsrm.compiler.Klang.nodes.expressions.*; import de.hsrm.compiler.Klang.nodes.statements.*; @@ -13,4 +15,7 @@ public interface Visitor { R visit(IfStatement e); R visit(PrintStatement e); R visit(Block e); + R visit(FunctionDefinition e); + R visit(FunctionCall e); + R visit(Program e); } \ No newline at end of file