Added while loop

This commit is contained in:
Marvin Kaiser
2020-01-13 16:00:42 +01:00
parent 33215a1b4a
commit bd4ae1d605
15 changed files with 428 additions and 299 deletions

View File

@@ -1,2 +1,4 @@
# Klang - The Kaiser language
This is the project for Klang - the Kaiser language.
This is the project for Klang - the Kaiser language.
0 is false

View File

@@ -18,7 +18,7 @@ runTest: ./src/test/test
./src/test/test
./src/test/test: ./src/test/tests.s
gcc -o ./src/test/test ./src/test/tests.s ./src/test/functionCall/functionCall.c ./src/test/recursive/recursive.c ./src/test/comparison/comparison.c ./src/test/testCode.c
gcc -o ./src/test/test ./src/test/tests.s ./src/test/functionCall/functionCall.c ./src/test/while/while.c ./src/test/recursive/recursive.c ./src/test/comparison/comparison.c ./src/test/testCode.c
./src/test/tests.s: target/klang-1.0-jar-with-dependencies.jar
java -cp target/klang-1.0-jar-with-dependencies.jar de.hsrm.compiler.Klang.Klang < ./src/test/tests.k > ./src/test/tests.s

View File

@@ -26,6 +26,7 @@ statement
| variable_declaration
| variable_assignment
| return_statement
| whileLoop
;
print
@@ -79,12 +80,17 @@ arguments
: (expression (COMMA expression)*)?
;
whileLoop
: WHILE OPAR cond = expression CPAR braced_block
;
PRINT: 'print';
IF: 'if';
ELSE: 'else';
FUNC: 'function';
RETURN: 'return';
LET: 'let';
WHILE: 'while';
SCOL: ';';
OBRK: '{';

View File

