diff --git a/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 b/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 index a6dbbb7..b266c6c 100644 --- a/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 +++ b/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 @@ -23,6 +23,7 @@ braced_block statement : print | if_statement + | variable_declaration | variable_assignment | return_statement ; @@ -33,7 +34,11 @@ print if_statement : IF OPAR cond = expression CPAR then = braced_block (ELSE (alt = braced_block | elif = if_statement) )? - ; + ; + +variable_declaration + : LET IDENT (EQUAL expression)? SCOL + ; variable_assignment : IDENT EQUAL expression SCOL @@ -72,6 +77,7 @@ IF: 'if'; ELSE: 'else'; FUNC: 'function'; RETURN: 'return'; +LET: 'let'; SCOL: ';'; OBRK: '{'; diff --git a/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java b/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java index a41643b..e17066d 100644 --- a/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java +++ b/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java @@ -1,11 +1,16 @@ package de.hsrm.compiler.Klang; +import java.util.Set; +import java.util.HashSet; + import de.hsrm.compiler.Klang.nodes.*; import de.hsrm.compiler.Klang.nodes.expressions.*; import de.hsrm.compiler.Klang.nodes.statements.*; import de.hsrm.compiler.Klang.types.Type; public class ContextAnalysis extends KlangBaseVisitor { + Set vars = new HashSet<>(); + @Override public Node visitProgram(KlangParser.ProgramContext ctx) { FunctionDefinition[] funcs = new FunctionDefinition[ctx.functionDef().size()]; @@ -52,16 +57,38 @@ public class ContextAnalysis extends KlangBaseVisitor { } } + @Override + public Node visitVariable_declaration(KlangParser.Variable_declarationContext ctx) { + String name = ctx.IDENT().getText(); + + if (this.vars.contains(name)) { + throw new RuntimeException("Redeclaration of variable with name \"" + name +"\"."); + } + + this.vars.add(name); + + if (ctx.expression() != null) { + return new VariableDeclaration(name, (Expression) this.visit(ctx.expression())); + } else { + return new VariableDeclaration(name); + } + } + @Override public Node visitVariable_assignment(KlangParser.Variable_assignmentContext ctx) { String name = ctx.IDENT().getText(); + + if (!this.vars.contains(name)) { + throw new RuntimeException("Variable with name \"" + name + "\" not defined."); + } + Expression expression = (Expression) this.visit(ctx.expression()); return new VariableAssignment(name, expression); } @Override public Node visitReturn_statement(KlangParser.Return_statementContext ctx) { - Expression expression = (Expression) this.visit(ctx.expression()); + Expression expression = (Expression) this.visit(ctx.expression()); return new ReturnStatement(expression); } @@ -97,6 +124,12 @@ public class ContextAnalysis extends KlangBaseVisitor { @Override public Node visitVariable(KlangParser.VariableContext ctx) { + String name = ctx.IDENT().getText(); + + if (!this.vars.contains(name)) { + throw new RuntimeException("Variable with name \"" + name + "\" not defined."); + } + return new Variable(ctx.IDENT().getText()); } @@ -115,9 +148,16 @@ public class ContextAnalysis extends KlangBaseVisitor { @Override public Node visitFunctionDef(KlangParser.FunctionDefContext ctx) { String name = ctx.funcName.getText(); + + // Create a new set for the variables of the current function + // this will be filled in the variable declaration visitor aswell + this.vars = new HashSet<>(); + 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(); + String paramName = ctx.parameters().IDENT(i).getText(); + params[i] = paramName; + this.vars.add(paramName); // add the param as a variable } Node block = this.visit(ctx.braced_block()); return new FunctionDefinition(name, params, (Block) block); diff --git a/src/main/java/de/hsrm/compiler/Klang/nodes/statements/VariableDeclaration.java b/src/main/java/de/hsrm/compiler/Klang/nodes/statements/VariableDeclaration.java new file mode 100644 index 0000000..623cffd --- /dev/null +++ b/src/main/java/de/hsrm/compiler/Klang/nodes/statements/VariableDeclaration.java @@ -0,0 +1,23 @@ +package de.hsrm.compiler.Klang.nodes.statements; + +import de.hsrm.compiler.Klang.nodes.expressions.Expression; +import de.hsrm.compiler.Klang.visitors.Visitor; + +public class VariableDeclaration extends Statement { + public String name; + public Expression expression; + + public VariableDeclaration(String name, Expression expression) { + this.name = name; + this.expression = expression; + } + + public VariableDeclaration(String name) { + this(name, null); + } + + @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 7142326..09d870a 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/EvalVisitor.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/EvalVisitor.java @@ -101,6 +101,17 @@ public class EvalVisitor implements Visitor { return null; } + @Override + public Value visit(VariableDeclaration e) { + Value initialValue = null; + if (e.expression != null) { + initialValue = e.expression.welcome(this); + } + + this.env.put(e.name, initialValue); + return null; + } + @Override public Value visit(VariableAssignment e) { Value result = e.expression.welcome(this); diff --git a/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java b/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java index cc01a65..38e62f4 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java @@ -162,6 +162,18 @@ public class GenASM implements Visitor { throw new RuntimeException("Das machen wir mal nicht, ne?!"); } + @Override + public Void visit(VariableDeclaration e) { + // If there is an initialization present, + // push it to the location of the local var + if (e.expression != null) { + e.expression.welcome(this); + int offset = this.env.get(e.name); + this.ex.write(" movq %rax, " + offset + "(%rbp)\n"); + } + return null; + } + @Override public Void visit(VariableAssignment e) { e.expression.welcome(this); diff --git a/src/main/java/de/hsrm/compiler/Klang/visitors/GetVars.java b/src/main/java/de/hsrm/compiler/Klang/visitors/GetVars.java index 8c7444d..1bef69b 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/GetVars.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/GetVars.java @@ -84,8 +84,13 @@ class GetVars implements Visitor { } @Override - public Void visit(VariableAssignment e) { + public Void visit(VariableDeclaration e) { vars.add(e.name); + return null; + } + + @Override + public Void visit(VariableAssignment e) { e.expression.welcome(this); return null; } 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 0e74dc0..009c74c 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/PrettyPrintVisitor.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/PrettyPrintVisitor.java @@ -153,6 +153,18 @@ public class PrettyPrintVisitor implements Visitor { return null; } + @Override + public Void visit(VariableDeclaration e) { + ex.write("let " + e.name); + + if (e.expression != null) { + ex.write(" = " + e.expression.welcome(this)); + } + + ex.write(";"); + return null; + } + @Override public Void visit(VariableAssignment e) { ex.write(e.name + " = "); 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 662500d..6b944d7 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/Visitor.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/Visitor.java @@ -17,6 +17,7 @@ public interface Visitor { R visit(NegateExpression e); R visit(IfStatement e); R visit(PrintStatement e); + R visit(VariableDeclaration e); R visit(VariableAssignment e); R visit(ReturnStatement e); R visit(Block e);