diff --git a/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 b/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 index 4d8b903..136d971 100644 --- a/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 +++ b/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 @@ -72,13 +72,17 @@ expression | OPAR lhs=expression GT rhs=expression CPAR #greaterThanExpression | OPAR lhs=expression LTE rhs=expression CPAR #lessThanOrEqualToExpression | OPAR lhs=expression GTE rhs=expression CPAR #GreaterThanOrEqualToExpression + | OPAR lhs=expression OR rhs=expression CPAR #OrExpression + | OPAR lhs=expression AND rhs=expression CPAR #AndExpression | SUB expression #negateExpression + | NOT expression #NotExpression | functionCall #functionCallExpression ; atom : INTEGER_LITERAL #intAtom - | IDENT # variable + | BOOLEAN_LITERAL #boolAtom + | IDENT #variable ; functionCall @@ -126,6 +130,9 @@ LT: '<'; GT: '>'; LTE: '<='; GTE: '>='; +OR: '||'; +AND: '&&'; +NOT: '!'; MUL: '*'; ADD: '+'; @@ -137,6 +144,11 @@ INTEGER_LITERAL : [0-9]+ ; +BOOLEAN_LITERAL + : 'true' + | 'false' + ; + IDENT : [a-zA-Z][a-zA-Z0-9]* ; diff --git a/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java b/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java index 87cc448..80facdb 100644 --- a/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java +++ b/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java @@ -126,6 +126,16 @@ public class ContextAnalysis extends KlangBaseVisitor { return new ReturnStatement(expression); } + @Override + public Node visitOrExpression(KlangParser.OrExpressionContext ctx) { + return new OrExpression((Expression) this.visit(ctx.lhs), (Expression) this.visit(ctx.rhs)); + } + + @Override + public Node visitAndExpression(KlangParser.AndExpressionContext ctx) { + return new AndExpression((Expression) this.visit(ctx.lhs), (Expression) this.visit(ctx.rhs)); + } + @Override public Node visitAdditionExpression(KlangParser.AdditionExpressionContext ctx) { return new AdditionExpression((Expression) this.visit(ctx.lhs), (Expression) this.visit(ctx.rhs)); @@ -186,6 +196,11 @@ public class ContextAnalysis extends KlangBaseVisitor { return new NegateExpression((Expression) this.visit(ctx.expression())); } + @Override + public Node visitNotExpression(KlangParser.NotExpressionContext ctx) { + return new NotExpression((Expression) this.visit(ctx.expression())); + } + @Override public Node visitVariable(KlangParser.VariableContext ctx) { String name = ctx.IDENT().getText(); @@ -209,6 +224,13 @@ public class ContextAnalysis extends KlangBaseVisitor { return n; } + @Override + public Node visitBoolAtom(KlangParser.BoolAtomContext ctx) { + Node n = new BooleanExpression(ctx.getText().equals("true") ? true : false); + n.type = Type.getBooleanType(); + return n; + } + @Override public Node visitFunctionDef(KlangParser.FunctionDefContext ctx) { String name = ctx.funcName.getText(); diff --git a/src/main/java/de/hsrm/compiler/Klang/Value.java b/src/main/java/de/hsrm/compiler/Klang/Value.java index ebaec1e..81c05ea 100644 --- a/src/main/java/de/hsrm/compiler/Klang/Value.java +++ b/src/main/java/de/hsrm/compiler/Klang/Value.java @@ -10,4 +10,8 @@ public class Value { public int asInteger() { return (int) this.value; } + + public boolean asBoolean() { + return (boolean) this.value; + } } diff --git a/src/main/java/de/hsrm/compiler/Klang/nodes/expressions/AndExpression.java b/src/main/java/de/hsrm/compiler/Klang/nodes/expressions/AndExpression.java new file mode 100644 index 0000000..523a8fe --- /dev/null +++ b/src/main/java/de/hsrm/compiler/Klang/nodes/expressions/AndExpression.java @@ -0,0 +1,14 @@ +package de.hsrm.compiler.Klang.nodes.expressions; + +import de.hsrm.compiler.Klang.visitors.Visitor; + +public class AndExpression extends BinaryExpression { + public AndExpression(Expression lhs, Expression rhs) { + super(lhs, rhs); + } + + @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/nodes/expressions/BooleanExpression.java b/src/main/java/de/hsrm/compiler/Klang/nodes/expressions/BooleanExpression.java new file mode 100644 index 0000000..fadb6f5 --- /dev/null +++ b/src/main/java/de/hsrm/compiler/Klang/nodes/expressions/BooleanExpression.java @@ -0,0 +1,16 @@ +package de.hsrm.compiler.Klang.nodes.expressions; + +import de.hsrm.compiler.Klang.visitors.Visitor; + +public class BooleanExpression extends Expression { + public boolean value; + + public BooleanExpression(boolean 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/nodes/expressions/NotExpression.java b/src/main/java/de/hsrm/compiler/Klang/nodes/expressions/NotExpression.java new file mode 100644 index 0000000..f35dd29 --- /dev/null +++ b/src/main/java/de/hsrm/compiler/Klang/nodes/expressions/NotExpression.java @@ -0,0 +1,16 @@ +package de.hsrm.compiler.Klang.nodes.expressions; + +import de.hsrm.compiler.Klang.visitors.Visitor; + +public class NotExpression extends UnaryExpression { + + public NotExpression(Expression lhs) { + super(lhs); + } + + @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/nodes/expressions/OrExpression.java b/src/main/java/de/hsrm/compiler/Klang/nodes/expressions/OrExpression.java new file mode 100644 index 0000000..6514275 --- /dev/null +++ b/src/main/java/de/hsrm/compiler/Klang/nodes/expressions/OrExpression.java @@ -0,0 +1,14 @@ +package de.hsrm.compiler.Klang.nodes.expressions; + +import de.hsrm.compiler.Klang.visitors.Visitor; + +public class OrExpression extends BinaryExpression { + public OrExpression(Expression lhs, Expression rhs) { + super(lhs, rhs); + } + + @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/BooleanType.java b/src/main/java/de/hsrm/compiler/Klang/types/BooleanType.java new file mode 100644 index 0000000..d5d1517 --- /dev/null +++ b/src/main/java/de/hsrm/compiler/Klang/types/BooleanType.java @@ -0,0 +1,20 @@ +package de.hsrm.compiler.Klang.types; + +public class BooleanType extends PrimitiveType { + + private static BooleanType instance = null; + + public static BooleanType getType() { + if (instance != null) { + return instance; + } + instance = new BooleanType(); + return instance; + } + + @Override + public boolean isBooleanType() { + 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 b45c08f..3a87c7a 100644 --- a/src/main/java/de/hsrm/compiler/Klang/types/PrimitiveType.java +++ b/src/main/java/de/hsrm/compiler/Klang/types/PrimitiveType.java @@ -10,4 +10,8 @@ public abstract class PrimitiveType extends Type { public boolean isIntegerType() { return false; }; + + public boolean isBooleanType() { + 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 db90f30..bc429d7 100644 --- a/src/main/java/de/hsrm/compiler/Klang/types/Type.java +++ b/src/main/java/de/hsrm/compiler/Klang/types/Type.java @@ -8,5 +8,9 @@ public abstract class Type { return IntegerType.getType(); } + public static BooleanType getBooleanType() { + return BooleanType.getType(); + } + public abstract boolean isPrimitiveType(); } \ 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 aae571b..7151a76 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/EvalVisitor.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/EvalVisitor.java @@ -23,6 +23,11 @@ public class EvalVisitor implements Visitor { return new Value(e.value); } + @Override + public Value visit(BooleanExpression e) { + return new Value(e.value); + } + @Override public Value visit(EqualityExpression e) { Value lhs = e.lhs.welcome(this); @@ -124,6 +129,26 @@ public class EvalVisitor implements Visitor { return new Value(-a.asInteger()); } + @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()); + } + + @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()); + } + + @Override + public Value visit(NotExpression e) { + Value lhs = e.lhs.welcome(this); + return new Value(!lhs.asBoolean()); + } + @Override public Value visit(Variable e) { Value result = this.env.get(e.name); 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 d021f1d..8dcc6e0 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java @@ -78,6 +78,12 @@ public class GenASM implements Visitor { return null; } + @Override + public Void visit(BooleanExpression e) { + this.ex.write(" movq $" + (e.value ? 1 : 0) + ", %rax\n"); + return null; + } + @Override public Void visit(Variable e) { this.ex.write(" movq " + this.env.get(e.name) + "(%rbp), %rax\n"); @@ -272,6 +278,103 @@ public class GenASM implements Visitor { return null; } + @Override + public Void visit(OrExpression e) { + int lblTrue = ++lCount; + int lblFalse = ++lCount; + int lblEnd = ++lCount; + + // Werte LHS aus + // Wenn LHS != 0 bedeutet das true + // also können wir direkt sagen dass das Ergebnis true ist + e.lhs.welcome(this); + this.ex.write(" cmpq $0, %rax\n"); + this.ex.write(" jne .L" + lblTrue + "\n"); + + // LHS war false, also werte RHS aus + // Wenn RHS == 0 bedeutet das false, + // also ist das Gesamtergebnis false + e.rhs.welcome(this); + this.ex.write(" cmpq $0, %rax\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(" 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(" movq $0, %rax\n"); + + // Das hier ist das ende + this.ex.write(".L" + lblEnd + ":\n"); + return null; + } + + @Override + public Void visit(AndExpression e) { + int lblTrue = ++lCount; + int lblFalse = ++lCount; + int lblEnd = ++lCount; + + // Werte LHS aus + // Wenn LHS == 0, bedeutet das false + // also können wir direkt sagen dass das Ergebnis false ist + e.lhs.welcome(this); + this.ex.write(" cmpq $0, %rax\n"); + this.ex.write(" je .L" + lblFalse + "\n"); + + // LHS war true, also werte RHS aus. + // Wenn RHS == 0, bedeutet das false + // also ist das Gesamtergebnis false + e.rhs.welcome(this); + this.ex.write(" cmpq $0, %rax\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(" 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(" movq $0, %rax\n"); + + // Das hier ist das ende + this.ex.write(".L" + lblEnd +":\n"); + return null; + } + + @Override + 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"); + + // Hier ist das Ergebnis true + // Springe am false Teil vorbei + this.ex.write(" movq $1, %rax\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("movq $0, %rax\n"); + + // Hier ist das Ende + this.ex.write(".L" +lblEnd + ":\n"); + return null; + } + @Override public Void visit(IfStatement e) { int lblElse = ++lCount; @@ -324,7 +427,7 @@ public class GenASM implements Visitor { this.ex.write(" jnz .L" + lblStart + "\n"); return null; } - + @Override public Void visit(ForLoop e) { int lblStart = ++lCount; @@ -338,7 +441,7 @@ public class GenASM implements Visitor { e.step.welcome(this); this.ex.write(" jmp .L" + lblStart + "\n"); this.ex.write(".L" + lblEnd + ":\n"); - + return null; } @@ -453,7 +556,7 @@ public class GenASM implements Visitor { this.ex.write("\n"); } this.ex.write(".globl " + mainName + "\n"); - this.ex.write(".type " +mainName + ", @function\n"); + this.ex.write(".type " + mainName + ", @function\n"); this.ex.write(mainName + ":\n"); this.ex.write(" pushq %rbp\n"); this.ex.write(" movq %rsp, %rbp\n"); 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 319b18f..0d55d41 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/GetVars.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/GetVars.java @@ -22,6 +22,11 @@ class GetVars implements Visitor { return null; } + @Override + public Void visit(BooleanExpression e) { + return null; + } + @Override public Void visit(Variable e) { return null; @@ -110,6 +115,26 @@ class GetVars implements Visitor { return null; } + @Override + public Void visit(OrExpression e) { + e.lhs.welcome(this); + e.rhs.welcome(this); + return null; + } + + @Override + public Void visit(AndExpression e) { + e.lhs.welcome(this); + e.rhs.welcome(this); + return null; + } + + @Override + public Void visit(NotExpression e) { + e.lhs.welcome(this); + return null; + } + @Override public Void visit(IfStatement e) { e.cond.welcome(this); 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 14b9e97..0b35907 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(BooleanExpression e) { + ex.write(e.value); + return null; + } + @Override public Void visit(EqualityExpression e) { ex.write("("); @@ -189,6 +195,33 @@ public class PrettyPrintVisitor implements Visitor { return null; } + @Override + public Void visit(OrExpression e) { + ex.write("("); + e.lhs.welcome(this); + ex.write(" || "); + e.rhs.welcome(this); + ex.write(")"); + return null; + } + + @Override + public Void visit(AndExpression e) { + ex.write("("); + e.lhs.welcome(this); + ex.write(" && "); + e.rhs.welcome(this); + ex.write(")"); + return null; + } + + @Override + public Void visit(NotExpression e) { + ex.write("!"); + e.lhs.welcome(this); + return null; + } + @Override public Void visit(IfStatement e) { ex.write("if ("); 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 02784b5..b0abb24 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/Visitor.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/Visitor.java @@ -8,7 +8,11 @@ import de.hsrm.compiler.Klang.nodes.loops.*; import de.hsrm.compiler.Klang.nodes.statements.*; public interface Visitor { + R visit(OrExpression e); + R visit(AndExpression e); + R visit (NotExpression e); R visit(IntegerExpression e); + R visit(BooleanExpression e); R visit(Variable e); R visit(AdditionExpression e); R visit(EqualityExpression e); diff --git a/src/test/comparison/comparison.c b/src/test/comparison/comparison.c index c6d12d4..46bc381 100644 --- a/src/test/comparison/comparison.c +++ b/src/test/comparison/comparison.c @@ -12,6 +12,26 @@ int comparisonTest(char* name, int x, int y, int expected, int result) { } } +int boolTestOne(char* name, bool x, bool expected, bool result) { + if (expected == result) { + bool_succPrefixOne(name, x, expected, result); + return 0; + } else { + bool_errPrefixOne(name, x, expected, result); + return 1; + } +} + +int boolTestTwo(char* name, bool a, bool b, bool expected, bool result) { + if (expected == result) { + bool_succInfixTwo(name, a, b, expected, result); + return 0; + } else { + bool_errInfixTwo(name, a, b, expected, result); + return 1; + } +} + void runComparisonTests() { printf("\nComparison Tests \n"); comparisonTest("==", 1, 1, 1, eq(1, 1)); @@ -43,4 +63,17 @@ void runComparisonTests() { comparisonTest(">=", 1, 0, 1, gte(1, 0)); comparisonTest(">=", 0, 1, 0, gte(0, 1)); comparisonTest(">=", 0, 0, 1, gte(0, 0)); + + boolTestTwo("&&", true, true, true, and(true, true)); + boolTestTwo("&&", true, false, false, and(true, false)); + boolTestTwo("&&", false, true, false, and(false, true)); + boolTestTwo("&&", false, false, false, and(false, false)); + + boolTestTwo("||", true, true, true, or(true, true)); + boolTestTwo("||", true, false, true, or(true, false)); + boolTestTwo("||", false, true, true, or(false, true)); + boolTestTwo("||", false, false, false, or(false, false)); + + boolTestOne("!", true, false, not(true)); + boolTestOne("!", false, true, not(false)); } \ No newline at end of file diff --git a/src/test/comparison/comparison.h b/src/test/comparison/comparison.h index 9d4b35a..f5a9566 100644 --- a/src/test/comparison/comparison.h +++ b/src/test/comparison/comparison.h @@ -1,6 +1,12 @@ +#include + int eq(int x, int y); int neq(int x, int y); int lt(int x, int y); int lte(int x, int y); int gt(int x, int y); int gte(int x, int y); + +bool and(bool a, bool b); +bool or(bool a, bool b); +bool not(bool a); \ No newline at end of file diff --git a/src/test/print/print.c b/src/test/print/print.c index 511a67e..21109f9 100644 --- a/src/test/print/print.c +++ b/src/test/print/print.c @@ -1,6 +1,13 @@ #include #include "print.h" +char* printBool(bool a) { + if (a == true) { + return "true"; + } + return "false"; +} + void succInfixTwo(char* name, int x, int y, int expected, int result) { incSuccess(); printf("\033[0;32mSUCCESS:\t%d %s %d\tGOT: %d\tExpected: %d\033[0;0m\n", x, name, y, result, expected); @@ -39,4 +46,24 @@ void succPrefixTwo(char* name, int x, int y, int expected, int result) { void errPrefixTwo(char* name, int x, int y, int expected, int result) { incFailure(); printf("\033[0;31mERROR:\t\t%s(%d, %d)\tGOT: %d\tExpected: %d\033[0;0m\n", name, x, y, result, expected); +} + +void bool_succPrefixOne(char* name, bool x, bool expected, bool result) { + incSuccess(); + printf("\033[0;32mSUCCESS:\t%s%s\tGOT: %s\tExpected: %s\033[0;0m\n", name, printBool(x), printBool(result), printBool(expected)); +} + +void bool_errPrefixOne(char* name, bool x, bool expected, bool result) { + incFailure(); + printf("\033[0;31mERROR:\t\t%s%s\tGOT: %s\tExpected: %s\033[0;0m\n", name, printBool(x), printBool(result), printBool(expected)); +} + +void bool_succInfixTwo(char* name, bool a, bool b, bool expected, bool result) { + incSuccess(); + printf("\033[0;32mSUCCESS:\t%s %s %s\tGOT: %s\tExpected: %s\033[0;0m\n", printBool(a), name, printBool(b), printBool(result), printBool(expected)); +} + +void bool_errInfixTwo(char* name, bool a, bool b, bool expected, bool result) { + incFailure(); + printf("\033[0;31mERROR:\t\t%s %s %s\tGOT: %s\tExpected: %s\033[0;0m\n", printBool(a), name, printBool(b), printBool(result), printBool(expected)); } \ No newline at end of file diff --git a/src/test/print/print.h b/src/test/print/print.h index d274b51..637cc5c 100644 --- a/src/test/print/print.h +++ b/src/test/print/print.h @@ -1,3 +1,5 @@ +#include + void incSuccess(); void incFailure(); @@ -6,8 +8,15 @@ void err(char* name, int expected, int result); void succPrefixOne(char* name, int x, int expected, int result); void errPrefixOne(char* name, int x, int expected, int 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 succInfixTwo(char* name, int x, int y, int expected, int result); -void errInfixTwo(char* name, int x, int y, int expected, int result); \ No newline at end of file +void errInfixTwo(char* name, int x, int y, int expected, int result); + +void bool_succPrefixOne(char* name, bool x, bool expected, bool result); +void bool_errPrefixOne(char* name, bool x, bool expected, bool result); + +void bool_succInfixTwo(char* name, bool x, bool y, bool expected, bool result); +void bool_errInfixTwo(char* name, bool x, bool y, bool expected, bool result); diff --git a/src/test/test.k b/src/test/test.k index 6a6abbf..5478bca 100644 --- a/src/test/test.k +++ b/src/test/test.k @@ -162,4 +162,16 @@ function myFor(end) { return x; } +function and(a, b) { + return (a && b); +} + +function or(a, b) { + return (a || b); +} + +function not(a) { + return !a; +} + add(1, 1);