@@ -5,6 +5,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.whileLoop;
import de.hsrm.compiler.Klang.nodes.statements.*;
import de.hsrm.compiler.Klang.types.Type;
@@ -57,6 +58,14 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
}
}
@Override
public Node visitWhileLoop(KlangParser.WhileLoopContext ctx) {
Node condition = this.visit(ctx.cond);
Node block = this.visit(ctx.braced_block());
return new whileLoop((Expression) condition, (Block) block);
}
@Override
public Node visitVariable_declaration(KlangParser.Variable_declarationContext ctx) {
String name = ctx.IDENT().getText();

View File

@@ -0,0 +1,24 @@
package de.hsrm.compiler.Klang.nodes.loops;
import de.hsrm.compiler.Klang.nodes.Block;
import de.hsrm.compiler.Klang.nodes.statements.Statement;;
import de.hsrm.compiler.Klang.nodes.expressions.Expression;
import de.hsrm.compiler.Klang.visitors.Visitor;
public class whileLoop extends Statement {
public Expression cond;
public Block block;
public Block alt;
public whileLoop(Expression cond, Block block) {
this.cond = cond;
this.block = block;
}
@Override
public <R> R welcome(Visitor<R> v) {
return v.visit(this);
}
}

View File

@@ -8,6 +8,7 @@ import de.hsrm.compiler.Klang.nodes.Block;
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.whileLoop;
import de.hsrm.compiler.Klang.nodes.statements.*;
public class EvalVisitor implements Visitor<Value> {
@@ -151,6 +152,18 @@ public class EvalVisitor implements Visitor<Value> {
return result;
}
@Override
public Value visit(whileLoop e) {
Value condition = e.cond.welcome(this);
Value result = null;
while(condition.asInteger() != 0) {
System.out.println(condition.asInteger());
result = e.block.welcome(this);
}
return result;
}
@Override
public Value visit(PrintStatement e) {
Value value = e.expression.welcome(this);

View File

@@ -8,6 +8,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.whileLoop;
import de.hsrm.compiler.Klang.nodes.statements.*;
public class GenASM implements Visitor<Void> {
@@ -264,30 +265,44 @@ public class GenASM implements Visitor<Void> {
@Override
public Void visit(IfStatement e) {
int lblElse = ++lCount;
int lblEnd = ++lCount;
boolean hasElse = e.alt != null || e.elif != null;
e.cond.welcome(this);
this.ex.write(" cmp $0, %rax\n");
// in case of cond evaluating to false, jump to else/elif
// Jump to end if there is no else part, this saves a label declaration
if (hasElse) {
this.ex.write(" jz .L" + lblElse + "\n");
int lblElse = ++lCount;
int lblEnd = ++lCount;
boolean hasElse = e.alt != null || e.elif != null;
e.cond.welcome(this);
this.ex.write(" cmp $0, %rax\n");
// in case of cond evaluating to false, jump to else/elif
// Jump to end if there is no else part, this saves a label declaration
if (hasElse) {
this.ex.write(" jz .L" + lblElse + "\n");
} else {
this.ex.write(" jz .L" + lblEnd + "\n");
}
e.then.welcome(this);
if (hasElse) {
this.ex.write(" jmp .L" + lblEnd + "\n");
this.ex.write(".L" + lblElse + ":\n");
if (e.alt != null) {
e.alt.welcome(this);
} else {
this.ex.write(" jz .L" + lblEnd + "\n");
e.elif.welcome(this);
}
e.then.welcome(this);
if (hasElse) {
this.ex.write(" jmp .L" + lblEnd + "\n");
this.ex.write(".L" + lblElse + ":\n");
if (e.alt != null) {
e.alt.welcome(this);
} else {
e.elif.welcome(this);
}
}
this.ex.write(".L" + lblEnd + ":\n");
return null;
}
this.ex.write(".L" + lblEnd + ":\n");
return null;
}
@Override
public Void visit(whileLoop e) {
int lblCond = ++lCount;
int lblEnd = ++lCount;
this.ex.write(".L" + lblCond + ":\n");
e.cond.welcome(this);
this.ex.write(" cmp $0, %rax\n");
this.ex.write(" jz .L" + lblEnd + "\n");
e.block.welcome(this);
this.ex.write(" jmp .L" + lblCond + "\n");
this.ex.write(".L" + lblEnd + ":\n");
return null;
}
@Override
@@ -351,10 +366,10 @@ public class GenASM implements Visitor<Void> {
// Merke dir die offsets der parameter, die direkt auf den stack gelegt wurden
int offset = 16; // Per Stack übergebene Parameter liegen über unserm BSP
// Per stack übergebene variablen in env registrieren
for (int i = this.rs.length; i < e.parameters.length; i++) {
env.put(e.parameters[i], offset);
offset += 8;
}
for (int i = this.rs.length; i < e.parameters.length; i++) {
env.put(e.parameters[i], offset);
offset += 8;
}
// pushe die aufrufparameter aus den Registern wieder auf den Stack
offset = 0;
@@ -363,7 +378,7 @@ public class GenASM implements Visitor<Void> {
offset -= 8;
this.env.put(e.parameters[i], offset); // negative, liegt unter aktuellem BP
}
// Reserviere Platz auf dem Stack für jede lokale variable
for (String lok_var : vars) {
offset -= 8;
@@ -384,7 +399,7 @@ public class GenASM implements Visitor<Void> {
}
// Den Rest auf den stack pushen
for (int i = e.arguments.length -1; i >= this.rs.length; i--) {
for (int i = e.arguments.length - 1; i >= this.rs.length; i--) {
e.arguments[i].welcome(this);
this.ex.write(" pushq %rax\n");
}

View File

@@ -4,6 +4,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.whileLoop;
import de.hsrm.compiler.Klang.nodes.statements.*;
class GetVars implements Visitor<Void> {
@@ -119,6 +120,13 @@ class GetVars implements Visitor<Void> {
return null;
}
@Override
public Void visit(whileLoop e) {
e.cond.welcome(this);
e.block.welcome(this);
return null;
}
@Override
public Void visit(PrintStatement e) {
e.expression.welcome(this);

View File

@@ -3,298 +3,308 @@ package de.hsrm.compiler.Klang.visitors;
import java.io.*;
import de.hsrm.compiler.Klang.nodes.*;
import de.hsrm.compiler.Klang.nodes.expressions.*;
import de.hsrm.compiler.Klang.nodes.loops.whileLoop;
import de.hsrm.compiler.Klang.nodes.statements.*;
public class PrettyPrintVisitor implements Visitor<Void> {
public static class ExWriter {
Writer w;
String indent = "";
public static class ExWriter {
Writer w;
String indent = "";
void addIndent() {
indent = indent + " ";
}
void subIndent() {
indent = indent.substring(2);
}
void nl() {
write("\n" + indent);
}
int lbl = 0;
int next() {
return lbl++;
}
public ExWriter(Writer w) {
this.w = w;
}
void lnwrite(Object o) {
nl();
write(o);
}
void write(Object o) {
try {
w.write(o + "");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
void addIndent() {
indent = indent + " ";
}
public ExWriter ex;
public PrettyPrintVisitor(ExWriter ex) {
this.ex = ex;
void subIndent() {
indent = indent.substring(2);
}
@Override
public Void visit(Program e) {
for (var funcDef : e.funcs) {
funcDef.welcome(this);
ex.nl();
ex.nl();
}
e.expression.welcome(this);
ex.write(";");
return null;
void nl() {
write("\n" + indent);
}
@Override
public Void visit(IntegerExpression e) {
ex.write(e.value);
return null;
int lbl = 0;
int next() {
return lbl++;
}
@Override
public Void visit(EqualityExpression e) {
ex.write("(");
e.lhs.welcome(this);
ex.write(" == ");
e.rhs.welcome(this);
ex.write(")");
return null;
public ExWriter(Writer w) {
this.w = w;
}
@Override
public Void visit(NotEqualityExpression e) {
ex.write("(");
e.lhs.welcome(this);
ex.write(" != ");
e.rhs.welcome(this);
ex.write(")");
return null;
}
@Override
public Void visit(GTExpression e) {
ex.write("(");
e.lhs.welcome(this);
ex.write(" > ");
e.rhs.welcome(this);
ex.write(")");
return null;
}
@Override
public Void visit(GTEExpression e) {
ex.write("(");
e.lhs.welcome(this);
ex.write(" >= ");
e.rhs.welcome(this);
ex.write(")");
return null;
}
@Override
public Void visit(LTExpression e) {
ex.write("(");
e.lhs.welcome(this);
ex.write(" < ");
e.rhs.welcome(this);
ex.write(")");
return null;
}
@Override
public Void visit(LTEExpression e) {
ex.write("(");
e.lhs.welcome(this);
ex.write(" <= ");
e.rhs.welcome(this);
ex.write(")");
return null;
void lnwrite(Object o) {
nl();
write(o);
}
@Override
public Void visit(AdditionExpression e) {
ex.write("(");
e.lhs.welcome(this);
ex.write(" + ");
e.rhs.welcome(this);
ex.write(")");
return null;
void write(Object o) {
try {
w.write(o + "");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
public ExWriter ex;
public PrettyPrintVisitor(ExWriter ex) {
this.ex = ex;
}
@Override
public Void visit(Program e) {
for (var funcDef : e.funcs) {
funcDef.welcome(this);
ex.nl();
ex.nl();
}
e.expression.welcome(this);
ex.write(";");
return null;
}
@Override
public Void visit(IntegerExpression e) {
ex.write(e.value);
return null;
}
@Override
public Void visit(EqualityExpression e) {
ex.write("(");
e.lhs.welcome(this);
ex.write(" == ");
e.rhs.welcome(this);
ex.write(")");
return null;
}
@Override
public Void visit(NotEqualityExpression e) {
ex.write("(");
e.lhs.welcome(this);
ex.write(" != ");
e.rhs.welcome(this);
ex.write(")");
return null;
}
@Override
public Void visit(GTExpression e) {
ex.write("(");
e.lhs.welcome(this);
ex.write(" > ");
e.rhs.welcome(this);
ex.write(")");
return null;
}
@Override
public Void visit(GTEExpression e) {
ex.write("(");
e.lhs.welcome(this);
ex.write(" >= ");
e.rhs.welcome(this);
ex.write(")");
return null;
}
@Override
public Void visit(LTExpression e) {
ex.write("(");
e.lhs.welcome(this);
ex.write(" < ");
e.rhs.welcome(this);
ex.write(")");
return null;
}
@Override
public Void visit(LTEExpression e) {
ex.write("(");
e.lhs.welcome(this);
ex.write(" <= ");
e.rhs.welcome(this);
ex.write(")");
return null;
}
@Override
public Void visit(AdditionExpression e) {
ex.write("(");
e.lhs.welcome(this);
ex.write(" + ");
e.rhs.welcome(this);
ex.write(")");
return null;
}
@Override
public Void visit(SubstractionExpression e) {
ex.write("(");
e.lhs.welcome(this);
ex.write(" - ");
e.rhs.welcome(this);
ex.write(")");
return null;
}
@Override
public Void visit(MultiplicationExpression e) {
ex.write("(");
e.lhs.welcome(this);
ex.write(" * ");
e.rhs.welcome(this);
ex.write(")");
return null;
}
@Override
public Void visit(DivisionExpression e) {
ex.write("(");
e.lhs.welcome(this);
ex.write(" / ");
e.rhs.welcome(this);
ex.write(")");
return null;
}
@Override
public Void visit(ModuloExpression e) {
ex.write("(");
e.lhs.welcome(this);
ex.write(" % ");
e.rhs.welcome(this);
ex.write(")");
return null;
}
@Override
public Void visit(NegateExpression e) {
ex.write(" - ");
e.lhs.welcome(this);
return null;
}
@Override
public Void visit(IfStatement e) {
ex.write("if (");
e.cond.welcome(this);
ex.write(") ");
e.then.welcome(this);
if (e.alt != null) {
ex.write(" else ");
e.alt.welcome(this);
} else if (e.elif != null) {
ex.write(" else ");
e.elif.welcome(this);
}
return null;
}
@Override
public Void visit(whileLoop e) {
ex.write("while (");
e.cond.welcome(this);
ex.write(") ");
e.block.welcome(this);
return null;
}
@Override
public Void visit(PrintStatement e) {
ex.write("print ");
e.expression.welcome(this);
ex.write(";");
return null;
}
@Override
public Void visit(VariableDeclaration e) {
ex.write("let " + e.name);
if (e.expression != null) {
ex.write(" = ");
e.expression.welcome(this);
}
@Override
public Void visit(SubstractionExpression e) {
ex.write("(");
e.lhs.welcome(this);
ex.write(" - ");
e.rhs.welcome(this);
ex.write(")");
return null;
ex.write(";");
return null;
}
@Override
public Void visit(VariableAssignment e) {
ex.write(e.name + " = ");
e.expression.welcome(this);
ex.write(";");
return null;
}
@Override
public Void visit(ReturnStatement e) {
ex.write("return ");
e.expression.welcome(this);
ex.write(";");
return null;
}
@Override
public Void visit(Block e) {
ex.write("{");
ex.addIndent();
for (Statement stmt : e.statements) {
ex.nl();
stmt.welcome(this);
}
ex.subIndent();
ex.nl();
ex.write("}");
return null;
}
@Override
public Void visit(MultiplicationExpression e) {
ex.write("(");
e.lhs.welcome(this);
ex.write(" * ");
e.rhs.welcome(this);
ex.write(")");
return null;
@Override
public Void visit(FunctionDefinition e) {
ex.write("function ");
ex.write(e.name);
ex.write("(");
boolean first = true;
for (String param : e.parameters) {
if (!first) {
ex.write(", ");
} else {
first = false;
}
ex.write(param);
}
ex.write(") ");
e.block.welcome(this);
return null;
}
@Override
public Void visit(DivisionExpression e) {
ex.write("(");
e.lhs.welcome(this);
ex.write(" / ");
e.rhs.welcome(this);
ex.write(")");
return null;
@Override
public Void visit(FunctionCall e) {
ex.write(e.name);
ex.write("(");
boolean first = true;
for (Expression arg : e.arguments) {
if (!first) {
ex.write(", ");
} else {
first = false;
}
arg.welcome(this);
}
ex.write(")");
return null;
}
@Override
public Void visit(ModuloExpression e) {
ex.write("(");
e.lhs.welcome(this);
ex.write(" % ");
e.rhs.welcome(this);
ex.write(")");
return null;
}
@Override
public Void visit(NegateExpression e) {
ex.write(" - ");
e.lhs.welcome(this);
return null;
}
@Override
public Void visit(IfStatement e) {
ex.write("if (");
e.cond.welcome(this);
ex.write(") ");
e.then.welcome(this);
if (e.alt != null) {
ex.write(" else ");
e.alt.welcome(this);
} else if (e.elif != null) {
ex.write(" else ");
e.elif.welcome(this);
}
return null;
}
@Override
public Void visit(PrintStatement e) {
ex.write("print ");
e.expression.welcome(this);
ex.write(";");
return null;
}
@Override
public Void visit(VariableDeclaration e) {
ex.write("let " + e.name);
if (e.expression != null) {
ex.write(" = ");
e.expression.welcome(this);
}
ex.write(";");
return null;
}
@Override
public Void visit(VariableAssignment e) {
ex.write(e.name + " = ");
e.expression.welcome(this);
ex.write(";");
return null;
}
@Override
public Void visit(ReturnStatement e) {
ex.write("return ");
e.expression.welcome(this);
ex.write(";");
return null;
}
@Override
public Void visit(Block e) {
ex.write("{");
ex.addIndent();
for (Statement stmt : e.statements) {
ex.nl();
stmt.welcome(this);
}
ex.subIndent();
ex.nl();
ex.write("}");
return null;
}
@Override
public Void visit(FunctionDefinition e) {
ex.write("function ");
ex.write(e.name);
ex.write("(");
boolean first = true;
for (String param : e.parameters) {
if (!first) {
ex.write(", ");
} else {
first = false;
}
ex.write(param);
}
ex.write(") ");
e.block.welcome(this);
return null;
}
@Override
public Void visit(FunctionCall e) {
ex.write(e.name);
ex.write("(");
boolean first = true;
for (Expression arg : e.arguments) {
if (!first) {
ex.write(", ");
} else {
first = false;
}
arg.welcome(this);
}
ex.write(")");
return null;
}
@Override
public Void visit(Variable e) {
ex.write(e.name);
return null;
}
@Override
public Void visit(Variable e) {
ex.write(e.name);
return null;
}
}

View File

@@ -4,6 +4,7 @@ import de.hsrm.compiler.Klang.nodes.Block;
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.*;
import de.hsrm.compiler.Klang.nodes.statements.*;
public interface Visitor<R> {
@@ -22,6 +23,7 @@ public interface Visitor<R> {
R visit(ModuloExpression e);
R visit(NegateExpression e);
R visit(IfStatement e);
R visit(whileLoop e);
R visit(PrintStatement e);
R visit(VariableDeclaration e);
R visit(VariableAssignment e);

View File

@@ -114,6 +114,9 @@ int main(){
// Tests for comparison expressions
failed += runComparisonTests();
// Tests for while loop
failed += runWhileTests();
printf("\n=== Failed Tests: %d\n", failed);
if (failed > 0) {

View File

@@ -4,4 +4,5 @@
int runFunctionCallTests();
int runRecursiveTests();
int runComparisonTests();
int runComparisonTests();
int runWhileTests();

View File

@@ -133,4 +133,12 @@ function gte(x, y) {
return (x >= y);
}
function myWhile(end) {
let cond = 0;
while ((cond < end)) {
cond = (cond + 1);
}
return cond;
}
add(1, 1);

27
src/test/while/while.c Normal file
View File

@@ -0,0 +1,27 @@
#include <stdio.h>
#include "while.h"
void printWhileSuccess(char* name, int x, int expected, int result) {
printf("SUCCESS:\t%s(%d)\tGOT: %d\tExpected: %d\n", name, x, result, expected);
}
void printWhileError(char* name, int x, int expected, int result) {
printf("ERROR:\t\t%s(%d)\tGOT: %d\tExpected: %d\n", name, x, result, expected);
}
int whileTest(char* name, int x, int expected, int result) {
if (expected == result) {
printWhileSuccess(name, x, expected, result);
return 0;
} else {
printWhileError(name, x, expected, result);
return 1;
}
}
int runWhileTests() {
printf("\nWhile Tests \n");
int failed = 0;
failed += whileTest("while", 5, 5, myWhile(5));
return failed;
}

1
src/test/while/while.h Normal file
View File

@@ -0,0 +1 @@
int myWhile(int x);