| @@ -0,0 +1,45 @@ | |||
| package interpreter; | |||
| import expression.*; | |||
| import java.util.HashMap; | |||
| import java.util.Map; | |||
| public class Evaluator extends ExpressionVisitor<Integer> { | |||
| final Expression expression; | |||
| final Map<String, Integer> valuation = new HashMap<>(); | |||
| public Evaluator(Expression expression, Map<String, Integer> valuation) { | |||
| this.expression = expression; | |||
| this.valuation.putAll(valuation); | |||
| } | |||
| public int eval() { | |||
| return visit(expression); | |||
| } | |||
| @Override | |||
| public Integer visitAddition(Addition addition) { | |||
| return visit(addition.leftHandSide) + visit(addition.rightHandSide); | |||
| } | |||
| @Override | |||
| public Integer visitSubtraction(Subtraction subtraction) { | |||
| return visit(subtraction.leftHandSide) - visit(subtraction.rightHandSide); | |||
| } | |||
| @Override | |||
| public Integer visitInt(Int integer) { | |||
| return integer.value; | |||
| } | |||
| @Override | |||
| public Integer visitIdentifier(Identifier identifier) { | |||
| if (valuation.containsKey(identifier.name)) { | |||
| return valuation.get(identifier.name); | |||
| } else { | |||
| throw new InterpreterException("Identifier " + identifier.name + " not found."); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,28 @@ | |||
| package interpreter; | |||
| import expression.*; | |||
| import java.lang.reflect.Method; | |||
| public abstract class ExpressionVisitor<T> { | |||
| public T visit(Expression expression) { | |||
| String methodName = "visit" + expression.getClass().getSimpleName(); | |||
| Method method; | |||
| try { | |||
| method = this.getClass().getMethod(methodName, expression.getClass()); | |||
| } catch (NoSuchMethodException e) { | |||
| throw new RuntimeException(e); | |||
| } | |||
| Object result; | |||
| try { | |||
| result = method.invoke(this, expression); | |||
| } catch (Exception e) { | |||
| throw new RuntimeException(e); | |||
| } | |||
| return (T) result; | |||
| } | |||
| public abstract T visitAddition(Addition addition); | |||
| public abstract T visitSubtraction(Subtraction subtraction); | |||
| public abstract T visitInt(Int integer); | |||
| public abstract T visitIdentifier(Identifier identifier); | |||
| } | |||
| @@ -0,0 +1,63 @@ | |||
| package interpreter; | |||
| import program.*; | |||
| import java.util.HashMap; | |||
| import java.util.Map; | |||
| public class Interpreter extends ProgramVisitor { | |||
| final Program program; | |||
| final Map<String, Integer> valuation = new HashMap<>(); | |||
| public Map<String, Integer> getValuation() { | |||
| Map<String, Integer> result = new HashMap<>(); | |||
| result.putAll(valuation); | |||
| return result; | |||
| } | |||
| public Interpreter(Program program) { | |||
| this.program = program; | |||
| visit(program); | |||
| } | |||
| public Interpreter(Program program, Map<String, Integer> valuation) { | |||
| this.program = program; | |||
| this.valuation.putAll(valuation); | |||
| visit(program); | |||
| } | |||
| @Override | |||
| public void visitAssignment(Assignment assignment) { | |||
| Evaluator evaluator = new Evaluator(assignment.expression, valuation); | |||
| valuation.put(assignment.identifier.name, evaluator.eval()); | |||
| } | |||
| @Override | |||
| public void visitComposition(Composition composition) { | |||
| visit(composition.first); | |||
| visit(composition.second); | |||
| } | |||
| @Override | |||
| public void visitConditional(Conditional conditional) { | |||
| Evaluator evaluator = new Evaluator(conditional.condition, valuation); | |||
| if (evaluator.eval() != 0) { | |||
| visit(conditional.thenCase); | |||
| } else { | |||
| visit(conditional.elseCase); | |||
| } | |||
| } | |||
| private boolean enterLoop(Loop loop) { | |||
| Evaluator evaluator = new Evaluator(loop.condition, valuation); | |||
| return evaluator.eval() != 0; | |||
| } | |||
| @Override | |||
| public void visitLoop(Loop loop) { | |||
| while(enterLoop(loop)) { | |||
| visit(loop.program); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,7 @@ | |||
| package interpreter; | |||
| public class InterpreterException extends RuntimeException { | |||
| public InterpreterException(String error) { | |||
| super(error); | |||
| } | |||
| } | |||
| @@ -0,0 +1,18 @@ | |||
| package interpreter; | |||
| import program.*; | |||
| public abstract class ProgramVisitor { | |||
| public void visit(Program program) { | |||
| try { | |||
| this.getClass().getMethod("visit" + program.getClass().getSimpleName(), program.getClass()).invoke(this, program); | |||
| } catch(Exception ex) { | |||
| throw new RuntimeException(ex); | |||
| } | |||
| } | |||
| public abstract void visitAssignment(Assignment assignment); | |||
| public abstract void visitComposition(Composition composition); | |||
| public abstract void visitConditional(Conditional conditional); | |||
| public abstract void visitLoop(Loop loop); | |||
| } | |||
| @@ -0,0 +1,21 @@ | |||
| package interpreter; | |||
| import expression.*; | |||
| import org.junit.Test; | |||
| import java.util.HashMap; | |||
| import java.util.Map; | |||
| import static org.junit.Assert.assertEquals; | |||
| public class EvaluatorTest { | |||
| @Test | |||
| public void testEval() { | |||
| Map<String, Integer> valuation = new HashMap<>(); | |||
| valuation.put("x", 7); | |||
| valuation.put("y", 2); | |||
| Expression expression = new Addition(new Identifier("x"), new Subtraction(new Identifier("y"), new Int(-4))); | |||
| Evaluator evaluator = new Evaluator(expression, valuation); | |||
| assertEquals(13, evaluator.eval()); | |||
| } | |||
| } | |||
| @@ -0,0 +1,36 @@ | |||
| package interpreter; | |||
| import expression.Addition; | |||
| import expression.Identifier; | |||
| import expression.Int; | |||
| import expression.Subtraction; | |||
| import org.junit.Test; | |||
| import program.Assignment; | |||
| import program.Composition; | |||
| import program.Loop; | |||
| import program.Program; | |||
| import java.util.Map; | |||
| import static org.junit.Assert.assertEquals; | |||
| public class InterpreterTest { | |||
| @Test | |||
| public void testSem() { | |||
| Program initialization = new Composition( | |||
| new Composition( | |||
| new Assignment(new Identifier("a"), new Int(2)), | |||
| new Assignment(new Identifier("b"), new Int(4))), | |||
| new Assignment(new Identifier("r"), new Int(0))); | |||
| Program body = new Composition( | |||
| new Assignment(new Identifier("r"), new Addition(new Identifier("r"), new Identifier("b"))), | |||
| new Assignment(new Identifier("a"), new Subtraction(new Identifier("a"), new Int(1)))); | |||
| Program loop = new Loop(new Identifier("a"), body); | |||
| Program program = new Composition(initialization, loop); | |||
| Interpreter interpreter = new Interpreter(program); | |||
| Map<String, Integer> valuation = interpreter.getValuation(); | |||
| assertEquals(8, valuation.get("r").intValue()); | |||
| assertEquals(0, valuation.get("a").intValue()); | |||
| assertEquals(4, valuation.get("b").intValue()); | |||
| } | |||
| } | |||