Programmieren in Java Vorlesung 10: Ein Interpreter für While Prof. Dr. Peter Thiemann Albert-Ludwigs-Universität Freiburg, Germany SS 2015 Peter Thiemann (Univ. Freiburg) Programmieren in Java JAVA 1 / 18 Inhalt Interpreter für While Die Sprache While Ausführung von While Testen Peter Thiemann (Univ. Freiburg) Programmieren in Java JAVA 2 / 18 Interpreter für While Interpreter für While Interpreter I I Ein Interpreter ist ein Programm zur Ausführung von anderen Programmen Eingaben I I I Ein Programm (-text) P in einer Sprache L Die Eingabe für das Programm P Ausgabe I Die Ausgabe des Programms P Peter Thiemann (Univ. Freiburg) Programmieren in Java JAVA 4 / 18 Interpreter für While Architektur des Interpreters I Parser I I I Einlesen des Programmtextes Erstellen einer Objektrepräsentation des Programmtextes abstract syntax tree (AST) Runner I I I Durchlaufen des AST Ausführen der Statements Auswerten von Ausdrücken Peter Thiemann (Univ. Freiburg) Programmieren in Java JAVA 5 / 18 Die Sprache While Interpreter für While Die Sprache While Syntax von While BNF für While hstmti ::= | | | hstmt1 i ::= | I I I hvar i = hexpr i Zuweisung if ( hexpr i ) hstmti else hstmti Bedingte Anweisung while ( hexpr i ) hstmti While Schleife { hstmt1 i Sequenz } . . . leer hstmti ; hstmt1 i nächste Anweisung hstmti = Statement = Anweisung hstmt1i spezifiziert eine Liste von Anweisungen, wobei jede Anweisung durch Semikolon abgeschlossen ist und das Ende mit schließender geschweifter Klammer markiert ist hexpri = arithmetische Ausdrücke, wie gehabt Peter Thiemann (Univ. Freiburg) Programmieren in Java JAVA 7 / 18 Interpreter für While Die Sprache While Objektrepräsentation (AST) 1 2 3 1 2 3 4 5 6 I Composite und Visitor Pattern I Hier: Visitor ohne Rückgabewert public interface IStmt { void accept(StmtVisitor v); } public interface StmtVisitor { void visitAssign(Assign s); void visitIf(If s); void visitSequence(Sequence s); void visitWhile(While s); } Peter Thiemann (Univ. Freiburg) Programmieren in Java JAVA 8 / 18 Interpreter für While Die Sprache While Objektrepräsentation (AST) II 1 2 3 4 5 6 7 1 2 3 4 5 6 7 8 public class Assign implements IStmt { public final String var; public final IExpr exp; public void accept(StmtVisitor v) { v.visitAssign(this); } } public class If implements IStmt { public final IExpr condition; public final IStmt trueBranch; public final IStmt falseBranch; public void accept(StmtVisitor v) { v.visitIf(this); } } I 1 2 3 4 5 6 7 1 2 3 4 5 6 public class While implements IStmt { public final IExpr condition; public final IStmt body; public void accept(StmtVisitor v) { v.visitWhile(this); } } public class Sequence implements IStmt { public final Collection<IStmt> stmts; public void accept(StmtVisitor v) { v.visitSequence(this); } } Für jede Art Anweisung eine Klasse (mit Standardkonstruktor) Peter Thiemann (Univ. Freiburg) Programmieren in Java JAVA 9 / 18 Parser für While Interpreter für While Die Sprache While Parser für While 1 2 3 4 5 6 I Gleiches Muster wie für Ausdrücke: recursive descent parser I Möglichkeit: Erweiterung des Ausdrucksparsers mittels Vererbung I Kleine Änderungen am Ausdrucksparser lecture20150622.Parser erforderlich: die privaten Methoden für den Scanner müssen protected gemacht werden protected boolean lookingAt(String regex) { return scan.lookingAt(regex); } protected String getLexeme(String regex) { return scan.getLexeme(regex); } Peter Thiemann (Univ. Freiburg) Programmieren in Java JAVA 11 / 18 Interpreter für While Die Sprache While Parser für If-Anweisung (Beispiel, Auszug) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public IStmt parseStmt() { String lexeme = scan.getLexeme(REGEX WORD); if (”if”.equals(lexeme)) { // ”if” . ”(” <expr> ”)” <stmt> ”else” <stmt> if (scan.getLexeme(REGEX OPEN PAREN) != null) { // ”if” ”(” . <expr> ”)” <stmt> ”else” <stmt> IExpr condition = parseExpr(); // ”if” ”(” <expr> . ”)” <stmt> ”else” <stmt> if (scan.getLexeme(REGEX CLOSE PAREN) != null) { // ”if” ”(” <expr> ”)” . <stmt> ”else” <stmt> IStmt trueBranch = parseStmt(); // ”if” ”(” <expr> ”)” <stmt> . ”else” <stmt> if (scan.getLexeme(”else”) != null) { // ”if” ”(” <expr> ”)” <stmt> ”else” . <stmt> IStmt falseBranch = parseStmt(); // ”if” ”(” <expr> ”)” <stmt> ”else” <stmt> . return new If(condition, trueBranch, falseBranch); }}}} Peter Thiemann (Univ. Freiburg) Programmieren in Java JAVA 12 / 18 Ausführung von While Interpreter für While Ausführung von While Ausführung von While I Durch RunVisitor, eine Implementierung von StmtVisitor I Interner Zustand des RunVisitor ist die Belegung der Variablen I Repräsentiert durch eine Abbildung von Variablennamen auf Zahlen: Map<String,Integer> Peter Thiemann (Univ. Freiburg) Programmieren in Java JAVA 14 / 18 Interpreter für While Ausführung von While RunVisitor public void visitIf(If s) { if (s.condition.accept(eval) != 0) { s.trueBranch.accept(this); } else { s.falseBranch.accept(this); } } public void visitSequence(Sequence s) { for(IStmt stmt : s.stmts) { stmt.accept(this); } } public void visitWhile(While s) { while( s.condition.accept(eval) != 0) { s.body.accept(this); } } 1 1 2 public class RunVisitor implements StmtVisitor { 2 3 3 4 5 4 public final Map<String,Integer> state; private final IExprVisitor eval; 6 7 8 9 10 11 14 15 16 6 7 public RunVisitor( Map<String,Integer> state) { this.state = state; this.eval = new Eval(state); } 12 13 5 8 9 10 11 12 13 public void visitAssign(Assign s) { int value = s.exp.accept(eval); state.put(s.var, value); } 14 15 16 17 18 Peter Thiemann (Univ. Freiburg) } Programmieren in Java JAVA 15 / 18 Testen des Interpreters Interpreter für While Testen Testen des Interpreters 1 2 I Mittels JUnit Testfällen I Für jeden Testfall muss zunächst eine Belegung der Variablen, also eine Map, generiert werden und damit ein RunVisitor instanziert werden: Map<String,Integer> state = new HashMap<String,Integer>(); RunVisitor r = new RunVisitor(state); I Anstatt diese Anweisungen in jedem Testfall zu wiederholen, kann eine Before-Methode geschrieben werden. I Dafür müssen die Werte in Instanzvariable der Testklasse verlagert werden. Peter Thiemann (Univ. Freiburg) Programmieren in Java JAVA 17 / 18 Interpreter für While Testen Before-Methode 1 2 3 4 5 6 7 8 9 10 11 12 13 public class RunVisitorTest { private Map<String, Integer> state; private RunVisitor r; @Before public void setup() { state = new HashMap<String,Integer>(); r = new RunVisitor(state); } @Test public void test() { IStmt ass1 = new Assign(”x”, cnst(1)); ass1.accept(r); assertEquals(state.get(”x”), new Integer(1)); } } Vor jedem Testfall mit Annotation @Test I wird eine neue RunVisitorTest Instanz erzeugt I werden die Methoden mit Annotation @Before ausgeführt Peter Thiemann (Univ. Freiburg) Programmieren in Java JAVA 18 / 18