From 0316a7d4bf0a5382e97b5442979fc7a6aeb25522 Mon Sep 17 00:00:00 2001 From: Marvin Kaiser Date: Tue, 3 Mar 2020 20:45:55 +0100 Subject: [PATCH] 25: Start adding Float Type --- .../antlr4/de/hsrm/compiler/Klang/Klang.g4 | 8 + .../hsrm/compiler/Klang/ContextAnalysis.java | 105 +++++- .../java/de/hsrm/compiler/Klang/Value.java | 12 + .../nodes/expressions/FloatExpression.java | 16 + .../hsrm/compiler/Klang/types/FloatType.java | 40 +++ .../compiler/Klang/types/IntegerType.java | 7 +- .../compiler/Klang/types/NumericType.java | 8 + .../compiler/Klang/types/PrimitiveType.java | 8 + .../de/hsrm/compiler/Klang/types/Type.java | 6 + .../compiler/Klang/visitors/EvalVisitor.java | 229 +++++++++++++- .../hsrm/compiler/Klang/visitors/GenASM.java | 298 ++++++++++++++---- .../hsrm/compiler/Klang/visitors/GetVars.java | 12 +- .../Klang/visitors/PrettyPrintVisitor.java | 6 + .../hsrm/compiler/Klang/visitors/Visitor.java | 1 + 14 files changed, 658 insertions(+), 98 deletions(-) create mode 100644 src/main/java/de/hsrm/compiler/Klang/nodes/expressions/FloatExpression.java create mode 100644 src/main/java/de/hsrm/compiler/Klang/types/FloatType.java create mode 100644 src/main/java/de/hsrm/compiler/Klang/types/NumericType.java diff --git a/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 b/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 index d4d6f03..e8021af 100644 --- a/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 +++ b/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 @@ -87,6 +87,7 @@ expression atom : INTEGER_LITERAL #intAtom | BOOLEAN_LITERAL #boolAtom + | FLOAT_LITERAL #floatAtom | IDENT #variable ; @@ -97,6 +98,7 @@ type_annotation type : INTEGER | BOOLEAN + | FLOAT ; functionCall @@ -131,6 +133,7 @@ WHILE: 'while'; DO: 'do'; FOR: 'for'; +PERIOD: '.'; COL: ':'; SCOL: ';'; OBRK: '{'; @@ -157,11 +160,16 @@ DIV: '/'; BOOLEAN: 'bool'; INTEGER: 'int'; +FLOAT: 'float'; INTEGER_LITERAL : [0-9]+ ; +FLOAT_LITERAL + : INTEGER_LITERAL PERIOD INTEGER_LITERAL + ; + BOOLEAN_LITERAL : 'true' | 'false' diff --git a/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java b/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java index cc191f3..c6104e8 100644 --- a/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java +++ b/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java @@ -18,6 +18,13 @@ public class ContextAnalysis extends KlangBaseVisitor { Map funcs; Type currentDeclaredReturnType; + private void checkNumeric(Node lhs, Node rhs, int line, int col) { + if (!lhs.type.isNumericType() || !rhs.type.isNumericType()) { + String error = "Only numeric types are allowed for this expression."; + throw new RuntimeException(Helper.getErrorPrefix(line, col) + error); + } + } + public ContextAnalysis(Map funcs) { this.funcs = funcs; } @@ -256,6 +263,10 @@ public class ContextAnalysis extends KlangBaseVisitor { result.type = Type.getBooleanType(); result.line = ctx.start.getLine(); result.col = ctx.start.getCharPositionInLine(); + if (!lhs.type.equals(Type.getBooleanType()) || !rhs.type.equals(Type.getBooleanType())) { + String error = "|| is only defined for bool."; + throw new RuntimeException(Helper.getErrorPrefix(result.line, result.col) + error); + } return result; } @@ -267,6 +278,10 @@ public class ContextAnalysis extends KlangBaseVisitor { result.type = Type.getBooleanType(); result.line = ctx.start.getLine(); result.col = ctx.start.getCharPositionInLine(); + if (!lhs.type.equals(Type.getBooleanType()) || !rhs.type.equals(Type.getBooleanType())) { + String error = "&& is only defined for bool."; + throw new RuntimeException(Helper.getErrorPrefix(result.line, result.col) + error); + } return result; } @@ -277,11 +292,15 @@ public class ContextAnalysis extends KlangBaseVisitor { int line = ctx.start.getLine(); int col = ctx.start.getCharPositionInLine(); AdditionExpression result = new AdditionExpression((Expression) lhs, (Expression) rhs); + try { result.type = lhs.type.combine(rhs.type); } catch (Exception e) { throw new RuntimeException(Helper.getErrorPrefix(line, col) + e.getMessage()); } + + checkNumeric(lhs, rhs, line, col); + result.line = ctx.start.getLine(); result.col = ctx.start.getCharPositionInLine(); return result; @@ -319,9 +338,10 @@ public class ContextAnalysis extends KlangBaseVisitor { int line = ctx.start.getLine(); int col = ctx.start.getCharPositionInLine(); - if (lhs.type != Type.getIntegerType() || rhs.type != Type.getIntegerType()) { - String error = "Both operants of this expression have to be a number."; - throw new RuntimeException(Helper.getErrorPrefix(line, col) + error); + try { + lhs.type.combine(rhs.type); + } catch (Exception e) { + throw new RuntimeException(Helper.getErrorPrefix(line, col) + e.getMessage()); } NotEqualityExpression result = new NotEqualityExpression((Expression) lhs, (Expression) rhs); @@ -338,11 +358,14 @@ public class ContextAnalysis extends KlangBaseVisitor { int line = ctx.start.getLine(); int col = ctx.start.getCharPositionInLine(); - if (lhs.type != Type.getIntegerType() || rhs.type != Type.getIntegerType()) { - String error = "Both operants of this expression have to be a number."; - throw new RuntimeException(Helper.getErrorPrefix(line, col) + error); + try { + lhs.type.combine(rhs.type); + } catch (Exception e) { + throw new RuntimeException(Helper.getErrorPrefix(line, col) + e.getMessage()); } + checkNumeric(lhs, rhs, line, col); + LTExpression result = new LTExpression((Expression) lhs, (Expression) rhs); result.type = Type.getBooleanType(); result.line = line; @@ -357,8 +380,14 @@ public class ContextAnalysis extends KlangBaseVisitor { int line = ctx.start.getLine(); int col = ctx.start.getCharPositionInLine(); - if (lhs.type != Type.getIntegerType() || rhs.type != Type.getIntegerType()) { - String error = "Both operants of this expression have to be a number."; + try { + lhs.type.combine(rhs.type); + } catch (Exception e) { + throw new RuntimeException(Helper.getErrorPrefix(line, col) + e.getMessage()); + } + + if (!lhs.type.isNumericType() || !rhs.type.isNumericType()) { + String error = "Only numeric types are allowed for this expression."; throw new RuntimeException(Helper.getErrorPrefix(line, col) + error); } @@ -376,11 +405,14 @@ public class ContextAnalysis extends KlangBaseVisitor { int line = ctx.start.getLine(); int col = ctx.start.getCharPositionInLine(); - if (lhs.type != Type.getIntegerType() || rhs.type != Type.getIntegerType()) { - String error = "Both operants of this expression have to be a number."; - throw new RuntimeException(Helper.getErrorPrefix(line, col) + error); + try { + lhs.type.combine(rhs.type); + } catch (Exception e) { + throw new RuntimeException(Helper.getErrorPrefix(line, col) + e.getMessage()); } + checkNumeric(lhs, rhs, line, col); + LTEExpression result = new LTEExpression((Expression) lhs, (Expression) rhs); result.type = Type.getBooleanType(); result.line = line; @@ -395,11 +427,14 @@ public class ContextAnalysis extends KlangBaseVisitor { int line = ctx.start.getLine(); int col = ctx.start.getCharPositionInLine(); - if (lhs.type != Type.getIntegerType() || rhs.type != Type.getIntegerType()) { - String error = "Both operants of this expression have to be a number."; - throw new RuntimeException(Helper.getErrorPrefix(line, col) + error); + try { + lhs.type.combine(rhs.type); + } catch (Exception e) { + throw new RuntimeException(Helper.getErrorPrefix(line, col) + e.getMessage()); } + checkNumeric(lhs, rhs, line, col); + GTEExpression result = new GTEExpression((Expression) lhs, (Expression) rhs); result.type = Type.getBooleanType(); result.line = line; @@ -414,11 +449,15 @@ public class ContextAnalysis extends KlangBaseVisitor { int line = ctx.start.getLine(); int col = ctx.start.getCharPositionInLine(); SubstractionExpression result = new SubstractionExpression((Expression) lhs, (Expression) rhs); + try { result.type = lhs.type.combine(rhs.type); } catch (Exception e) { throw new RuntimeException(Helper.getErrorPrefix(line, col) + e.getMessage()); } + + checkNumeric(lhs, rhs, line, col); + result.line = line; result.col = col; return result; @@ -431,11 +470,15 @@ public class ContextAnalysis extends KlangBaseVisitor { int line = ctx.start.getLine(); int col = ctx.start.getCharPositionInLine(); MultiplicationExpression result = new MultiplicationExpression((Expression) lhs, (Expression) rhs); + try { result.type = lhs.type.combine(rhs.type); } catch (Exception e) { throw new RuntimeException(Helper.getErrorPrefix(line, col) + e.getMessage()); } + + checkNumeric(lhs, rhs, line, col); + result.line = line; result.col = col; return result; @@ -448,11 +491,15 @@ public class ContextAnalysis extends KlangBaseVisitor { int line = ctx.start.getLine(); int col = ctx.start.getCharPositionInLine(); DivisionExpression result = new DivisionExpression((Expression) lhs, (Expression) rhs); + try { result.type = lhs.type.combine(rhs.type); } catch (Exception e) { throw new RuntimeException(Helper.getErrorPrefix(line, col) + e.getMessage()); } + + checkNumeric(lhs, rhs, line, col); + result.line = line; result.col = col; return result; @@ -465,11 +512,20 @@ public class ContextAnalysis extends KlangBaseVisitor { int line = ctx.start.getLine(); int col = ctx.start.getCharPositionInLine(); ModuloExpression result = new ModuloExpression((Expression) lhs, (Expression) rhs); + try { result.type = lhs.type.combine(rhs.type); } catch (Exception e) { throw new RuntimeException(Helper.getErrorPrefix(line, col) + e.getMessage()); } + + checkNumeric(lhs, rhs, line, col); + + if (lhs.type.equals(Type.getFloatType()) || rhs.type.equals(Type.getFloatType())) { + String error = "Only integers are allowed for modulo."; + throw new RuntimeException(Helper.getErrorPrefix(line, col) + error); + } + result.line = line; result.col = col; return result; @@ -482,6 +538,12 @@ public class ContextAnalysis extends KlangBaseVisitor { result.type = expression.type; result.line = ctx.start.getLine(); result.col = ctx.start.getCharPositionInLine(); + + if (!result.type.isNumericType()) { + String error = "Only numeric types are allowed for this expression."; + throw new RuntimeException(Helper.getErrorPrefix(result.line, result.col) + error); + } + return result; } @@ -492,6 +554,12 @@ public class ContextAnalysis extends KlangBaseVisitor { result.type = expression.type; result.line = ctx.start.getLine(); result.col = ctx.start.getCharPositionInLine(); + + if (!result.type.equals(Type.getBooleanType())) { + String error = "Only boolean type is allowed for this expression."; + throw new RuntimeException(Helper.getErrorPrefix(result.line, result.col) + error); + } + return result; } @@ -534,6 +602,15 @@ public class ContextAnalysis extends KlangBaseVisitor { return n; } + @Override + public Node visitFloatAtom(KlangParser.FloatAtomContext ctx) { + Node n = new FloatExpression(Double.parseDouble(ctx.getText())); + n.type = Type.getFloatType(); + n.line = ctx.start.getLine(); + n.col = ctx.start.getCharPositionInLine(); + return n; + } + @Override public Node visitBoolAtom(KlangParser.BoolAtomContext ctx) { Node n = new BooleanExpression(ctx.getText().equals("true") ? true : false); diff --git a/src/main/java/de/hsrm/compiler/Klang/Value.java b/src/main/java/de/hsrm/compiler/Klang/Value.java index 1b2eeb9..c0551c6 100644 --- a/src/main/java/de/hsrm/compiler/Klang/Value.java +++ b/src/main/java/de/hsrm/compiler/Klang/Value.java @@ -1,12 +1,20 @@ package de.hsrm.compiler.Klang; +import de.hsrm.compiler.Klang.types.Type; + public class Value { + public Type type; private Object value; public Value(Object value) { this.value = value; } + public Value(Object value, Type type) { + this.value = value; + this.type = type; + } + public Object asObject() { return this.value; } @@ -14,6 +22,10 @@ public class Value { public int asInteger() { return (int) this.value; } + + public double asFloat() { + return (double) this.value; + } public boolean asBoolean() { return (boolean) this.value; diff --git a/src/main/java/de/hsrm/compiler/Klang/nodes/expressions/FloatExpression.java b/src/main/java/de/hsrm/compiler/Klang/nodes/expressions/FloatExpression.java new file mode 100644 index 0000000..e7e4e09 --- /dev/null +++ b/src/main/java/de/hsrm/compiler/Klang/nodes/expressions/FloatExpression.java @@ -0,0 +1,16 @@ +package de.hsrm.compiler.Klang.nodes.expressions; + +import de.hsrm.compiler.Klang.visitors.Visitor; + +public class FloatExpression extends Expression { + public double value; + + public FloatExpression(double value) { + this.value = value; + } + + @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/types/FloatType.java b/src/main/java/de/hsrm/compiler/Klang/types/FloatType.java new file mode 100644 index 0000000..14f3fd7 --- /dev/null +++ b/src/main/java/de/hsrm/compiler/Klang/types/FloatType.java @@ -0,0 +1,40 @@ +package de.hsrm.compiler.Klang.types; + +public class FloatType extends NumericType { + + private static FloatType instance = null; + + public static FloatType getType() { + if (instance != null) { + return instance; + } + instance = new FloatType(); + return instance; + } + + @Override + public boolean isFloatType() { + return true; + } + + @Override + public String getName() { + return "float"; + } + + @Override + public Type combine(Type that) { + // Combining two equal types always works + if (that.equals(this)) { + return this; + } + + if (that.equals(Type.getIntegerType())) { + return Type.getFloatType(); + } + + // Every remaining type will throw a RuntimeException + throw new RuntimeException("Type missmatch: cannot combine " + this.getName() + " and " + that.getName()); + } + +} \ No newline at end of file diff --git a/src/main/java/de/hsrm/compiler/Klang/types/IntegerType.java b/src/main/java/de/hsrm/compiler/Klang/types/IntegerType.java index c3fad32..41064d1 100644 --- a/src/main/java/de/hsrm/compiler/Klang/types/IntegerType.java +++ b/src/main/java/de/hsrm/compiler/Klang/types/IntegerType.java @@ -1,6 +1,6 @@ package de.hsrm.compiler.Klang.types; -public class IntegerType extends PrimitiveType { +public class IntegerType extends NumericType { private static IntegerType instance = null; @@ -29,8 +29,9 @@ public class IntegerType extends PrimitiveType { return this; } - // Check other possible combinations - // if (that.equals(Type.getFloatType())) return Type.getFloatType(); + if (that.equals(Type.getFloatType())) { + return Type.getFloatType(); + } // Every remaining type will throw a RuntimeException throw new RuntimeException("Type missmatch: cannot combine " + this.getName() + " and " + that.getName()); diff --git a/src/main/java/de/hsrm/compiler/Klang/types/NumericType.java b/src/main/java/de/hsrm/compiler/Klang/types/NumericType.java new file mode 100644 index 0000000..9c03a29 --- /dev/null +++ b/src/main/java/de/hsrm/compiler/Klang/types/NumericType.java @@ -0,0 +1,8 @@ +package de.hsrm.compiler.Klang.types; + +public abstract class NumericType extends PrimitiveType { + @Override + public boolean isNumericType() { + return true; + } +} \ No newline at end of file diff --git a/src/main/java/de/hsrm/compiler/Klang/types/PrimitiveType.java b/src/main/java/de/hsrm/compiler/Klang/types/PrimitiveType.java index 3a87c7a..7493c37 100644 --- a/src/main/java/de/hsrm/compiler/Klang/types/PrimitiveType.java +++ b/src/main/java/de/hsrm/compiler/Klang/types/PrimitiveType.java @@ -14,4 +14,12 @@ public abstract class PrimitiveType extends Type { public boolean isBooleanType() { return false; }; + + public boolean isFloatType() { + return false; + }; + + public boolean isNumericType() { + return false; + } } \ No newline at end of file diff --git a/src/main/java/de/hsrm/compiler/Klang/types/Type.java b/src/main/java/de/hsrm/compiler/Klang/types/Type.java index a4771b5..75a8157 100644 --- a/src/main/java/de/hsrm/compiler/Klang/types/Type.java +++ b/src/main/java/de/hsrm/compiler/Klang/types/Type.java @@ -12,10 +12,15 @@ public abstract class Type { return BooleanType.getType(); } + public static FloatType getFloatType() { + return FloatType.getType(); + } + public static Type getByName(String name) { switch (name) { case "bool": return getBooleanType(); case "int": return getIntegerType(); + case "float": return getFloatType(); default: throw new RuntimeException("Unknown type " + name); } } @@ -23,4 +28,5 @@ public abstract class Type { public abstract String getName(); public abstract Type combine(Type that); public abstract boolean isPrimitiveType(); + public abstract boolean isNumericType(); } \ 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 5147648..2e3495d 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/EvalVisitor.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/EvalVisitor.java @@ -13,6 +13,7 @@ import de.hsrm.compiler.Klang.nodes.loops.DoWhileLoop; import de.hsrm.compiler.Klang.nodes.loops.ForLoop; import de.hsrm.compiler.Klang.nodes.loops.WhileLoop; import de.hsrm.compiler.Klang.nodes.statements.*; +import de.hsrm.compiler.Klang.types.Type; public class EvalVisitor implements Visitor { @@ -21,115 +22,309 @@ public class EvalVisitor implements Visitor { @Override public Value visit(IntegerExpression e) { - return new Value(e.value); + Value result = new Value(e.value); + result.type = Type.getIntegerType(); + return result; + } + + @Override + public Value visit(FloatExpression e) { + Value result = new Value(e.value); + result.type = Type.getFloatType(); + return result; } @Override public Value visit(BooleanExpression e) { - return new Value(e.value); + Value result = new Value(e.value); + result.type = Type.getBooleanType(); + return result; } @Override public Value visit(EqualityExpression e) { Value lhs = e.lhs.welcome(this); Value rhs = e.rhs.welcome(this); - return new Value(lhs.asObject() == rhs.asObject()); + Type resultType = Type.getBooleanType(); + Type combineType = lhs.type.combine(rhs.type); + + switch(combineType.getName()) { + case "bool": { + return new Value(lhs.asBoolean() == rhs.asBoolean(), resultType); + } + case "int": { + return new Value(lhs.asInteger() == rhs.asInteger(), resultType); + } + case "float": { + return new Value(lhs.asFloat() == rhs.asFloat(), resultType); + } + default: { + return new Value(lhs.asObject() == rhs.asObject(), resultType); + } + } } @Override public Value visit(NotEqualityExpression e) { Value lhs = e.lhs.welcome(this); Value rhs = e.rhs.welcome(this); - return new Value(lhs.asObject() != rhs.asObject()); + Type resultType = Type.getBooleanType(); + Type combineType = lhs.type.combine(rhs.type); + + switch(combineType.getName()) { + case "bool": { + return new Value(lhs.asBoolean() != rhs.asBoolean(), resultType); + } + case "int": { + return new Value(lhs.asInteger() != rhs.asInteger(), resultType); + } + case "float": { + return new Value(lhs.asFloat() != rhs.asFloat(), resultType); + } + default: { + return new Value(lhs.asObject() != rhs.asObject(), resultType); + } + } } @Override public Value visit(GTExpression e) { Value lhs = e.lhs.welcome(this); Value rhs = e.rhs.welcome(this); - return new Value(lhs.asInteger() > rhs.asInteger()); + Type resultType = Type.getBooleanType(); + Type combineType = lhs.type.combine(rhs.type); + + switch(combineType.getName()) { + case "int": { + return new Value(lhs.asInteger() > rhs.asInteger(), resultType); + } + case "float": { + return new Value(lhs.asFloat() > rhs.asFloat(), resultType); + } + default: { + throw new RuntimeException("Unknown Type encountered"); + } + } } @Override public Value visit(GTEExpression e) { Value lhs = e.lhs.welcome(this); Value rhs = e.rhs.welcome(this); - return new Value(lhs.asInteger() >= rhs.asInteger()); + Type resultType = Type.getBooleanType(); + Type combineType = lhs.type.combine(rhs.type); + + switch(combineType.getName()) { + case "int": { + return new Value(lhs.asInteger() >= rhs.asInteger(), resultType); + } + case "float": { + return new Value(lhs.asFloat() >= rhs.asFloat(), resultType); + } + default: { + throw new RuntimeException("Unknown Type encountered"); + } + } } @Override public Value visit(LTExpression e) { Value lhs = e.lhs.welcome(this); Value rhs = e.rhs.welcome(this); - return new Value(lhs.asInteger() < rhs.asInteger()); + Type resultType = Type.getBooleanType(); + Type combineType = lhs.type.combine(rhs.type); + + switch(combineType.getName()) { + case "int": { + return new Value(lhs.asInteger() < rhs.asInteger(), resultType); + } + case "float": { + return new Value(lhs.asFloat() < rhs.asFloat(), resultType); + } + default: { + throw new RuntimeException("Unknown Type encountered"); + } + } } @Override public Value visit(LTEExpression e) { Value lhs = e.lhs.welcome(this); Value rhs = e.rhs.welcome(this); - return new Value(lhs.asInteger() <= rhs.asInteger()); + Type combineType = lhs.type.combine(rhs.type); + Type resultType = Type.getBooleanType(); + + switch(combineType.getName()) { + case "int": { + return new Value(lhs.asInteger() <= rhs.asInteger(), resultType); + } + case "float": { + return new Value(lhs.asFloat() <= rhs.asFloat(), resultType); + } + default: { + throw new RuntimeException("Unknown Type encountered"); + } + } } @Override public Value visit(AdditionExpression e) { Value lhs = e.lhs.welcome(this); Value rhs = e.rhs.welcome(this); - return new Value(lhs.asInteger() + rhs.asInteger()); + Type resultType = lhs.type.combine(rhs.type); + + switch(resultType.getName()) { + case "int": { + return new Value(lhs.asInteger() + rhs.asInteger(), resultType); + } + case "float": { + return new Value(lhs.asFloat() + rhs.asFloat(), resultType); + } + default: { + throw new RuntimeException("Unknown Type encountered"); + } + } } @Override public Value visit(SubstractionExpression e) { Value lhs = e.lhs.welcome(this); Value rhs = e.rhs.welcome(this); - return new Value(lhs.asInteger() - rhs.asInteger()); + Type resultType = lhs.type.combine(rhs.type); + + switch(resultType.getName()) { + case "int": { + return new Value(lhs.asInteger() - rhs.asInteger(), resultType); + } + case "float": { + return new Value(lhs.asFloat() - rhs.asFloat(), resultType); + } + default: { + throw new RuntimeException("Unknown Type encountered"); + } + } } @Override public Value visit(MultiplicationExpression e) { Value lhs = e.lhs.welcome(this); Value rhs = e.rhs.welcome(this); - return new Value(lhs.asInteger() * rhs.asInteger()); + Type resultType = lhs.type.combine(rhs.type); + + switch(resultType.getName()) { + case "int": { + return new Value(lhs.asInteger() * rhs.asInteger(), resultType); + } + case "float": { + return new Value(lhs.asFloat() * rhs.asFloat(), resultType); + } + default: { + throw new RuntimeException("Unknown Type encountered"); + } + } } @Override public Value visit(DivisionExpression e) { Value lhs = e.lhs.welcome(this); Value rhs = e.rhs.welcome(this); - return new Value(lhs.asInteger() / rhs.asInteger()); + Type resultType = lhs.type.combine(rhs.type); + + switch(resultType.getName()) { + case "int": { + return new Value(lhs.asInteger() / rhs.asInteger(), resultType); + } + case "float": { + return new Value(lhs.asFloat() / rhs.asFloat(), resultType); + } + default: { + throw new RuntimeException("Unknown Type encountered"); + } + } } @Override public Value visit(ModuloExpression e) { Value lhs = e.lhs.welcome(this); Value rhs = e.rhs.welcome(this); - return new Value(lhs.asInteger() % rhs.asInteger()); + Type resultType = lhs.type.combine(rhs.type); + + switch(resultType.getName()) { + case "int": { + return new Value(lhs.asInteger() % rhs.asInteger(), resultType); + } + case "float": { + return new Value(lhs.asFloat() % rhs.asFloat(), resultType); + } + default: { + throw new RuntimeException("Unknown Type encountered"); + } + } } @Override public Value visit(NegateExpression e) { Value a = e.lhs.welcome(this); - return new Value(-a.asInteger()); + Type resultType = a.type; + + switch(resultType.getName()) { + case "int": { + return new Value(-a.asInteger(), resultType); + } + case "float": { + return new Value(-a.asFloat(), resultType); + } + default: { + throw new RuntimeException("Unknown Type encountered"); + } + } } @Override public Value visit(OrExpression e) { Value lhs = e.lhs.welcome(this); Value rhs = e.rhs.welcome(this); - return new Value(lhs.asBoolean() || rhs.asBoolean()); + Type resultType = lhs.type.combine(rhs.type); + + switch(resultType.getName()) { + case "bool": { + return new Value(lhs.asBoolean() || rhs.asBoolean(), resultType); + } + default: { + throw new RuntimeException("Unknown Type encountered"); + } + } } @Override public Value visit(AndExpression e) { Value lhs = e.lhs.welcome(this); Value rhs = e.rhs.welcome(this); - return new Value(lhs.asBoolean() && rhs.asBoolean()); + Type resultType = lhs.type.combine(rhs.type); + + switch(resultType.getName()) { + case "bool": { + return new Value(lhs.asBoolean() && rhs.asBoolean(), resultType); + } + default: { + throw new RuntimeException("Unknown Type encountered"); + } + } } @Override public Value visit(NotExpression e) { Value lhs = e.lhs.welcome(this); - return new Value(!lhs.asBoolean()); + Type resultType = lhs.type; + + switch(resultType.getName()) { + case "bool": { + return new Value(!lhs.asBoolean(), resultType); + } + default: { + throw new RuntimeException("Unknown Type encountered"); + } + } } @Override 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 d9ecf17..cf94562 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java @@ -12,6 +12,7 @@ import de.hsrm.compiler.Klang.nodes.loops.DoWhileLoop; import de.hsrm.compiler.Klang.nodes.loops.ForLoop; import de.hsrm.compiler.Klang.nodes.loops.WhileLoop; import de.hsrm.compiler.Klang.nodes.statements.*; +import de.hsrm.compiler.Klang.types.Type; public class GenASM implements Visitor { @@ -55,13 +56,83 @@ public class GenASM implements Visitor { } } + private class FloatWriter { + private StringBuilder sb = new StringBuilder(); + private int id = -1; + + public String getFloat(double d) { + String binary = Long.toBinaryString(Double.doubleToLongBits(d)); + String upper = binary.substring(0, 30); + String lower = binary.substring(31, 61); + long first = Long.parseLong(lower, 2); + long second = Long.parseLong(upper, 2); + String lbl = ".FL" + ++id; + sb.append(lbl); + sb.append(":\n"); + sb.append("\t.long "); + sb.append(first); + sb.append("\n"); + sb.append("\t.long "); + sb.append(second); + sb.append("\n"); + return lbl; + } + + public String getNegateFloat() { + String lbl = ".FL" + ++id; + sb.append(lbl); + sb.append(":\n"); + sb.append("\t.long "); + sb.append("0"); + sb.append("\n"); + sb.append("\t.long "); + sb.append("-2147483648"); + sb.append("\n"); + return lbl; + } + + public String getFloatSection() { + return sb.toString(); + } + } + public ExWriter ex; + private FloatWriter fw = new FloatWriter(); private String mainName; Map env = new HashMap<>(); Set vars; String[] rs = { "%rdi", "%rsi", "%rdx", "%rcx", "%r8", "%r9" }; + String[] frs = {"xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7"}; private int lCount = 0; // Invariante: lCount ist benutzt + private void intToFloat(String src, String dst) { + this.ex.write(" cvtsi2sd " + src +", " + dst + "\n"); + } + + private boolean prepareRegisters(Expression lhs, Expression rhs) { + boolean lhsIsFloat = lhs.type.equals(Type.getFloatType()); + boolean rhsIsFloat = rhs.type.equals(Type.getFloatType()); + if (lhsIsFloat || rhsIsFloat) { + lhs.welcome(this); + if (!lhsIsFloat) { + this.intToFloat("%rax", "%xmm1"); + } else { + this.ex.write(" movsd %xmm0, %xmm1\n"); + } + rhs.welcome(this); + if (!rhsIsFloat) { + this.intToFloat("%rax", "%xmm1"); + } + return true; + } + lhs.welcome(this); + this.ex.write(" pushq %rax\n"); + rhs.welcome(this); + this.ex.write(" popq %rbx\n"); + return false; + } + + public GenASM(ExWriter ex, String mainName) { this.ex = ex; this.mainName = mainName; @@ -78,6 +149,13 @@ public class GenASM implements Visitor { return null; } + @Override + public Void visit(FloatExpression e) { + String floatLabel = fw.getFloat(e.value); + this.ex.write(" movsd " + floatLabel + "(%rip), %xmm0\n"); + return null; + } + @Override public Void visit(BooleanExpression e) { this.ex.write(" movq $" + (e.value ? 1 : 0) + ", %rax\n"); @@ -86,7 +164,11 @@ public class GenASM implements Visitor { @Override public Void visit(Variable e) { - this.ex.write(" movq " + this.env.get(e.name) + "(%rbp), %rax\n"); + if (e.type.equals(Type.getFloatType())) { + this.ex.write(" movsd " + this.env.get(e.name) + "(%rbp), %xmm0\n"); + } else { + this.ex.write(" movq " + this.env.get(e.name) + "(%rbp), %rax\n"); + } return null; } @@ -95,19 +177,20 @@ public class GenASM implements Visitor { int lblTrue = ++lCount; int lblEnd = ++lCount; - e.lhs.welcome(this); - this.ex.write(" pushq %rax\n"); - e.rhs.welcome(this); - this.ex.write(" popq %rbx\n"); - this.ex.write(" cmp %rax, %rbx\n"); - this.ex.write(" je .L" + lblTrue + "\n"); - // false - this.ex.write(" movq $0, %rax\n"); - this.ex.write(" jmp .L" + lblEnd + "\n"); - this.ex.write(".L" + lblTrue + ":\n"); - // true - this.ex.write(" movq $1, %rax\n"); - this.ex.write(".L" + lblEnd + ":\n"); + boolean isFloatOperation = this.prepareRegisters(e.lhs, e.rhs); + if (isFloatOperation) { + this.ex.write(" ucomisd %xmm0, %xmm1\n"); + } else { + this.ex.write(" cmp %rax, %rbx\n"); + } + this.ex.write(" je .L" + lblTrue + "\n"); + // false + this.ex.write(" movq $0, %rax\n"); + this.ex.write(" jmp .L" + lblEnd + "\n"); + this.ex.write(".L" + lblTrue + ":\n"); + // true + this.ex.write(" movq $1, %rax\n"); + this.ex.write(".L" + lblEnd + ":\n"); return null; } @@ -116,11 +199,12 @@ public class GenASM implements Visitor { int lblTrue = ++lCount; int lblEnd = ++lCount; - e.lhs.welcome(this); - this.ex.write(" pushq %rax\n"); - e.rhs.welcome(this); - this.ex.write(" popq %rbx\n"); - this.ex.write(" cmp %rax, %rbx\n"); + boolean isFloatOperation = this.prepareRegisters(e.lhs, e.rhs); + if (isFloatOperation) { + this.ex.write(" ucomisd %xmm0, %xmm1\n"); + } else { + this.ex.write(" cmp %rax, %rbx\n"); + } this.ex.write(" jne .L" + lblTrue + "\n"); // false this.ex.write(" movq $0, %rax\n"); @@ -137,11 +221,12 @@ public class GenASM implements Visitor { int lblTrue = ++lCount; int lblEnd = ++lCount; - e.lhs.welcome(this); - this.ex.write(" pushq %rax\n"); - e.rhs.welcome(this); - this.ex.write(" popq %rbx\n"); - this.ex.write(" cmp %rax, %rbx\n"); + boolean isFloatOperation = this.prepareRegisters(e.lhs, e.rhs); + if (isFloatOperation) { + this.ex.write(" ucomisd %xmm0, %xmm1\n"); + } else { + this.ex.write(" cmp %rax, %rbx\n"); + } this.ex.write(" jg .L" + lblTrue + "\n"); // false this.ex.write(" movq $0, %rax\n"); @@ -158,11 +243,13 @@ public class GenASM implements Visitor { int lblTrue = ++lCount; int lblEnd = ++lCount; - e.lhs.welcome(this); - this.ex.write(" pushq %rax\n"); - e.rhs.welcome(this); - this.ex.write(" popq %rbx\n"); - this.ex.write(" cmp %rax, %rbx\n"); + + boolean isFloatOperation = this.prepareRegisters(e.lhs, e.rhs); + if (isFloatOperation) { + this.ex.write(" ucomisd %xmm0, %xmm1\n"); + } else { + this.ex.write(" cmp %rax, %rbx\n"); + } this.ex.write(" jge .L" + lblTrue + "\n"); // false this.ex.write(" movq $0, %rax\n"); @@ -179,11 +266,12 @@ public class GenASM implements Visitor { int lblTrue = ++lCount; int lblEnd = ++lCount; - e.lhs.welcome(this); - this.ex.write(" pushq %rax\n"); - e.rhs.welcome(this); - this.ex.write(" popq %rbx\n"); - this.ex.write(" cmp %rax, %rbx\n"); + boolean isFloatOperation = this.prepareRegisters(e.lhs, e.rhs); + if (isFloatOperation) { + this.ex.write(" ucomisd %xmm0, %xmm1\n"); + } else { + this.ex.write(" cmp %rax, %rbx\n"); + } this.ex.write(" jl .L" + lblTrue + "\n"); // false this.ex.write(" movq $0, %rax\n"); @@ -200,11 +288,12 @@ public class GenASM implements Visitor { int lblTrue = ++lCount; int lblEnd = ++lCount; - e.lhs.welcome(this); - this.ex.write(" pushq %rax\n"); - e.rhs.welcome(this); - this.ex.write(" popq %rbx\n"); - this.ex.write(" cmp %rax, %rbx\n"); + boolean isFloatOperation = this.prepareRegisters(e.lhs, e.rhs); + if (isFloatOperation) { + this.ex.write(" ucomisd %xmm0, %xmm1\n"); + } else { + this.ex.write(" cmp %rax, %rbx\n"); + } this.ex.write(" jle .L" + lblTrue + "\n"); // false this.ex.write(" movq $0, %rax\n"); @@ -218,43 +307,47 @@ public class GenASM implements Visitor { @Override public Void visit(AdditionExpression e) { - e.lhs.welcome(this); - this.ex.write(" pushq %rax\n"); - e.rhs.welcome(this); - this.ex.write(" popq %rbx\n"); - this.ex.write(" addq %rbx, %rax\n"); + boolean isFloatOperation = this.prepareRegisters(e.lhs, e.rhs); + if (isFloatOperation) { + this.ex.write(" addsd %xmm1, %xmm0\n"); + } else { + this.ex.write(" addq %rbx, %rax\n"); + } return null; } @Override public Void visit(SubstractionExpression e) { - e.rhs.welcome(this); - this.ex.write(" pushq %rax\n"); - e.lhs.welcome(this); - this.ex.write(" popq %rbx\n"); - this.ex.write(" subq %rbx, %rax\n"); + boolean isFloatOperation = this.prepareRegisters(e.lhs, e.rhs); + if (isFloatOperation) { + this.ex.write(" subsd %xmm1, %xmm0\n"); + } else { + this.ex.write(" subq %rax, %rbx\n"); + this.ex.write(" movq %rbx, %rax\n"); + } return null; } @Override public Void visit(MultiplicationExpression e) { - e.lhs.welcome(this); - this.ex.write(" pushq %rax\n"); - e.rhs.welcome(this); - this.ex.write(" popq %rbx\n"); - this.ex.write(" imulq %rbx, %rax\n"); + boolean isFloatOperation = this.prepareRegisters(e.lhs, e.rhs); + if (isFloatOperation) { + this.ex.write(" mulsd %xmm1, %xmm0\n"); + } else { + this.ex.write(" imulq %rbx, %rax\n"); + } return null; } @Override public Void visit(DivisionExpression e) { - e.lhs.welcome(this); - this.ex.write(" pushq %rax\n"); - e.rhs.welcome(this); - this.ex.write(" movq %rax, %rbx\n"); - this.ex.write(" popq %rax\n"); - this.ex.write(" xor %rdx, %rdx\n"); // clear upper part of division - this.ex.write(" idiv %rbx\n"); // %rax/%rbx, quotient now in %rax + boolean isFloatOperation = this.prepareRegisters(e.lhs, e.rhs); + if (isFloatOperation) { + this.ex.write(" divsd %xmm1, %xmm0\n"); + } else { + this.ex.write(" xor %rdx, %rdx\n"); // clear upper part of division + this.ex.write(" idiv %rbx\n"); // %rax/%rbx, quotient now in %rax + } return null; } @@ -274,7 +367,13 @@ public class GenASM implements Visitor { @Override public Void visit(NegateExpression e) { e.lhs.welcome(this); - this.ex.write(" neg %rax\n"); + if (e.lhs.type.equals(Type.getFloatType())) { + String floatLabel = fw.getNegateFloat(); + this.ex.write(" movsd " + floatLabel + "(%rip), %xmm1\n"); + this.ex.write(" xorpd %xmm1, %xmm0\n"); + } else { + this.ex.write(" neg %rax\n"); + } return null; } @@ -497,7 +596,8 @@ public class GenASM implements Visitor { // hole die anzahl der lokalen variablen this.vars = new TreeSet(); - GetVars getvars = new GetVars(vars); + HashMap types = new HashMap(); + GetVars getvars = new GetVars(vars, types); getvars.visit(e); // Erzeuge ein environment @@ -532,6 +632,74 @@ public class GenASM implements Visitor { @Override public Void visit(FunctionCall e) { + /* + Idee: + Über arguments iterieren, sich für jedes Argument merken an welche Position es kommt + Über e.arguments iterieren, jedes welcomen, ergebnis auf den stack pushen + Vom stack in die jeweiligen register / den richtigen Platz auf den Stack pushen + */ + // // An xmmIdxy[i] steht ein index, der in e.arguments zeigt + // // this.frs[i] = register | xmmIdxs[i] = index in arguments das in dieses register gehört + // int[] xmmIdxs = new int[this.frs.length]; + // int fi = 0; + // // Selbe Idee wie bei xmmIdxs + // int[] rIdxs = new int[this.rs.length]; + // int ri = 0; + //// Selbe Idee wie bei xmmIdxs + // ArrayList stackIdxs = new ArrayList(); + // + // // Go through arguments + // // sort them into the memory regions they go when being passed to function later on + // for (int i = 0; i < e.arguments.length; i++) { + // var arg = e.arguments[i]; + // if (arg.type.equals(Type.getFloatType())) { + // if (fi >= this.frs.length) { + // // Float onto stack + // stackIdxs.add(i); + // } else { + // // Float into float reg + // xmmIdxs[fi] = i; + // fi += 1; + // } + // } else { + // if (ri >= this.rs.length) { + // // bool/int onto stack + // stackIdxs.add(i); + // } else { + // // bool/int into reg + // rIdxs[ri] = i; + // ri += 1; + // } + // } + // } + + // // Welcome the arguments in order + // for (var arg : e.arguments) { + // arg.welcome(this); + // if (arg.type.equals(Type.getFloatType())) { + // this.ex.write(" movq %xmm0, %rax\n"); + // this.ex.write(" pushq %rax\n"); + // } else { + // this.ex.write(" pushq %rax\n"); + // } + // } + // // Move floats from stack to xmm registers + // TODO: Check if indexInArguments is valid + // for (int i = 0; i < xmmIdxs.length ; i++) { + // int indexInArguments = xmmIdxs[i]; + // int rspOffset = (((e.arguments.length - indexInArguments) - 1) * 8) * -1; + // this.ex.write(" movsd " + rspOffset + "(%rsp), " + this.frs[i] + "\n"); + // } + + // // Move primitives from stack to all purpose registers + // TODO: Check if indexInArguments is valid + // for (int i = 0; i < rIdxs.length ; i++) { + // int indexInArguments = rIdxs[i]; + // int rspOffset = (((e.arguments.length - indexInArguments) - 1) * 8) * -1; + // this.ex.write(" movq " + rspOffset + "(%rsp), " + this.rs[i] + "\n"); + // } + // int stackStart = (e.arguments.length - 1) * 8 * -1; + // Die ersten sechs params in die register schieben for (int i = 0; i < Math.min(this.rs.length, e.arguments.length); i++) { e.arguments[i].welcome(this); @@ -565,6 +733,10 @@ public class GenASM implements Visitor { this.ex.write(" movq %rbp, %rsp\n"); this.ex.write(" popq %rbp\n"); this.ex.write(" ret\n"); + + // PRINT FLOATS HERE + this.ex.write("\n"); + this.ex.write(fw.getFloatSection()); return null; } 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 b471245..666b124 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/GetVars.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/GetVars.java @@ -1,5 +1,6 @@ package de.hsrm.compiler.Klang.visitors; +import java.util.Map; import java.util.Set; import de.hsrm.compiler.Klang.nodes.*; @@ -8,13 +9,16 @@ import de.hsrm.compiler.Klang.nodes.loops.DoWhileLoop; import de.hsrm.compiler.Klang.nodes.loops.ForLoop; import de.hsrm.compiler.Klang.nodes.loops.WhileLoop; import de.hsrm.compiler.Klang.nodes.statements.*; +import de.hsrm.compiler.Klang.types.Type; class GetVars implements Visitor { public Set vars; + public Map types; - public GetVars(Set vars) { + public GetVars(Set vars, Map types) { this.vars = vars; + this.types = types; } @Override @@ -22,6 +26,11 @@ class GetVars implements Visitor { return null; } + @Override + public Void visit(FloatExpression e) { + return null; + } + @Override public Void visit(BooleanExpression e) { return null; @@ -179,6 +188,7 @@ class GetVars implements Visitor { @Override public Void visit(VariableDeclaration e) { vars.add(e.name); + types.put(e.name, e.type); 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 fe4d8f8..da410f5 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/PrettyPrintVisitor.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/PrettyPrintVisitor.java @@ -72,6 +72,12 @@ public class PrettyPrintVisitor implements Visitor { return null; } + @Override + public Void visit(FloatExpression e) { + ex.write(e.value); + return null; + } + @Override public Void visit(BooleanExpression e) { ex.write(e.value); 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 77ffc43..57402f4 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/Visitor.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/Visitor.java @@ -13,6 +13,7 @@ public interface Visitor { R visit(AndExpression e); R visit (NotExpression e); R visit(IntegerExpression e); + R visit(FloatExpression e); R visit(BooleanExpression e); R visit(Variable e); R visit(AdditionExpression e);