Prof. Dr. Manfred Schmidt-Schauß Künstliche Intelligenz/Softwaretechnologie Fachbereich Informatik und Mathematik/ Institut für Informatik Goethe-Universität Frankfurt am Main Grundlagen der Programmierung 2 Sommersemester 2015 Aufgabenblatt Nr. 7 Abgabe: Mittwoch 03. Juni 2015 vor! der Vorlesung Aufgabe 1 (25 Punkte) Ziel dieser Aufgabe ist das Implementieren von zwei Stackmaschinenprogrammen. Im Rahmen einer aktuellen Bachelorarbeit wird an der Professur ein Online-System zum Lernen und Ausprobieren von Stackmaschinenprogrammen entwickelt, welches Sie zum Lernen und Testen verwenden können. hine mac tack e/s t.d kfur fran niik.u rmat o f n .i w.ki w w / / ttp: h Wir wären sehr dankbar, wenn Sie nach dem Ausprobieren auch den Bewerten-Knopf drücken und das System bewerten und Anregungen zur Verbesserung geben. Das System ist unter http://www.ki.informatik.uni-frankfurt.de/stackmachine verfügbar. Neben den beiden Teilaufgaben gibt es im System auch einige Einführungsaufgaben, die Ihnen den Einstieg erleichtern sollen (für die Lösung der Einführungsaufgaben gibt es keine Punkte). a) Geben Sie ein Stackmaschinenprogramm an, das für jeden Stack der Form [a, b] (wobei a oben auf dem Stack liegt) als Resultat den Stack [l, m, n] liefert, wobei l = 2∗a+2∗b, m = 3∗(2∗a−b) und n = b − 2 ∗ a. (10 Punkte) b) Geben Sie ein Stackmaschinenprogramm an, das einen nicht-leeren Stack erwartet, dessen oberstes Element eine positive Ganzzahl ist und prüft, ob das oberste Element gerade oder ungerade ist, und im ersten Fall das Element durch 1 und im anderen Fall durch 0 ersetzt. Verwenden Sie dafür nicht die Division, sondern ziehen Sie solange 2 ab, bis sie 0 oder 1 erreichen. Tipp: Verwenden Sie Sprungmarkierungen und Befehle. (15 Punkte) 1 Aufgabe 2 (35 Punkte) Wie in der Vorlesung und im Skript erläutert, kann die Auswertung einer Stackmaschine mit den Befehlen pop, pushK, push, slide, branchz, jump und mit arithmetischen Operationen +, − und ∗ sowie Marken wie folgt als Funktion I definiert werden: I I I I I I I I I I Programm [] (pop : prest) ((pushK k) : prest) ((push i) : prest) (+ : prest) (− : prest) (∗ : prest) ((slide m n) : prest) (marke : prest) ((branchz marke) : prest) I (jump marke) : prest) Stack stack (a : srest) stack stack (a : b : srest) (a : b : srest) (a : b : srest) stack stack (a : srest) Kopie prg prg prg prg prg prg prg prg prg prg stack prg Nächster Aufruf (Resultat) stack I prest srest prg I prest (k : stack ) prg I prest ((stack !!i) : stack ) prg I prest (b + a : srest) prg I prest (b − a : srest) prg I prest (b ∗ a : srest) prg I prest (take m stack ++ (drop (n + m) stack )) prg I prest stack prg if (0 == a) then I (dropWhile (marke /=) prg) srest prg else I prest srest prg −→ I (dropWhile (marke /=) prg) stack prg −→ −→ −→ −→ −→ −→ −→ −→ −→ −→ a) Führen Sie das Stackmaschinenprogramm (bestehend aus 15 Befehlen) 1 2 3 4 5 pushK 2; push 0; pushK 4; marke1.; push 2; -; push 0; 8 pushK 2; 9 slide 1 2; 10 -; 6 11 7 12 13 14 15 push 0; branchz marke2; jump marke1; marke2.; pop beginnend mit leerem Stack per Hand entsprechend der obigen Regeln aus, indem Sie das Programm und den Stack nach Ausführung jedes Befehls angeben. (10 Punkte) b) In dieser Aufgabe soll die Stackmaschine in Haskell implementiert werden. Befehle der Stackmaschine werden durch den folgenden Datentyp Kommando repräsentiert. Für Marken werden dabei Zahlen verwendet und Mult, Add und Sub stehen für die arithmetischen Operationen: data Befehl = PushK Int | Pop | Push Int | Mult | Add | Sub | Mark Marke | Jump Marke | Branchz Marke | Slide Int Int deriving (Eq,Show) type Marke = Int Ein Stackmaschinenprogramm ist eine Liste von Befehlen und der Stack ist eine Liste von Zahlen type StackProgramm = [Befehl] type Stack = [Int] Implementieren Sie in Haskell eine Funktion run :: StackProgramm -> Stack, die ein Stackmaschinenprogramm erwartet und den resultierenden Stack als Ergebnis liefert. Implementieren Sie hierfür zunächst eine Hilfsfunktion interpretiere :: StackProgramm -> Stack -> StackProgramm -> Stack die genau die oben angegebene Funktion I in Haskell umsetzt, und rufen Sie diese innerhalb von run auf. (25 Punkte) 2 Aufgabe 3 (40 Punkte) Wir betrachten erneut die Pferdeprogramme von Aufgabenblatt 6 und deren Haskell-Repräsentation vom Typ Code: type Code = [Command] data Command = Hopp (Dir,Dir) | Wiederhole Int Code deriving (Show) data Dir = N | W | O | S deriving (Show) Ziel der Aufgabe ist es, Zwischencode für die Stackmaschine aus Aufgabe 1 aus Pferdeprogrammen zu erzeugen. D.h. Sie sollen eine Funktion codeGenerierung :: Code -> StackProgramm in Haskell implementieren, die aus einem Pferdeprogramm ein Stackmaschinenprogramm erzeugt. Dafür modellieren wir den Zustand des Pferdes wie folgt im Stack der Maschine: Der Zustand wird durch zwei Einträge im Stack repräsentiert: [posx,posy], wobei posx und posy die Position des Pferdes auf der x-Achse und y-Achse angeben. Da das Pferd am Anfang an Position (0,0) steht, ist der Stack am Anfang [0,0]. Hinweise: • Implementieren Sie codeGenerierung, indem Sie zunächst den Code für jeden der einzelnen Befehle programmieren. Dabei sollte der Stack vor Ausführung des Codes die Form [posx,posy] haben und nach Ausführung eines Befehls von der Form [posx’,posy’] sein, wobei posx’ und posy’ den neuen Zustand des Pferdes beschreibt. • Der Code für Wiederhole i code ist der schwierigste und sollte Sprungmarkierungen benutzen und nicht den Code code i-mal entfalten, denn dies führt zu sehr langen Stackmaschinenprogrammen. Verknüpfen Sie den Parser von Aufgabenblatt 6, den Stackmaschinenauswerter von Aufgabe 1 dieses Blattes und die Kodegenerierung dieser Aufgabe, um Pferdeprogramme auszuführen. 3