| @@ -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()); | |||||
| } | |||||
| } | |||||