Added function call and function definition

This commit is contained in:
Marvin Kaiser
2019-11-18 16:39:12 +01:00
parent 9385618252
commit 13caee0667
8 changed files with 242 additions and 76 deletions

View File

@@ -1,11 +1,19 @@
grammar Klang; grammar Klang;
parse parse
: block <EOF> : program <EOF>
; ;
block program
: statement+ : functionDef* expression
;
functionDef
: FUNC funcName=IDENT OPAR parameters CPAR braced_block
;
parameters
: (IDENT (COMMA IDENT)*)?
; ;
braced_block braced_block
@@ -31,6 +39,15 @@ expression
| atom MOD atom #moduloExpression | atom MOD atom #moduloExpression
| SUB atom #unaryNegateExpression | SUB atom #unaryNegateExpression
| atom #atomExpression | atom #atomExpression
| functionCall #functionCallExpression
;
functionCall
: IDENT OPAR arguments CPAR SCOL
;
arguments
: (expression (COMMA expression)*)?
; ;
atom atom
@@ -40,12 +57,14 @@ atom
PRINT: 'print'; PRINT: 'print';
IF: 'if'; IF: 'if';
ELSE: 'else'; ELSE: 'else';
FUNC: 'function';
SCOL: ';'; SCOL: ';';
OBRK: '{'; OBRK: '{';
CBRK: '}'; CBRK: '}';
OPAR: '('; OPAR: '(';
CPAR: ')'; CPAR: ')';
COMMA: ',';
MULT: '*'; MULT: '*';
ADD: '+'; ADD: '+';
@@ -56,6 +75,10 @@ INTEGER_LITERAL
: [0-9]+ : [0-9]+
; ;
IDENT
: [a-zA-Z][a-zA-Z0-9]*
;
WS WS
: [ \t\r\n] -> skip : [ \t\r\n] -> skip
; ;

View File

@@ -7,17 +7,13 @@ import de.hsrm.compiler.Klang.types.Type;
public class ContextAnalysis extends KlangBaseVisitor<Node> { public class ContextAnalysis extends KlangBaseVisitor<Node> {
@Override @Override
public Node visitBlock(KlangParser.BlockContext ctx) { public Node visitProgram(KlangParser.ProgramContext ctx) {
Statement[] statements = new Statement[ctx.statement().size()]; FunctionDefinition[] funcs = new FunctionDefinition[ctx.functionDef().size()];
for (int i = 0; i < ctx.functionDef().size(); i++) {
for (int i = 0; i < ctx.statement().size(); i++) { funcs[i] = (FunctionDefinition) this.visit(ctx.functionDef(i));
Node currentStatement = this.visit(ctx.statement(i));
statements[i] = (Statement) currentStatement;
} }
Expression expression = (Expression) this.visit(ctx.expression());
Block result = new Block(statements); return new Program(funcs, expression);
result.type = null;
return result;
} }
@Override @Override
@@ -28,7 +24,7 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
Node currentStatement = this.visit(ctx.statement(i)); Node currentStatement = this.visit(ctx.statement(i));
statements[i] = (Statement) currentStatement; statements[i] = (Statement) currentStatement;
} }
Block result = new Block(statements); Block result = new Block(statements);
result.type = null; result.type = null;
return result; return result;
@@ -48,7 +44,7 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
if (ctx.alt != null) { if (ctx.alt != null) {
Node elseBlock = this.visit(ctx.alt); Node elseBlock = this.visit(ctx.alt);
return new IfStatement((Expression) condition, (Block) thenBlock, (Block) elseBlock); return new IfStatement((Expression) condition, (Block) thenBlock, (Block) elseBlock);
} else if(ctx.elif != null) { } else if (ctx.elif != null) {
Node elif = this.visit(ctx.elif); Node elif = this.visit(ctx.elif);
return new IfStatement((Expression) condition, (Block) thenBlock, (IfStatement) elif); return new IfStatement((Expression) condition, (Block) thenBlock, (IfStatement) elif);
} else { } else {
@@ -102,4 +98,25 @@ public class ContextAnalysis extends KlangBaseVisitor<Node> {
n.type = Type.getIntegerType(); n.type = Type.getIntegerType();
return n; return n;
} }
@Override
public Node visitFunctionDef(KlangParser.FunctionDefContext ctx) {
String name = ctx.funcName.getText();
String[] params = new String[ctx.parameters().IDENT().size()];
for (int i = 0; i < ctx.parameters().IDENT().size(); i++) {
params[i] = ctx.parameters().IDENT(i).getText();
}
Node block = this.visit(ctx.braced_block());
return new FunctionDefinition(name, params, (Block) block);
}
@Override
public Node visitFunctionCallExpression(KlangParser.FunctionCallExpressionContext ctx) {
String name = ctx.functionCall().IDENT().getText();
Expression[] args = new Expression[ctx.functionCall().arguments().expression().size()];
for (int i = 0; i < ctx.functionCall().arguments().expression().size(); i++) {
args[i] = (Expression) this.visit(ctx.functionCall().arguments().expression(i));
}
return new FunctionCall(name, args);
}
} }

