Added implementation for a visitor

This commit is contained in:
Marvin Kaiser
2019-10-28 16:13:37 +01:00
parent 0a9d702198
commit bc4cc334bd
48 changed files with 740 additions and 790 deletions

View File

@@ -0,0 +1,227 @@
package de.hsrm.compiler.Klang;
import org.antlr.v4.runtime.misc.NotNull;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class EvalVisitor extends KlangBaseVisitor<Value> {
// used to compare floating point numbers
public static final double SMALL_VALUE = 0.00000000001;
// store variables (there's only one global scope!)
private Map<String, Value> memory = new HashMap<String, Value>();
// assignment/id overrides
@Override
public Value visitAssignment(KlangParser.AssignmentContext ctx) {
String id = ctx.ID().getText();
Value value = this.visit(ctx.expr());
return memory.put(id, value);
}
@Override
public Value visitIdAtom(KlangParser.IdAtomContext ctx) {
String id = ctx.getText();
Value value = memory.get(id);
if(value == null) {
throw new RuntimeException("no such variable: " + id);
}
return value;
}
// atom overrides
@Override
public Value visitStringAtom(KlangParser.StringAtomContext ctx) {
String str = ctx.getText();
// strip quotes
str = str.substring(1, str.length() - 1).replace("\"\"", "\"");
return new Value(str);
}
@Override
public Value visitNumberAtom(KlangParser.NumberAtomContext ctx) {
return new Value(Double.valueOf(ctx.getText()));
}
@Override
public Value visitBooleanAtom(KlangParser.BooleanAtomContext ctx) {
return new Value(Boolean.valueOf(ctx.getText()));
}
@Override
public Value visitNilAtom(KlangParser.NilAtomContext ctx) {
return new Value(null);
}
// expr overrides
@Override
public Value visitParExpr(KlangParser.ParExprContext ctx) {
return this.visit(ctx.expr());
}
@Override
public Value visitPowExpr(KlangParser.PowExprContext ctx) {
Value left = this.visit(ctx.expr(0));
Value right = this.visit(ctx.expr(1));
return new Value(Math.pow(left.asDouble(), right.asDouble()));
}
@Override
public Value visitUnaryMinusExpr(KlangParser.UnaryMinusExprContext ctx) {
Value value = this.visit(ctx.expr());
return new Value(-value.asDouble());
}
@Override
public Value visitNotExpr(KlangParser.NotExprContext ctx) {
Value value = this.visit(ctx.expr());
return new Value(!value.asBoolean());
}
@Override
public Value visitMultiplicationExpr(@NotNull KlangParser.MultiplicationExprContext ctx) {
Value left = this.visit(ctx.expr(0));
Value right = this.visit(ctx.expr(1));
switch (ctx.op.getType()) {
case KlangParser.MULT:
return new Value(left.asDouble() * right.asDouble());
case KlangParser.DIV:
return new Value(left.asDouble() / right.asDouble());
case KlangParser.MOD:
return new Value(left.asDouble() % right.asDouble());
default:
throw new RuntimeException("unknown operator: " + KlangParser.tokenNames[ctx.op.getType()]);
}
}
@Override
public Value visitAdditiveExpr(@NotNull KlangParser.AdditiveExprContext ctx) {
Value left = this.visit(ctx.expr(0));
Value right = this.visit(ctx.expr(1));
switch (ctx.op.getType()) {
case KlangParser.PLUS:
return left.isDouble() && right.isDouble() ?
new Value(left.asDouble() + right.asDouble()) :
new Value(left.asString() + right.asString());
case KlangParser.MINUS:
return new Value(left.asDouble() - right.asDouble());
default:
throw new RuntimeException("unknown operator: " + KlangParser.tokenNames[ctx.op.getType()]);
}
}
@Override
public Value visitRelationalExpr(@NotNull KlangParser.RelationalExprContext ctx) {
Value left = this.visit(ctx.expr(0));
Value right = this.visit(ctx.expr(1));
switch (ctx.op.getType()) {
case KlangParser.LT:
return new Value(left.asDouble() < right.asDouble());
case KlangParser.LTEQ:
return new Value(left.asDouble() <= right.asDouble());
case KlangParser.GT:
return new Value(left.asDouble() > right.asDouble());
case KlangParser.GTEQ:
return new Value(left.asDouble() >= right.asDouble());
default:
throw new RuntimeException("unknown operator: " + KlangParser.tokenNames[ctx.op.getType()]);
}
}
@Override
public Value visitEqualityExpr(@NotNull KlangParser.EqualityExprContext ctx) {
Value left = this.visit(ctx.expr(0));
Value right = this.visit(ctx.expr(1));
switch (ctx.op.getType()) {
case KlangParser.EQ:
return left.isDouble() && right.isDouble() ?
new Value(Math.abs(left.asDouble() - right.asDouble()) < SMALL_VALUE) :
new Value(left.equals(right));
case KlangParser.NEQ:
return left.isDouble() && right.isDouble() ?
new Value(Math.abs(left.asDouble() - right.asDouble()) >= SMALL_VALUE) :
new Value(!left.equals(right));
default:
throw new RuntimeException("unknown operator: " + KlangParser.tokenNames[ctx.op.getType()]);
}
}
@Override
public Value visitAndExpr(KlangParser.AndExprContext ctx) {
Value left = this.visit(ctx.expr(0));
Value right = this.visit(ctx.expr(1));
return new Value(left.asBoolean() && right.asBoolean());
}
@Override
public Value visitOrExpr(KlangParser.OrExprContext ctx) {
Value left = this.visit(ctx.expr(0));
Value right = this.visit(ctx.expr(1));
return new Value(left.asBoolean() || right.asBoolean());
}
// log override
@Override
public Value visitLog(KlangParser.LogContext ctx) {
Value value = this.visit(ctx.expr());
System.out.println(value);
return value;
}
// if override
@Override
public Value visitIf_stat(KlangParser.If_statContext ctx) {
List<KlangParser.Condition_blockContext> conditions = ctx.condition_block();
boolean evaluatedBlock = false;
for(KlangParser.Condition_blockContext condition : conditions) {
Value evaluated = this.visit(condition.expr());
if(evaluated.asBoolean()) {
evaluatedBlock = true;
// evaluate this block whose expr==true
this.visit(condition.stat_block());
break;
}
}
if(!evaluatedBlock && ctx.stat_block() != null) {
// evaluate the else-stat_block (if present == not null)
this.visit(ctx.stat_block());
}
return Value.VOID;
}
// while override
@Override
public Value visitWhile_stat(KlangParser.While_statContext ctx) {
Value value = this.visit(ctx.expr());
while(value.asBoolean()) {
// evaluate the code block
this.visit(ctx.stat_block());
// evaluate the expression
value = this.visit(ctx.expr());
}
return Value.VOID;
}
}

View File

@@ -19,6 +19,7 @@ public class Klang {
KlangParser parser = new KlangParser(tokens);
ParseTree tree = parser.parse(); // begin parsing at init rule
System.out.println(tree.toStringTree(parser)); // print LISP-style tree
EvalVisitor visitor = new EvalVisitor();
visitor.visit(tree);
}
}

View File

@@ -0,0 +1,59 @@
package de.hsrm.compiler.Klang;
public class Value {
public static Value VOID = new Value(new Object());
final Object value;
public Value(Object value) {
this.value = value;
}
public Boolean asBoolean() {
return (Boolean)value;
}
public Double asDouble() {
return (Double)value;
}
public String asString() {
return String.valueOf(value);
}
public boolean isDouble() {
return value instanceof Double;
}
@Override
public int hashCode() {
if(value == null) {
return 0;
}
return this.value.hashCode();
}
@Override
public boolean equals(Object o) {
if(value == o) {
return true;
}
if(value == null || o == null || o.getClass() != value.getClass()) {
return false;
}
Value that = (Value)o;
return this.value.equals(that.value);
}
@Override
public String toString() {
return String.valueOf(value);
}
}