Merge branch '24-structs' into 'master'

Resolve "Structs"

Closes #24

See merge request mkais001/klang!17
This commit is contained in:
Dennis Kaiser
2020-03-09 14:43:17 +01:00
30 changed files with 1199 additions and 19 deletions

View File

@@ -8,6 +8,8 @@ import de.hsrm.compiler.Klang.nodes.Block;
import de.hsrm.compiler.Klang.nodes.FunctionDefinition;
import de.hsrm.compiler.Klang.nodes.Parameter;
import de.hsrm.compiler.Klang.nodes.Program;
import de.hsrm.compiler.Klang.nodes.StructDefinition;
import de.hsrm.compiler.Klang.nodes.StructField;
import de.hsrm.compiler.Klang.nodes.expressions.*;
import de.hsrm.compiler.Klang.nodes.loops.DoWhileLoop;
import de.hsrm.compiler.Klang.nodes.loops.ForLoop;
@@ -18,7 +20,13 @@ import de.hsrm.compiler.Klang.types.Type;
public class EvalVisitor implements Visitor<Value> {
Map<String, FunctionDefinition> funcs = new HashMap<>();
Map<String, StructDefinition> structs;
Map<String, Value> env = new HashMap<>();
Map<String, Map<String, Value>> heap = new HashMap<>();
public EvalVisitor(Map<String, StructDefinition> structs) {
this.structs = structs;
}
@Override
public Value visit(IntegerExpression e) {
@@ -463,4 +471,70 @@ public class EvalVisitor implements Visitor<Value> {
return null;
}
@Override
public Value visit(StructDefinition e) {
// We get these from a previous visitor
return null;
}
@Override
public Value visit(StructField e) {
// Nothing to do here...
return null;
}
@Override
public Value visit(StructFieldAccessExpression e) {
Value var = this.env.get(e.varName);
Map<String, Value> struct = var.asStruct();
Value currentValue = struct.get(e.path[0]);
for (int i = 1; i < e.path.length; i++) {
currentValue = currentValue.asStruct().get(e.path[i]);
}
return currentValue;
}
@Override
public Value visit(ConstructorCall e) {
StructDefinition structDef = this.structs.get(e.structName);
Map<String, Value> struct = new HashMap<>();
for (int i = 0; i < e.args.length; i++) {
var arg = e.args[i].welcome(this);
struct.put(structDef.fields[i].name, arg);
}
return new Value(struct);
}
@Override
public Value visit(NullExpression e) {
return null;
}
@Override
public Value visit(DestructorCall e) {
this.env.remove(e.name);
return null;
}
@Override
public Value visit(FieldAssignment e) {
Value val = this.env.get(e.varName);
String fieldNameToUpdate = e.path[e.path.length - 1];
// Find the struct that holds the field to be updated
Map<String, Value> struct = val.asStruct();
for (int i = 0; i < e.path.length - 1; i++) {
struct = struct.get(e.path[i]).asStruct();
}
// if we are here, struct contains a reference to the struct that holds the field to be updated
struct.put(fieldNameToUpdate, e.expression.welcome(this));
return null;
}
}

View File

@@ -7,6 +7,7 @@ import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import de.hsrm.compiler.Klang.helper.Helper;
import de.hsrm.compiler.Klang.nodes.*;
import de.hsrm.compiler.Klang.nodes.expressions.*;
import de.hsrm.compiler.Klang.nodes.loops.DoWhileLoop;
@@ -107,6 +108,7 @@ public class GenASM implements Visitor<Void> {
private FloatWriter fw = new FloatWriter();
private String mainName;
Map<String, Integer> env = new HashMap<>();
Map<String, StructDefinition> structs;
Set<String> vars;
String[] registers = { "%rdi", "%rsi", "%rdx", "%rcx", "%r8", "%r9" };
String[] floatRegisters = { "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7" };
@@ -147,14 +149,15 @@ public class GenASM implements Visitor<Void> {
return false;
}
}
public GenASM(ExWriter ex, String mainName) {
public GenASM(ExWriter ex, String mainName, Map<String, StructDefinition> structs) {
this.ex = ex;
this.mainName = mainName;
this.structs = structs;
}
public GenASM(ExWriter ex) {
this.ex = ex;
this.mainName = "main";
public GenASM(ExWriter ex, Map<String, StructDefinition> structs) {
this(ex, "main", structs);
}
@Override
@@ -790,4 +793,115 @@ public class GenASM implements Visitor<Void> {
return null;
}
@Override
public Void visit(StructDefinition e) {
// We get these from a previous visitor
return null;
}
@Override
public Void visit(StructField e) {
// Nothing to do here...
return null;
}
@Override
public Void visit(StructFieldAccessExpression e) {
var structDef = this.structs.get(e.structName);
int offset = this.env.get(e.varName);
// move struct address into rax
this.ex.write(" movq " + offset + "(%rbp), %rax\n");
// "follow" the first path element by moving the referenced value into rax
this.ex.write(" movq " + Helper.getFieldOffset(structDef, e.path[0]) + "(%rax), %rax\n");
for (int i = 1; i < e.path.length; i++) {
// "follow" the current path element
structDef = this.structs.get(structDef.fields[Helper.getFieldIndex(structDef, e.path[i - 1])].type.getName());
this.ex.write(" movq " + Helper.getFieldOffset(structDef, e.path[i]) + "(%rax), %rax\n");
}
// desired value now in rax
// push rax to xmm0 if the result type is a float
if (e.type.equals(Type.getFloatType())) {
this.ex.write(" movq %rax, %xmm0\n");
}
return null;
}
@Override
public Void visit(ConstructorCall e) {
// push arguments onto the stack
for (var arg: e.args) {
arg.welcome(this);
// move float values from xmm0 to rax first
if (arg.type.equals(Type.getFloatType())) {
this.ex.write(" movq %xmm0, %rax\n");
}
this.ex.write(" pushq %rax\n");
}
// allocate heap memory by calling malloc
var structDef = this.structs.get(e.structName);
this.ex.write(" movl $" + Helper.getFieldSizeBytes(structDef) + ", %edi\n");
this.ex.write(" call malloc@PLT\n"); // struct address now in rax
// push args into struct memory, last arg is ontop of the stack
for (int i = e.args.length - 1; i >= 0; i--) {
this.ex.write(" popq " + Helper.getFieldOffset(structDef, i) + "(%rax)\n");
}
return null;
}
@Override
public Void visit(NullExpression e) {
this.ex.write(" movq $0, %rax\n");
return null;
}
@Override
public Void visit(DestructorCall e) {
this.ex.write(" movq " +this.env.get(e.name) + "(%rbp), %rdi\n");
this.ex.write(" call free@PLT\n");
return null;
}
@Override
public Void visit(FieldAssignment e) {
var structDef = this.structs.get(e.structName);
int offset = this.env.get(e.varName);
String fieldNameToUpdate = e.path[e.path.length - 1];
e.expression.welcome(this);
// Move it from xmm0 rax if its a flaot
if (e.expression.type.equals(Type.getFloatType())) {
this.ex.write(" movq %xmm0, %rax\n");
}
// Push the expression onto the stack
this.ex.write(" pushq %rax\n");
// move struct address into rax
this.ex.write(" movq " + offset + "(%rbp), %rax\n");
// If there are at least two elements in the path,
// move the address of the next referenced struct into rax
for (int i = 1; i < e.path.length - 1; i++) {
structDef = this.structs.get(structDef.fields[Helper.getFieldIndex(structDef, e.path[i - 1])].type.getName());
this.ex.write(" movq " + Helper.getFieldOffset(structDef, e.path[i]) + "(%rax), %rax\n");
}
// pop the expression that is ontop of the stack into the field of the struct that has to be updated
this.ex.write(" popq " + Helper.getFieldOffset(structDef, fieldNameToUpdate) + "(%rax)\n");
this.ex.write(" movq $0, %rax\n"); // clear rax sind an assignment has no result
return null;
}
}

View File

@@ -234,4 +234,38 @@ class GetVars implements Visitor<Void> {
return null;
}
@Override
public Void visit(StructDefinition e) {
return null;
}
@Override
public Void visit(StructField e) {
return null;
}
@Override
public Void visit(StructFieldAccessExpression e) {
return null;
}
@Override
public Void visit(ConstructorCall e) {
return null;
}
@Override
public Void visit(NullExpression e) {
return null;
}
@Override
public Void visit(DestructorCall e) {
return null;
}
@Override
public Void visit(FieldAssignment e) {
return null;
}
}

View File

@@ -61,6 +61,13 @@ public class PrettyPrintVisitor implements Visitor<Void> {
ex.nl();
ex.nl();
}
for (var structDef: e.structs.values()) {
structDef.welcome(this);
ex.nl();
ex.nl();
}
e.expression.welcome(this);
ex.write(";");
return null;
@@ -370,4 +377,76 @@ public class PrettyPrintVisitor implements Visitor<Void> {
return null;
}
@Override
public Void visit(StructDefinition e) {
ex.write("struct " + e.name + " {");
ex.addIndent();
for(var field: e.fields) {
ex.nl();
field.welcome(this);
}
ex.subIndent();
ex.nl();
ex.write("}");
return null;
}
@Override
public Void visit(StructField e) {
ex.write(e.name +": " + e.type.getName() + ";");
return null;
}
@Override
public Void visit(StructFieldAccessExpression e) {
ex.write(e.varName);
for (int i = 0; i < e.path.length; i++) {
ex.write(".");
ex.write(e.path[i]);
}
return null;
}
@Override
public Void visit(ConstructorCall e) {
ex.write("create " + e.structName + "(");
boolean first = true;
for (Expression arg : e.args) {
if (!first) {
ex.write(", ");
} else {
first = false;
}
arg.welcome(this);
}
ex.write(")");
return null;
}
@Override
public Void visit(NullExpression e) {
ex.write("null");
return null;
}
@Override
public Void visit(DestructorCall e) {
ex.write("destroy " + e.name + ";");
return null;
}
@Override
public Void visit(FieldAssignment e) {
ex.write(e.varName);
for (int i = 0; i < e.path.length; i++) {
ex.write(".");
ex.write(e.path[i]);
}
ex.write(" = ");
e.expression.welcome(this);
ex.write(";");
return null;
}
}