View File

@@ -0,0 +1,22 @@
package de.hsrm.compiler.Klang.nodes;
import de.hsrm.compiler.Klang.visitors.Visitor;
public class FunctionDefinition extends Node {
public String name;
public String[] parameters;
public Block block;
public FunctionDefinition(String name, String[] parameters, Block block) {
this.name = name;
this.parameters = parameters;
this.block = block;
}
@Override
public <R> R welcome(Visitor<R> v) {
return v.visit(this);
}
}

View File

@@ -0,0 +1,20 @@
package de.hsrm.compiler.Klang.nodes;
import de.hsrm.compiler.Klang.nodes.expressions.Expression;
import de.hsrm.compiler.Klang.visitors.Visitor;
public class Program extends Node {
public FunctionDefinition[] funcs;
public Expression expression;
public Program(FunctionDefinition[] funcs, Expression expression) {
this.funcs = funcs;
this.expression = expression;
}
@Override
public <R> R welcome(Visitor<R> v) {
return v.visit(this);
}
}

View File

@@ -0,0 +1,19 @@
package de.hsrm.compiler.Klang.nodes.expressions;
import de.hsrm.compiler.Klang.visitors.Visitor;
public class FunctionCall extends Expression {
public String name;
public Expression[] arguments;
public FunctionCall(String name, Expression[] arguments) {
this.name = name;
this.arguments = arguments;
}
@Override
public <R> R welcome(Visitor<R> v) {
return v.visit(this);
}
}

View File

