diff --git a/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 b/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 index 9d76fbe..d895218 100644 --- a/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 +++ b/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 @@ -52,6 +52,7 @@ arguments atom : INTEGER_LITERAL #intAtom + | IDENT # variable ; PRINT: 'print'; diff --git a/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java b/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java index 7efd07f..f2a62d2 100644 --- a/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java +++ b/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java @@ -87,6 +87,11 @@ public class ContextAnalysis extends KlangBaseVisitor { return result; } + @Override + public Node visitVariable(KlangParser.VariableContext ctx) { + return new Variable(ctx.IDENT().getText()); + } + @Override public Node visitAtomExpression(KlangParser.AtomExpressionContext ctx) { return this.visit(ctx.atom()); diff --git a/src/main/java/de/hsrm/compiler/Klang/nodes/expressions/Variable.java b/src/main/java/de/hsrm/compiler/Klang/nodes/expressions/Variable.java new file mode 100644 index 0000000..fd99e82 --- /dev/null +++ b/src/main/java/de/hsrm/compiler/Klang/nodes/expressions/Variable.java @@ -0,0 +1,18 @@ +package de.hsrm.compiler.Klang.nodes.expressions; + +import de.hsrm.compiler.Klang.visitors.Visitor; + +public class Variable extends Expression { + + public String name; + + public Variable(String name) { + this.name = name; + } + + @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 fedb689..cd639a2 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/EvalVisitor.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/EvalVisitor.java @@ -1,13 +1,20 @@ package de.hsrm.compiler.Klang.visitors; +import java.util.HashMap; +import java.util.Map; + 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.Program; import de.hsrm.compiler.Klang.nodes.expressions.*; import de.hsrm.compiler.Klang.nodes.statements.*; public class EvalVisitor implements Visitor { + Map funcs = new HashMap<>(); + Map env = new HashMap<>(); + @Override public Value visit(IntegerExpression e) { return new Value(e.value); @@ -40,6 +47,17 @@ public class EvalVisitor implements Visitor { return new Value(-a.asInteger()); } + @Override + public Value visit(Variable e) { + Value result = this.env.get(e.name); + + if (result == null) { + throw new RuntimeException("Variable with name " +e.name + " not found."); + } + + return result; + } + @Override public Value visit(IfStatement e) { // In the future we have to make sure that the @@ -69,22 +87,55 @@ public class EvalVisitor implements Visitor { @Override public Value visit(Block e) { + Value result = null; for (var stmt : e.statements) { - stmt.welcome(this); + result = stmt.welcome(this); } - return null; + return result; } @Override public Value visit(FunctionDefinition e) { - // TODO Auto-generated method stub - return null; + // Ein Eval über eine FunDef macht keinen Sinn + throw new RuntimeException("Wir sind im Eval und visiten eine Funktionsdefinition.. WUT?!"); } @Override public Value visit(FunctionCall e) { - // TODO Auto-generated method stub - return null; + // Die funktionsdefinition speichern + FunctionDefinition func = this.funcs.get(e.name); + + // Stelle sicher, dass die Länge der argumente und parameter übereinstimmen + if (e.arguments.length != func.parameters.length) { + throw new RuntimeException("Error with function call " +e.name + ": Number of parameters wrong"); + } + + // Baue ein neues environment + Map newEnv = new HashMap<>(); + for (int i = 0; i < func.parameters.length; i++) { + newEnv.put(func.parameters[i], e.arguments[i].welcome(this)); + } + var oldEnv = this.env; + this.env = newEnv; + + // Execute + Value result = func.block.welcome(this); + + // Das alte env wiederherstellen + this.env = oldEnv; + + return result; + } + + @Override + public Value visit(Program e) { + // Funktionsdefinitionen für die Auswertung + // von Funktionsaufrufen speichern + for (var funcDef: e.funcs) { + this.funcs.put(funcDef.name, funcDef); + } + + return e.expression.welcome(this); } } \ 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 8fd2849..5f655d4 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/PrettyPrintVisitor.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/PrettyPrintVisitor.java @@ -55,13 +55,13 @@ public class PrettyPrintVisitor implements Visitor { @Override public Void visit(Program e) { - for (var funcDef : e.funcs) { - funcDef.welcome(this); - ex.nl(); - ex.nl(); - } - e.expression.welcome(this); - return null; + for (var funcDef : e.funcs) { + funcDef.welcome(this); + ex.nl(); + ex.nl(); + } + e.expression.welcome(this); + return null; } @Override @@ -139,40 +139,46 @@ 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); + @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; } - 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); + @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; + } + + @Override + public Void visit(Variable e) { + ex.write(e.name); + return null; } - 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 29017d2..7c2efd8 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/Visitor.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/Visitor.java @@ -8,6 +8,7 @@ import de.hsrm.compiler.Klang.nodes.statements.*; public interface Visitor { R visit(IntegerExpression e); + R visit(Variable e); R visit(MultiplicativeExpression e); R visit(AdditiveExpression e); R visit(NegateExpression e);