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..3db76bd 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); @@ -620,10 +697,8 @@ public class ContextAnalysis extends KlangBaseVisitor { Expression[] args = new Expression[argCount]; for (int i = 0; i < argCount; i++) { Expression expression = (Expression) this.visit(ctx.functionCall().arguments().expression(i)); - try { - expression.type.combine(func.signature[i]); // Make sure the types are matching - } catch (Exception e) { - throw new RuntimeException(Helper.getErrorPrefix(line, col) + "argument " + i + " " + e.getMessage()); + if (!expression.type.equals(func.signature[i])) { + throw new RuntimeException(Helper.getErrorPrefix(line, col) + "argument " + i + " Expected " + func.signature[i].getName() + " but got: " + expression.type.getName()); } args[i] = expression; } 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..f8edb42 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java @@ -1,6 +1,7 @@ package de.hsrm.compiler.Klang.visitors; import java.io.*; +import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import java.util.Set; @@ -12,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 GenASM implements Visitor { @@ -55,13 +57,96 @@ public class GenASM implements Visitor { } } + private class FloatWriter { + private StringBuilder sb = new StringBuilder(); + private int id = -1; + + public String getFloat(double d) { + Long longBits = Double.doubleToRawLongBits(d); + String binary = Long.toBinaryString(longBits); + int padCount = 64 - binary.length(); + while (padCount > 0) { + binary = "0" + binary; + padCount--; + } + String upper = binary.substring(0, 32); + String lower = binary.substring(32, 64); + 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[] registers = { "%rdi", "%rsi", "%rdx", "%rcx", "%r8", "%r9" }; + String[] floatRegisters = { "%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); + this.ex.write(" movsd %xmm0, %xmm2\n"); + rhs.welcome(this); + this.ex.write(" movsd %xmm0, %xmm1\n"); + this.ex.write(" movsd %xmm2, %xmm0\n"); + return true; + } else if (lhsIsFloat && !rhsIsFloat) { + lhs.welcome(this); + rhs.welcome(this); + this.intToFloat("%rax", "%xmm1"); + return true; + } else if (!lhsIsFloat && rhsIsFloat) { + lhs.welcome(this); + this.intToFloat("%rax", "%xmm2"); + rhs.welcome(this); + this.ex.write(" movsd %xmm0, %xmm1\n"); + this.ex.write(" movsd %xmm2, %xmm0\n"); + return true; + } else { + lhs.welcome(this); + this.ex.write(" pushq %rax\n"); + rhs.welcome(this); + this.ex.write(" movq %rax, %rbx\n"); + this.ex.write(" popq %rax\n"); + return false; + } + } public GenASM(ExWriter ex, String mainName) { this.ex = ex; this.mainName = mainName; @@ -78,6 +163,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 +178,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,11 +191,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 %xmm1, %xmm0\n"); + } else { + this.ex.write(" cmp %rbx, %rax\n"); + } this.ex.write(" je .L" + lblTrue + "\n"); // false this.ex.write(" movq $0, %rax\n"); @@ -116,11 +213,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 +235,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 %xmm1, %xmm0\n"); + } else { + this.ex.write(" cmp %rbx, %rax\n"); + } this.ex.write(" jg .L" + lblTrue + "\n"); // false this.ex.write(" movq $0, %rax\n"); @@ -158,11 +257,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 %xmm1, %xmm0\n"); + } else { + this.ex.write(" cmp %rbx, %rax\n"); + } this.ex.write(" jge .L" + lblTrue + "\n"); // false this.ex.write(" movq $0, %rax\n"); @@ -179,11 +279,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 %xmm1, %xmm0\n"); + } else { + this.ex.write(" cmp %rbx, %rax\n"); + } this.ex.write(" jl .L" + lblTrue + "\n"); // false this.ex.write(" movq $0, %rax\n"); @@ -200,11 +301,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 %xmm1, %xmm0\n"); + } else { + this.ex.write(" cmp %rbx, %rax\n"); + } this.ex.write(" jle .L" + lblTrue + "\n"); // false this.ex.write(" movq $0, %rax\n"); @@ -218,43 +320,46 @@ 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 %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(" cqto\n"); // sign extend rax into rdx since we're dealing with signed values + this.ex.write(" idiv %rbx\n"); // %rax/%rbx, quotient now in %rax + } return null; } @@ -265,7 +370,7 @@ public class GenASM implements Visitor { 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(" cqto\n"); // sign extend rax into rdx since we're dealing with signed values this.ex.write(" idiv %rbx\n"); // %rax/%rbx, remainder now in %rdx this.ex.write(" movq %rdx, %rax\n"); return null; @@ -274,7 +379,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; } @@ -331,20 +442,20 @@ public class GenASM implements Visitor { // also ist das Gesamtergebnis false e.rhs.welcome(this); this.ex.write(" cmpq $0, %rax\n"); - this.ex.write(" je .L" + lblFalse +"\n"); + this.ex.write(" je .L" + lblFalse + "\n"); // Die Expression wertet zu true aus // Springe am false Teil vorbei - this.ex.write(".L" + lblTrue +":\n"); + this.ex.write(".L" + lblTrue + ":\n"); this.ex.write(" movq $1, %rax\n"); this.ex.write(" jmp .L" + lblEnd + "\n"); // Die Expressoin wertet zu false aus - this.ex.write(".L" + lblFalse +":\n"); + this.ex.write(".L" + lblFalse + ":\n"); this.ex.write(" movq $0, %rax\n"); // Das hier ist das ende - this.ex.write(".L" + lblEnd +":\n"); + this.ex.write(".L" + lblEnd + ":\n"); return null; } @@ -352,26 +463,26 @@ public class GenASM implements Visitor { public Void visit(NotExpression e) { int lblFalse = ++lCount; int lblEnd = ++lCount; - + // Werte LHS aus // Wenn LHS != 0 bedeutet das true, also jumpe zum false Teil // Wenn nicht, falle durch zum true Teil e.lhs.welcome(this); this.ex.write(" cmpq $0, %rax\n"); - this.ex.write(" jne .L" +lblFalse +"\n"); + this.ex.write(" jne .L" + lblFalse + "\n"); // Hier ist das Ergebnis true // Springe am false Teil vorbei this.ex.write(" movq $1, %rax\n"); - this.ex.write(" jmp .L" +lblEnd +"\n"); + this.ex.write(" jmp .L" + lblEnd + "\n"); // Hier ist das Ergebnis false // Falle zum Ende durch - this.ex.write(".L" +lblFalse + ":\n"); + this.ex.write(".L" + lblFalse + ":\n"); this.ex.write("movq $0, %rax\n"); // Hier ist das Ende - this.ex.write(".L" +lblEnd + ":\n"); + this.ex.write(".L" + lblEnd + ":\n"); return null; } @@ -466,7 +577,15 @@ public class GenASM implements Visitor { public Void visit(VariableAssignment e) { e.expression.welcome(this); int offset = this.env.get(e.name); - this.ex.write(" movq %rax, " + offset + "(%rbp)\n"); + + // Determine where the result of this expression was placed into + // and move it onto the stack from there + if (e.expression.type.equals(Type.getFloatType())) { + this.ex.write(" movq %xmm0, " + offset + "(%rbp)\n"); + } else { + this.ex.write(" movq %rax, " + offset + "(%rbp)\n"); + } + return null; } @@ -497,26 +616,59 @@ 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 this.env = new HashMap(); // Merke dir die offsets der parameter, die direkt auf den stack gelegt wurden - int offset = 16; // Per Stack übergebene Parameter liegen über unserm BSP + int offset = 16; // Per Stack übergebene Parameter liegen über unserem BSP + int ri = 0; + int fi = 0; // Per stack übergebene variablen in env registrieren - for (int i = this.rs.length; i < e.parameters.length; i++) { - env.put(e.parameters[i].name, offset); - offset += 8; + var registerParameters = new ArrayList(); + for (int i = 0; i < e.parameters.length; i++) { + if (e.parameters[i].type.equals(Type.getFloatType())) { + if (fi >= this.floatRegisters.length) { + // parameter is on stack already + env.put(e.parameters[i].name, offset); + offset += 8; + } else { + // parameter is in a xmm register + registerParameters.add(e.parameters[i]); + fi++; + } + } else { + if (ri >= this.registers.length) { + // parameter is on stack already + env.put(e.parameters[i].name, offset); + offset += 8; + } else { + // parameter is in a register + registerParameters.add(e.parameters[i]); + ri++; + } + } } - - // pushe die aufrufparameter aus den Registern wieder auf den Stack + offset = 0; - for (int i = 0; i < Math.min(this.rs.length, e.parameters.length); i++) { - this.ex.write(" pushq " + this.rs[i] + "\n"); - offset -= 8; - this.env.put(e.parameters[i].name, offset); // negative, liegt unter aktuellem BP + ri = 0; + fi = 0; + for (var param: registerParameters) { + if (param.type.equals(Type.getFloatType())) { + this.ex.write(" movq "+ this.floatRegisters[fi] + ", %rax\n"); + this.ex.write(" pushq %rax\n"); + offset -= 8; + this.env.put(param.name, offset); // negative, liegt unter aktuellem BP + fi++; + } else { + this.ex.write(" pushq " + this.registers[ri] + "\n"); + offset -= 8; + this.env.put(param.name, offset); // negative, liegt unter aktuellem BP + ri++; + } } // Reserviere Platz auf dem Stack für jede lokale variable @@ -532,16 +684,80 @@ public class GenASM implements Visitor { @Override public Void visit(FunctionCall e) { - // 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); - this.ex.write(" movq %rax, " + this.rs[i] + "\n"); - } + if (e.arguments.length > 0) { + // Mapping arguments index -> xmm registers index + int[] xmmIdxs = new int[this.floatRegisters.length]; + int fi = -1; - // Den Rest auf den stack pushen - for (int i = e.arguments.length - 1; i >= this.rs.length; i--) { - e.arguments[i].welcome(this); - this.ex.write(" pushq %rax\n"); + // Mapping arguments index -> all purpose registers index + int[] rIdxs = new int[this.registers.length]; + int ri = -1; + + // Mapping arguments index -> stack + ArrayList stackIdxs = new ArrayList(); + + // Go through arguments + // sort them into the memory regions they go when being passed to functions + for (int i = 0; i < e.arguments.length; i++) { + var arg = e.arguments[i]; + if (arg.type.equals(Type.getFloatType())) { + if (fi < this.floatRegisters.length - 1) { + // Float into float reg + fi += 1; + xmmIdxs[fi] = i; + } else { + // Float onto stack + stackIdxs.add(i); + } + } else { + if (ri < this.registers.length - 1) { + // bool/int into reg + ri += 1; + rIdxs[ri] = i; + } else { + // bool/int onto stack + stackIdxs.add(i); + } + } + } + + // Welcome the arguments in order, push everything onto the stack + 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 + for (int i = 0; i <= fi; i++) { + int indexInArguments = xmmIdxs[i]; + int rspOffset = (((e.arguments.length - indexInArguments) - 1) * 8); + this.ex.write(" movsd " + rspOffset + "(%rsp), " + this.floatRegisters[i] + "\n"); + } + + // Move primitives from stack to all purpose registers + for (int i = 0; i <= ri; i++) { + int indexInArguments = rIdxs[i]; + int rspOffset = (((e.arguments.length - indexInArguments) - 1) * 8); + this.ex.write(" movq " + rspOffset + "(%rsp), " + this.registers[i] + "\n"); + } + + // Move everything else from a higher stack position to our stack frame start + int stackStartOffset = ((e.arguments.length) * 8); + for (int i = stackIdxs.size() - 1; i >= 0; i--) { + stackStartOffset -= 8; + int indexInArguments = stackIdxs.get(i); + int rspOffset = (((e.arguments.length - indexInArguments) - 1) * 8); + this.ex.write(" movq " + rspOffset + "(%rsp), %rax\n"); + this.ex.write(" movq %rax, " + stackStartOffset + "(%rsp)\n"); + } + + // Rescue RSP + this.ex.write(" addq $" + stackStartOffset + ", %rsp\n"); } this.ex.write(" call " + e.name + "\n"); @@ -565,6 +781,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); diff --git a/src/test/comparison/comparison.c b/src/test/comparison/comparison.c index 46bc381..2679894 100644 --- a/src/test/comparison/comparison.c +++ b/src/test/comparison/comparison.c @@ -2,7 +2,7 @@ #include "comparison.h" #include "../print/print.h" -int comparisonTest(char* name, int x, int y, int expected, int result) { +int comparisonTest(char* name, long x, long y, long expected, long result) { if (expected == result) { succInfixTwo(name, x, y, expected, result); return 0; diff --git a/src/test/comparison/comparison.h b/src/test/comparison/comparison.h index 2030b9f..6e88f8f 100644 --- a/src/test/comparison/comparison.h +++ b/src/test/comparison/comparison.h @@ -1,11 +1,11 @@ #include -bool eq(int x, int y); -bool neq(int x, int y); -bool lt(int x, int y); -bool lte(int x, int y); -bool gt(int x, int y); -bool gte(int x, int y); +bool eq(long x, long y); +bool neq(long x, long y); +bool lt(long x, long y); +bool lte(long x, long y); +bool gt(long x, long y); +bool gte(long x, long y); bool and(bool a, bool b); bool or(bool a, bool b); diff --git a/src/test/functionCall/functionCall.c b/src/test/functionCall/functionCall.c index 0ac208b..c438ddf 100644 --- a/src/test/functionCall/functionCall.c +++ b/src/test/functionCall/functionCall.c @@ -2,7 +2,7 @@ #include "functionCall.h" #include "../print/print.h" -int argumentTest(char* name, int expected, int result) { +int argumentTest(char* name, long expected, long result) { if (expected == result) { succ(name, expected, result); return 0; @@ -12,6 +12,16 @@ int argumentTest(char* name, int expected, int result) { } } +int argumentTest_f(char* name, long expected, long result) { + if (expected == result) { + succ_f(name, expected, result); + return 0; + } else { + err_f(name, expected, result); + return 1; + } +} + int runFunctionCallTests () { printf("\nFunction Call Tests \n"); // Checks that parameters are correctly passed from gcc to functions @@ -36,4 +46,50 @@ int runFunctionCallTests () { argumentTest("get8(...args)", 8, get8()); argumentTest("get9(...args)", 9, get9()); argumentTest("get10(...args)", 10, get10()); + + printf("\nFunction Call Tests With Floats \n"); + argumentTest_f("farg1(...args)", 1.0, farg1(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0)); + argumentTest_f("farg2(...args)", 2.0, farg2(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0)); + argumentTest_f("farg3(...args)", 3.0, farg3(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0)); + argumentTest_f("farg4(...args)", 4.0, farg4(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0)); + argumentTest_f("farg5(...args)", 5.0, farg5(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0)); + argumentTest_f("farg6(...args)", 6.0, farg6(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0)); + argumentTest_f("farg7(...args)", 7.0, farg7(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0)); + argumentTest_f("farg8(...args)", 8.0, farg8(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0)); + argumentTest_f("farg9(...args)", 9.0, farg9(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0)); + argumentTest_f("farg10(...args)", 10.0, farg10(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0)); + // Checks that parameters are correctly passed from klang to functions + argumentTest_f("fget1(...args)", 1.0, fget1()); + argumentTest_f("fget2(...args)", 2.0, fget2()); + argumentTest_f("fget3(...args)", 3.0, fget3()); + argumentTest_f("fget4(...args)", 4.0, fget4()); + argumentTest_f("fget5(...args)", 5.0, fget5()); + argumentTest_f("fget6(...args)", 6.0, fget6()); + argumentTest_f("fget7(...args)", 7.0, fget7()); + argumentTest_f("fget8(...args)", 8.0, fget8()); + argumentTest_f("fget9(...args)", 9.0, fget9()); + argumentTest_f("fget10(...args)", 10.0, fget10()); + + printf("\nFunction Call Tests With Floats And Integers \n"); + argumentTest_f("fargMix1(...args)", 1.0, fargMix1(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0)); + argumentTest_f("fargMix2(...args)", 2, fargMix2(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0)); + argumentTest_f("fargMix3(...args)", 3.0, fargMix3(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0)); + argumentTest_f("fargMix4(...args)", 4, fargMix4(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0)); + argumentTest_f("fargMix5(...args)", 5.0, fargMix5(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0)); + argumentTest_f("fargMix6(...args)", 6, fargMix6(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0)); + argumentTest_f("fargMix7(...args)", 7.0, fargMix7(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0)); + argumentTest_f("fargMix8(...args)", 8, fargMix8(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0)); + argumentTest_f("fargMix9(...args)", 9.0, fargMix9(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0)); + argumentTest_f("fargMix10(...args)", 10, fargMix10(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0)); + // Checks that parameters are correctly passed from klang to functions + argumentTest_f("fgetMix1(...args)", 1.0, fgetMix1()); + argumentTest("fgetMix2(...args)", 2, fgetMix2()); + argumentTest_f("fgetMix3(...args)", 3.0, fgetMix3()); + argumentTest("fgetMix4(...args)", 4, fgetMix4()); + argumentTest_f("fgetMix5(...args)", 5.0, fgetMix5()); + argumentTest("fgetMix6(...args)", 6, fgetMix6()); + argumentTest_f("fgetMix7(...args)", 7.0, fgetMix7()); + argumentTest("fgetMix8(...args)", 8, fgetMix8()); + argumentTest_f("fgetMix9(...args)", 9.0, fgetMix9()); + argumentTest("fgetMix10(...args)", 10, fgetMix10()); } \ No newline at end of file diff --git a/src/test/functionCall/functionCall.h b/src/test/functionCall/functionCall.h index 56fbff7..7aac291 100644 --- a/src/test/functionCall/functionCall.h +++ b/src/test/functionCall/functionCall.h @@ -1,21 +1,65 @@ -int arg1(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j); -int arg2(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j); -int arg3(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j); -int arg4(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j); -int arg5(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j); -int arg6(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j); -int arg7(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j); -int arg8(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j); -int arg9(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j); -int arg10(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j); +long arg1(long a, long b, long c, long d, long e, long f, long g, long h, long i, long j); +long arg2(long a, long b, long c, long d, long e, long f, long g, long h, long i, long j); +long arg3(long a, long b, long c, long d, long e, long f, long g, long h, long i, long j); +long arg4(long a, long b, long c, long d, long e, long f, long g, long h, long i, long j); +long arg5(long a, long b, long c, long d, long e, long f, long g, long h, long i, long j); +long arg6(long a, long b, long c, long d, long e, long f, long g, long h, long i, long j); +long arg7(long a, long b, long c, long d, long e, long f, long g, long h, long i, long j); +long arg8(long a, long b, long c, long d, long e, long f, long g, long h, long i, long j); +long arg9(long a, long b, long c, long d, long e, long f, long g, long h, long i, long j); +long arg10(long a, long b, long c, long d, long e, long f, long g, long h, long i, long j); -int get1(); -int get2(); -int get3(); -int get4(); -int get5(); -int get6(); -int get7(); -int get8(); -int get9(); -int get10(); \ No newline at end of file +long get1(); +long get2(); +long get3(); +long get4(); +long get5(); +long get6(); +long get7(); +long get8(); +long get9(); +long get10(); + +double farg1(double a, double b, double c, double d, double e, double f, double g, double h, double i, double j); +double farg2(double a, double b, double c, double d, double e, double f, double g, double h, double i, double j); +double farg3(double a, double b, double c, double d, double e, double f, double g, double h, double i, double j); +double farg4(double a, double b, double c, double d, double e, double f, double g, double h, double i, double j); +double farg5(double a, double b, double c, double d, double e, double f, double g, double h, double i, double j); +double farg6(double a, double b, double c, double d, double e, double f, double g, double h, double i, double j); +double farg7(double a, double b, double c, double d, double e, double f, double g, double h, double i, double j); +double farg8(double a, double b, double c, double d, double e, double f, double g, double h, double i, double j); +double farg9(double a, double b, double c, double d, double e, double f, double g, double h, double i, double j); +double farg10(double a, double b, double c, double d, double e, double f, double g, double h, double i, double j); + +double fargMix1(double a, long b, double c, long d, double e, long f, double g, long h, double i, long j); +long fargMix2(double a, long b, double c, long d, double e, long f, double g, long h, double i, long j); +double fargMix3(double a, long b, double c, long d, double e, long f, double g, long h, double i, long j); +long fargMix4(double a, long b, double c, long d, double e, long f, double g, long h, double i, long j); +double fargMix5(double a, long b, double c, long d, double e, long f, double g, long h, double i, long j); +long fargMix6(double a, long b, double c, long d, double e, long f, double g, long h, double i, long j); +double fargMix7(double a, long b, double c, long d, double e, long f, double g, long h, double i, long j); +long fargMix8(double a, long b, double c, long d, double e, long f, double g, long h, double i, long j); +double fargMix9(double a, long b, double c, long d, double e, long f, double g, long h, double i, long j); +long fargMix10(double a, long b, double c, long d, double e, long f, double g, long h, double i, long j); + +double fget1(); +double fget2(); +double fget3(); +double fget4(); +double fget5(); +double fget6(); +double fget7(); +double fget8(); +double fget9(); +double fget10(); + +double fgetMix1(); +long fgetMix2(); +double fgetMix3(); +long fgetMix4(); +double fgetMix5(); +long fgetMix6(); +double fgetMix7(); +long fgetMix8(); +double fgetMix9(); +long fgetMix10(); \ No newline at end of file diff --git a/src/test/loop/loop.c b/src/test/loop/loop.c index 55fa9a9..08c87d1 100644 --- a/src/test/loop/loop.c +++ b/src/test/loop/loop.c @@ -2,7 +2,7 @@ #include "loop.h" #include "../print/print.h" -int loopTest(char* name, int x, int expected, int result) { +int loopTest(char* name, long x, long expected, long result) { if (expected == result) { succPrefixOne(name, x, expected, result); return 0; diff --git a/src/test/loop/loop.h b/src/test/loop/loop.h index 7e8887e..fe403c8 100644 --- a/src/test/loop/loop.h +++ b/src/test/loop/loop.h @@ -1,3 +1,3 @@ -int myWhile(int x); -int myDoWhile(int x); -int myFor(int x); \ No newline at end of file +long myWhile(long x); +long myDoWhile(long x); +long myFor(long x); \ No newline at end of file diff --git a/src/test/math/math.c b/src/test/math/math.c index c5fb382..42f245d 100644 --- a/src/test/math/math.c +++ b/src/test/math/math.c @@ -1,38 +1,69 @@ #include #include "math.h" +#include #include "../print/print.h" -int cAdd(int x, int y) +long cAdd(long x, long y) { return x + y; } -int cSub(int x, int y) +long cSub(long x, long y) { return x - y; } -int cMul(int x, int y) +long cMul(long x, long y) { return x * y; } -int cModulo(int x, int y) +long cModulo(long x, long y) { return x % y; } -int cNeg(int x) +long cDiv(long x, long y) +{ + return x / y; +} +long cNeg(long x) { return -x; } -int cId(int x) +long cId(long x) { return x; } -int cSelfMinus(int x) +long cSelfMinus(long x) { x = x - 1; return x; } -int math_testExpected(char *name, int x, int y, int expected, int result) +double fcAdd(double x, double y) +{ + return x + y; +} +double fcSub(double x, double y) +{ + return x - y; +} +double fcMul(double x, double y) +{ + return x * y; +} +double fcNeg(double x) +{ + return -x; +} +double fcId(double x) +{ + return x; +} +double fcSelfMinus(double x) +{ + x = x - 1; + return x; +} + +int math_testExpected(char *name, long x, long y, long expected, long result) { if (expected == result) { @@ -46,14 +77,34 @@ int math_testExpected(char *name, int x, int y, int expected, int result) } } -int math_test(char *name, int (*correctFunction)(int, int), int (*testFunction)(int, int), int x, int y) +int math_testExpected_f(char *name, double x, double y, double expected, double result) +{ + if (expected == result) + { + float_succPrefixTwo(name, x, y, expected, result); + return 0; + } + else + { + float_errPrefixTwo(name, x, y, expected, result); + return 1; + } +} + +int math_test(char *name, long (*correctFunction)(long, long), long (*testFunction)(long, long), long x, long y) { int expected = correctFunction(x, y); int result = testFunction(x, y); return math_testExpected(name, x, y, expected, result); } -int math_testOneArg(char *name, int (*correctFunction)(int), int (*testFunction)(int), int x) +float math_test_f(char *name, double (*correctFunction)(double, double), double (*testFunction)(double, double), double x, double y) { + double expected = correctFunction(x, y); + double result = testFunction(x, y); + return math_testExpected_f(name, x, y, expected, result); +} + +int math_testOneArg(char *name, long (*correctFunction)(long), long (*testFunction)(long), long x) { int expected = correctFunction(x); int result = testFunction(x); @@ -69,7 +120,23 @@ int math_testOneArg(char *name, int (*correctFunction)(int), int (*testFunction) } } -void math_simpleTest(char *name, int expected, int result) { +double math_testOneArg_f(char *name, double (*correctFunction)(double), double (*testFunction)(double), double x) +{ + float expected = correctFunction(x); + float result = testFunction(x); + if (expected == result) + { + float_succPrefixOne(name, x, expected, result); + return 0; + } + else + { + float_errPrefixOne(name, x, expected, result); + return 1; + } +} + +void math_simpleTest(char *name, long expected, long result) { if (expected == result) { succ(name, expected, result); } else { @@ -77,6 +144,16 @@ void math_simpleTest(char *name, int expected, int result) { } } +int math_argumentTest_f(char* name, double expected, double result) { + if (expected == result) { + succ_f(name, expected, result); + return 0; + } else { + err_f(name, expected, result); + return 1; + } +} + int runMathTests() { printf("\nAddition Tests \n"); @@ -100,6 +177,15 @@ int runMathTests() math_test("mul", cMul, mul, 1, 5); math_test("mul", cMul, mul, -1, -1); + printf("\nDivision Tests\n"); + math_test("div", cDiv, div, 10, 2); + math_test("div", cDiv, div, 8, 4); + math_test("div", cDiv, div, 6, -2); + math_test("div", cDiv, div, -9, 3); + math_test("div", cDiv, div, 9, 2); + math_test("div", cDiv, div, 9, -2); + math_test("div", cDiv, div, -9, 2); + printf("\nModulo Tests \n"); math_test("modulo", cModulo, modulo, 1, 1); math_test("modulo", cModulo, modulo, 1, 5); @@ -110,17 +196,62 @@ int runMathTests() math_testOneArg("neg", cNeg, neg, 0); math_testOneArg("neg", cNeg, neg, 1); math_testOneArg("neg", cNeg, neg, -1); + math_testOneArg("neg", cNeg, neg, -10); printf("\nIdentity Tests\n"); math_testOneArg("id", cId, id, 0); math_testOneArg("id", cId, id, -1); math_testOneArg("id", cId, id, 15); + printf("\nFloat Addition Tests \n"); + math_test_f("fadd", fcAdd, fadd, 0.0, 0.0); + math_test_f("fadd", fcAdd, fadd, 1.0, 1.0); + math_test_f("fadd", fcAdd, fadd, 2.0, 0.0); + math_test_f("fadd", fcAdd, fadd, 1.0, 5.0); + math_test_f("fadd", fcAdd, fadd, -1.0, -1.0); + math_test_f("fadd", fcAdd, fadd, 10.0, 10.0); + math_test_f("fadd", fcAdd, fadd, 1.337, 0.0); + math_test_f("fadd", fcAdd, fadd, 1.5, 2.0); + math_test_f("fadd", fcAdd, fadd, -10.0, 10.0); + math_test_f("fadd", fcAdd, fadd, -10.0, -10.0); + math_test_f("fadd", fcAdd, fadd, -10.0, -1.0); + + printf("\nFloat Subtraction Tests \n"); + math_test_f("fsub", fcSub, fsub, 0.0, 0.0); + math_test_f("fsub", fcSub, fsub, 1.0, 1.0); + math_test_f("fsub", fcSub, fsub, 2.0, 0.0); + math_test_f("fsub", fcSub, fsub, 1.0, 5.0); + math_test_f("fsub", fcSub, fsub, -1.0, -1.0); + math_test_f("fsub", fcSub, fsub, -1.0, 0.0); + math_test_f("fsub", fcSub, fsub, -1.0, 1.337); + + printf("\nFloat Multiplication Tests \n"); + math_test_f("fmul", fcMul, fmul, 0.0, 0.0); + math_test_f("fmul", fcMul, fmul, 1.0, 1.0); + math_test_f("fmul", fcMul, fmul, 2.0, 0.0); + math_test_f("fmul", fcMul, fmul, 1.0, 5.0); + math_test_f("fmul", fcMul, fmul, -1.0, -1.0); + + printf("\nFloat Negative Tests\n"); + math_testOneArg_f("fneg", fcNeg, fneg, 0.0); + math_testOneArg_f("fneg", fcNeg, fneg, 1.0); + math_testOneArg_f("fneg", fcNeg, fneg, -1.0); + math_testOneArg_f("fneg", fcNeg, fneg, -10.0); + + printf("\nFloat Identity Tests\n"); + math_testOneArg_f("fid", fcId, fid, 0.0); + math_testOneArg_f("fid", fcId, fid, -1.0); + math_testOneArg_f("fid", fcId, fid, 15.0); + printf("\nMisc Tests\n"); math_testOneArg("selfMinus", cSelfMinus, selfMinus, 5); math_testOneArg("selfMinus", cSelfMinus, selfMinus, 0); math_testOneArg("selfMinus", cSelfMinus, selfMinus, 100); math_testOneArg("selfMinus", cSelfMinus, selfMinus, -50); + math_testOneArg_f("fselfMinus", fcSelfMinus, fselfMinus, 5); + math_testOneArg_f("fselfMinus", fcSelfMinus, fselfMinus, 0); + math_testOneArg_f("fselfMinus", fcSelfMinus, fselfMinus, 100); + math_testOneArg_f("fselfMinus", fcSelfMinus, fselfMinus, -50); math_simpleTest("precedence t1", 16, t1()); math_simpleTest("precedence t2", 16, t2()); math_simpleTest("precedence t3", 16, t3()); @@ -129,4 +260,53 @@ int runMathTests() math_simpleTest("precedence t6", 16, t6()); math_simpleTest("precedence t7", 16, t7()); math_simpleTest("precedence t8", 18, t8()); + + printf("\nFloat And Integer Addition\n"); + math_argumentTest_f("mixadd(1.0, 1)", 2.0, mixadd(1.0, 1)); + math_argumentTest_f("mixadd(0.0, 0)", 0.0, mixadd(0.0, 0)); + math_argumentTest_f("mixadd(10.0, 10)", 20.0, mixadd(10.0, 10)); + math_argumentTest_f("mixadd(1.337, 0)", 1.337, mixadd(1.337, 0)); + math_argumentTest_f("mixadd(1.5, 2)", 3.5, mixadd(1.5, 2)); + math_argumentTest_f("mixadd(-10.0, 10)", 0.0, mixadd(-10.0, 10)); + math_argumentTest_f("mixadd(-10.0, -10)", -20.0, mixadd(-10.0, -10)); + math_argumentTest_f("mixadd(-10.0, -1)", -11.0, mixadd(-10.0, -1)); + + printf("\nFloat And Integer Subtraction\n"); + math_argumentTest_f("mixsub(10.0, 10)", 0.0, mixsub(10.0, 10)); + math_argumentTest_f("mixsub(0.0, 0)", 0.0, mixsub(0.0, 0)); + math_argumentTest_f("mixsub(-10.0, 10)", -20.0, mixsub(-10.0, 10)); + math_argumentTest_f("mixsub(-1.0, 1)", -2.0, mixsub(-1.0, 1)); + math_argumentTest_f("mixsub(0.0, -1)", 1.0, mixsub(0.0, -1)); + + printf("\nFloat And Integer Multiplication\n"); + math_argumentTest_f("mixmul(0.0, 0)", 0.0, mixmul(0.0, 0)); + math_argumentTest_f("mixmul(10.0, 0)", 0.0, mixmul(10.0, 0)); + math_argumentTest_f("mixmul(-1.0, 0)", 0.0, mixmul(-1.0, 0)); + math_argumentTest_f("mixmul(-10.0, 0)", 0.0, mixmul(-10.0, 0)); + math_argumentTest_f("mixmul(10.0, -1)", -10.0, mixmul(10.0, -1)); + math_argumentTest_f("mixmul(0.0, -1)", 0.0, mixmul(0.0, -1)); + math_argumentTest_f("mixmul(-1.0, -1)", 1, mixmul(-1.0, -1)); + math_argumentTest_f("mixmul(1.0, 1)", 1, mixmul(1.0, 1)); + math_argumentTest_f("mixmul(1.0, 1)", 0, mixmul(0.0, 1)); + math_argumentTest_f("mixmul(1.0, 1)", -1, mixmul(-1.0, 1)); + math_argumentTest_f("mixmul(1.5, 6)", 9, mixmul(1.5, 6)); + math_argumentTest_f("mixmul(2.0, 2)", 4, mixmul(2.0, 2)); + math_argumentTest_f("mixmul(100.0, 10)", 1000.0, mixmul(100.0, 10)); + + printf("\nFloat And Integer Division\n"); + math_argumentTest_f("mixdiv(10.0, 0)", INFINITY, mixdiv(10.0, 0)); + math_argumentTest_f("mixdiv(10.0, 1)", 10.0, mixdiv(10.0, 1)); + math_argumentTest_f("mixdiv(-1.0, -1)", 1, mixdiv(-1.0, -1)); + math_argumentTest_f("mixdiv(0.0, 1)", 0.0, mixdiv(0.0, 1)); + math_argumentTest_f("mixdiv(-1.0, 1)", -1.0, mixdiv(-1.0, 1)); + math_argumentTest_f("mixdiv(1.5, 2)", 1.5 / 2, mixdiv(1.5, 2)); + math_argumentTest_f("mixdiv(1.0, 10)", 1.0 / 10, mixdiv(1.0, 10)); + math_argumentTest_f("mixdiv(1.0, 100)", 1.0 / 100, mixdiv(1.0, 100)); + math_argumentTest_f("mixdiv(1.0, 1000)", 1.0 / 1000, mixdiv(1.0, 1000)); + math_argumentTest_f("mixdiv(1.0, 10000)", 1.0 / 10000, mixdiv(1.0, 10000)); + math_argumentTest_f("mixdiv(1.0, 100000)", 1.0 / 100000, mixdiv(1.0, 100000)); + math_argumentTest_f("mixdiv(1.0, 1000000)", 1.0 / 1000000, mixdiv(1.0, 1000000)); + math_argumentTest_f("mixdiv(1.0, 10000000)", 1.0 / 10000000, mixdiv(1.0, 10000000)); + + } \ No newline at end of file diff --git a/src/test/math/math.h b/src/test/math/math.h index 1801543..0af7ad9 100644 --- a/src/test/math/math.h +++ b/src/test/math/math.h @@ -2,18 +2,29 @@ Die nachfolgenden Funktionen werden später dazu gelinkt Der Ursprung ist die tests.k Datei, dort sind diese Funktionen implementiert */ -int add(int x, int y); -int sub(int x, int y); -int mul(int x, int y); -int modulo(int x, int y); -int neg(int x); -int id(int x); -int selfMinus(int x); -int t1(); -int t2(); -int t3(); -int t4(); -int t5(); -int t6(); -int t7(); -int t8(); \ No newline at end of file +long add(long x, long y); +long sub(long x, long y); +long mul(long x, long y); +long div(long x, long y); +long modulo(long x, long y); +long neg(long x); +long id(long x); +long selfMinus(long x); +long t1(); +long t2(); +long t3(); +long t4(); +long t5(); +long t6(); +long t7(); +long t8(); +double fadd(double x, double y); +double fsub(double x, double y); +double fmul(double x, double y); +double fneg(double x); +double fid(double x); +double fselfMinus(double x); +double mixadd(double x, long y); +double mixsub(double x, long y); +double mixmul(double x, long y); +double mixdiv(double x, long y); \ No newline at end of file diff --git a/src/test/print/print.c b/src/test/print/print.c index 21109f9..b995765 100644 --- a/src/test/print/print.c +++ b/src/test/print/print.c @@ -8,44 +8,74 @@ char* printBool(bool a) { return "false"; } -void succInfixTwo(char* name, int x, int y, int expected, int result) { +void succInfixTwo(char* name, long x, long y, long expected, long result) { incSuccess(); - printf("\033[0;32mSUCCESS:\t%d %s %d\tGOT: %d\tExpected: %d\033[0;0m\n", x, name, y, result, expected); + printf("\033[0;32mSUCCESS:\t%ld %s %ld\tGOT: %ld\tExpected: %ld\033[0;0m\n", x, name, y, result, expected); } -void errInfixTwo(char* name, int x, int y, int expected, int result) { +void errInfixTwo(char* name, long x, long y, long expected, long result) { incFailure(); - printf("\033[0;31mERROR:\t\t%d %s %d\tGOT: %d\tExpected: %d\033[0;0m\n", x, name, y, result, expected); + printf("\033[0;31mERROR:\t\t%ld %s %ld\tGOT: %ld\tExpected: %ld\033[0;0m\n", x, name, y, result, expected); } -void succ(char* name, int expected, int result) { +void succ(char* name, long expected, long result) { incSuccess(); - printf("\033[0;32mSUCCESS:\t%s:\tGOT: %d\tExpected: %d\033[0;0m\n", name, result, expected); + printf("\033[0;32mSUCCESS:\t%s:\tGOT: %ld\tExpected: %ld\033[0;0m\n", name, result, expected); } -void err(char* name, int expected, int result) { +void err(char* name, long expected, long result) { incFailure(); - printf("\033[0;31mERROR:\t\t%s:\tGOT: %d\tExpected: %d\033[0;0m\n", name, result, expected); + printf("\033[0;31mERROR:\t\t%s:\tGOT: %ld\tExpected: %ld\033[0;0m\n", name, result, expected); } -void succPrefixOne(char* name, int x, int expected, int result) { +void succ_f(char* name, double expected, double result) { incSuccess(); - printf("\033[0;32mSUCCESS:\t%s(%d)\tGOT: %d\tExpected: %d\033[0;0m\n", name, x, result, expected); + printf("\033[0;32mSUCCESS:\t%s:\tGOT: %f\tExpected: %f\033[0;0m\n", name, result, expected); } -void errPrefixOne(char* name, int x, int expected, int result) { +void err_f(char* name, double expected, double result) { incFailure(); - printf("\033[0;31mERROR:\t\t%s(%d)\tGOT: %d\tExpected: %d\033[0;0m\n", name, x, result, expected); + printf("\033[0;31mERROR:\t\t%s:\tGOT: %f\tExpected: %f\033[0;0m\n", name, result, expected); } -void succPrefixTwo(char* name, int x, int y, int expected, int result) { +void succPrefixOne(char* name, long x, long expected, long result) { incSuccess(); - printf("\033[0;32mSUCCESS:\t%s(%d, %d)\tGOT: %d\tExpected: %d\033[0;0m\n", name, x, y, result, expected); + printf("\033[0;32mSUCCESS:\t%s(%ld)\tGOT: %ld\tExpected: %ld\033[0;0m\n", name, x, result, expected); } -void errPrefixTwo(char* name, int x, int y, int expected, int result) { +void errPrefixOne(char* name, long x, long expected, long result) { incFailure(); - printf("\033[0;31mERROR:\t\t%s(%d, %d)\tGOT: %d\tExpected: %d\033[0;0m\n", name, x, y, result, expected); + printf("\033[0;31mERROR:\t\t%s(%ld)\tGOT: %ld\tExpected: %ld\033[0;0m\n", name, x, result, expected); +} + +void float_succPrefixOne(char* name, double x, double expected, double result) { + incSuccess(); + printf("\033[0;32mSUCCESS:\t%s(%f)\tGOT: %f\tExpected: %f\033[0;0m\n", name, x, result, expected); +} + +void float_errPrefixOne(char* name, double x, double expected, double result) { + incFailure(); + printf("\033[0;31mERROR:\t\t%s(%f)\tGOT: %f\tExpected: %f\033[0;0m\n", name, x, result, expected); +} + +void succPrefixTwo(char* name, long x, long y, long expected, long result) { + incSuccess(); + printf("\033[0;32mSUCCESS:\t%s(%ld, %ld)\tGOT: %ld\tExpected: %ld\033[0;0m\n", name, x, y, result, expected); +} + +void errPrefixTwo(char* name, long x, long y, long expected, long result) { + incFailure(); + printf("\033[0;31mERROR:\t\t%s(%ld, %ld)\tGOT: %ld\tExpected: %ld\033[0;0m\n", name, x, y, result, expected); +} + +void float_succPrefixTwo(char* name, double x, double y, double expected, double result) { + incSuccess(); + printf("\033[0;32mSUCCESS:\t%s(%f, %f)\tGOT: %f\tExpected: %f\033[0;0m\n", name, x, y, result, expected); +} + +void float_errPrefixTwo(char* name, double x, double y, double expected, double result) { + incFailure(); + printf("\033[0;31mERROR:\t\t%s(%f, %f)\tGOT: %f\tExpected: %f\033[0;0m\n", name, x, y, result, expected); } void bool_succPrefixOne(char* name, bool x, bool expected, bool result) { diff --git a/src/test/print/print.h b/src/test/print/print.h index 637cc5c..2c08103 100644 --- a/src/test/print/print.h +++ b/src/test/print/print.h @@ -3,17 +3,26 @@ void incSuccess(); void incFailure(); -void succ(char* name, int expected, int result); -void err(char* name, int expected, int result); +void succ(char* name, long expected, long result); +void err(char* name, long expected, long result); -void succPrefixOne(char* name, int x, int expected, int result); -void errPrefixOne(char* name, int x, int expected, int result); +void succ_f(char* name, double expected, double result); +void err_f(char* name, double expected, double result); -void succPrefixTwo(char* name, int x, int y, int expected, int result); -void errPrefixTwo(char* name, int x, int y, int expected, int result); +void succPrefixOne(char* name, long x, long expected, long result); +void errPrefixOne(char* name, long x, long expected, long result); -void succInfixTwo(char* name, int x, int y, int expected, int result); -void errInfixTwo(char* name, int x, int y, int expected, int result); +void float_succPrefixOne(char* name, double x, double expected, double result); +void float_errPrefixOne(char* name, double x, double expected, double result); + +void succPrefixTwo(char* name, long x, long y, long expected, long result); +void errPrefixTwo(char* name, long x, long y, long expected, long result); + +void float_succPrefixTwo(char* name, double x, double y, double expected, double result); +void float_errPrefixTwo(char* name, double x, double y, double expected, double result); + +void succInfixTwo(char* name, long x, long y, long expected, long result); +void errInfixTwo(char* name, long x, long y, long expected, long result); void bool_succPrefixOne(char* name, bool x, bool expected, bool result); void bool_errPrefixOne(char* name, bool x, bool expected, bool result); diff --git a/src/test/recursive/recursive.c b/src/test/recursive/recursive.c index 61ee88c..f063a2b 100644 --- a/src/test/recursive/recursive.c +++ b/src/test/recursive/recursive.c @@ -2,7 +2,7 @@ #include "recursive.h" #include "../print/print.h" -int recursiveTest(char* name, int x, int expected, int result) { +int recursiveTest(char* name, long x, long expected, long result) { if (expected == result) { succPrefixOne(name, x, expected, result); return 0; diff --git a/src/test/recursive/recursive.h b/src/test/recursive/recursive.h index 704036e..592a361 100644 --- a/src/test/recursive/recursive.h +++ b/src/test/recursive/recursive.h @@ -1 +1 @@ -int fac(int x); \ No newline at end of file +long fac(long x); \ No newline at end of file diff --git a/src/test/test.k b/src/test/test.k index a5c08ec..539f333 100644 --- a/src/test/test.k +++ b/src/test/test.k @@ -10,6 +10,10 @@ function mul(x: int, y: int): int { return (x * y); } +function div(x: int, y: int): int { + return (x / y); +} + function modulo(x: int, y: int): int { return (x % y); } @@ -102,6 +106,195 @@ function get10(): int { return arg10(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); } +// FLOATS + +function farg1(a: float, b: float, c: float, d: float, e: float, f: float, g: float, h: float, i: float ,j: float): float { + return a; +} + +function fget1(): float { + return farg1(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0); +} + +function farg2(a: float, b: float, c: float, d: float, e: float, f: float, g: float, h: float, i: float ,j: float): float { + return b; +} + +function fget2(): float { + return farg2(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0); +} + +function farg3(a: float, b: float, c: float, d: float, e: float, f: float, g: float, h: float, i: float ,j: float): float { + return c; +} + +function fget3(): float { + return farg3(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0); +} + +function farg4(a: float, b: float, c: float, d: float, e: float, f: float, g: float, h: float, i: float ,j: float): float { + return d; +} + +function fget4(): float { + return farg4(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0); +} + +function farg5(a: float, b: float, c: float, d: float, e: float, f: float, g: float, h: float, i: float ,j: float): float { + return e; +} + +function fget5(): float { + return farg5(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0); +} + +function farg6(a: float, b: float, c: float, d: float, e: float, f: float, g: float, h: float, i: float ,j: float): float { + return f; +} + +function fget6(): float { + return farg6(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0); +} + +function farg7(a: float, b: float, c: float, d: float, e: float, f: float, g: float, h: float, i: float ,j: float): float { + return g; +} + +function fget7(): float { + return farg7(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0); +} + +function farg8(a: float, b: float, c: float, d: float, e: float, f: float, g: float, h: float, i: float ,j: float): float { + return h; +} + +function fget8(): float { + return farg8(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0); +} + +function farg9(a: float, b: float, c: float, d: float, e: float, f: float, g: float, h: float, i: float ,j: float): float { + return i; +} + +function fget9(): float { + return farg9(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0); +} + +function farg10(a: float, b: float, c: float, d: float, e: float, f: float, g: float, h: float, i: float ,j: float): float { + return j; +} + +function fget10(): float { + return farg10(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0); +} + +function fargMix1(a: float, b: int, c: float, d: int, e: float, f: int, g: float, h: int, i: float ,j: int): float { + return a; +} + +function fgetMix1(): float { + return fargMix1(1.0, 2, 3.0, 4, 5.0, 6, 7.0, 8, 9.0, 10); +} + +function fargMix2(a: float, b: int, c: float, d: int, e: float, f: int, g: float, h: int, i: float ,j: int): int { + return b; +} + +function fgetMix2(): int { + return fargMix2(1.0, 2, 3.0, 4, 5.0, 6, 7.0, 8, 9.0, 10); +} + +function fargMix3(a: float, b: int, c: float, d: int, e: float, f: int, g: float, h: int, i: float ,j: int): float { + return c; +} + +function fgetMix3(): float { + return fargMix3(1.0, 2, 3.0, 4, 5.0, 6, 7.0, 8, 9.0, 10); +} + +function fargMix4(a: float, b: int, c: float, d: int, e: float, f: int, g: float, h: int, i: float ,j: int): int { + return d; +} + +function fgetMix4(): int { + return fargMix4(1.0, 2, 3.0, 4, 5.0, 6, 7.0, 8, 9.0, 10); +} + +function fargMix5(a: float, b: int, c: float, d: int, e: float, f: int, g: float, h: int, i: float ,j: int): float { + return e; +} + +function fgetMix5(): float { + return fargMix5(1.0, 2, 3.0, 4, 5.0, 6, 7.0, 8, 9.0, 10); +} + +function fargMix6(a: float, b: int, c: float, d: int, e: float, f: int, g: float, h: int, i: float ,j: int): int { + return f; +} + +function fgetMix6(): int { + return fargMix6(1.0, 2, 3.0, 4, 5.0, 6, 7.0, 8, 9.0, 10); +} + +function fargMix7(a: float, b: int, c: float, d: int, e: float, f: int, g: float, h: int, i: float ,j: int): float { + return g; +} + +function fgetMix7(): float { + return fargMix7(1.0, 2, 3.0, 4, 5.0, 6, 7.0, 8, 9.0, 10); +} + +function fargMix8(a: float, b: int, c: float, d: int, e: float, f: int, g: float, h: int, i: float ,j: int): int { + return h; +} + +function fgetMix8(): int { + return fargMix8(1.0, 2, 3.0, 4, 5.0, 6, 7.0, 8, 9.0, 10); +} + +function fargMix9(a: float, b: int, c: float, d: int, e: float, f: int, g: float, h: int, i: float ,j: int): float { + return i; +} + +function fgetMix9(): float { + return fargMix9(1.0, 2, 3.0, 4, 5.0, 6, 7.0, 8, 9.0, 10); +} + +function fargMix10(a: float, b: int, c: float, d: int, e: float, f: int, g: float, h: int, i: float ,j: int): int { + return j; +} + +function fgetMix10(): int { + return fargMix10(1.0, 2, 3.0, 4, 5.0, 6, 7.0, 8, 9.0, 10); +} + +function fadd(x: float, y: float): float { + return x + y; +} + +function fsub(x: float, y: float): float { + return x - y; +} + +function fmul(x: float, y: float): float { + return x * y; +} + +function fneg(x: float): float { + return -x; +} + +function fid(x: float): float { + return x; +} + +function fselfMinus(x: float): float { + x = (x - 1); + return x; +} + +// END FLOATS + function fac(x: int): int { if (x) { return (x * fac((x - 1))); @@ -206,6 +399,20 @@ function t8(): int { return (1 + 5) * 3; } +function mixadd(x: float, y: int): float { + return x + y; +} +function mixsub(x: float, y: int): float { + return x - y; +} + +function mixmul(x: float, y: int): float { + return x * y; +} + +function mixdiv(x: float, y: int): float { + return x / y; +} add(1, 1);