View File

@@ -4,6 +4,8 @@ import de.hsrm.compiler.Klang.nodes.Block;
import de.hsrm.compiler.Klang.nodes.FunctionDefinition;
import de.hsrm.compiler.Klang.nodes.Parameter;
import de.hsrm.compiler.Klang.nodes.Program;
import de.hsrm.compiler.Klang.nodes.StructDefinition;
import de.hsrm.compiler.Klang.nodes.StructField;
import de.hsrm.compiler.Klang.nodes.expressions.*;
import de.hsrm.compiler.Klang.nodes.loops.*;
import de.hsrm.compiler.Klang.nodes.statements.*;
@@ -11,7 +13,7 @@ import de.hsrm.compiler.Klang.nodes.statements.*;
public interface Visitor<R> {
R visit(OrExpression e);
R visit(AndExpression e);
R visit (NotExpression e);
R visit(NotExpression e);
R visit(IntegerExpression e);
R visit(FloatExpression e);
R visit(BooleanExpression e);
@@ -40,4 +42,11 @@ public interface Visitor<R> {
R visit(FunctionCall e);
R visit(Program e);
R visit(Parameter e);
R visit(StructDefinition e);
R visit(StructField e);
R visit(StructFieldAccessExpression e);
R visit(ConstructorCall e);
R visit(NullExpression e);
R visit(DestructorCall e);
R visit(FieldAssignment e);
}