diff --git a/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 b/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 index a930eb1..4d8b903 100644 --- a/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 +++ b/src/main/antlr4/de/hsrm/compiler/Klang/Klang.g4 @@ -31,6 +31,7 @@ statement | return_statement | whileLoop | doWhileLoop + | forLoop ; print @@ -41,6 +42,11 @@ if_statement : IF OPAR cond = expression CPAR then = braced_block (ELSE (alt = braced_block | elif = if_statement) )? ; +variableDeclarationOrAssignment + : variable_assignment + | variable_declaration + ; + variable_declaration : LET IDENT (EQUAL expression)? ; @@ -66,7 +72,6 @@ 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 - | SUB expression #negateExpression | functionCall #functionCallExpression ; @@ -92,6 +97,12 @@ doWhileLoop : DO braced_block WHILE OPAR cond = expression CPAR SCOL ; +forLoop + : FOR OPAR init = variableDeclarationOrAssignment SCOL + cond = expression SCOL + step = variable_assignment CPAR braced_block + ; + PRINT: 'print'; IF: 'if'; ELSE: 'else'; @@ -100,6 +111,7 @@ RETURN: 'return'; LET: 'let'; WHILE: 'while'; DO: 'do'; +FOR: 'for'; SCOL: ';'; OBRK: '{'; diff --git a/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java b/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java index 393b34f..87cc448 100644 --- a/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java +++ b/src/main/java/de/hsrm/compiler/Klang/ContextAnalysis.java @@ -6,6 +6,7 @@ import java.util.HashSet; import de.hsrm.compiler.Klang.nodes.*; import de.hsrm.compiler.Klang.nodes.expressions.*; 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; @@ -81,6 +82,14 @@ public class ContextAnalysis extends KlangBaseVisitor { return new DoWhileLoop((Expression) condition, (Block) block); } + @Override + public Node visitForLoop(KlangParser.ForLoopContext ctx) { + Node init = this.visit(ctx.init); + Node condition = this.visit(ctx.cond); + Node step = this.visit(ctx.step); + Node block = this.visit(ctx.braced_block()); + return new ForLoop((Statement) init, (Expression) condition, (VariableAssignment) step, (Block) block); + } @Override public Node visitVariable_declaration(KlangParser.Variable_declarationContext ctx) { diff --git a/src/main/java/de/hsrm/compiler/Klang/nodes/loops/ForLoop.java b/src/main/java/de/hsrm/compiler/Klang/nodes/loops/ForLoop.java new file mode 100644 index 0000000..cc0d5c3 --- /dev/null +++ b/src/main/java/de/hsrm/compiler/Klang/nodes/loops/ForLoop.java @@ -0,0 +1,28 @@ +package de.hsrm.compiler.Klang.nodes.loops; + +import de.hsrm.compiler.Klang.nodes.statements.Statement; +import de.hsrm.compiler.Klang.nodes.statements.VariableAssignment; +import de.hsrm.compiler.Klang.nodes.Block; +import de.hsrm.compiler.Klang.nodes.expressions.Expression; +import de.hsrm.compiler.Klang.visitors.Visitor; + +public class ForLoop extends Statement { + + public Statement init; + public Expression condition; + public VariableAssignment step; + public Block block; + + public ForLoop(Statement init, Expression condition, VariableAssignment step, Block block) { + this.init = init; + this.condition = condition; + this.step = step; + this.block = block; + } + + @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/visitors/EvalVisitor.java b/src/main/java/de/hsrm/compiler/Klang/visitors/EvalVisitor.java index 13d7b6d..aae571b 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/EvalVisitor.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/EvalVisitor.java @@ -9,6 +9,7 @@ import de.hsrm.compiler.Klang.nodes.FunctionDefinition; import de.hsrm.compiler.Klang.nodes.Program; import de.hsrm.compiler.Klang.nodes.expressions.*; 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.*; @@ -175,6 +176,20 @@ public class EvalVisitor implements Visitor { return result; } + @Override + public Value visit(ForLoop e) { + e.init.welcome(this); + Value cond = e.condition.welcome(this); + Value result = null; + while (cond.asInteger() != 0) { + result = e.block.welcome(this); + e.step.welcome(this); + cond = e.condition.welcome(this); + } + + return result; + } + @Override public Value visit(PrintStatement e) { Value value = e.expression.welcome(this); 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 f4a6a98..eeb48aa 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/GenASM.java @@ -9,6 +9,7 @@ import java.util.TreeSet; import de.hsrm.compiler.Klang.nodes.*; import de.hsrm.compiler.Klang.nodes.expressions.*; 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.*; @@ -291,7 +292,7 @@ public class GenASM implements Visitor { this.ex.write(".L" + lblEnd + ":\n"); return null; } - + @Override public Void visit(WhileLoop e) { int lblCond = ++lCount; @@ -306,7 +307,6 @@ public class GenASM implements Visitor { return null; } - @Override public Void visit(DoWhileLoop e) { int lblStart = ++lCount; @@ -317,6 +317,23 @@ public class GenASM implements Visitor { this.ex.write(" jnz .L" + lblStart + "\n"); return null; } + + @Override + public Void visit(ForLoop e) { + int lblStart = ++lCount; + int lblEnd = ++lCount; + e.init.welcome(this); + this.ex.write(".L" + lblStart + ":\n"); + e.condition.welcome(this); + this.ex.write(" cmp $0, %rax\n"); + this.ex.write(" jz .L" + lblEnd + "\n"); + e.block.welcome(this); + e.step.welcome(this); + this.ex.write(" jmp .L" + lblStart + "\n"); + this.ex.write(".L" + lblEnd + ":\n"); + + return null; + } @Override public Void visit(PrintStatement e) { 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 5faa807..319b18f 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/GetVars.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/GetVars.java @@ -5,6 +5,7 @@ import java.util.Set; import de.hsrm.compiler.Klang.nodes.*; import de.hsrm.compiler.Klang.nodes.expressions.*; 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.*; @@ -135,6 +136,15 @@ class GetVars implements Visitor { return null; } + @Override + public Void visit(ForLoop e) { + e.init.welcome(this); + e.condition.welcome(this); + e.step.welcome(this); + e.block.welcome(this); + return null; + } + @Override public Void visit(PrintStatement e) { e.expression.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 2108d7b..14b9e97 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/PrettyPrintVisitor.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/PrettyPrintVisitor.java @@ -224,6 +224,19 @@ public class PrettyPrintVisitor implements Visitor { return null; } + @Override + public Void visit(ForLoop e) { + ex.write("for ("); + e.init.welcome(this); + ex.write(" "); + e.condition.welcome(this); + ex.write("; "); + e.step.welcome(this); + ex.write(") "); + e.block.welcome(this); + return null; + } + @Override public Void visit(PrintStatement e) { ex.write("print "); @@ -241,7 +254,6 @@ public class PrettyPrintVisitor implements Visitor { e.expression.welcome(this); } - ex.write(";"); return null; } @@ -249,7 +261,6 @@ public class PrettyPrintVisitor implements Visitor { public Void visit(VariableAssignment e) { ex.write(e.name + " = "); e.expression.welcome(this); - ex.write(";"); return null; } @@ -268,6 +279,9 @@ public class PrettyPrintVisitor implements Visitor { for (Statement stmt : e.statements) { ex.nl(); stmt.welcome(this); + if (stmt.getClass() == VariableAssignment.class || stmt.getClass() == VariableDeclaration.class) { + ex.write(";"); + } } ex.subIndent(); ex.nl(); 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 3dbbf15..02784b5 100644 --- a/src/main/java/de/hsrm/compiler/Klang/visitors/Visitor.java +++ b/src/main/java/de/hsrm/compiler/Klang/visitors/Visitor.java @@ -25,6 +25,7 @@ public interface Visitor { R visit(IfStatement e); R visit(WhileLoop e); R visit(DoWhileLoop e); + R visit(ForLoop e); R visit(PrintStatement e); R visit(VariableDeclaration e); R visit(VariableAssignment e); diff --git a/src/test/loop/loop.c b/src/test/loop/loop.c index b02eb38..b647e51 100644 --- a/src/test/loop/loop.c +++ b/src/test/loop/loop.c @@ -2,11 +2,11 @@ #include "loop.h" void printLoopSuccess(char* name, int x, int expected, int result) { - printf("SUCCESS:\t%s(%d)\tGOT: %d\tExpected: %d\n", name, x, result, expected); + printf("\033[0;32mSUCCESS:\t%s(%d)\tGOT: %d\tExpected: %d\033[0;0m\n", name, x, result, expected); } void printLoopError(char* name, int x, int expected, int result) { - printf("ERROR:\t\t%s(%d)\tGOT: %d\tExpected: %d\n", name, x, result, expected); + printf("\033[0;31mERROR:\t\t%s(%d)\tGOT: %d\tExpected: %d\033[0;0m\n", name, x, result, expected); } int loopTest(char* name, int x, int expected, int result) { @@ -25,6 +25,8 @@ int runLoopTests() { failed += loopTest("while", 5, 5, myWhile(5)); failed += loopTest("doWhile", 0, 1, myDoWhile(0)); failed += loopTest("doWhile", 1, 1, myDoWhile(1)); + failed += loopTest("for", 5, 5, myFor(5)); + failed += loopTest("for", 0, 0, myFor(0)); return failed; } \ No newline at end of file diff --git a/src/test/loop/loop.h b/src/test/loop/loop.h index bc6107c..7e8887e 100644 --- a/src/test/loop/loop.h +++ b/src/test/loop/loop.h @@ -1,2 +1,3 @@ int myWhile(int x); -int myDoWhile(int x); \ No newline at end of file +int myDoWhile(int x); +int myFor(int x); \ No newline at end of file diff --git a/src/test/tests.k b/src/test/tests.k index 9186df4..6a6abbf 100644 --- a/src/test/tests.k +++ b/src/test/tests.k @@ -154,4 +154,12 @@ function myDoWhile(end) { return cond; } +function myFor(end) { + let x = 0; + for (let i = 0; (i < end); i = (i + 1)) { + x = (x + 1); + } + return x; +} + add(1, 1);