Merge branch 'feature/variable-declaration' into 'master'
Feature/variable declaration See merge request mkais001/klang!3
This commit is contained in:
@@ -23,6 +23,7 @@ braced_block
|
|||||||
statement
|
statement
|
||||||
: print
|
: print
|
||||||
| if_statement
|
| if_statement
|
||||||
|
| variable_declaration
|
||||||
| variable_assignment
|
| variable_assignment
|
||||||
| return_statement
|
| return_statement
|
||||||
;
|
;
|
||||||
@@ -35,6 +36,10 @@ if_statement
|
|||||||
: IF OPAR cond = expression CPAR then = braced_block (ELSE (alt = braced_block | elif = 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
|
variable_assignment
|
||||||
: IDENT EQUAL expression SCOL
|
: IDENT EQUAL expression SCOL
|
||||||
;
|
;
|
||||||
@@ -72,6 +77,7 @@ IF: 'if';
|
|||||||
ELSE: 'else';
|
ELSE: 'else';
|
||||||
FUNC: 'function';
|
FUNC: 'function';
|
||||||
RETURN: 'return';
|
RETURN: 'return';
|
||||||
|
LET: 'let';
|
||||||
|
|
||||||
SCOL: ';';
|
SCOL: ';';
|
||||||
OBRK: '{';
|
OBRK: '{';
|
||||||
|
|||||||
@@ -1,11 +1,16 @@
|
|||||||
package de.hsrm.compiler.Klang;
|
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.*;
|
||||||
import de.hsrm.compiler.Klang.nodes.expressions.*;
|
import de.hsrm.compiler.Klang.nodes.expressions.*;
|
||||||
import de.hsrm.compiler.Klang.nodes.statements.*;
|
import de.hsrm.compiler.Klang.nodes.statements.*;
|
||||||
import de.hsrm.compiler.Klang.types.Type;
|
import de.hsrm.compiler.Klang.types.Type;
|
||||||
|
|
||||||
public class ContextAnalysis extends KlangBaseVisitor<Node> {
|
public class ContextAnalysis extends KlangBaseVisitor<Node> {
|
||||||
|
Set<String> vars = new HashSet<>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Node visitProgram(KlangParser.ProgramContext ctx) {
|
public Node visitProgram(KlangParser.ProgramContext ctx) {
|
||||||
FunctionDefinition[] funcs = new FunctionDefinition[ctx.functionDef().size()];
|
FunctionDefinition[] funcs = new FunctionDefinition[ctx.functionDef().size()];
|
||||||
@@ -52,9 +57,31 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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
|
@Override
|
||||||
public Node visitVariable_assignment(KlangParser.Variable_assignmentContext ctx) {
|
public Node visitVariable_assignment(KlangParser.Variable_assignmentContext ctx) {
|
||||||
String name = ctx.IDENT().getText();
|
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());
|
Expression expression = (Expression) this.visit(ctx.expression());
|
||||||
return new VariableAssignment(name, expression);
|
return new VariableAssignment(name, expression);
|
||||||
}
|
}
|
||||||
@@ -97,6 +124,12 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Node visitVariable(KlangParser.VariableContext ctx) {
|
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());
|
return new Variable(ctx.IDENT().getText());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,9 +148,16 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
|
|||||||
@Override
|
@Override
|
||||||
public Node visitFunctionDef(KlangParser.FunctionDefContext ctx) {
|
public Node visitFunctionDef(KlangParser.FunctionDefContext ctx) {
|
||||||
String name = ctx.funcName.getText();
|
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()];
|
String[] params = new String[ctx.parameters().IDENT().size()];
|
||||||
for (int i = 0; i < ctx.parameters().IDENT().size(); i++) {
|
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());
|
Node block = this.visit(ctx.braced_block());
|
||||||
return new FunctionDefinition(name, params, (Block) block);
|
return new FunctionDefinition(name, params, (Block) block);
|
||||||
|
|||||||
@@ -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> R welcome(Visitor<R> v) {
|
||||||
|
return v.visit(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -101,6 +101,17 @@ public class EvalVisitor implements Visitor<Value> {
|
|||||||
return null;
|
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
|
@Override
|
||||||
public Value visit(VariableAssignment e) {
|
public Value visit(VariableAssignment e) {
|
||||||
Value result = e.expression.welcome(this);
|
Value result = e.expression.welcome(this);
|
||||||
|
|||||||
@@ -162,6 +162,18 @@ public class GenASM implements Visitor<Void> {
|
|||||||
throw new RuntimeException("Das machen wir mal nicht, ne?!");
|
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
|
@Override
|
||||||
public Void visit(VariableAssignment e) {
|
public Void visit(VariableAssignment e) {
|
||||||
e.expression.welcome(this);
|
e.expression.welcome(this);
|
||||||
|
|||||||
@@ -84,8 +84,13 @@ class GetVars implements Visitor<Void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Void visit(VariableAssignment e) {
|
public Void visit(VariableDeclaration e) {
|
||||||
vars.add(e.name);
|
vars.add(e.name);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Void visit(VariableAssignment e) {
|
||||||
e.expression.welcome(this);
|
e.expression.welcome(this);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -153,6 +153,18 @@ public class PrettyPrintVisitor implements Visitor<Void> {
|
|||||||
return null;
|
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
|
@Override
|
||||||
public Void visit(VariableAssignment e) {
|
public Void visit(VariableAssignment e) {
|
||||||
ex.write(e.name + " = ");
|
ex.write(e.name + " = ");
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ public interface Visitor<R> {
|
|||||||
R visit(NegateExpression e);
|
R visit(NegateExpression e);
|
||||||
R visit(IfStatement e);
|
R visit(IfStatement e);
|
||||||
R visit(PrintStatement e);
|
R visit(PrintStatement e);
|
||||||
|
R visit(VariableDeclaration e);
|
||||||
R visit(VariableAssignment e);
|
R visit(VariableAssignment e);
|
||||||
R visit(ReturnStatement e);
|
R visit(ReturnStatement e);
|
||||||
R visit(Block e);
|
R visit(Block e);
|
||||||
|
|||||||
Reference in New Issue
Block a user