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 2013 Aufgabenblatt Nr. 6 Abgabe: Mittwoch 29. Mai 2013 vor! der Vorlesung Aufgabe 1 (35 Punkte) Ein Telefonbuch sei als String von einem oder mehreren Telefonbucheinträgen – bestehend aus Namen und Telefonnumern – gegeben, wobei • Telefonbucheinträge sind durch das Symbol # getrennt • Name und Telefonnummer sind durch einen Doppelpunkt : getrennt • Namen sind dabei entweder in der Form Vorname Nachname (durch genau ein Leerzeichen getrennt), oder in der Form Nachname, Vorname (Leerzeichen sind nicht erlaubt) gegeben. Sowohl Nachname als auch Vorname sind Worte, die mit einem Großbuchstaben beginnen und ansonsten nur aus Buchstaben und dem Bindestrich - bestehen. • Telefonnummern sind in der Form (Ortsvorwahl)Rufnummer gegeben, wobei die Ortsvorwahl und die Rufnummern nur aus Ziffern bestehen und die Ortsvorwahl stets mit einer 0 beginnt. a) Geben Sie eine kontextfreie Grammatik an, die genau obige Telefonbücher erzeugen kann. Sie können die folgenden Produktionen als bereits gegeben verwenden: (10 Punkte) Wort Buchstaben Buchstabe Großbuchstabe Kleinbuchstabe Nummer ::= ::= ::= ::= ::= ::= Großbuchstabe Buchstaben ε | Buchstabe Buchstaben Großbuchstabe | Kleinbuchstabe | A | ... | Z a | ... | z 0 | . . . | 9 | 0 Nummer | . . . | 9 Nummer b) Der Datentyp Datensatz sei definiert als: data Datensatz = Datensatz Vorname Nachname Vorwahl Rufnummer deriving(Eq,Show) type Vorname = String type Nachname = String type Vorwahl = String type Rufnummer = String Implementieren Sie in Haskell eine Funktion parseTelefon :: String -> [Datensatz], die ein Telefonbuch als String erhält und und diesen in eine Liste von Datensätzen überführt. Ist das oben beschriebene Format nicht erfüllt, so soll ein Fehler gemeldet werden. Sie können die funktionalen Parserkombinatoren aus der Vorlesung verwenden (dies ist aber kein Zwang für diese Aufgabe). (25 Punkte) Beispielaufrufe: *> parseTelefon "Helga Mueller:(069)123456" [Datensatz "Helga" "Mueller" "069" "123456"] *> parseTelefon "Helga Mueller:(069)123456#Maier,Fritz:(010)100" [Datensatz "Helga" "Mueller" "069" "123456",Datensatz "Fritz" "Maier" "010" "100"] *> parseTelefon "Helga Mueller:(069)123456???Maier,Fritz:(010)100" *** Exception: parse error *> parseTelefon "Helga Mueller:(999)123456" *** Exception: parse error *> parseTelefon "Helga Mueller:(0999)123456" [Datensatz "Helga" "Mueller" "0999" "123456"] 1 Aufgabe 2 (65 Punkte) Eine Schildkröte kann Programme verarbeiten, die durch die folgende kontextfreie Grammatik mit Startsymbol Code den Nichtterminalen Code, Command, Number und den Terminalen ;, turnRight, turnLeft, walk, repeat, {, }, 0,. . . ,9 erzeugt werden können: Code ::= Command | Command ; Code Command ::= turnRight | turnLeft | walk Number | repeat Number { Code } Number ::= 0 | . . . | 9 | 0 Number | . . . | 9 Number a) Geben Sie eine Linksherleitung für das folgende Programm an: (10 Punkte) turnLeft; repeat 10 {turnLeft; walk 5} b) Geben Sie eine Rechtsherleitung für das folgende Programm an: (10 Punkte) turnLeft; walk 5; turnRight c) Als Syntaxbaum für Schildkrötenprogramme verwenden wir den Typ Sequence, der eine Liste von AST-Einträgen darstellt, wobei AST definiert sei als: data AST = REPEAT Int Sequence | TURNRIGHT | TURNLEFT | WALK Int deriving(Eq,Show) type Sequence = [AST] Implementieren Sie mithilfe der in der Vorlesung vorgestellten funktionalen Parserkombinatoren einen rekursiv absteigenden Parser für Schildkrötenprogramme, der als Eingabe ein Programm als String erhält und als Ausgabe den Syntaxbaum von Typ Sequence liefert. (30 Punkte) Hinweis: Falls Sie Zahlen vom Typ Integer in Zahlen vom Typ Int konvertieren müssen, können Sie hierfür die Funktion fromIntegral verwenden. Beispielaufrufe: *> parseKroete "turnLeft; walk 10; repeat 5 {turnLeft; repeat 2 {walk 20}}" [TURNLEFT,WALK 10,REPEAT 5 [TURNLEFT,REPEAT 2 [WALK 20]]] d) Die Semantik der Befehle sei wie folgt festgelegt: – – – – turnRight dreht die Schildkröte um 90 Grad nach rechts turnLeft dreht die Schildkröte um 90 Grad nach links walk i lässt die Schildkröte i Meter in die aktuelle Richtung laufen. repeat i c: Der Code c wird i-mal hintereinander ausgeführt. Wir nehmen an, dass die Schildkröte am Anfang am Punkt (0,0) der zweidimensionalen Ebene steht und sie Richtung Osten zeigt. Implementieren Sie eine Funktion endPunkt :: Sequence -> (Int,Int), die ein Schildkrötenprogramm erwartet und die Position der Schildkröte nach Ausführung des Programms berechnet. (15 Punkte) Beispielaufrufe: *> endPunkt (45,100) *> endPunkt (5,15) *> endPunkt (20,-20) *> endPunkt (0,0) [WALK 20,REPEAT 5 [TURNLEFT,WALK 20,TURNRIGHT,WALK 5]] [REPEAT 5 [TURNLEFT,WALK 20,REPEAT 10 [TURNRIGHT,WALK 5]]] (parseKroete "walk 20; turnRight; walk 20") (parseKroete "walk 20; turnLeft; turnLeft; walk 20") 2