Programmierung 1 - Repetitorium WS 2002/2003 Programmierung 1 - Repetitorium Andreas Augustin und Marc Wagner Homepage: http://info1.marcwagner.info Programmierung 1 - Repetitorium Montag, den 07.04.03 Kapitel 1 Grundlagen Programmierung 1 - Repetitorium 1.1 Programme Es folgen einige grundlegende Begriffe zum Verständnis von Programmen : Wert = Objekte, mit denen gerechnet werden kann (Zahlen) Ausdrücke = Beschreibung von Werten (47+3) Konstante (4,7,3) Operatoren (,+) Bezeichner = Name für programmiersprachliche Objekte Deklarationen = Bindung von Bezeichner an Objekte (val x = 47+3) Schlüsselwort (val) Programm = Folge von Deklarationen Typen von Werten (int) Negative Zahlen (~7) Programmierung 1 - Repetitorium 1.2 Interpreter Ein Interpreter ist ein Software-Werkzeug, mit dem die Programme einer Programmiersprache schrittweise ausgeführt werden können. Als Interpreter für Standard ML wurde in der Vorlesung „Programmierung 1“ der Moscow ML Interpreter gewählt. Weitere Informationen zu Standard ML : http://www.dina.dk/~sestoft/mosmllib Programmierung 1 - Repetitorium 1.3 Vergleiche und Konditionale Vergleichsoperatoren < <= = <> Ergebnistyp von Vergleichen ist bool. Boolesche Werte sind true und false. Allgemeine Form eines Konditionals (Wenn-dann-sonst-Entscheidung) : if e1 then e2 else e3 e1 Bedingung vom Typ bool e2 Konsequenz e3 Alternative e2 und e3 müssen typgleich sein Programmierung 1 - Repetitorium 1.4 Prozeduren Prozedurdeklaration besteht aus fun quadrat (x:int) = xx Schlüsselwort fun Bezeichner quadrat, an den die Prozedur gebunden wird Argumentmuster (x:int) mit Argumentvariablen und deren Typ Schlüsselwort = Ausdruck xx beschreibt das Ergebnis der Prozedur und wird als Rumpf der Prozedur bezeichnet. Die Prozedur quadrat hat den Typ int -> int. Prozeduranwendung quadrat 4 besteht aus Prozedurbezeichner quadrat Argumentausdruck 4 Eine Klammerung des Argumentausdrucks einer Prozeduranwendung ist nur erforderlich, wenn er aus mehreren Teilausdrücken zusammengesetzt ist. Reihenfolge der Auswertung nach absteigender Priorität : ~ , prozeduranwendung, div mod , + - , if then else Programmierung 1 - Repetitorium 1.5 Lokale Deklarationen und Hilfsprozeduren Mit let ... in ... end können lokale Bezeichner für Hilfswerte sowie Hilfsprozeduren eingeführt werden. fun hoch8 (x:int) = let val a = x*x val b = a*a in b*b end fun hoch8 (x:int) = let fun q (y:int) = y*y in q(q(q(x))) end Die Gültigkeit der lokalen Deklarationen und Hilfsprozeduren endet mit dem Schlüsselwort end. Programmierung 1 - Repetitorium 1.6 Tupel Tupel sind Werte, die mehrere Werte zusammenfassen. n-stelliges Tupel ( v1 , ... , vn ) mit der i-ten Komponente vi Paare sind zweistellige Tupel Auf Komponenten eines Tupels kann man mit Hilfe von Projektionen zugreifen. #2 (3,true,7) true leeres Tupel ( ) Typ unit Baumdarstellung des Tupels ( 7 , ( 2 , true ) , ~3 ) ist : () 7 () 2 ~3 true Programmierung 1 - Repetitorium 1.7 Prozeduren und Tupel Tupel können als Argumente und Ergebnisse von Prozeduren verwendet werden. fun swap (x:int, y:bool) = (y,x) val swap : int*bool -> bool*int swap vertauscht die Komponenten eines Paares. swap (4,false) (false,4) : bool*int Programmierung 1 - Repetitorium 1.8 Rekursive Prozeduren Eine Prozedur, die mittels Selbstapplikation definiert ist, bezeichnet man als rekursive Prozedur. fun potenz (x:int, n:int) = if n>0 then x*potenz(x,n-1) else 1 Der Ergebnistyp der rekursiven Prozedur wird unabhängig vom Prozedurrumpf direkt nach dem Argumentmuster deklariert. Auswertungsprotokoll (vereinfachte Fassung) potenz(4,2) →* →* →* →* 4potenz(4,1) 4(4potenz(4,0)) 4(41) 16 Rekursionsbaum der Prozeduraufrufe potenz(4,2) potenz(4,1) potenz(4,0) Programmierung 1 - Repetitorium 1.9 Prozeduren und Umgebungen Unter freien Bezeichnern einer Deklaration versteht man diejenigen Bezeichner, die in der Deklaration ein Auftreten haben, welches nicht im Rahmen der Deklaration gebunden ist. fun q (x:int) = 3 + (p x) Eine Umgebung ist eine Sammlung von Bezeichnerbindungen, sodass keinem Bezeichner mehr als ein Wert zugeordnet wird. Programm : Auswertungsumgebung : fun fun fun val { p → (fun p (x:int) = 2x, { }), q → (fun q (x:int) = 3 + (p x), { p → (fun p (x:int) = x, { }) }), y→8} p q p y (x:int) = x (x:int) = 3 + (p x) (x:int) = 2x = q 5 Programmierung 1 - Repetitorium 1.10 Syntax Zeichendarstellung paar(2x-3) Baumdarstellung paar - 2 3 zusammengesetzt aus atomaren Ausdrücken und den Formen für Operator und Prozeduranwendungen x Wortdarstellung paar ( 2 x – 3 ) Programmierung 1 - Repetitorium 1.11 Klammern f 2 + + x f(2(x+3)) f + 2 x 3 3 3 f 2 (f 2)(x+3) f(2x)+3 Die wichtigsten Klammersparregeln : Punkt vor Strich 34+5 (34)+5 Operatoranwendung gruppiert nach links 2+3+4 (2+3)+4 Prozeduranwendung vor Operatoranwendung f 3+4 (f 3)+4 Prozeduranwendung gruppiert nach links f g 3 (f g) 3 x Programmierung 1 - Repetitorium 1.12 Syntaxübersicht Wörter sind Konstanten, Operatoren, Schlüsselwörter, Bezeichner. Phrasen sind Ausdrücke, Deklarationen, Programme, Typen und Argumentmuster. Ausdrücke sind Atomare Ausdrücke (Konstante/Bezeichner), Applikationen (Operatoranwendungen, Projektionen, Prozeduranwendungen), Konditionale (if <Bedingung> then <Konsequenz> else <Alternative>), Tupel-Ausdrücke, Let-Ausdrücke (let <Deklarationen> in <Ausdruck> end). Deklarationen : val <Bezeichner> = <Ausdruck> val (<Bezeichner>, ... ,<Bezeichner>) = <Ausdruck> fun <Bezeichner> <Argumentmuster> = <Ausdruck> fun <Bezeichner> <Argumentmuster> : Ergebnistyp = <Ausdruck> Programme : Folge von Deklarationen Argumentmuster : Typen : (<Bezeichner> : <Typ> , ... , <Bezeichner> : <Typ>) Atomare Typen (int, bool, unit), Prozedurtypen <Typ> <Typ> Tupeltypen <Typ> ... <Typ> Programmierung 1 - Repetitorium 1.13 Semantische Zulässigkeit Bevor ein Interpreter ein Programm ausführt, prüft er zunächst, ob das Programm semantisch zulässig ist. Die damit verbundenen Bedingungen betreffen die Bindung von Bezeichnern und den typgerechten Aufbau von Ausdrücken. Wohlgetypte Phrasen sind typgerecht aufgebaut, d.h. jedes vorkommende Auftreten eines Bezeichners ist durch eine Deklaration gebunden. Die Bedingungen zur Wohlgetyptheit lassen sich mit Hilfe von Typregeln formulieren. Dazu später mehr. Programmierung 1 - Repetitorium 1.14 Verarbeitungsphasen statische Phasen : 1. Lexikalische Analyse (eingegebene Zeichenfolge = Folge von Wörtern?) 2. Syntaktische Analyse / Parsing (Ergebnis von 1. = Programm?) 3. Semantische Analyse / Elaboration (Ergebnis von 2. = semantisch zulässig?) dynamische Phasen : 4. Ausführung / Evaluation (Auswertung des Programms) Programmierung 1 - Repetitorium 1.15 Auswertung Auswertungsprobleme : Auswertung von Ausdrücken (geg. Ausdruck e und Umgebung V, bestimme den Wert, den e für V liefert) Auswertung von Deklarationen (geg. Deklaration d und Umgebung V, bestimme die Umgebung, die d für V liefert) Auswertung von Prozeduraufrufen (geg. Prozedur p und Wert v, der als Argument für p zulässig ist, bestimme den Wert, den p für v liefert) Programmierung 1 - Repetitorium 1.16 Laufzeitfehler und Divergenz Möglichkeiten für den Verlauf der Ausführung eines Programms : - Reguläre Terminierung (Ausführung endet nach endlich vielen Schritten OK) - Abbruch wegen Laufzeitfehlern (Abbruch aufgrund eines Fehlersignals) - Abbruch durch den Benutzer (Ctrl + C) - Abbruch wegen Ressourcenüberschreitung (Speicherplatz erschöpft) - Divergenz (Ausführung endet nicht) Programmierung 1 - Repetitorium 1.17 Festkomma- und Gleitkommazahlen Festkommazahlen = ganze Zahlen (Moscow ML : Typ int [-230 , ... , 230 -1]) Bei Überlauf : Laufzeitfehler Overflow Gleitkommazahl x = m 10n (Moscow ML : Typ real ) Operatoren können überladen sein, was bedeutet, dass sie auf mehr als einen Typ angewendet werden können. Mischungen sind nicht zulässig, da Festkomma- und Gleitkommazahlen zu unterschiedlichen Darstellungssystemen gehören. Bei Überlauf : Rundungsfehler (Akkumulierung möglich) Programmierung 1 - Repetitorium 1.18 Standardstrukturen Für die Erledigung von Standardaufgaben gibt es Standardprozeduren, welche von Standardstrukturen zur Verfügung gestellt werden. Die Objekte einer Standardstruktur werden durch zusammengesetzte Bezeichner identifiziert (z.B. Math.pi), die aus dem Bezeichner der Struktur (z.B. Math) und aus dem lokalen Bezeichner des Objektes (z.B. pi) bestehen.