@@ -2,76 +2,89 @@ package de.hsrm.compiler.Klang.visitors;
import de.hsrm.compiler.Klang.Value; import de.hsrm.compiler.Klang.Value;
import de.hsrm.compiler.Klang.nodes.Block; import de.hsrm.compiler.Klang.nodes.Block;
import de.hsrm.compiler.Klang.nodes.FunctionDefinition;
import de.hsrm.compiler.Klang.nodes.expressions.*; import de.hsrm.compiler.Klang.nodes.expressions.*;
import de.hsrm.compiler.Klang.nodes.statements.*; import de.hsrm.compiler.Klang.nodes.statements.*;
public class EvalVisitor implements Visitor<Value> { public class EvalVisitor implements Visitor<Value> {
@Override @Override
public Value visit(IntegerExpression e) { public Value visit(IntegerExpression e) {
return new Value(e.value); return new Value(e.value);
}
@Override
public Value visit(MultiplicativeExpression e) {
Value a = e.lhs.welcome(this);
Value b = e.rhs.welcome(this);
return new Value(a.asInteger() * b.asInteger());
}
@Override
public Value visit(AdditiveExpression e) {
Value a = e.lhs.welcome(this);
Value b = e.rhs.welcome(this);
return new Value(a.asInteger() + b.asInteger());
}
@Override
public Value visit(ModuloExpression e) {
Value a = e.lhs.welcome(this);
Value b = e.rhs.welcome(this);
return new Value(a.asInteger() % b.asInteger());
}
@Override
public Value visit(NegateExpression e) {
Value a = e.lhs.welcome(this);
return new Value(-a.asInteger());
}
@Override
public Value visit(IfStatement e) {
// In the future we have to make sure that the
// value is actually a type that we can use as boolean
Value condition = e.cond.welcome(this);
if (condition.asInteger() != 0) {
e.then.welcome(this);
} else if (e.alt != null) {
e.alt.welcome(this);
} else if (e.elif != null) {
e.elif.welcome(this);
} }
@Override return null;
public Value visit(MultiplicativeExpression e) { }
Value a = e.lhs.welcome(this);
Value b = e.rhs.welcome(this); @Override
return new Value(a.asInteger() * b.asInteger()); public Value visit(PrintStatement e) {
Value value = e.expression.welcome(this);
// In the future we have to determine of which type the value is
// before calling an "asX()" method
System.out.println(value.asInteger());
return null;
}
@Override
public Value visit(Block e) {
for (var stmt : e.statements) {
stmt.welcome(this);
} }
return null;
}
@Override @Override
public Value visit(AdditiveExpression e) { public Value visit(FunctionDefinition e) {
Value a = e.lhs.welcome(this); // TODO Auto-generated method stub
Value b = e.rhs.welcome(this); return null;
return new Value(a.asInteger() + b.asInteger()); }
}
@Override @Override
public Value visit(ModuloExpression e) { public Value visit(FunctionCall e) {
Value a = e.lhs.welcome(this); // TODO Auto-generated method stub
Value b = e.rhs.welcome(this); return null;
return new Value(a.asInteger() % b.asInteger()); }
}
@Override
public Value visit(NegateExpression e) {
Value a = e.lhs.welcome(this);
return new Value(-a.asInteger());
}
@Override
public Value visit(IfStatement e) {
// In the future we have to make sure that the
// value is actually a type that we can use as boolean
Value condition = e.cond.welcome(this);
if (condition.asInteger() != 0) {
e.then.welcome(this);
} else if (e.alt != null) {
e.alt.welcome(this);
} else if (e.elif != null) {
e.elif.welcome(this);
}
return null;
}
@Override
public Value visit(PrintStatement e) {
Value value = e.expression.welcome(this);
// In the future we have to determine of which type the value is
// before calling an "asX()" method
System.out.println(value.asInteger());
return null;
}
@Override
public Value visit(Block e) {
for (var stmt: e.statements) {
stmt.welcome(this);
}
return null;
}
} }

View File

@@ -53,6 +53,17 @@ public class PrettyPrintVisitor implements Visitor<Void> {
this.ex = 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);
return null;
}
@Override @Override
public Void visit(IntegerExpression e) { public Void visit(IntegerExpression e) {
ex.write(e.value); ex.write(e.value);
@@ -128,4 +139,40 @@ public class PrettyPrintVisitor implements Visitor<Void> {
return null; 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;
}
} }

View File

@@ -1,6 +1,8 @@
package de.hsrm.compiler.Klang.visitors; package de.hsrm.compiler.Klang.visitors;
import de.hsrm.compiler.Klang.nodes.Block; 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.expressions.*;
import de.hsrm.compiler.Klang.nodes.statements.*; import de.hsrm.compiler.Klang.nodes.statements.*;
@@ -13,4 +15,7 @@ public interface Visitor<R> {
R visit(IfStatement e); R visit(IfStatement e);
R visit(PrintStatement e); R visit(PrintStatement e);
R visit(Block e); R visit(Block e);
R visit(FunctionDefinition e);
R visit(FunctionCall e);
R visit(Program e);
} }