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 2014 Aufgabenblatt Nr. 6 Abgabe: Mittwoch 28. Mai 2014 vor! der Vorlesung Aufgabe 1 (35 Punkte) Das Bankhaus Lotter, Lug & Trug möchte seine Datenverwaltung von Bankkontonummern auf den neuen IBAN-Standard anpassen. Die alte Datenverwaltung enthält Einträge im alten und im neuen Format. Sie besteht aus einer Textdatei mit Einträgen der Form: • BLZ:B1 B2 B3 B4 B5 B6 B7 B8 KNR:Kontonummer wobei Bi jeweils Ziffern sind (und die Bankleitzahl darstellen) und Kontonummer eine Folge von 1 bis 10 Ziffern ist, • IBAN:DEP1 P2 B1 B2 B3 B4 B5 B6 B7 B8 K1 K2 K3 K4 K5 K6 K7 K8 K9 K10 wobei B1 B2 B3 B4 B5 B6 B7 B8 die Bankleitzahl ist, K1 K2 K3 K4 K5 K6 K7 K8 K9 K10 die Kontonummer ist (diese wird mit 0en von links aufgefüllt, falls sie weniger als 10 Stellen hat), DE das Länderzeichen für Deutschland ist (andere Konten werden nicht berücksichtigt) und P1 P2 zwei Ziffern sind, welche eine Prüfsumme darstellen: Berechnung der Prüfsumme:1 Hierfür wird die Ziffernfolge bestehend aus Bankleitzahl, Kontonummer und anschließend 131400 als Ganzzahl interpretiert. Sei daher X := B1 B2 B3 B4 B5 B6 B7 B8 K1 K2 K3 K4 K5 K6 K7 K8 K9 K10 131400. Anschließend wird der Rest der Division von X durch 97 berechnet, sei X mod 97 = Y . Danach berechne Q = 98−Y . Wenn Q zweistellig ist, dann setze P1 P2 = Q und ansonsten P1 P2 = 0Q. Z.B. ergibt dies für DE??123456781234567890: X = 123456781234567890131400, X mod 97 = 11 = Y und 98 − Y = 98 − 11 = 87 = Q. Die Prüfziffern sind daher P1 = 8 und P2 = 7. Jeder solcher Datensatz befindet sich in einer separaten Zeile, aber auch leere Zeilen sind erlaubt. Ziel der Aufgabe ist es, sämtliche Einträge ins neue Format zu bringen, d.h. eine Funktion konvertiere :: String -> String zu implementieren. Als Zwischendatenstruktur soll der Datentyp Bankkonto verwendet werden: data Bankkonto = IBAN PruefZiffer PruefZiffer BLZ KONTONR | BLZKonto BLZ KONTONR deriving(Eq,Show) type PruefZiffer = Char type BLZ = [Char] -- Liste von Ziffern type KONTONR = [Char] -- Liste von Ziffern a) Implementieren Sie eine Funktion parse :: String -> [Bankkonto], welche die Eingabe parst und in eine Liste von Bankkonten überführt. (20 Punkte) 1 Wir stellen hier nur die allgemeine Methode dar, in Realität gibt es Abweichungen von dieser Methode. 1 b) Implementieren Sie eine Funktion insIBANFormat :: Bankkonto -> Bankkonto, die ein Bankkonto erhält und dieses in den IBAN-Standard überführt, wenn es im alten Standard aus Bankleitzahl und Kontonummer vorliegt, und Einträge im IBAN-Format unverändert lässt. Implementieren Sie danach eine Funktion alleInsIBANFormat :: [Bankkonto] -> [Bankkonto], die eine Liste von Bankkonten erhält und alle Konten ins IBAN-Format überführt. (10 Punkte) c) Implementieren Sie die Funktion konvertiere :: String -> String, welche die Eingabe parst, anschließend ins IBAN-Format überführt und schließlich alle Einträge im IBAN-Format (zeilenweise) als String ausgibt. (5 Punkte) Zum Testen können Sie die folgende main-Funktion verwenden, die den Dateiinhalt der Datei Bankkonten.txt einliest und nach dem Konvertieren den neuen Inhalt ausdruckt: main = do inhalt <- readFile "Bankkonten.txt" putStrLn (konvertiere inhalt) Aufgabe 2 (15 Punkte) Die folgende Kontextfreie Grammatik mit Nichtterminal und Startsymbol A und den Terminalen b, c, d und e sei definiert durch: A ::= bA | c | Ad | e Implementieren Sie für diese Grammatik einen rekursiv absteigenden Parser in Haskell mithilfe der Parserkombinatoren aus der Vorlesung. Die Rückgabe des Parsers soll dabei das erkannte Wort sein. Da die Grammatik links-rekursiv ist, wird der zugehörige Parser nicht immer terminieren. Welche Eingaben kann der Parser trotzdem erkennen? Aufgabe 3 (50 Punkte) Jumpy ist eine springende Spielfigur, die Programme verarbeiten kann, welche durch die folgende kontextfreie Grammatik mit Startsymbol Kode den Nichtterminalen Kode, Befehl, Zahl, ZZ, Zif und den Terminalen ;, RIGHT, LEFT, UP, DOWN, REPEAT, (, ), 0,. . . ,9 erzeugt werden können: Kode Befehl Zahl ZZ Zif ::= ::= ::= ::= ::= Befehl | Befehl ; Kode LEFT Zahl | RIGHT Zahl | UP Zahl | DOWN Zahl | REPEAT Zahl ( Kode ) 0 | Zif | ZifZZ 0 | Zif | 0ZZ | ZifZZ 1 | ... | 9 a) Geben Sie eine Linksherleitung für das folgende Programm an: (8 Punkte) LEFT 20; REPEAT 5 (UP 3; RIGHT 4) b) Geben Sie eine Rechtsherleitung für das folgende Programm an: (8 Punkte) UP 6; LEFT 1; DOWN 20 c) Als Syntaxbaum für Jumpy-Programme verwenden wir den Typ Sequenz, der eine Liste von Befehl-Einträgen darstellt, wobei Befehl definiert sei als: 2 data Befehl = Wiederhole Int Sequenz | Springe Richtung Int deriving(Eq,Show) data Richtung = Links | Rechts | Oben | Unten deriving(Eq,Show) type Sequenz = [Befehl] Implementieren Sie mithilfe der in der Vorlesung vorgestellten funktionalen Parserkombinatoren einen rekursiv absteigenden Parser für Jumpy-Programme, der als Eingabe ein Programm als String erhält und als Ausgabe den Syntaxbaum vom Typ Sequenz liefert. (25 Punkte) Hinweis: Sie können für den Parser für das Nichtterminal Zahl direkt den vordefinierten Parser natural verwenden. Beispielaufrufe: *Main> parseJumpy "REPEAT 100 (LEFT 5; UP 4; REPEAT 4 (DOWN 2))" [Wiederhole 100 [Springe Links 5,Springe Oben 4,Wiederhole 4 [Springe Unten 2]]] d) Die Semantik der Befehle sei wie folgt festgelegt: – LEFT X, RIGHT X, UP X, DOWN X lässt Jumpy um X Felder nach links, rechts, oben bzw. unten springen. – REPEAT i (c): Der Code c wird i-mal hintereinander ausgeführt. Wir nehmen an, dass Jumpy am Anfang im Feld mit den Koordinaten (0,0) der zweidimensionalen Ebene steht. Implementieren Sie eine Funktion run :: String -> (Int,Int), die ein Jumpy-Programm erwartet und die Position von Jumpy nach Ausführung des Programms berechnet. (7 Punkte) Beispielaufrufe: *Main> run "LEFT 10; UP 20; REPEAT 10 (RIGHT 4)" (30,20) *Main> run "UP 100; REPEAT 5 (LEFT 1; REPEAT 2 (DOWN 1))" (-5,90) 3