pdf, 8 pro Seite - HTWK Fakultät Informatik, Mathematik und

Werbung
Einleitung
Prinzipien von Programmiersprachen
Vorlesung
Wintersemester 2007 – 2016
Beispiel: mehrsprachige Projekte
ein typisches Projekt besteht aus:
• Datenbank: SQL
Johannes Waldmann, HTWK Leipzig
• Verarbeitung: Java
26. Januar 2017
• Oberfläche: HTML
• Client-Code: Java-Script
und das ist noch nicht die ganze Wahrheit:
nenne weitere Sprachen, die üblicherweise in einem
solchen Projekt vorkommen
– Typeset by FoilTEX –
– Typeset by FoilTEX –
1
Konzepte
Sprache
• Hierarchien (baumartige Strukturen)
• wird benutzt, um Ideen festzuhalten/zu transportieren
(Wort, Satz, Text, Kontext)
– zusammengesetzte (arithmetische, logische) Ausdrücke
– zusammengesetzte Anweisungen (Blöcke)
– Klassen, Module
• wird beschrieben durch
–
–
–
–
Lexik
Syntax
Semantik
Pragmatik
• Typen beschreiben Daten
• Namen stehen für Werte, Wiederverwendung
• Flexibilität durch Parameter (Unterprogramme,
Polymorphie)
• natürliche Sprachen / formale Sprachen
– Typeset by FoilTEX –
2
– Typeset by FoilTEX –
3
Paradigmen
Ziele der LV
Arbeitsweise:
• imperativ
• isoliert beschreiben
Programm ist Folge von Befehlen (=
Zuständsänderungen)
• an Beispielen in (bekannten und unbekannten) Sprachen
wiedererkennen
• deklarativ (Programm ist Spezifikation)
Ziel:
– funktional (Gleichungssystem)
– logisch (logische Formel über Termen)
– Constraint (log. F. über anderen Bereichen)
• verbessert die Organisation des vorhandenen Wissens
• gestattet die Beurteilung und das Erlernen neuer
Sprachen
• objektorientiert (klassen- oder prototyp-basiert)
• nebenläufig (nichtdeterministisch, explizite Prozesse)
• hilft bei Entwurf eigener (anwendungsspezifischer)
Sprachen
• (hoch) parallel (deterministisch, implizit)
– Typeset by FoilTEX –
4
– Typeset by FoilTEX –
Beziehungen zu anderen LV
5
Organisation
• Grundlagen der Informatik, der Programmierung:
• Vorlesung
strukturierte (imperative) Programmierung
• Übungen (alle in Z430)
• Softwaretechnik 1/2:
objektorientierte Modellierung und Programmierung,
funktionale Programmierung und OO-Entwurfsmuster
• Compilerbau: Implementierung von Syntax und Semantik
Sprachen für bestimmte Anwendungen, mit bestimmten
Paradigmen:
Online-Übungsaufgaben (Übungsgruppe wählen)
https://autotool.imn.htwk-leipzig.de/new/
vorlesung/236/aufgaben
• Prüfungszulassung: regelmäßiges und erfolgreiches
Bearbeiten von Übungsaufgaben
• Klausur: 120 min, ohne Hilfsmittel
• Datenbanken, Computergrafik, künstliche Intelligenz,
Web-Programmierung, parallele/nebenläufige
Programmierung
– Typeset by FoilTEX –
Methoden, Konzepte, Paradigmen
6
– Typeset by FoilTEX –
7
Inhalt
Literatur
• http://www.imn.htwk-leipzig.de/˜waldmann/
edu/ws16/pps/folien/
(nach Sebesta: Concepts of Programming Languages)
• Robert W. Sebesta: Concepts of Programming
Languages, Addison-Wesley 2004, . . .
• Konzepte:
• Methoden: (3) Beschreibung von Syntax und Semantik
– (5) Namen, Bindungen, Sichtbarkeiten
– (6) Typen von Daten, Typen von Bezeichnern
– (7) Ausdrücke und Zuweisungen, (8) Anweisungen und
Ablaufsteuerung, (9) Unterprogramme
Zum Vergleich/als Hintergrund:
• Abelson, Sussman, Sussman: Structure and
Interpretation of Computer Programs, MIT Press 1984
http://mitpress.mit.edu/sicp/
• Paradigmen:
• Turbak, Gifford: Design Concepts of Programming
Languages, MIT Press 2008
http://mitpress.mit.edu/catalog/item/
default.asp?ttype=2&tid=11656
– Typeset by FoilTEX –
– (12) Objektorientierung ( (11) Abstrakte Datentypen )
– (15) Funktionale Programmierung
8
– Typeset by FoilTEX –
9
:set +t
length $ takeWhile (== ’0’) $ reverse $ show $ produ
1. Anwendungsgebiete von Programmiersprachen,
Kellermaschine in PostScript.
wesentliche Vertreter
42 42 scale 7 9 translate .07 setlinewidth .5 setgra
zu Skriptsprachen: finde die Anzahl der "*.java"-Dateien
setgray}def 1 0 0 42 1 0 c 0 1 1{0 3 3 90 270 arc 0
unter $HOME/workspace, die den Bezeichner String
arcn 270 90 c -2 2 4{-6 moveto 0 12 rlineto}for -5 2
enthalten. (Benutze eine Pipe aus drei Unix-Kommandos.)
9 0 rlineto}for stroke 0 0 3 1 1 0 c 180 rotate init
Lösungen:
Mit gv oder kghostview ansehen (Options: watch file).
find workspace/ -name "*.java" | xargs grep -l String
| wc -l
Mit Editor Quelltext ändern. Finden Sie den Autor dieses
find workspace/ -name "*.java"
-exec grep -l String {} \; | wc -l
Programms!
2. Maschinenmodelle (Bsp: Register, Turing, Stack,
(Lösung: John Tromp, siehe auch
Funktion)
http://www.iwriteiam.nl/SigProgPS.html)
funktionales Programmieren in Haskell
3. http://99-bottles-of-beer.net/ (top rated . . . )
(http://www.haskell.org/)
ghci
Übungen
– Typeset by FoilTEX –
10
– Typeset by FoilTEX –
11
• geschachtelte arithmetische Ausdrücke in Java und C:
vergleiche Bytecode mit Assemblercode
Übung: Beispiele für Übersetzer
Java:
• vergleiche Assemblercode für Intel und Sparc (einloggen
javac Foo.java # erzeugt Bytecode (Foo.class) auf kain, dann gcc wie oben)
java Foo
# führt Bytecode aus (JVM)
gcc für Java (gcj):
Einzelheiten der Übersetzung:
gcj -c Foo.java # erzeugt Objektcode
javap -c Foo
# druckt Bytecode
gcj -o Foo Foo.o --main=Foo # linken, wie oben
C:
• Assemblercode ansehen, vergleichen
gcc -c bar.c
# erzeugt Objekt(Maschinen)code (bar.o)
gcc -o bar bar.o # linkt (lädt) Objektcode (Resultat:
bar)
gcj -S Foo.java
# erzeugt Assemblercode (Foo.s)
./bar
# führt gelinktes Programm aus
• Kompatibilität des Bytecodes ausprobieren zwischen
Einzelheiten:
Sun-Java und GCJ (beide Richtungen)
gcc -S bar.c # erzeugt Assemblercode (bar.s)
Aufgaben:
gcj -C Foo.java # erzeugt Class-File (Foo.class)
– Typeset by FoilTEX –
12
– Typeset by FoilTEX –
13
– Typeset by FoilTEX –
14
– Typeset by FoilTEX –
15
Syntax von Programmiersprachen
Token-Typen
Token-Typen sind üblicherweise
Programme als Bäume
• reservierte Wörter (if, while, class, . . . )
• ein Programmtext repräsentiert eine Hierarchie (einen
Baum) von Teilprogrammen
• Bezeichner (foo, bar, . . . )
• Die Semantik des Programmes wird durch Induktion über
diesen Baum definiert.
• In den Knoten des Baums stehen Token,
• Literale für ganze Zahlen, Gleitkommazahlen, Strings,
Zeichen
• Trennzeichen (Komma, Semikolon)
• Klammern (runde: paren(these)s, eckige: brackets,
geschweifte: braces, spitze: angle brackets)
• jedes Token hat einen Typ und einen Inhalt (eine
Zeichenkette).
• Operatoren (=, +, &&, . . . )
• diese Prinzip kommt aus der Mathematik (arithmetische
Ausdrücke, logische Formeln)
– Typeset by FoilTEX –
• Leerzeichen, Kommentare (whitespace)
alle Token eines Typs bilden eine formale Sprache
16
Formale Sprachen
– Typeset by FoilTEX –
17
Spezifikation formaler Sprachen
man kann eine formale Sprache beschreiben durch:
• ein Alphabet ist eine Menge von Zeichen,
• ein Wort ist eine Folge von Zeichen,
• algebraisch (Sprach-Operationen)
Beispiele:
• Generieren (Grammatik), Bsp: kontextfreie Grammatik,
• Alphabet Σ = {a, b},
• Akzeptanz (Automat), Bsp: Kellerautomat,
• Sprache L = Menge aller Wörter über Σ gerader Länge.
• logisch
(Eigenschaften),
(p < r ∧ w[p] = a ∧ w[r] = c)
w | ∀p, r :
⇒ ∃q : (p < q ∧ q < r ∧ w[q] = b)
Bsp: reguläre Ausdrücke
• eine formale Sprache ist eine Menge von Wörtern.
• Wort w = ababaaab,
• Sprache (Menge) aller Gleitkomma-Konstanten in C.
– Typeset by FoilTEX –
18
Sprach-Operationen
– Typeset by FoilTEX –
19
Reguläre Sprachen/Ausdrücke
Aus Sprachen L1, L2 konstruiere:
Die Menge E(Σ) der regulären Ausdrücke
über einem Alphabet (Buchstabenmenge) Σ
ist die kleinste Menge E, für die gilt:
• Mengenoperationen
– Vereinigung L1 ∪ L2,
– Durchschnitt L1 ∩ L2, Differenz L1 \ L2;
• Verkettung L1 · L2 = {w1 · w2 | w1 ∈ L1, w2 ∈ L2}
S
k
• Stern (iterierte Verkettung) L∗1 =
k≥0 L1
Def: Sprache regulär : ⇐⇒ kann durch diese Operationen
aus endlichen Sprachen konstruiert werden.
Satz: Durchschnitt und Differenz braucht man dabei nicht.
• für jeden Buchstaben x ∈ Σ : x ∈ E
(autotool: Ziffern oder Kleinbuchstaben)
• das leere Wort ∈ E (autotool: Eps)
• die leere Menge ∅ ∈ E (autotool: Empty)
• wenn A, B ∈ E, dann
– (Verkettung) A · B ∈ E (autotool: * oder weglassen)
– (Vereinigung) A + B ∈ E (autotool: +)
– (Stern, Hülle) A∗ ∈ E (autotool: ˆ*)
Jeder solche Ausdruck beschreibt eine reguläre Sprache.
– Typeset by FoilTEX –
20
Beispiele/Aufgaben zu regulären Ausdrücken
Wir fixieren das Alphabet Σ = {a, b}.
• alle Wörter, die mit a beginnen und mit b enden: aΣ b.
∗
• alle Wörter, die wenigstens drei a enthalten Σ∗aΣ∗aΣ∗aΣ∗
• alle Wörter mit gerade vielen a und beliebig vielen b?
– Typeset by FoilTEX –
21
Erweiterte reguläre Ausdrücke
1. zusätzliche Operatoren (Durchschnitt, Differenz, Potenz),
die trotzdem nur reguläre Sprachen erzeugen
Beispiel: Σ∗ \ (Σ∗abΣ∗)2
2. zusätzliche nicht-reguläre Operatoren
Beispiel: exakte Wiederholungen L k := {wk | w ∈ L}
beachte Unterschied zu Lk
• Alle Wörter, die ein aa oder ein bb enthalten: Σ∗(aa ∪ bb)Σ∗ 3. Markierung von Teilwörtern, definiert (evtl. nicht-reguläre)
Menge von Wörtern mit Positionen darin
• (Wie lautet das Komplement dieser Sprache?)
wenn nicht-reguläre Sprachen entstehen können, ist keine
effiziente Verarbeitung (mit endlichen Automaten) möglich.
auch reguläre Operatoren werden gern schlecht implementiert
(http://swtch.com/˜rsc/regexp/regexp1.html)
– Typeset by FoilTEX –
22
– Typeset by FoilTEX –
23
Bemerkung zu Reg. Ausdr.
Wie beweist man w ∈ L(X)?
(Wort w gehört zur Sprache eines regulären Ausdrucks X)
• wenn X = X1 + X2:
beweise w ∈ L(X1) oder beweise w ∈ L(X2)
• wenn X = X1 · X2:
zerlege w = w1 · w2 und beweise w1 ∈ L(X1) und
beweise w2 ∈ L(X2).
• wenn X = X1∗:
wähle einen Exponenten k ∈ N und beweise w ∈ L(X1k )
(nach vorigem Schema)
• (Σ , ·, ) ist Monoid
• . . . aber keine Gruppe, weil man im Allgemeinen nicht
dividieren kann. Welche Relation ergibt sich als
Teilbarkeit“: u | w := ∃v : u · v = w
”
• Zeichne Hasse-Diagramme der Teilbarkeitsrelation
– auf natürlichen Zahlen {0, 1, . . . , 10},
– auf Wörtern {a, b}≤2
• (Pow(Σ∗), ∪, ·, . . . , . . . ) ist Halbring.
Beispiel für Distributivgesetz?
Beispiel: w = abba, X = (ab∗)∗.
w = abb · a = ab2 · ab0 ∈ ab∗ · ab∗ ⊆ (ab∗)2 ⊆ (ab∗)∗.
– Typeset by FoilTEX –
Übungen Reg. Ausdr.
∗
Welches sind jeweils die neutralen Elemente der
Operationen?
24
– Typeset by FoilTEX –
25
(vgl. oben) Welche Relation auf Sprachen (Mengen)
ergibt sich als Teilbarkeit“ bzgl. ∪ ?
”
• Damit ab+c = ab · ac immer gilt, muß man a0 wie
definieren?
• Block-Kommentare und weitere autotool-Aufgaben
• reguläre Ausdrücke für Tokenklassen in der
Standard-Pascal-Definition
http://www.standardpascal.org/iso7185.
html#6.1Lexicaltokens
Welche Notation wird für unsere Operatoren + und Stern
benutzt? Was bedeuten die eckigen Klammern?
– Typeset by FoilTEX –
26
– Typeset by FoilTEX –
27
– Typeset by FoilTEX –
28
– Typeset by FoilTEX –
29
– Typeset by FoilTEX –
30
– Typeset by FoilTEX –
31
Wort-Ersetzungs-Systeme
Grammatiken
Grammatik G besteht aus:
Berechnungs-Modell (Markov-Algorithmen)
• Zustand (Speicherinhalt): Zeichenfolge (Wort)
• Schritt: Ersetzung eines Teilwortes
Regelmenge R ⊆ Σ∗ × Σ∗
Regel-Anwendung:
u →R v ⇐⇒ ∃x, z ∈ Σ∗, (l, r) ∈ R : u = x · l · z ∧ x · r · z = v.
Beispiel: Bubble-Sort: {ba → ab, ca → ac, cb → bc}
Beispiel: Potenzieren: ab → bba
Aufgaben: gibt es unendlich lange Rechnungen für:
R1 = {1000 → 0001110}, R2 = {aabb → bbbaaa}?
– Typeset by FoilTEX –
Grammatik
{ terminale
= mkSet "abc"
(üblich: Kleinbuchst., Zif, variablen
fern)
= mkSet "SA"
, start = ’S’
Variablen-Alphabet V
, regeln = mkSet
(üblich: Großbuchstaben)
[ ("S", "abc")
, ("ab", "aabbA")
Startsymbol S ∈ V
, ("Ab", "bA")
, ("Ac", "cc")
Regelmenge
]
(Wort-Ersetzungs-System)
}
• Terminal-Alphabet Σ
Id
•
•
•
R ⊆ (Σ ∪ V )∗ × (Σ ∪ V )∗
von G erzeugte Sprache: L(G) = {w | S →∗R w ∧ w ∈ Σ∗}.
– Typeset by FoilTEX –
Formale Sprachen: Chomsky-Hierarchie
Id
Typ-3-Grammatiken
• (Typ 0) aufzählbare Sprachen (beliebige Grammatiken,
Turingmaschinen)
• (Typ 1) kontextsensitive Sprachen (monotone
Grammatiken, linear beschränkte Automaten)
• (Typ 2) kontextfreie Sprachen (kontextfreie Grammatiken,
Kellerautomaten)
• (Typ 3) reguläre Sprachen (rechtslineare Grammatiken,
reguläre Ausdrücke, endliche Automaten)
(= rechtslineare Grammatiken)
jede Regel hat die Form
Tokenklassen sind meist reguläre Sprachen.
Programmiersprachen werden kontextfrei beschrieben (mit
Zusatzbedingungen).
• G1 = ({a, b}, {S, T }, S, {S → , S → aT, T → bS})
– Typeset by FoilTEX –
Id
• Variable → Terminal Variable
• Variable → Terminal
• Variable → (vgl. lineares Gleichungssystem)
Beispiele
• G2 = ({a, b}, {S, T }, S, {S → , S → aS, S → bT, T →
aT, T → bS})
– Typeset by FoilTEX –
Kontextfreie Sprachen
Sätze über reguläre Sprachen
Für jede Sprache L sind die folgenden Aussagen
äquivalent:
Def (Wdhlg): G ist kontextfrei (Typ-2), falls
∀(l, r) ∈ R(G) : l ∈ V .
geeignet zur Beschreibung von Sprachen mit
hierarchischer Struktur.
Anweisung -> Bezeichner = Ausdruck
| if Ausdruck then Anweisung else Anweisung
Ausdruck -> Bezeichner | Literal
| Ausdruck Operator Ausdruck
Bsp: korrekt geklammerte Ausdrücke:
G = ({a, b}, {S}, S, {S → aSbS, S → }).
Bsp: Palindrome:
G = ({a, b}, {S}, S, {S → aSa, S → bSb, S → ).
Bsp: alle Wörter w über Σ = {a, b} mit |w|a = |w|b
• es gibt einen regulären Ausdruck X mit L = L(X),
• es gibt eine Typ-3-Grammatik G mit L = L(G),
• es gibt einen endlichen Automaten A mit L = L(A).
Beweispläne:
• Grammatik ↔ Automat (Variable = Zustand)
• Ausdruck → Automat (Teilbaum = Zustand)
• Automat → Ausdruck (dynamische Programmierung)
LA(p, q, r) = alle Pfade von p nach r über Zustände ≤ q.
– Typeset by FoilTEX –
Id
Id
– Typeset by FoilTEX –
Klammer-Sprachen
Id
Übungen
Abstraktion von vollständig geklammerten Ausdrücke mit
zweistelligen Operatoren
• Beispiele Wort-Ersetzung (ab → baa, usw.)
• Dyck-Sprache: Beweis L(G) ⊆ D
(4*(5+6)-(7+8)) ⇒ (()()) ⇒ aababb
(Induktionsbehauptung? Induktionsschritt?)
Höhendifferenz: h : {a, b}∗ → Z : w 7→ |w|a − |w|b
• Dyck-Sprache: Beweis D ⊆ L(G)
Präfix-Relation: u ≤ w : ⇐⇒ ∃v : u · v = w
Dyck-Sprache: D = {w | h(w) = 0 ∧ ∀u ≤ w : h(u) ≥ 0}
• CF-Grammatik für {w | w ∈ {a, b}∗, |w|a = |w|b}
CF-Grammatik: G = ({a, b}, {S}, S, {S → , S → aSbS})
• CF-Grammatik für {w | w ∈ {a, b}∗, 2 · |w|a = |w|b}
Satz: L(G) = D. Beweis (Plan):
L(G) ⊆ D Induktion über Länge der Ableitung
D ⊆ L(G) Induktion über Wortlänge
– Typeset by FoilTEX –
Id
– Typeset by FoilTEX –
Id
(erweiterte) Backus-Naur-Form
Ableitungsbäume für CF-Sprachen
• Noam Chomsky: Struktur natürlicher Sprachen (1956)
• John Backus, Peter Naur: Definition der Syntax von Algol
(1958)
• für jeden inneren Knoten k von T gilt m(k) ∈ V
Backus-Naur-Form (BNF) ≈ kontextfreie Grammatik
<assignment> -> <variable> = <expression>
<number> -> <digit> <number> | <digit>
Erweiterte BNF
• für jedes Blatt b von T gilt m(b) ∈ Σ ∪ {}
• für die Wurzel w von T gilt m(w) = S(G) (Startsymbol)
• für jeden inneren Knoten k von T mit Kindern
k1, k2, . . . , kn gilt (m(k), m(k1)m(k2) . . . m(kn)) ∈ R(G) (d.
h. jedes m(ki) ∈ V ∪ Σ)
• Wiederholungen (Stern, Plus) <digit>ˆ+
• Auslassungen
• für jeden inneren Knoten k von T mit einzigem Kind
k1 = gilt (m(k), ) ∈ R(G).
if <expr> then <stmt> [ else <stmt> ]
kann in BNF übersetzt werden
– Typeset by FoilTEX –
Def: ein geordneter Baum T mit Markierung
m : T → Σ ∪ {} ∪ V ist Ableitungsbaum für eine
CF-Grammatik G, wenn:
Id
– Typeset by FoilTEX –
Id
Eindeutigkeit
Ableitungsbäume (II)
Def: der Rand eines geordneten, markierten Baumes
(T, m) ist die Folge aller Blatt-Markierungen (von links nach
rechts).
Beachte: die Blatt-Markierungen sind ∈ {} ∪ Σ, d. h.
Terminalwörter der Länge 0 oder 1.
Für Blätter: rand(b) = m(b), für innere Knoten:
rand(k) = rand(k1) rand(k2) . . . rand(kn)
Satz: w ∈ L(G) ⇐⇒ existiert Ableitungsbaum (T, m) für G
mit rand(T, m) = w.
Def: G heißt eindeutig, falls ∀w ∈ L(G) genau ein
Ableitungsbaum (T, m) existiert.
Bsp: ist {S → aSb|SS|} eindeutig?
(beachte: mehrere Ableitungen S →∗R w sind erlaubt, und
wg. Kontextfreiheit auch gar nicht zu vermeiden.)
Die naheliegende Grammatik für arith. Ausdr.
expr -> number | expr + expr | expr * expr
ist mehrdeutig (aus zwei Gründen!)
Auswege:
• Transformation zu eindeutiger Grammatik (benutzt
zusätzliche Variablen)
• Operator-Assoziativitäten und -Präzedenzen
– Typeset by FoilTEX –
Id
– Typeset by FoilTEX –
Assoziativität
Assoziativität (II)
X1 + X2 + X3 auffassen als (X1 + X2) + X3
Grammatik-Regeln
Ausdruck -> Zahl | Ausdruck + Ausdruck
ersetzen durch
Ausdruck -> Summe
Summe
-> Summand | Summe + Summand
Summand -> Zahl
• Definition: Operation ist assoziativ
• Bsp: Plus ist nicht assoziativ (für Gleitkommazahlen) (Ü)
• für nicht assoziativen Operator muß man festlegen,
was x y z bedeuten soll:
?
?
?
?
Id
(3 + 2) + 4 = 3 + 2 + 4 = 3 + (2 + 4)
(3 − 2) − 4 = 3 − 2 − 4 = 3 − (2 − 4)
?
?
(3 ∗ ∗2) ∗ ∗4 = 3 ∗ ∗2 ∗ ∗4 = 3 ∗ ∗(2 ∗ ∗4)
• . . . und dann die Grammatik entsprechend einrichten
– Typeset by FoilTEX –
Id
Id
Zusammenfassung Operator/Grammatik
Präzedenzen
?
– Typeset by FoilTEX –
Ziele:
?
(3 + 2) ∗ 4 = 3 + 2 ∗ 4 = 3 + (2 ∗ 4)
• Klammern einsparen
Grammatik-Regel
summand -> zahl
erweitern zu
summand -> zahl | produkt
produkt -> ...
(Assoziativität beachten)
• trotzdem eindeutig bestimmter Syntaxbaum
Festlegung:
• Assoziativität:
bei Kombination eines Operators mit sich
• Präzedenz:
bei Kombination verschiedener Operatoren
Realisierung in CFG:
• Links/Rechts-Assoziativität ⇒ Links/Rechts-Rekursion
• verschiedene Präzedenzen ⇒ verschiedene Variablen
– Typeset by FoilTEX –
Id
– Typeset by FoilTEX –
Id
Das hängende else
Übung Operator/Grammatik
naheliegende EBNF-Regel für Verzweigungen:
<statement> -> if <expression>
then <statement> [ else <statement> ]
führt zu einer mehrdeutigen Grammatik.
Dieser Satz hat zwei Ableitungsbäume:
if X1 then if X2 then S1 else S2
Übung:
• Verhältnis von plus zu minus, mal zu durch?
• Klammern?
• unäre Operatoren (Präfix/Postfix)?
• Festlegung: das in der Luft hängende“ (dangling) else
”
gehört immer zum letzten verfügbaren then.
• Realisierung durch Grammatik mit (Hilfs-)Variablen
<statement>, <statement-no-short-if>
– Typeset by FoilTEX –
Id
– Typeset by FoilTEX –
Semantik von Programmiersprachen
Attributgrammatiken (I)
• Attribut: Annotation an Knoten des Syntaxbaums.
Statische und dynamische Semantik
A : Knotenmenge → Attributwerte
Semantik = Bedeutung
(Bsp: N)
• Attributgrammatik besteht aus:
• statisch (kann zur Übersetzungszeit geprüft werden)
– kontextfreier Grammatik G (Bsp: {S → e | mSS})
– für jeden Knotentyp (Terminal + Regel)
eine Menge (Relation) von erlaubten Attribut-Tupeln
(A(X0), A(X1), . . . , A(Xn))
für Knoten X0 mit Kindern [X1, . . . , Xn]
Beispiele:
– Typ-Korrektheit von Ausdrücken,
– Bedeutung (Bindung) von Bezeichnern
Hilfsmittel: Attributgrammatiken
S → mSS , A(X0) + A(X3) = A(X2);
S → e, A(X0) = A(X1);
Terminale: A(e) = 1, A(m) = 0
• dynamisch (beschreibt Ausführung des Programms)
operational, axiomatisch, denotational
– Typeset by FoilTEX –
Id
Id
– Typeset by FoilTEX –
Id
Donald E. Knuth
Attributgrammatiken (II)
ein Ableitungsbaum mit Annotationen ist
korrekt bezüglich einer Attributgrammatik, wenn
• The Art Of Computer Programming (1968, . . . )
(Band 3: Sortieren und Suchen)
• zur zugrundeliegenden CF-Grammatik paßt
• in jedem Knoten das Attribut-Tupel (von Knoten und
Kindern) zur erlaubten Tupelmenge gehört
• TEX, Metafont, Literate Programming (1983, . . . )
(Leslie Lamport: LATEX)
Plan:
• Attribut-Grammatiken
• Baum beschreibt Syntax, Attribute beschreiben Semantik
Ursprung: Donald Knuth: Semantics of Context-Free
Languages, (Math. Systems Theory 2, 1968)
technische Schwierigkeit: Attributwerte effizient
bestimmen. (beachte: (zirkuläre) Abhängigkeiten)
– Typeset by FoilTEX –
• die Bezeichnung NP-vollständig“
”
• ...
http://www-cs-faculty.stanford.edu/˜uno/
Id
Arten von Attributen
– Typeset by FoilTEX –
Id
Attributgrammatiken–Beispiele
• synthetisiert:
• Auswertung arithmetischer Ausdrücke (dynamisch)
hängt nur von Attributwerten in Kindknoten ab
• Bestimmung des abstrakten Syntaxbaumes
• ererbt (inherited)
• Typprüfung (statisch)
hängt nur von Attributwerten in Elternknoten und (linken)
Geschwisterknoten ab
• Kompilation (für Kellermaschine) (statisch)
Wenn Abhängigkeiten bekannt sind, kann man
Attributwerte durch Werkzeuge bestimmen lassen.
– Typeset by FoilTEX –
Id
– Typeset by FoilTEX –
Id
Regeln zur Typprüfung
Konkrete und abstrakte Syntax
. . . bei geschachtelten Funktionsaufrufen
• konkreter Syntaxbaum = der Ableitungsbaum
• Funktion f hat Typ A → B
• abstrakter Syntaxbaum = wesentliche Teile des
konkreten Baumes
• Ausdruck X hat Typ A
unwesentlich sind z. B. die Knoten, die zu Hilfsvariablen
der Grammatik gehören.
abstrakter Syntaxbaum kann als synthetisiertes Attribut
konstruiert werden.
E -> E + P
E -> P
;
;
• dann hat Ausdruck f (X) den Typ B
Beispiel
String x = "foo"; String y = "bar";
E.abs = new Plus(E.abs, P.abs)
Boolean.toString (x.length() < y.length()));
E.abs = P.abs
(Curry-Howard-Isomorphie)
– Typeset by FoilTEX –
Id
– Typeset by FoilTEX –
Id
cd pps-ws15/rechner ; make ; make test ; make clean
Übung Attributgrammatiken/SableCC
(dafür muß sablecc gefunden werden, siehe
http://www.imn.htwk-leipzig.de/˜waldmann/
etc/pool/)
• SableCC: http://sablecc.org/
SableCC is a parser generator for building compilers,
interpreters . . . , strictly-typed abstract syntax trees and
tree walkers
• Struktur:
– rechner.grammar enthält Attributgrammatik, diese
beschreibt die Konstruktion des abstrakten
linke-seite { -> attribut-typ }
Syntaxbaumes (AST) aus dem Ableitungsbaum
= { zweig-name } rechte-seite { -> attribut-wert
} Syntaxbaum)
(konkreten
– Eval.java enthält Besucherobjekt, dieses beschreibt
• Quelltexte:
die Attributierung der AST-Knoten durch Zahlen
git clone https://gitlab.imn.htwk-leipzig.de/waldmann/pps-ws15.git
– Hauptprogramm in Interpreter.java
Benutzung:
– bauen, testen, aufräumen: siehe Makefile
• Syntax einer Regel
– Typeset by FoilTEX –
Id
– generierte Dateien in rechner/*
– Typeset by FoilTEX –
Id
die Grammatik ist nicht eindeutig (genauer: wird von
Sablecc nicht als eindeutig erkannt)
• Aufgaben:
Kommentar: in Java fehlen: algebraische Datentypen,
Pattern Matching, Funktionen höherer Ordnung. Deswegen
muß SableCC das simulieren — das sieht nicht schön aus.
Die richtige“ Lösung sehen Sie später im Compilerbau.
”
Abstrakter Syntaxbaum, Interpreter:
http://www.imn.htwk-leipzig.de/˜waldmann/
edu/ws11/cb/folien/main/node12.html,
Kombinator-Parser:
http://www.imn.htwk-leipzig.de/˜waldmann/
edu/ws11/cb/folien/main/node70.html
Multiplikation, Subtraktion, Klammern, Potenzen
Bemerkungen (häufige/nicht offensichtliche Fehlerquellen)
• Redefinition of ... : nicht so:
foo -> bar ; foo -> baz; sondern so:
foo -> {eins} bar | {zwei} baz;
Regeln mit gleicher linker Seite zusammenfassen,
die rechten Seiten durch Label ({eins},{zwei})
unterscheiden
• ... conflict ... :
– Typeset by FoilTEX –
Id
– Typeset by FoilTEX –
Id
– Typeset by FoilTEX –
Id
– Typeset by FoilTEX –
Id
Dynamische Semantik
Bsp. Operationale Semantik (I)
arithmetischer Ausdruck ⇒ Programm für Kellermaschine
3 ∗ x + 1 ⇒ push 3, push x, mal, push 1, plus
• operational:
beschreibt Wirkung von Anweisungen durch Änderung
des Speicherbelegung
• Code für Konstante/Variable c : push c;
• Code für Ausdruck x ◦ y: code(x); code(y); o;
• denotational:
• Ausführung eines binären Operators ◦:
ordnet jedem (Teil-)Programm einen Wert zu, Bsp: eine
Funktion (höherer Ordnung).
x <- pop; y <- pop; push (x o y);
Beweis von Programmeigenschaften durch
Term-Umformungen
Der erzeugte Code ist synthetisiertes Attribut!
Beispiele: Java-Bytecode (javac, javap),
CIL (gmcs, monodis)
Bemerkung: soweit scheint alles trivial—interessant wird es
bei Teilausdrücken mit Nebenwirkungen, Bsp. x++ - --x;
• axiomatisch (Bsp: Hoare-Kalkül):
enthält Schlußregeln, um Aussagen über Programme zu
beweisen
– Typeset by FoilTEX –
Id
– Typeset by FoilTEX –
Bsp: Operationale Semantik (II)
Id
Denotationale Semantik
Schleife
while (B) A
wird übersetzt in Sprungbefehle
if (B) ...
Beispiele
(vervollständige!)
Aufgabe: übersetze for(A; B; C) D in while!
Vorteile denotationaler Semantik:
• jedes (nebenwirkungsfreie) Unterprogramm ist eine
Funktion von Argument nach Resultat
• jede Anweisung ist eine Funktion von Speicherbelegung
nach Speicherbelegung
• Bedeutung eines Programmes = mathematisches Objekt
• durch Term beschreiben, durch äquivalente
Umformungen verarbeiten (equational reasoning)
Vorteil deklarativer Programierung:
Programmiersprache ist Beschreibungssprache
– Typeset by FoilTEX –
Id
Beispiele Denotationale Semantik
– Typeset by FoilTEX –
Id
Beispiel: Semantik von Unterprogr.
Unterprogramme definiert durch Gleichungssysteme.
Sind diese immer lösbar? (überhaupt? eindeutig?)
Geben Sie geschlossenen arithmetischen Ausdruck für:
f (x) = if x > 52
then x - 11
else f (f (x + 12))
• jeder arithmetische Ausdruck (aus Konstanten und
Operatoren)
beschreibt eine Zahl
• jeder aussagenlogische Ausdruck (aus Variablen und
Operatoren)
beschreibt eine Funktion (von Variablenbelegung nach
Wahrheitswert)
g(x,y)
if x
else
else
• jeder reguläre Ausdruck
beschreibt eine formale Sprache
=
<= 0 then 0
if y <= 0 then 0
1 + g (g (x-1, y), g (x, y-1))
• jedes rekursive definierte Unterprogramm
beschreibt eine Funktion (?)
– Typeset by FoilTEX –
Id
– Typeset by FoilTEX –
Eiffel
Axiomatische Semantik
Notation für Aussagen über Speicherbelegungen:
{ V } A { N }
Bertrand Meyer, http://www.eiffel.com/
class Stack [G]
feature
count : INTEGER
item : G is require not empty do ... end
empty : BOOLEAN is do .. end
full : BOOLEAN is do .. end
put (x: G) is
require not full do ...
ensure not empty
item = x
count = old count + 1
Beispiel sinngemäß aus: B. Meyer: Object Oriented
Software Construction, Prentice Hall 1997
• für jede Belegung s, in der Vorbedingung V gilt:
• wenn Anweisung A ausgeführt wird,
• und Belegung t erreicht wird, dann gilt dort
Nachbedingung N
Beispiel:{ x >= 5 } y := x + 3 { y >= 7 }
Gültigkeit solcher Aussagen kann man
• beweisen (mit Hoare-Kalkül)
• prüfen (testen)
Beachte: {x >= 5} while (true) ; {x == 42}
– Typeset by FoilTEX –
Id
Id
– Typeset by FoilTEX –
Id
Hoare-Kalkül
Axiom für Schleifen
Kalkül: für jede Form der Anweisung ein Axiom, Beispiele:
• Zuweisung: { N[x/E] } x := E { N }
• wenn { V } C { Z } und
dann { V } C; D { N }
{ Z } D { N }
• wenn { V } A { N } und V’ => V und N => N’
dann { V’ } A { N’ }
• wenn { V und
B } C { N }
und { V und not B } D { N }
dann { V } if (B) then C else D { N }
• Schleife . . . benötigt Invariante
– Typeset by FoilTEX –
Id
Schreiben Sie eine Java-Methode, deren Kompilation
genau diesen Bytecode erzeugt: a)
public static int h(int, int);
Code:
0: iconst_3
1: iload_0
2: iadd
3: iload_1
4: iconst_4
5: isub
6: imul
7: ireturn
b)
14: goto
17: iload_2
18: ireturn
– Typeset by FoilTEX –
Id
public static int g(int, int);
Code:
0: iload_0
1: istore_2
2: iload_1
3: ifle
17
6: iload_2
7: iload_0
8: imul
9: istore_2
10: iload_1
11: iconst_1
12: isub
13: istore_1
Übungen (Stackmaschine)
– Typeset by FoilTEX –
wenn { I and B } A { I },
dann { I } while (B) do A { I and not B }
Beispiel:
Eingabe int p, q;
// p = P und q = Q
int c = 0;
// inv: p * q + c = P * Q
while (q > 0) {
???
}
// c = P * Q
Moral: erst Schleifeninvariante (Spezifikation), dann
Implementierung.
Id
– Typeset by FoilTEX –
2
Id
Übungen (Invarianten)
Ergänze das Programm:
Eingabe: natürliche Zahlen a, b;
// a = A und b = B
int p = 1; int c = ???;
// Invariante: cˆb * p = AˆB
while (b > 0) {
???
b = abrunden (b/2);
}
Ausgabe: p; // p = AˆB
– Typeset by FoilTEX –
Id
– Typeset by FoilTEX –
Id
– Typeset by FoilTEX –
Id
– Typeset by FoilTEX –
Id
Typen
Historische Entwicklung
• keine Typen (alles ist Maschinenwort)
Warum Typen?
• vorgegebene Typen (Fortran: Integer, Real, Arrays)
• Typ ist Menge von Werten mit Operationen
• für jede eigene Menge von Werten (Variablen) aus dem
Anwendungsbereich benutze eine eigenen Typ
• benutzerdefinierte Typen
(algebraische Datentypen;
Spezialfälle: enum, struct, class)
• halte verschiedene Typen sauber getrennt, mit Hilfe der
Programmiersprache
• abstrakte Datentypen (interface)
• der Typ einer Variablen/Funktion ist ihre beste
Dokumentation
• (data) dependent types (z.B. in Agda, Idris)
– Typeset by FoilTEX –
• polymorphe Typen (z.B. List<E>, aber auch Arrays)
Id
– Typeset by FoilTEX –
Zahlenbereiche
Überblick
• Maschinenzahlen (oft im Sprachstandard festgelegt)
• einfache (primitive) Typen
– ganze Zahlen (in binärem Zweierkomplement)
– gebrochene Zahlen (in binärer Gleitkommadarstellung)
Goldberg 1991: What Every Computer Scientist Should
Know About Floating-Point Arithmetic
http://docs.oracle.com/cd/E19957-01/
806-3568/ncg_goldberg.html
– Zahlen, Wahrheitswerte, Zeichen
– benutzerdefinierte Aufzählungstypen
– Teilbereiche
• zusammengesetzte (strukturierte) Typen
Produkt (records)
Summe (unions) (Spezialfall: Aufzählungen)
rekursive Typen
Potenz (Funktionen: Arrays, (Tree/Hash-)Maps,
Unterprogramme)
– Verweistypen (Zeiger)
–
–
–
–
– Typeset by FoilTEX –
Id
• Abstraktionen (oft in Bibliotheken, Bsp.
https://gmplib.org//manual/)
– beliebig große Zahlen
– exakte rationale Zahlen
Id
Aufzählungstypen
können einer Teilmenge ganzer Zahlen zugeordnet werden
– Typeset by FoilTEX –
Id
• automatisch von int umgewandelt?
• vorgegeben: int, char, boolean
• nutzerdefiniert (enum)
typedef enum {
Mon, Tue, Wed, Thu, Fri, Sat, Sun
} day;
data Day = Mon | Tue | Wed | Thu | Fri | Sat | Sun
Ü: enum in Java
Designfragen:
• automatisch nach int umgewandelt?
– Typeset by FoilTEX –
Id
– Typeset by FoilTEX –
Maßeinheiten in F#
Zeichen und Zeichenketten
physikalische Größe = Maßzahl × Einheit.
viele teure Softwarefehler durch Ignorieren der Einheiten.
in F# (Syme, 200?), aufbauend auf ML (Milner, 197?)
[<Measure>] type kg ;;
let x = 1<kg> ;;
x * x ;;
[<Measure>] type s ;;
let y = 2<s> ;;
x * y ;;
x + y ;;
http://msdn.microsoft.com/en-us/library/
dd233243.aspx
– Typeset by FoilTEX –
Id
• das naive Modell ist:
– Zeichen paßt in (kurze) Maschinenzahl (z.B.
char = byte)
– Zeichenketten sind (Zeiger auf) Arrays
das ist historisch begründet (US-amerikanische
Hardware-Hersteller)
• das umfassende Modell ist http:
//www.unicode.org/versions/Unicode9.0.0/
jedes Zeichen wird durch encoding scheme (z.B. UTF8)
auf Folge von Bytes abgebildet.
Id
– Typeset by FoilTEX –
Id
Zusammengesetzte Typen
Produkttypen (Records)
Typ = Menge, Zusammensetzung = Mengenoperation:
• Produkt (record, struct)
• disjunkte Summe (union, case class, enum)
• Rekursion,
z.B. data Tree a = ... | Branch (Tree a) ...
• Potenz (Funktion),
R x; ... B x.bar; ...
erstmalig in COBOL (≤ 1960)
Übung: Record-Konstruktion (in C, C++)?
z.B. type Sorter a = (List a -> List a)
– Typeset by FoilTEX –
R=A×B×C
Kreuzprodukt mit benannten Komponenten:
typedef struct {
A foo;
B bar;
C baz;
} R;
Id
– Typeset by FoilTEX –
Vereinigung mittels Interfaces
Summen-Typen
I repräsentiert die Vereinigung von A und B:
interface I { }
class A implements I { int foo; }
class B implements I { String bar; }
R=A∪B∪C
disjunkte (diskriminierte) Vereinigung (Pascal)
type tag = ( eins, zwei, drei );
type R = record case t : tag of
eins : ( a_value : A );
zwei : ( b_value : B );
drei : ( c_value : C );
end record;
nicht diskriminiert (C):
typedef union {
A a_value; B b_value; C c_value;
}
– Typeset by FoilTEX –
Notation dafür in Scala (http://scala-lang.org/)
abstract class I
case class A (foo : Int) extends I
case class B (bar : String) extends I
Verarbeitung durch Pattern matching
def g (x : I): Int = x match {
case A(f) => f + 1
case B(b) => b.length() }
Id
– Typeset by FoilTEX –
Id
Potenz-Typen
Rekursiv definierte Typen
B := {f : A → B} (Menge aller Funktionen
von A nach B)
ist sinnvolle Notation, denn |B||A| = B A
spezielle Realisierungen:
Haskell (http://haskell.org/)
data Tree a = Leaf a
| Branch ( Tree a ) ( Tree a )
data List a = Nil | Cons a ( List a )
Java
interface Tree<A> { }
class Leaf<A> implements Tree<A> { A key }
class Branch<A> implements Tree<A>
{ Tree<A> left, Tree<A> right }
das ist ein algebraischer Datentyp,
die Konstruktoren (Leaf, Nil) bilden die Signatur der
Algebra,
die Elemente der Algebra sind Terme (Bäume)
– Typeset by FoilTEX –
Id
A
• Funktionen (Unterprogramme)
• Wertetabellen (Funktion mit endlichem
Definitionsbereich) (Assoziative Felder, Hashmaps)
• Felder (Definitionsbereich ist Aufzählungstyp) (Arrays)
• Zeichenketten (Strings)
die unterschiedliche Notation dafür (Beispiele?) ist
bedauerlich.
Id
– Typeset by FoilTEX –
Felder (Arrays)
Id
Felder in C
Motivation: a[i] = * (a + w * i)
Zugriff auf beliebiges Element mit wenig Befehlen
Design-Entscheidungen:
int main () {
int a [10][10];
a[3][2] = 8;
printf ("%d\n", a[2][12]);
}
statische Dimensionierung, dynamische Allokation, keine
Bereichsprüfungen.
• welche Index-Typen erlaubt? (Zahlen? Aufzählungen?)
• Bereichsprüfungen bei Indizierungen?
• Index-Bereiche statisch oder dynamisch?
Form: rechteckig, Adress-Rechnung:
int [M][N];
a[x][y] ==> *(&a + (N*x + y))
• Allokation statisch oder dynamisch?
• Initialisierung?
• mehrdimensionale Felder gemischt oder rechteckig?
– Typeset by FoilTEX –
Id
– Typeset by FoilTEX –
Id
Felder in Java
Felder in C#
Unterschiede zwischen
int [][] feld =
{ {1,2,3}, {3,4}, {5}, {} };
for (int [] line : feld) {
for (int item : line) {
System.out.print (item + " ");
}
System.out.println ();
}
dynamische Dimensionierung und Allokation,
Bereichsprüfungen. Nicht notwendig rechteckig.
– Typeset by FoilTEX –
• int [][] a
• int [,]
in
• Benutzung (Zugriff)
• Initialisierung durch Array-Literal
Id
– Typeset by FoilTEX –
Id
Kosten der Bereichsüberprüfungen
Nicht rechteckige Felder in C?
es wird oft als Argument für C (und gegen Java) angeführt,
daß die erzwungene Bereichsüberprüfung bei jedem
Array-Zugriff so teuer sei.
sowas sollte man erst glauben, wenn man es selbst
gemessen hat.
modernen Java-Compiler sind sehr clever und können
theorem-prove away (most) subscript range checks
das kann man auch in der Assembler-Ausgabe des
JIT-Compilers sehen.
http://www.imn.htwk-leipzig.de/˜waldmann/
etc/safe-speed/
Das geht:
int a [] = {1,2,3};
int b [] = {4,5};
int c [] = {6};
e
= {a,b,c};
printf ("%d\n", e[1][1]);
aber welches ist dann der Typ von e?
(es ist nicht int e [][].)
– Typeset by FoilTEX –
a
Id
Verweistypen
– Typeset by FoilTEX –
Id
Verweis- und Wertsemantik in C#
• Typ T , Typ der Verweise auf T .
• für Objekte, deren Typ class ... ist:
Verweis-Semantik (wie in Java)
• Operationen: new, put, get, delete
• ähnlich zu Arrays (das Array ist der Hauptspeicher)
• für Objekte, deren Typ struct ... ist:
• Java: alle nicht primitiven Typen sind Verweistypen,
De-Referenzierung ist implizit
Testfall:
class s {public int foo; public string bar;}
s x = new s(); x.foo = 3; x.bar = "bar";
s y = x; y.bar = "foo";
Console.WriteLine (x.bar);
Wert-Semantik
explizite Verweise in C, Pascal
implizite Verweise:
• C#: class ist Verweistyp, struct ist Werttyp
– Typeset by FoilTEX –
und dann class durch struct ersetzen
Id
– Typeset by FoilTEX –
Algebraische Datentypen in Pascal, C
Id
Übung Typen
Rekursion unter Verwendung von Verweistypen
Pascal:
type Tree = ˆ Node ;
type Tag = ( Leaf, Branch );
type Node = record case t : Tag of
Leaf : ( key : T ) ;
Branch : ( left : Tree ; right : Tree );
end record;
C: ähnlich, benutze typedef
• für Mengen
A = ∅, B = {0}, C = {1, 2}, D = {3, 4, 5}, E = {6, 7, 8, 9},
geben Sie an:
– alle Elemente von
A × C, B × D, A ∪ B, B A, AB , C B , B C , C D
– ein Element aus (C × D)E
– die Kardinalitäten von (C × D)E , C D∪E
• algebraische Datentypen und Polymorphie in Haskell
(vgl. VL Fortgeschrittene Programmierung (Bachelor)
http://www.imn.htwk-leipzig.de/˜waldmann/
edu/ss16/fop/folien/#(20),
– Typeset by FoilTEX –
Id
– Typeset by FoilTEX –
Id
Bezeichner, Bindungen, Bereiche
http://www.imn.htwk-leipzig.de/˜waldmann/
edu/ss16/fop/folien/#(41))
Variablen
• Arrays in C (Assemblercode anschauen)
vereinfacht: Variable bezeichnet eine (logische)
Speicherzelle
genauer: Variable besitzt Attribute
• rechteckige und geschachtelte Arrays in C#
• Wert/Verweis (struct/class) in C#
•
•
•
•
•
•
Name
Adresse
Wert
Typ
Lebensdauer
Sichtbarkeitsbereich
Bindungen dieser Attribute statisch oder dynamisch
– Typeset by FoilTEX –
Id
– Typeset by FoilTEX –
Id
Namen
Namen in der Mathematik
• ein Name bezeichnet einen unveränderlichen Wert
X1
X
x2n+1
e=
, sin = (x 7→
(−1)n
)
n!
(2n + 1)!
n≥0
n≥0
• welche Buchstaben/Zeichen sind erlaubt?
• reservierte Bezeichner?
• auch n und x sind dabei lokale Konstanten (werden aber
gern Variablen“ genannt)
”
• auch die Variablen“ in Gleichungssystemen sind
”
(unbekannte) Konstanten {x + y = 1 ∧ 2x + y = 1}
in der Programmierung:
• Variable ist Name für Speicherstelle (= konstanter Zeiger)
• implizite Dereferenzierung beim Lesen und Schreiben
• Groß/Kleinschreibung?
• Konvention: long_name oder longName (camel-case)
(Fortran: long name)
im Zweifelsfall: Konvention der Umgebung einhalten
• Konvention: Typ im Namen (Bsp.: myStack = ...)
– verrät Details der Implementierung
– ist ungeprüfte Behauptung
besser: Stack<Ding> rest_of_input = ...
• Konstante: Zeiger auf schreibgeschützte Speicherstelle
– Typeset by FoilTEX –
Id
Typen für Variablen
– Typeset by FoilTEX –
Id
Dynamisch getypte Sprachen
Daten sind typisiert, Namen sind nicht typisiert.
LISP, Clojure, PHP, Python, Perl, Javascript, . . .
var foo = function(x) {return 3*x;};
foo(1);
foo = "bar";
foo(1);
• dynamisch (Wert hat Typ)
• statisch (Name hat Typ)
– deklariert (durch Programmierer)
– inferiert (durch Übersetzer)
z. B. var in C#3
Vor/Nachteile: Lesbarkeit, Sicherheit, Kosten
– Typeset by FoilTEX –
Id
– Typeset by FoilTEX –
Id
Typdeklarationen
Statisch getypte Sprachen
Daten sind typisiert, Namen sind typisiert
Invariante:
• zur Laufzeit ist der dynamische Typ des Namens (der Typ
des Wertes des Namens)
immer gleich dem statischen Typ des Namens (der
deklariert oder inferiert wurde)
woher kommt der statische Typ?
• Programmierer deklariert Typen von Namen
C, Java, . . .
• Compiler inferiert Typen von Namen
im einfachsten Fall (Java, C#):
Typname Variablenname [ = Initialisierung ] ;
int [] a = { 1, 2, 3 };
Func<double,double> f = (x => sin(x));
gern auch komplizierter (C): dort gibt es keine Syntax für
Typen, sondern nur für Deklarationen von Namen.
double f (double x) { return sin(x); }
int * p;
double ( * a [2]) (double) ;
Beachte: * und [] werden von außen nach innen “
”
angewendet
Ü: Syntaxbäume zeichnen, a benutzen
ML, F#, Haskell, C# (var)
– Typeset by FoilTEX –
Id
– Typeset by FoilTEX –
Id
Konstanten
Typinferenz in C# und Java
C#:
public class infer {
public static void Main (string [] argv)
var arg = argv[0];
var len = arg.Length;
System.Console.WriteLine (len);
}
}
Ü: das var in C# ist nicht das var aus Javascript.
Java:
für formale Parameter von anonymen Unterprogrammen
Function<Integer,Integer> f = (x) -> x;
– Typeset by FoilTEX –
Id
= Variablen, an die genau einmal zugewiesen wird
• C: const (ist Attribut für Typ)
{
• Java: final (ist Attribut für Variable)
Vorsicht:
class C { int foo; }
static void g (final C x) { x.foo ++; }
Merksatz: alle Deklarationen so lokal und so konstant wie
möglich!
(D. h. Attribute immutable usw.)
– Typeset by FoilTEX –
Lebensort und -Dauer von Name und Daten
Sichtbarkeit von Namen
= Bereich der Anweisungen/Deklarationen, in denen ein
Name benutzt werden kann.
• statisch (global, aber auch lokal:)
int f (int x) {
static int y = 3; y++; return x+y;
}
• global
• lokal: Block (und Unterblöcke)
• dynamisch
Üblich ist: Sichtbarkeit beginnt nach Deklaration und endet
am Ende des umgebenden Blockes
– Stack { int x = ... }
– Heap
∗ explizit (new/delete, malloc/free)
∗ implizit
Tatsächlich (Java, C):
Sichtbarkeit beginnt schon in der Initalisierung
int x = sizeof(x); printf ("%d\n", x);
Ü: ähnliches Beispiel für Java? Vgl. JLS Kapitel 6.
Beachte (in Java u.ä.) in { C x = new C(); } ist x
Stack-lokal, Inhalt ist Zeiger auf das Heap-globale Objekt.
– Typeset by FoilTEX –
Id
Id
– Typeset by FoilTEX –
Sichtbarkeit in JavaScript
Id
Überdeckungen
Namen sind sichtbar
Namen sind auch in inneren Blöcken sichtbar:
int x;
• global
while (..) {
• in Unterprogramm (Deklaration mit var)
int y;
(function() { { var x = 8; } return x; } ) () ... x + y ...
}
• in Block (Deklaration mit let)
innere Deklarationen verdecken äußere:
(function() { { let x = 8; } return x; } ) ()
int x;
Ü: erkläre das Verhalten von
while (..) {
(function(){let x=8; {x=9} return x} )()
int x;
(function(){let x=8; {x=9;let x=10} return x} )()
... x ...
}
durch die Sprachspezifikation
(und nicht durch Sekundärquellen)
– Typeset by FoilTEX –
Id
– Typeset by FoilTEX –
Id
Id
– Typeset by FoilTEX –
Id
Sichtbarkeit und Lebensdauer
. . . stimmen nicht immer überein:
• static-Variablen in C-Funktionen
sichtbar: in Funktion, Leben: Programm
void u () { static int x; }
• lokale Variablen in Unterprogrammen
sichtbar: innere Blöcke, Leben: bis Ende Unterpr.
void u () {
int *p; { int x = 8; p = &x; }
printf ("%d\n", *p);
}
– Typeset by FoilTEX –
Ausdrücke
Einleitung (II)
• in allen imperativen Sprachen gibt es Ausdrücke mit
Nebenwirkungen
Einleitung
• Ausdruck hat Wert (Zahl, Objekt, . . . )
(Ausdruck wird ausgewertet)
• Anweisung hat Wirkung (Änderung des
Programm/Welt-Zustandes)
(Anweisung wird ausgeführt)
• in den rein funktionalen Sprachen gibt es keine
(Neben-)Wirkungen, also keine Anweisungen
Vgl. Trennung (in Pascal, Ada)
• in den C-ähnlichen Sprachen ist = ein Operator,
(nämlich Unterprogramm-Aufrufe)
(sondern nur Ausdrücke).
(d. h. die Zuweisung ist syntaktisch ein Ausdruck)
• Funktion (Aufruf ist Ausdruck)
• Prozedur (Aufruf ist Anweisung)
• in den C-ähnlichen Sprachen:
Ü: wie in Java ausgedrückt? wie stark getrennt?
– Typeset by FoilTEX –
Ausdrücke ⊆ Anweisungen
Id
– Typeset by FoilTEX –
Designfragen für Ausdrücke
Syntax von Ausdrücken
• Syntax
• einfache Ausdrücke : Konstante, Variable
– Präzedenzen (Vorrang)
– Assoziativitäten (Gruppierung)
– kann Programmierer neue Operatoren definieren?
vorhandene überladen?
• zusammengesetzte Ausdrücke:
– Operator-Symbol zwischen Argumenten
– Funktions-Symbol vor Argument-Tupel
wichtige Spezialfälle für Operatoren:
• statische Semantik
– welche impliziten Typumwandlungen?
– explizite Typumwandlungen (cast)?
• arithmetische (von Zahlen nach Zahl)
• relationale (von Zahlen nach Wahrheitswert)
• dynamische Semantik
• boolesche (von Wahrheitswerten nach Wahrheitsw.)
– Ausdrücke dürfen (Neben-)Wirkungen haben?
– in welcher Reihenfolge treten die auf?
– Typeset by FoilTEX –
Wdhlg: Syntaxbaum, Präzedenz, Assoziativität.
Id
– Typeset by FoilTEX –
Syntax von Konstanten
Id
Der Plus-Operator in Java
Was druckt diese Anweisung?
System.out.println ( 12345 + 5432l );
. . . addiert Zahlen und verkettet Strings.
System.out.println ("foo" + 3 + 4);
System.out.println (3 + 4 + "bar");
dieses und einige der folgenden Beispiele aus: Joshua
Bloch, Neil Gafter: Java Puzzlers, Addison-Wesley, 2005.
– Typeset by FoilTEX –
Id
Id
– Typeset by FoilTEX –
Id
Automatische Typanpassungen
Überladene Operatornamen
aus praktischen Gründen sind arithmetische und
relationale Operatornamen überladen
(d. h.: ein Name für mehrere Bedeutungen)
Überladung wird aufgelöst durch die Typen der Argumente.
int x = 3; int y = 4; ... x + y ...
double a;
double b; ... a + b ...
String p;
String q; ... p + q ...
• in vielen Sprachen postuliert man eine Hierarchie von
Zahlbereichstypen:
byte ⊆ int ⊆ float ⊆ double
im allgemeinen ist das eine Halbordnung.
• Operator mit Argumenten verschiedener Typen:
(x :: int) + (y :: float)
beide Argumente werden zu kleinstem gemeinsamen
Obertyp promoviert, falls dieser eindeutig ist (sonst
statischer Typfehler)
(Halbordnung → Halbverband)
• (das ist die richtige Benutzung von promovieren)
– Typeset by FoilTEX –
Id
– Typeset by FoilTEX –
Id
Explizite Typumwandlungen
Implizite/Explizite Typumwandlungen
Was druckt dieses Programm?
long x = 1000 * 1000 * 1000 * 1000;
long y = 1000 * 1000;
System.out.println ( x / y );
Was druckt dieses Programm?
System.out.println ((int) (char) (byte) -1);
Moral: wenn man nicht auf den ersten Blick sieht, was ein
Programm macht, dann macht es wahrscheinlich nicht das,
was man will.
sieht gleich aus und heißt gleich (cast), hat aber
verschiedene Bedeutungen:
• Datum soll in anderen Typ gewandelt werden,
Repräsentation ändert sich:
double x = (double) 2 / (double) 3;
• Programmierer weiß es besser (als der Compiler),
Repräsentation ändert sich nicht:
List books;
Book b = (Book) books.get (7);
. . . kommt nur vor, wenn man die falsche
Programmiersprache benutzt (nämlich Java vor 1.5)
– Typeset by FoilTEX –
Id
Typ-Umwandlungen in Javascript
Der Verzweigungs-Operator
Id
– Typeset by FoilTEX –
Verzweigungs-Operator(II)
Id
Relationale Operatoren
(... ? ... : ... ) in C, C++, Java
Anwendung im Ziel einer Zuweisung (C++):
int main () {
int a = 4; int b = 5; int c = 6;
( c < 7 ? a : b ) = 8;
}
– Typeset by FoilTEX –
Id
Absicht: statt
lieber
if ( 0 == x % 2 ) {
x = if ( 0 == x % 2 ) {
x = x / 2;
x / 2
} else {
} else {
x = 3 * x + 1;
3 * x + 1
}
} ;
historische Notation dafür
x = ( 0 == x % 2 ) ? x / 2 : 3 * x + 1;
?/: ist ternärer Operator
Gary Bernhardt: WAT (2012)
https:
//www.destroyallsoftware.com/talks/wat
– Typeset by FoilTEX –
– Typeset by FoilTEX –
kleiner, größer, gleich,. . .
Was tut dieses Programm (C? Java?)
int a = -4; int b = -3; int c = -2;
if (a < b < c) {
printf ("aufsteigend");
}
Id
– Typeset by FoilTEX –
Logische (Boolesche) Ausdrücke
Id
Noch mehr Quizfragen
• und &&, || oder, nicht ! Negation
• System.out.println ("H" + "a");
System.out.println (’H’ + ’a’);
• nicht verwechseln mit Bit-Operationen &, |
• char x = ’X’; int i = 0;
System.out.print (true ? x : 0);
System.out.print (false ? i : x);
(in C gefährlich, in Java ungefährlich—warum?)
• verkürzte Auswertung?
Erklären durch Verweis auf Java Language Spec.
int [] a = ...; int k = ...;
if ( k >= 0 && a[k] > 7 ) { ... }
(Ü: wie sieht das in Ada aus?)
• Ü: welche relationalen Operatoren sind in Java für
boolean überladen?
– Typeset by FoilTEX –
Id
– Typeset by FoilTEX –
Id
Weitere Formen der Zuweisung
Der Zuweisungs-Operator
Syntax:
(in C-ähnlichen Sprachen)
• Algol, Pascal: Zuweisung :=, Vergleich =
• verkürzte Zuweisung: a += b
entsprechend für andere binäre Operatoren
• Fortran, C, Java: Zuweisung =, Vergleich ==
Semantik der Zuweisung a = b:
Ausdrücke links und rechts werden verschieden behandelt:
• bestimme Adresse (lvalue) p von a
• Inkrement/Dekrement
• bestimme Wert (rvalue) v von b
– Präfix-Version ++i, --j: Wert ist der geänderte
– Suffix-Version i++, j--: Wert ist der vorherige
• schreibe v auf p
– Typeset by FoilTEX –
– lvalue p von a wird bestimmt (nur einmal)
– rvalue v von b wird bestimmt
– Wert auf Adresse p wird um v erhöht
Id
– Typeset by FoilTEX –
Ausdrücke mit Nebenwirkungen
Id
Auswertungsreihenfolgen
(side effect; falsche Übersetzung: Seiteneffekt)
• in C-ähnlichen Sprachen: Zuweisungs-Operatoren bilden
Ausdrücke, d. h. Zuweisungen sind Ausdrücke und
können als Teile von Ausdrücken vorkommen.
• Wert einer Zuweisung ist der zugewiesene Wert
Kritisch: wenn Wert des Ausdrucks von
Auswertungsreihenfolge abhängt:
int a; int b = (a = 5) + (a = 6);
int d = 3; int e = (d++) - (++d);
int x = 3; int y = ++x + ++x + ++x;
• keine Nebenwirkungen: egal
int a; int b; a = b = 5; // wie geklammert? • mit Nebenwirkungen:
– C, C++: Reihenfolge nicht spezifiziert, wenn Wert davon
abhängt, dann ist Verhalten nicht definiert
– Java, C#: Reihenfolge genau spezifiziert (siehe JLS)
• Komma-Operator zur Verkettung von Ausdrücken (mit
Nebenwirkungen)
for (... ; ... ; i++,j--) { ... }
– Typeset by FoilTEX –
Id
– Typeset by FoilTEX –
Id
Auswertungsreihenfolge in C
Sprachstandard (C99, C++) benutzt Begriff sequence point
(Meilenstein): bei Komma, Fragezeichen, && und ||
die Nebenwirkungen zwischen Meilensteinen müssen
unabhängig sein (nicht die gleiche Speicherstelle
betreffen),
ansonsten ist das Verhalten undefiniert, d.h., der Compiler
darf beliebigen Code erzeugen, z.B. solchen, der die
Festplatte löscht oder Cthulhu heraufbeschwört. vgl.
Aussagen zu sequence points in
und
Gurevich, Huggins: Semantics of C, http://citeseerx.
http://gcc.gnu.org/readings.html
ist.psu.edu/viewdoc/summary?doi=10.1.1.29.6755
– Typeset by FoilTEX –
Id
– Typeset by FoilTEX –
Id
– Typeset by FoilTEX –
Id
– Typeset by FoilTEX –
Id
Anweisungen(I)
Programm-Ablauf-Steuerung
• Ausführen eines Programms im von-Neumann-Modell:
– Was? (Operation)
– Womit? (Operanden)
– Wohin? (Resultat)
– Wie weiter? (nächste Anweisung)
• Ablaufsteuerung durch strukturierte Programmierung:
– Nacheinander
– Verzweigung
– Wiederholung
– außer der Reihe (Sprung, Unterprogramm, Exception)
Definition
Semantik: Ausführen einer Anweisung bewirkt
Zustandsänderung
abstrakte Syntax:
• einfache Anweisung:
– Zuweisung
– leere Anweisung, break, continue, return, throw
– Unterprogramm-Aufruf
• zusammengesetzte Anweisung:
– Nacheinanderausführung (Block)
– Verzweigung (zweifach: if, mehrfach: switch)
– Wiederholung (Sprung, Schleife)
– Typeset by FoilTEX –
engl. control flow, falsche Übersetzung: Kontrollfluß;
to control = steuern, to check = kontrollieren/prüfen
Id
– Typeset by FoilTEX –
Id
Verzweigungen (zweifach)
Blöcke
Folge von (Deklarationen und) Anweisungen
Designfrage: Blöcke
in den meisten Sprachen:
if Bedingung then Anweisung1
[ else Anweisung2 ]
Designfragen:
• explizit (Klammern, begin/end)
• implizit (if . . . then . . . end if)
Designfrage/historische Entwicklung: Deklarationen . . .
• was ist als Bedingung gestattet (gibt es einen Typ für
Wahrheitswerte?)
• am Beginn des Programms (Maschinenp., COBOL,
Fortran)
• dangling else
– gelöst durch Festlegung (else gehört zu letztem if)
– vermieden durch Block-Bildung (Perl, Ada)
– tritt nicht auf, weil man else nie weglassen darf (vgl. ?/:)
(Haskell)
• am Beginn jedes Unter-Programms (Pascal)
• am Beginn jedes Blocks (C)
• an jeder Stelle jedes Blocks (C++, Java)
– Typeset by FoilTEX –
Id
– Typeset by FoilTEX –
Mehrfach-Verzweigung
Syntax:
switch (e) {
case c1 : s1 ;
case c2 : s2 ;
[ default : sn; ]
•
•
•
•
•
switch/break
Semantik
if (e == c1) s1
else if (e == c2) s2
... else sn
}
Bezeichnung: der Ausdruck e heißt Diskriminante
Vorsicht! Das ist nicht die Semantik in C(++), Java.
welche Typen für e? (z.B.: Aufzählungstypen)
Wertebereiche? (case c1 .. c2 : ...)
was passiert, wenn mehrere Fälle zutreffen?
(z.B.: statisch verhindert dadurch, daß ci verschiedene
Literale sein müssen)
– Typeset by FoilTEX –
switch (index) {
case 1 : odd ++;
case 2 : even ++;
default :
printf ("wrong index %d\n", index);
}
• Semantik in C, C++, Java ist nicht führe den zum Wert
”
der Diskriminante passenden Zweig aus“
• sondern . . . passenden Zweig aus sowie alle danach
”
folgenden Zweige“.
• C#: jeder Zweig muß mit break oder goto enden.
Id
– Typeset by FoilTEX –
Kompilation
Id
Pattern Matching
ein switch (mit vielen cases) wird übersetzt in:
• Fallunterscheidung nach dem Konstruktor
• (naiv) eine lineare Folge von binären Verzweigungen (if,
elsif)
• Bindung von lokalen Namen
abstract class Term
// Scala
case class Constant (value : Int)
extends Term
case class Plus (left: Term, right : Term)
extends Term
def eval(t: Term): Int = {
t match {
case Constant(v) => v
case Plus(l, r) => eval(l) + eval(r)
} }
• (semi-clever) einen balancierter Baum von binären
Verzweigungen
• (clever) eine Sprungtabelle
Übung:
• einen langen Switch (1000 Fälle) erzeugen (durch ein
Programm!)
• Assembler/Bytecode anschauen
– Typeset by FoilTEX –
Id
Id
– Typeset by FoilTEX –
Id
Wiederholungen
Schleifen steuern durch. . .
• Zähler
• Maschine, Assembler: (un-)bedingter Sprung
for p in 1 .. 10 loop .. end loop;
• strukturiert: Schleifen
• Daten
Designfragen für Schleifen:
map (\x -> x*x) [1,2,3] ==> [1,4,9]
Collection<String> c
= new LinkedList<String> ();
for (String s : c) { ... }
• wie wird Schleife gesteuert? (Bedingung, Zähler, Daten,
Zustand)
• an welcher Stelle in der Schleife findet Steuerung statt
(Anfang, Ende, dazwischen, evtl. mehreres)
• Bedingung
while ( x > 0 ) { if ( ... ) { x = ... } ... }
• Zustand (Iterator, hasNext, next)
– Typeset by FoilTEX –
Id
– Typeset by FoilTEX –
Id
Termination
Zählschleifen
Idee: vor Beginn steht Anzahl der Durchläufe fest.
Satz: Jedes Programm aus
richtig realisiert ist das nur in Ada:
for p in 1 .. 10 loop ... end loop;
• Zuweisungen
• Zähler p wird implizit deklariert
• Zählschleifen
• Verzweigungen
terminiert (hält) für jede Eingabe.
• Zähler ist im Schleifenkörper konstant
Äquivalenter Begriff (für Bäume anstatt Zahlen):
strukturelle Induktion (fold, Visitor, primitive Rekursion)
Vergleiche (beide Punkte) mit Java, C++, C
Satz: es gibt berechenbare Funktionen, die nicht primitiv
rekursiv sind.
Beispiel: Interpreter für primitiv rekursive Programme.
– Typeset by FoilTEX –
Id
Datengesteuerte Schleifen
Id
Zustandsgesteuerte Schleifen
Idee: führe für jeden Konstruktor eines algebraischen
Datentyps (Liste, Baum) eine Rechnung/Aktion aus.
foreach, Parallel.Foreach,...
– Typeset by FoilTEX –
– Typeset by FoilTEX –
So:
interface Iterator<T> {
boolean hasNext(); T next (); }
interface Iterable<T> {
Iterator<T> iterator(); }
for (T x : ...) { ... }
Oder so:
public interface IEnumerator<T> : IEnumerator {
bool MoveNext(); T Current { get; } }
interface IEnumerable<out T> : IEnumerable {
IEnumerator<T> GetEnumerator() }
foreach (T x in ...) { ... }
(sieben Unterschiede . . . )
Id
– Typeset by FoilTEX –
Implizite Iteratoren in C#
Id
Schleifen mit Bedingungen
using System.Collections.Generic;
das ist die allgemeinste Form, ergibt (partielle) rekursive
public class it {
Funktionen, die terminieren nicht notwendig für alle
public static IEnumerable<int> Data () { Argumente.
yield return 3;
Steuerung
yield return 1;
• am Anfang: while (Bedingung) Anweisung
yield return 4;
}
• am Ende: do Anweisung while (Bedingung)
public static void Main () {
Weitere Änderung des Ablaufes:
foreach (int i in Data()) {
System.Console.WriteLine (i);
• vorzeitiger Abbruch (break)
}
}
}
• vorzeitige Wiederholung (continue)
• beides auch nicht lokal
– Typeset by FoilTEX –
Id
– Typeset by FoilTEX –
Id
vorzeitiges Verlassen
Abarbeitung von Schleifen
operationale Semantik durch Sprünge:
while (B) A;
==>
start : if (!B) goto end;
A;
goto start;
end
: skip;
(das ist auch die Notation der autotool-Aufgabe)
• . . . der Schleife
while ( B1 ) {
A1;
if ( B2 ) break;
A2;
}
• . . . des Schleifenkörpers
while ( B1 ) {
A1;
if ( B2 ) continue;
A2;
}
Ü: do A while (B);
– Typeset by FoilTEX –
Id
– Typeset by FoilTEX –
Geschachtelte Schleifen
Id
Sprünge
manche Sprachen gestatten Markierungen (Labels) an
Schleifen, auf die man sich in break beziehen kann:
foo : for (int i = ...) {
bar : for (int j = ...) {
• bedingte, unbedingte (mit bekanntem Ziel)
– Maschinensprachen, Assembler, Java-Bytecode
– Fortran, Basic: if Bedingung then Zeilennummer
– Fortran: dreifach-Verzweigung (arithmetic-if)
if (...) break foo;
• “computed goto” (Zeilennr. des Sprungziels ausrechnen)
}
}
Wie könnte man das simulieren?
– Typeset by FoilTEX –
Id
Sprünge und Schleifen
• und jedes goto-Programm in ein while-Programm . . .
• . . . das normalerweise besser zu verstehen ist.
• strukturierte Programmierung = jeder Programmbaustein
hat genau einen Eingang und genau einen Ausgang
• aber: vorzeitiges Verlassen von Schleifen
• aber: Ausnahmen (Exceptions)
Id
Satz: zu jedem goto-Programm gibt es ein äquivalentes
while-Programm.
Beweis-Idee: 1 : A1, 2 : A2; .. 5: goto 7; ..
⇒
while (true) {
switch (pc) {
case 1 : A1 ; pc++ ; break; ...
case 5 : pc = 7 ; break; ...
}
}
Das nützt aber softwaretechnisch wenig, das übersetzte
Programm ist genauso schwer zu warten wie das Original.
– Typeset by FoilTEX –
Id
Was ist hier los?
Schleifen und Unterprogramme
zu jedem while-Programm kann man ein äquivalentes
angeben, das nur Verzweigungen (if) und Unterprogramme
benutzt.
Beweis-Idee: while (B) A; ⇒
void s () {
if (B) { A; s (); }
}
Anwendung: C-Programme ohne Schlüsselwörter.
– Typeset by FoilTEX –
Id
Sprünge und Schleifen (Beweis)
• man kann jedes while-Programm in ein goto-Programm
übersetzen
– Typeset by FoilTEX –
– Typeset by FoilTEX –
Id
class What {
public static void main (String [] args) {
System.out.println ("mozilla:open");
http://haskell.org
System.out.println ("mozilla:close");
}
}
– Typeset by FoilTEX –
Id
Denotationale Semantik (I)
Denotationale Semantik (II)
Semantik des Programms P ist Menge der Spuren von P .
vereinfachtes Modell, damit Eigenschaften entscheidbar
werden (sind die Programme P1, P2 äquivalent?)
Syntax: Programme
• Spur = eine Folge von Paaren von Zustand und Aktion,
• ein Zustand ist eine Belegung der Prädikatsymbole,
• jede Aktion zerstört alle Zustandsinformation.
• Aktionen,
Satz: Diese Spursprachen (von goto- und
while-Programmen) sind regulär.
Beweis: Konstruktion über endlichen Automaten.
• Zustandsprädikate (in Tests)
• Sequenz/Block, if, goto/while.
Beispiel:
while (B && !C) { P; if (C) Q; }
• Zustandsmenge = Prädikatbelegungen ×
Anweisungs-Nummer
• Transitionen? (Beispiele)
Damit ist Spur-Äquivalenz von Programmen entscheidbar.
Beziehung zu tatsächlicher Äquivalenz?
– Typeset by FoilTEX –
Id
Unterprogramme
Parameter-Übergabe (Semantik)
• Ein Unterprogramm ist ein Block mit einer Schnittstelle.
• Funktion: liefert Wert, Aufruf ist Ausdruck
Prozedur: liefert keinen Wert, Aufruf ist Anweisung
(benannt oder anonym = Lambda-Ausdruck)
• Schnittstelle beschreibt Datentransport zwischen Aufrufer
und Unterprogramm.
• zu Schnittstelle gehören
• in: (Argumente) vom Aufrufer zum Aufgerufenen
• out: (Resultate) vom Aufgerufenen zum Aufrufer
• in out: in beide Richtungen
– Deklarat. d. formalen Parameter (Name, Typ, Modus)
– bei Funktionen: Deklaration des Resultattyps
Id
– Typeset by FoilTEX –
Id
Parameterübergabe
Parameter-Übergabe (Implementierungen)
häufig benutzte Implementierungen:
• pass-by-value (Wert)
• Pascal: by-value (default) oder by-reference (VAR)
• copy in/copy out (Wert)
• C: immer by-value (Verweise ggf. selbst herstellen)
• C++ by-value oder by-reference (durch &)
void p(int & x) { x++; } int y = 3; p(y);
• pass-by-reference (Verweis)
d.h. der formale Parameter im Unterprogramm
bezeichnet die gleiche Speicherstelle
wie das Argument beim Aufrufer
(Argument-Ausdruck muß lvalue besitzen)
• Java: immer by-value
(beachte implizite Zeiger bei Verweistypen)
• C#: by-value (beachte implizite Zeiger bei Verweistypen,
class, jedoch nicht bei struct)
oder by-reference (mit Schlüsselwort ref)
• pass-by-name (textuelle Substitution)
selten . . . Algol68, CPP-Macros . . . Vorsicht!
– Typeset by FoilTEX –
Id
Datenaustausch zw. Aufrufer (caller) und Aufgerufenem
(callee): über globalen Speicher
#include <errno.h>
extern int errno;
oder über Parameter.
Datentransport (entspr. Schüsselwörtern in Ada)
Grundsätzliches
– Typeset by FoilTEX –
– Typeset by FoilTEX –
• Scala: by-value oder by-name (Scala Lang Spec 6.6)
Id
– Typeset by FoilTEX –
Call-by-value, call-by-reference (C#)
Id
Call-by-name
by value:
formaler Parameter wird durch Argument-Ausdruck ersetzt.
static void u (int x) { x = x + 1; }
Algol(68): Jensen’s device
int y = 3 ; u (y);
int sum (int i, int n; int f) {
Console.WriteLine(y); // 3
int s = 0;
by reference:
for (i=0; i<n; i++) { s += f; }
static void u (ref int x) { x = x + 1; }
return s;
int y = 3 ; u (ref y);
}
Console.WriteLine(y); // 4
int [10][10] a; int k; sum (k, 10, a[k][k]);
Übung: ref/kein ref; struct (Werttyp)/class (Verweistyp)
moderne Lösung
class C { public int foo }
int sum (int n; Func<int,int> f) {
static void u (ref C x) { x.foo=4; x=new C{foo=5};}
... { s += f (i); }
C y = new C {foo=3} ; C z = y; u (ref y);
}
Console.WriteLine(y.foo + " " + z.foo);
int [10][10] a; sum (10, (int k) => a[k][k]);
– Typeset by FoilTEX –
Id
– Typeset by FoilTEX –
Id
Call-by-name (Macros)
Call-by-name in Scala
#define thrice(x) 3*x // gefährlich
thrice (4+y) ==> 3*4+y
“the need for a preprocessor shows omissions in the
language”
• fehlendes Modulsystem (Header-Includes)
• fehlende generische Polymorphie (⇒ Templates in C+)
weitere Argumente:
• mangelndes Vertrauen in optimierende Compiler (inlining)
• bedingte Übersetzung
Ü: was kann der Präprozessor in C# und was nicht?
Warum? (Wo ist der C#-Standard?
Parameter-Typ ist => T, entspr. eine Aktion, die ein T
”
liefert“(in Haskell: IO T)
call-by-name
def F(b:Boolean,x: =>Int):Int =
{ if (b) x*x else 0 }
F(false,{print ("foo "); 3})
//
res5: Int = 0
F(true,{print ("foo "); 3})
//
foo foo res6: Int = 9
Man benötigt call-by-name zur Definition von Abstraktionen
über den Programmablauf.
Übung: If, While als Scala-Unterprogramm
http://stackoverflow.com/questions/13467103)
– Typeset by FoilTEX –
Id
Bedarfsauswertung
• [ error "foo" , 42 ] !! 0
[ error "foo" , 42 ] !! 1
length [ error "foo" , 42 ]
let xs = "bar" : xs
take 5 xs
• Definition: das Argument wird bei seiner ersten
Benutzung ausgewertet
• wenn es nicht benutzt wird, dann nicht ausgewertet;
wenn mehrfach benutzt, dann nur einmal ausgewertet
• Fibonacci-Folge
• das ist der Standard-Auswertungsmodus in Haskell:
alle Funktionen und Konstruktoren sind lazy
fib :: [ Integer ]
fib = 0 : 1 : zipWith (+) fib ( tail fib )
da es keine Nebenwirkungen gibt, bemerkt man das
zunächst nicht . . .
• Primzahlen (Sieb des Eratosthenes)
. . . und kann es ausnutzen beim Rechnen mit
unendlichen Datenstrukturen (Streams)
• Papier-Falt-Folge
Id
Id
Bedarfsauswertung für eine lokale Konstante
(Schlüsselwort lazy)
def F(b:Boolean,x: =>Int):Int =
{ lazy val y = x; if (b) y*y else 0 }
F(true,{print ("foo "); 3})
//
foo res8: Int = 9
F(false,{print ("foo "); 3})
//
res9: Int = 0
vgl. http:
//mathworld.wolfram.com/DragonCurve.html
Id
Argumente/Parameter
– Typeset by FoilTEX –
Id
Positionelle/benannte Argumente
Üblich ist Zuordnung über Position
void p (int height, String name) { ... }
p (8, "foo");
in Ada: Zuordnung über Namen möglich
procedure Paint (height : Float; width : Float);
Paint (width => 30, height => 40);
nach erstem benannten Argument keine positionellen mehr
erlaubt
• in der Deklaration benutzte Namen heißen (formale)
Parameter,
• bei Aufruf benutzte Ausdrücke heißen Argumente
(. . . nicht: aktuelle Parameter, denn engl. actual = dt.
tatsächlich)
Designfragen bei Parameterzuordnung:
• über Position oder Namen? gemischt?
code smell: lange Parameterliste,
refactoring: Parameterobjekt einführen
allerdings fehlt (in Java) benannte Notation für
Record-Konstanten.
• defaults für fehlende Argumente?
• beliebig lange Argumentlisten?
– Typeset by FoilTEX –
– Typeset by FoilTEX –
Beispiele f. Bedarfsauswertung (Scala)
let merge (x:xs) ys = x : merge ys xs
let updown = 0 : 1 : updown
let paper = merge updown paper
take 15 paper
– Typeset by FoilTEX –
Id
Beispiele f. Bedarfsauswertung (Haskell)
• andere Namen: (call-by-need, lazy evaluation)
– Typeset by FoilTEX –
– Typeset by FoilTEX –
Id
– Typeset by FoilTEX –
Id
Default-Werte
Variable Argumentanzahl (C)
C++:
void p (int x, int y, int z = 8);
p (3, 4, 5); p (3, 4);
Default-Parameter müssen in Deklaration am Ende der
Liste stehen
wieso geht das eigentlich:
#include <stdio.h>
char * fmt = really_complicated();
printf (fmt, x, y, z);
Anzahl und Typ der weiteren Argumente werden überhaupt
nicht geprüft:
Ada:
extern int printf
procedure P
(X : Integer; Y : Integer := 8; Z : Integer); (__const char *__restrict __format, ...);
P (4, Z => 7);
Beim Aufruf nach weggelassenem Argument nur noch
benannte Notation
– Typeset by FoilTEX –
Id
– Typeset by FoilTEX –
Variable Argumentanzahl (Java)
Id
Aufgaben zu Parameter-Modi (I)
static void check (String x, int ... ys) {
Erklären Sie den Unterschied zwischen (Ada)
for (int y : ys) { System.out.println (y); }
with Ada.Text_IO; use Ada.Text_IO;
}
procedure Check is
procedure Sub (X: in out Integer;
check ("foo",1,2); check ("bar",1,2,3,4);
Y: in out Integer;
letzter formaler Parameter kann für beliebig viele des
Z: in out Integer) is
gleichen Typs stehen.
begin
tatsächlich gilt int [] ys,
Y := 8; Z := X;
end;
das ergibt leider Probleme bei generischen Typen
Foo: Integer := 9;
Bar: Integer := 7;
begin
Sub (Foo,Foo,Bar);
Put_Line (Integer’Image(Foo));
– Typeset by FoilTEX –
Id
Put_Line (Integer’Image(Bar));
end Check;
(in Datei Check.adb schreiben, kompilieren mit
gnatmake Check.adb)
und (C++)
#include <iostream>
– Typeset by FoilTEX –
Id
int bar = 7;
sub (foo,foo,bar);
std::cout << foo << std::endl;
std::cout << bar << std::endl;
}
void sub (int & x, int & y, int & z) {
y = 8;
z = x;
}
int main () {
int foo = 9;
– Typeset by FoilTEX –
Id
– Typeset by FoilTEX –
Id
Id
– Typeset by FoilTEX –
Id
Aufgaben zu Parameter-Modi (II)
Durch welchen Aufruf kann man diese beiden
Unterprogramme semantisch voneinander unterscheiden:
Funktion (C++): (call by reference)
void swap (int & x, int & y)
{ int h = x; x = y; y = h; }
Makro (C): (call by name)
#define swap(x, y) \
{ int h = x; x = y; y = h; }
Kann man jedes der beiden von copy-in/copy-out
unterscheiden?
– Typeset by FoilTEX –
Weiters zu Unterprogrammen
UP und Sichtbarkeit von Namen
{ const x = 3;
function step(y) { return x + y; }
for (const z of [ 1,2,4 ]) {
console.log(step(z+1)); } }
Lokale Unterprogramme
• Unterprogramme sind wichtiges Mittel zur Abstraktion,
das möchte man überall einsetzen
• was ist die Ausgabe dieses Programms?
• also sind auch lokale Unterprogramme wünschenswert
• was ändert sich bei Umbenennung von z zu x?
(die Konzepte Block (mit lokalen Deklarationen) und
Unterprogramm sollen orthogonal sein)
• Antwort: nichts! — der Funktionskörper (x+y)
wird in seiner Definitionsumgebung ausgewertet,
nicht in seiner Aufruf-Umgebung.
int f (int x) {
int g (int y) { return y + 1; }
return g (g (x));
}
– Typeset by FoilTEX –
vgl. Spezifikation: https:
//tc39.github.io/ecma262/#sec-lexical-environments,
https://www.ecma-international.org/ecma-262/7.0/
Id
– Typeset by FoilTEX –
Frames, Ketten, Indizes
Lokale Unterprogramme: Beispiel
Während ein Unterprogramm rechnet, stehen seine lokalen
Daten in einem Aktivationsverbund (Frame).
with Ada.Text_Io; use Ada.Text_Io;
procedure Nested is
function F (X: Integer; Y: Integer)
return Integer is
function G (Y: Integer) return Integer is
begin
if (Y > 0) then return 1 + G(Y-1);
else return X; end if;
end G;
begin return G (Y); end F;
begin
Put_Line (Integer’Image (F(3,2)));
end Nested;
• Jeder Frame hat zwei Vorgänger:
– dynamischer Vorgänger:
(Frame des aufrufenden UP) benutzt zum Rückkehren
– statischer Vorgänger
(Frame des textuell umgebenden UP)
benutzt zum Zugriff auf “fremde” lokale Variablen
• Jeder Variablenzugriff hat Index-Paar (i, j):
im i-ten statischen Vorgänger der Eintrag Nr. j
lokale Variablen des aktuellen UP: Index (0, j)
Indizes werden statisch bestimmt, Frames zur Laufzeit.
– Typeset by FoilTEX –
Id
Flache Unterprogramme (C)
Id
Lokale Unterprogramme in C# und Java
Entwurfs-Entscheidung für C:
• in funktionalen Programmiersprachen
• jedes Unterprogramm ist global
(LISP, ML, Haskell, JavaScript)
Folgerung:
(function(f){return f(f(0))})
(function(x){return x+1})
• leichte Implementierung:
• C#, Java 8
– dynamischer Vorgänger = der vorige Frame (auf dem
Stack)
– statischer Vorgänger: gibt es nicht
int x = 3; Func<int,int> f = y => x + y;
Console.WriteLine (f(4));
• softwaretechnische Nachteile:
int x = 3; Function<Integer,Integer> f = y -> x + y;
System.out.println (f.apply(4));
globale Abstraktionen machen Programm
unübersichtlich.
– Typeset by FoilTEX –
– Typeset by FoilTEX –
Id
Id
– Typeset by FoilTEX –
Id
Unterprogramme als Argumente
Unterprogramme als Resultate
static int d ( Func<int,int> g ) {
return g(g(1));
}
static int p (int x) {
Func<int,int> f = y => x + y;
return d (f);
}
Betrachte Aufruf p(3).
Das innere Unterprogramm f muß auf den p-Frame
zugreifen, um den richtigen Wert des x zu finden.
Dazu Closure konstruieren: f mit statischem Vorgänger.
Wenn Unterprogramme als Argumente übergeben werden,
steht der statische Vorgänger im Stack.
(ansonsten muß man den Vorgänger-Frame auf andere
Weise retten, siehe später)
static int x = 3;
static Func<int,int> s (int y) {
return z => x + y + z;
}
static void Main () {
Func<int,int> p = s(4);
Console.WriteLine (p(3));
}
Wenn die von s(4) konstruierte Funktion p aufgerufen wird,
dann wird der s-Frame benötigt, steht aber nicht mehr im
Stack.
⇒ Die (Frames in den) Closures müssen im Heap verwaltet
werden.
– Typeset by FoilTEX –
– Typeset by FoilTEX –
Id
Id
Lokale anonyme Unterprogramme
Lokale Klassen (Java)
• static nested class: dient lediglich zur Gruppierung
• int [] x = { 1,0,0,1,0 };
Console.WriteLine
(x.Aggregate (0, (a, b) => 2*a + b));
http://code.msdn.microsoft.com/
LINQ-Aggregate-Operators-c51b3869
• foldl ( \ a b -> 2*a + b) 0 [1,0,0,1,0]
Haskell (http://haskell.org/)
class C { static class D { .. } .. }
• nested inner class:
class C { class D { .. } .. }
historische Schreibweise: λab.2a + b
(Alonzo Church: The Calculi of Lambda Conversion, 1941)
vgl. Henk Barendregt: The Impact of the Lambda Calculus,
1997, ftp:
//ftp.cs.ru.nl/pub/CompMath.Found/church.ps
– Typeset by FoilTEX –
Id
Lokale Funktionen in Java 8
jedes D-Objekt hat einen Verweis auf ein C-Objekt (≈
statische Kette) (bezeichnet durch C.this)
• local inner class: ( Zugriff auf lokale Variablen in m nur,
wenn diese final sind. Warum? )
class C { void m () { class D { .. } .. } }
– Typeset by FoilTEX –
Id
Unterprogramme/Zusammenfassung
in prozeduralen Sprachen:
interface Function<T,R> { R apply(T t); }
bisher (Java ≤ 7):
Function<Integer,Integer> f =
new Function<Integer,Integer> () {
public Integer apply (Integer x) {
return x*x;
} } ;
System.out.println (f.apply(4));
jetzt (Java 8): verkürzte Notation (Lambda-Ausdruck) für
Implementierung funktionaler Interfaces
Function<Integer,Integer> g = x -> x*x;
System.out.println (g.apply(4));
Anwendung u.a. in java.util.stream.Stream<T>
• falls alle UP global: dynamische Kette reicht
• lokale UP: benötigt auch statische Kette
• lokale UP as Daten: benötigt Closures
= (Code, statischer Link)
• UP als Argumente: Closures auf Stack
• UP als Resultate: Closures im Heap
in objektorientierten Sprachen: ähnliche Überlegungen bei
lokalen (inner, nested) Klassen.
– Typeset by FoilTEX –
Id
– Typeset by FoilTEX –
Id
– Typeset by FoilTEX –
Id
– Typeset by FoilTEX –
Id
Auswertung der Umfragen
http://www.imn.htwk-leipzig.de/˜waldmann/
edu/ws16/pps/umf/
– Typeset by FoilTEX –
Id
– Typeset by FoilTEX –
Id
Polymorphie
Ad-Hoc-Polymorphie
• ein Bezeichner ist überladen, wenn er mehrere
(gleichzeitig sichtbare) Deklarationen hat
Übersicht
poly-morph = viel-gestaltig; ein Bezeichner (z. B.
Unterprogramm-Name) mit mehreren Bedeutungen
Arten der Polymorphie:
• bei jeder Benutzung des Bezeichners wird die
Überladung dadurch aufgelöst, daß die Deklaration mit
dem jeweils (ad-hoc) passenden Typ ausgewählt wird
• statische P.
(Bedeutung wird zur Übersetzungszeit festgelegt):
Beispiel: Überladung im Argumenttyp:
static void p (int x, int
y) {
static void p (int x, String y) {
p (3, 4); p (3, "foo");
keine Überladung nur in Resultattyp, denn. . .
static int
f (boolean b) { ...
static String f (boolean b) { ...
– ad-hoc: Überladen von Bezeichnern
– generisch: Bezeichner mit Typ-Parametern
• dynamische P. (Bedeutung wird zur Laufzeit festgelegt):
– Implementieren (Überschreiben) von Methoden
– Typeset by FoilTEX –
Id
Typhierarchie als Halbordnung
Id
• bestimme die Menge P der zum Aufruf passenden
Methoden
(für diese gilt: statischer Typ der Argumente ≤n statischer
Typ der formalen Parameter)
• bestimme die Menge M der minimalen Elemente von P
(Def: m ist minimal falls ¬∃p ∈ P : p < m)
• M muß eine Einermenge sein, sonst ist Überladung nicht
auflösbar
Id
Generische Polymorphie
– Typeset by FoilTEX –
Id
Bsp: Generische Methode in C#
parametrische Polymorphie:
class C {
static T id<T> (T x) { return x; }
}
beachte Position(en) von
• Klassen und Methoden können Typ-Parameter erhalten.
• innerhalb der Implementierung der Klasse/Methode wird
der formale Typ-Parameter als (unbekannter) Typ
behandelt
• Deklaration des Typparameters
• Benutzungen des Typparameters
• bei der Benutzung der Klasse/Methode müssen alle
Typ-Argumente angegeben werden
string foo = C.id<string> ("foo");
int
bar = C.id<int>
(42);
(oder der Compiler inferiert diese in einigen Fällen)
• Instanziierung des Typparameters
• separate Kompilation (auch von generischen Klassen)
mit statischer Typprüfung
Id
Bsp: Generische Klasse in Java
– Typeset by FoilTEX –
Id
Bsp: Generische Methode in Java
class Pair<A,B> {
final A first; final B second;
Pair(A a, B b)
{ this.first = a; this.second = b; }
}
Pair<String,Integer> p =
new Pair<String,Integer>("foo", 42);
int x = p.second + 3;
vor allem für Container-Typen (Liste, Menge, Keller,
Schlange, Baum, . . . )
– Typeset by FoilTEX –
– Typeset by FoilTEX –
Ad-Hoc-Polymorphie und Typhierarchie
dadurch entsteht Halbordnung auf Methoden-Signaturen
(Tupel der Argument-Typen, ohne Resultat-Typ)
Bsp: Relation ≤2 auf T 2:
(t1, t2) ≤2 (t01, t02) : ⇐⇒ t1 ≤ t01 ∧ t2 ≤ t02
es gilt (D, D) ≤2 (C, C); (D, D) ≤2 (C, D);
(C, D) ≤2 (C, C); (E, C) ≤2 (C, C).
– Typeset by FoilTEX –
}
}
Auflösung von p (new D(), new D()) bzgl.
static void p (C x, D y);
static void p (C x, C y);
static void p (E x, C y);
Durch extends/implements entsteht Halbordnung auf
Typen, Bsp.
class C;class D extends C;class E extends C
definiert Relation
(≤) = {(C, C), (D, C), (D, D), (E, C), (E, E)}
auf T = {C, D, E}
– Typeset by FoilTEX –
... }
... }
• Deklaration des Typparameters
• Benutzungen des Typparameters
class C {
static <A,B> Pair<B,A> swap (Pair<A,B> p) {
return new Pair<B,A>(p.second, p.first); } }
• Benutzungen des Typparameters
Pair<String,Integer> p =
new Pair<String,Integer>("foo", 42);
Pair<Integer,String> q =
C.<String,Integer>swap(p);
Typargumente können auch inferiert werden:
Pair<Integer,String> q = C.swap(p);
Id
– Typeset by FoilTEX –
Id
Dynamische Polymorphie
(Objektorientierung)
Objekte, Methoden
Motivation: Objekt = Daten + Verhalten.
Einfachste Implementierung:
Übersicht
• Objekt ist Record,
poly-morph = viel-gestaltig; ein Bezeichner (z. B.
Unterprogramm-Name) mit mehreren Bedeutungen
Arten der Polymorphie:
• einige Komponenten sind Unterprogramme.
typedef struct {
int x; int y; // Daten
void (*print) (FILE *fp); // Verhalten
} point;
point *p; ... ; (*(p->print))(stdout);
Anwendung: Datei-Objekte in UNIX (seit 1970)
(Merksatz 1: all the world is a file) (Merksatz 2: those who
do not know UNIX are doomed to re-invent it, poorly)
• statische P.
(Bedeutung wird zur Übersetzungszeit festgelegt):
– ad-hoc: Überladen von Bezeichnern
– generisch: Bezeichner mit Typ-Parametern
• dynamische P. (Bedeutung wird zur Laufzeit festgelegt):
– Implementieren (Überschreiben) von Methoden
– Typeset by FoilTEX –
Id
– Typeset by FoilTEX –
Id
Objektbasierte Sprachen (JavaScript)
Klassenbasierte Sprachen
(d. h. objektorientiert, aber ohne Klassen)
Objekte, Attribute, Methoden:
var o = { a : 3,
m : function (x) { return x + this.a; } };
Vererbung zwischen Objekten:
var p = { __proto__ : o };
Attribut (/Methode) im Objekt nicht gefunden ⇒
weitersuchen im Prototyp ⇒ . . . Prototyp des Prototyps . . .
Übung: Überschreiben
p.m = function (x) { return x + 2*this.a }
var q = { __proto__ : p }
q.a = 4
alert (q.m(5))
gemeinsame Datenform und Verhalten von Objekten
typedef struct { int (*method[5])(); } cls;
typedef struct {
cls * c;
} obj;
obj *o; ... (*(o->c->method[3]))();
allgemein: Klasse:
– Typeset by FoilTEX –
– Typeset by FoilTEX –
Id
• Deklaration von Daten (Attributen)
• Deklaration und Implementierung von Methoden
Objekt:
• tatsächliche Daten (Attribute)
• Verweis auf Klasse (Methodentabelle)
this
Klassen in ECMA-Script
Motivation: Methode soll wissen, für welches Argument sie
gerufen wurde
typedef struct { int (*method[5])(obj *o);
} cls;
typedef struct {
int data [3]; // Daten des Objekts
cls *c; // Zeiger auf Klasse
} obj;
obj *o; ... (*(o->c->method[3]))(o);
int sum (obj *this) {
return this->data[0] + this->data[1]; }
jede Methode bekommt this als erstes Argument
(in Java, C# geschieht das implizit)
– Typeset by FoilTEX –
Id
Id
Vererbung
• syntaktische Hilfen zur Notation der
objekt(prototyp)-basierten Vererbung,
seit Version 6 (2015)
• class C {
constructor(x) { this.x=x }
m (y) { return this.x + y } }
let p = new C(8)
p.m(3)
• Definition siehe
https://www.ecma-international.org/
ecma-262/7.0/#sec-class-definitions
– Typeset by FoilTEX –
Id
Dynamische Polymorphie (Beispiel)
Def: Klasse D ist abgeleitet von Klasses C:
• D kann Menge der Attribute- und Methodendeklarationen
von C erweitern (aber nicht verkleinern oder ändern)
• D kann Implementierungen von in C deklarierten
Methoden übernehmen oder eigene festlegen
(überschreiben).
Anwendung: dynamische Polymorphie
• Wo ein Objekt der Basisklasse erwartet wird (der
statische Typ eines Bezeichners ist C),
class C {
int x = 2; int p () { return this.x + 3; }
}
C x = new C() ; int y = x.p ();
Überschreiben:
class E extends C {
int p () { return this.x + 4; }
}
C x =
// statischer Typ: C
new E() ; // dynamischer Typ: E
int y = x.p ();
• kann ein Objekt einer abgeleiteten Klasse (D) benutzt
werden (der dynamische Typ des Wertes ist D).
– Typeset by FoilTEX –
Id
– Typeset by FoilTEX –
Id
Vererbung bricht Kapselung
Überschreiben und Überladen
class C {
void p () { ... q(); ... };
void q () { .. };
}
Jetzt wird q überschrieben (evtl. auch unabsichtlich—in
Java), dadurch ändert sich das Verhalten von p.
class D extends C {
void q () { ... }
}
Korrektheit von D abhängig von Implementierung von C
⇒ object-orientation is, by its very nature, anti-modular . . .
http://existentialtype.wordpress.com/2011/
03/15/teaching-fp-to-freshmen/
– Typeset by FoilTEX –
• Überschreiben:
zwei Klassen, je eine Methode mit gleichem Typ
• Überladen:
eine Klasse, mehrere Methoden mit versch. Typen
• C++: Methoden, die man überschrieben darf, virtual
deklarieren
• C#: Überschreiben durch override angezeigen,
• Java: alle Methoden sind virtual, deswegen ist
Überschreiben von Überladen schlecht zu unterscheiden:
Quelle von Programmierfehlern
• Java-IDEs unterstützen Annotation @overrides
Id
Equals richtig implementieren
– Typeset by FoilTEX –
Id
Equals richtig implementieren (II)
class C {
. . . sondern so:
final int x; final int y;
public boolean equals (Object o) {
C (int x, int y) { this.x = x; this.y = y; } if (! (o instanceof C)) return false;
int hashCode () { return this.x + 31 * this.y;C }that = (C) o;
}
return this.x == that.x && this.y == that.y;
}
nicht so:
Die Methode boolean equals(Object o) wird aus
public boolean equals (C that) {
HashSet aufgerufen.
return this.x == that.x && this.y == that.y;
}
Sie muß deswegen überschrieben werden.
Das boolean equals (C that) hat den
Methodenamen nur überladen.
– Typeset by FoilTEX –
Id
– Typeset by FoilTEX –
Id
Mehr zu Polymorphie
Statische Attribute und Methoden
für diese findet kein dynamischer Dispatch statt.
(Beispiele—Puzzle 48, 54)
Damit das klar ist, wird dieser Schreibstil empfohlen:
Generische Fkt. höherer Ordg.
• Ziele:
– Flexibilität (nachnutzbarer Code)
– statische Typsicherheit
– Effizienz (Laufzeit)
• dynamisch: immer mit Objektnamen qualifiziert, auch
wenn dieser this lautet,
• statisch: immer mit Klassennamen qualifiziert (niemals
mit Objektnamen)
• wichtige Anwendung: Abstraktionen über den
Programmablauf, z.B. für parallele Ausführung, Bsp:
public static TAccumulate Aggregate<TSource, TAccumulate>(
this ParallelQuery<TSource> source,
TAccumulate seed,
Func<TAccumulate,TSource,TAccumulate> func )
– Typeset by FoilTEX –
Id
Bsp. Generische Fkt. höherer Ordg. (I)
– Typeset by FoilTEX –
Id
Bsp. Generische Fkt. höherer Ordg. (II)
Sortieren mit Vergleichsfunktion als Parameter
using System; class Bubble {
static void Sort<T>
(Func<T,T,bool> Less, T [] a) { ...
if (Less (a[j+1],a[j])) { ... } }
public static void Main (string [] argv) {
int [] a = { 4,1,2,3 };
Sort<int> ((int x, int y) => x <= y, a);
foreach (var x in a) Console.Write (x);
} }
Ü: (allgemeinster) Typ und Implementierung einer Funktion
Flip, die den Vergleich umkehrt:
Sort<int> (Flip( (x,y)=> x <= y ), a)
bulk operations“ auf Collections, z.B.
”
• Bibliothek https://hackage.haskell.org/package/
– Typeset by FoilTEX –
– Typeset by FoilTEX –
Id
containers-0.5.9.1/docs/Data-Map-Strict.html
• Beispiel:
intersectionWith
:: Ord k
=> (a -> b -> c)
-> Map k a -> Map k b -> Map k c
• ist effizienter als Iteration über alle Elemente eines
Arguments
Id
Vererbung und generische Polym.
Generics und Subtypen
• mit Sprachkonzepte Vererbung ist Erweiterung des
Sprachkonzeptes Generizität wünschenswert:
Warum geht das nicht:
class C { }
• beim Definition der Passung von parametrischen Typen
sollte die Vererbungsrelation ≤ auf Typen berücksichtigt
werden.
class E extends C { void m () { } }
List<E> x = new LinkedList<E>();
• Ansatz: wenn E ≤ C, dann auch List<E> ≤ List<C>
List<C> y = x; // Typfehler
Antwort: wenn das erlaubt wäre, dann:
• ist nicht typsicher, siehe folgendes Beispiel
• Modifikation: ko- und kontravariante Typparameter
– Typeset by FoilTEX –
Id
Obere Schranken für Typparameter
• Java: <S super T>
C#: class <T> where T : S { ... }
als Argument ist jeder Typ T erlaubt, der S implementiert
Als Argument ist jeder Typ S erlaubt, der Obertyp von T
ist.
static <T> int binarySearch
(List<? extends T> list, T key,
Comparator<? super T> c)
Comparable<T>
compareTo(T x); }
extends Comparable<T>>
(Collection<T> c) { .. }
– Typeset by FoilTEX –
Id
Untere Schranken für Typparameter
• Java: class<T extends S> { ... },
interface
{ int
static <T
T max
– Typeset by FoilTEX –
Id
variante generische Interfaces (C#)
– Typeset by FoilTEX –
Id
Vergleich: Varianz und Schranken
Kontravarianz (in P), Kovarianz (out P)
Unterscheidung:
interface I<in P> { // kontravariante Dekl.
• bei Schranken geht es um die Instantiierung
// P get (); kovariante Benutzung (verboten)
void set (P x); // kontravariante Benutzung (die Wahl der Typargumente)
}
• bei Varianz um den erzeugten Typ
class K<P> : I<P> { public void set (P x) {} }
(seine Zuweisungskompatibilität)
class C {} class E : C {} // E <= C
I<C> x = new K<C>();
I<E> y = x; // erlaubt, I<C> <= I<E>
• kontravariant: E ≤ C ⇒ I(E) ≥ I(C)
• kovariant: E ≤ C ⇒ I(E) ≤ I(C)
• invariant: E 6= C ⇒ I(E) 6≤ I(C)
– Typeset by FoilTEX –
Id
– Typeset by FoilTEX –
Generics und Arrays
Id
Übung Polymorphie
das gibt keinen Typfehler:
• Aufgabe zu Funktion Flip (C#),
class C { }
Quelltext: http://www.imn.htwk-leipzig.de/
class E extends C { void m () { } }
˜waldmann/edu/ws16/pps/code/kw55/
E [] x = { new E (), new E () }; C [] y = x;
y [0] = new C (); x [0].m();
• binarySearch aufrufen (Java), so daß beide ? von T
warum ist die Typprüfung für Arrays schwächer als für
verschieden sind
Collections?
Historische Gründe. Das sollte gehen:
void fill (Object[] a, Object x) { .. }
String [] a = new String [3];
fill (a, "foo");
Das sieht aber mit Generics besser so aus: . . .
– Typeset by FoilTEX –
Id
– Typeset by FoilTEX –
Id
Ergänzungen
Statische Typisierung: für und wider
Für statische Typisierung spricht vieles.
Es funktioniert auch seit Jahrtzehnten (Algol 1960, ML
1970, C++ 1980, Java 1990 usw.)
Was dagegen?
Statisch typisiert ⇒ sicher und effizient
• Programmtext soll Absicht des Programmierers
ausdrücken.
• dazu gehören Annahmen über Daten,
formuliert mittels Typen (foo::Book)
. . . alternative Formulierung:
Namen (fooBook, Kommentar foo // Book)
• nur durch statische Typisierung kann man
Absichten/Annahmen maschinell umfassend prüfen
. . . alternative Prüfung: Tests
• ist nützlich für Wiederverwendbarkeit
• ist nützlich für sichere und effiziente Ausführung
– Typeset by FoilTEX –
• Typsystem ist ausdrucksschwach:
(Bsp: keine polymorphen Container in C)
Programmierer kann Absicht nicht ausdrücken
• Typsystem ist ausdrucksstark:
(Bsp: kontravariante Typargumente in Java,C#)
Programmierer muß Sprachstandard lesen und verstehen
und dazu Konzepte (z.B. aus Vorlesung) kennen
Id
– Typeset by FoilTEX –
Id
wichtige“ falsche“ Sprachen: JS
”
”
Fachmännisches Programmieren
ECMA-Script (Javascript)
semantisch ist das LISP (z.B. Funktionen als Daten),
syntaktisch ist es Java
• Hardware: wer Flugzeug/Brücke/Staudamm/. . . baut,
kann (und darf) das auch nicht allein nach etwas
Selbststudium und mit Werkzeug aus dem Baumarkt
• Software: der (Bastel-)Prototyp wird oft zum Produkt,
der Bastler zum selbsternannten Programmierer
• Motivation: Software soll beim Kunden laufen
• technisches Problem: Kunde versteht/beherrscht seinen
Computer/Betriebssystem nicht
(z.B. kann oder will keine JRE)
so auch bei Programmiersprachen:
entworfen von oder für Leute ohne (viel) Fachwissen
• BASIC (1964) (Kemeny, Kurtz) to enable students in
fields other than science and math. to use computers
• Perl (1987) (Larry Wall: Chemie, Musik, Linguistik)
• PHP (1994) (Rasmus Lerdorf) Personal Home Page Tools
(like Perl but . . . simpler, more limited, less consistent.)
• stattdessen zwingt man Kunden zu Flash-Plugin oder
– Typeset by FoilTEX –
– Typeset by FoilTEX –
Id
wichtige“ falsche“ Sprachen: PHP
”
”
• Browser mit Javascript-Engine (der Browser ist das OS)
• das steckt z.B. Google viel Geld hinein:
https://code.google.com/p/v8/
aus verständlichen Gründen (Anzeige von Werbung)
Id
Aktuelle Entwicklungen: JS
• Facebook ist in PHP implementiert
. . . was ist mit Microsoft? Die haben auch viel Geld und
clevere Leute? — Ja:
• deswegen steckt Facebook viel Geld in diese Sprache
• ECMA-Script 6 übernimmt viele Konzepte moderner
(funktionaler) Programmierung, u.a.
– let (block scope), const (single assignment)
– desctructuring (pattern matching)
– tail calls (ohne Stack)
https://github.com/lukehoban/es6features
aus ebenfalls verständlichen Gründen :
– für Kunden: Reaktionszeit der Webseite
– für Betreiber: Entwicklungs- und Betriebskosten
• http://www.typescriptlang.org/
TypeScript adds optional types, classes, and modules to
JavaScript.
Personen: Luke Hoban, Anders Hejlsberg, Erik Meijer, . . .
– Typeset by FoilTEX –
Id
Aktuelle Entwicklungen: PHP
– Typeset by FoilTEX –
Die Zukunft: Typen für Ressourcen
https://www.rust-lang.org/
. . . a systems programming language that . . . prevents
segfaults and guarantees thread safety.
• HHVM: Hip Hop Virtual Machine
https://github.com/facebook/hhvm/blob/master/hphp/
doc/bytecode.specification
• jedes Datum hat genau einen Eigentümer,
• Hack http://hacklang.org/ Type Annotations,
Generics, Nullable types, Collections, Lambdas, . . .
man kann Daten übernehmen und ausborgen,
Julien Verlaguet: Facebook: Analyzing PHP statically,
2013, http://cufp.org/2013/
• statisch garantiert: für jedes Datum x:T gibt es
html
– one or more references (&T) to a resource,
– exactly one mutable reference (&mut T).
vgl. Neil Savage: Gradual Evolution, Communications of the
ACM, Vol. 57 No. 10, Pages 16-18, http://cacm.acm.org/
https://doc.rust-lang.org/book/
references-and-borrowing.html#the-rules
julien-verlaguet-facebook-analyzing-php-statically.
magazines/2014/10/178775-gradual-evolution/fulltext
– Typeset by FoilTEX –
Id
Id
– Typeset by FoilTEX –
Id
Die Zukunft: Datenabhängige Typen
Nicht reguläre Typen
https://idris-lang.org/ . . . aspects of a program’s
behaviour can be specified precisely in the type.
• ein rekursiver polymorpher Typ heißt regulär, wenn die
Typ-Argumente bei Rekursion gleich bleiben
• elementare Bausteine:
– Daten: 42, "foo", (x,y)=>x+y, Typen: bool, int
data List a = Nil | Cons a (List a),
• Kombinationen (Funktionen):
– Datum → Datum, Bsp. (x,y)=>x+y
– Typ → Typ, Bsp. List<T>
– Typ → Datum, Bsp. Collections.<String>sort()
– Datum → Type, (data-)dependent type, Bsp. Vektoren
data Vec : Nat -> Type -> Type
(++) : Vec p a -> Vec q a -> Vec (p+q) a
head : Vect (S p) a -> a
-- S = Nachfolger
– Typeset by FoilTEX –
Id
Zusammenfassung
. . . sonst nicht regulär
• data List a b = Nil | Cons a (List b a)
• data Tree a = Leaf a | Branch (Tree (a,a))
• Anwendung: Implementierung von
containers:Data.Sequence https://hackage.
haskell.org/package/containers-0.5.9.1/
docs/Data-Sequence.html#t:Seq
– Typeset by FoilTEX –
Id
Wie weiter? (LV)
Anwendung und Vertiefung von Themen PPS z.B. in VL
Themen
• Methoden zur Beschreibung der
– Syntax: reguläre Ausdrücke, kontextfreie Grammatiken
– Semantik: operational, denotational, axiomatisch
• Konzepte:
– Typen,
– Namen (Deklarationen), Blöcke (Sichtbarkeitsbereiche)
– Ausdrücke und Anweisungen (Wert und Wirkung),
– Unterprogramme (als Daten)
– Polymorphie (statisch, dynamisch)
• Wechselwirkungen der Konzepte
• Paradigmen: imperativ, funktional, objektorientert
• Programmverifikation
u.a. axiomatische Semantik imperativer Programme
• Compilerbau
– Realisierung der Semantik durch
∗ Interpretation
∗ Transformation
– abstrakte und konkrete Syntax (Parser)
• Constraint-Programmierung
• Fortgeschrittene Konzepte von Programmiersprachen
(OS)
• Symbolisches Rechnen (Transform. v. Syntaxbäumen)
– Typeset by FoilTEX –
– Typeset by FoilTEX –
Sprachen kommen und gehen, Konzepte bleiben.
Id
Wie weiter? (Masterprojekt/Arbeit, WHK)
Id
dafür Vertrag als wiss. Hilfskraft möglich
• Allgemeines und Aktuelles: http://www.imn.
htwk-leipzig.de/˜waldmann/edu/diplom/
• Termersetzung/Symbolisches Rechnen,
• Constraint-Programmierung
• E-Learning, insb. Reparatur/Erweiterung autotool,
insbesondere
– (Big) Data-Analyse und -Visualisierung
https://gitlab.imn.htwk-leipzig.de/
autotool/all0/issues/327
– Aufgaben zur Kryptologie https://gitlab.imn.
htwk-leipzig.de/autotool/all0/issues/366
– Typeset by FoilTEX –
Id
– Typeset by FoilTEX –
Id
http://cacm.acm.org/blogs/blog-cacm/
176450-python-is-now-the-most-popular-introductory
fulltext
Aktuelles/Übung
• Vortrag am Montag, dem 6. Februar:
https:
//portal.imn.htwk-leipzig.de/termine/
constraint-basierte-techniken-in-der-automatisierten-programmanalyse
• zur Diskussion der Lehre der Programmierung:
– E. W. Dijkstra über Haskell und Java (2001): http://
chrisdone.com/posts/dijkstra-haskell-java
vgl. auch EWD 1035
https://www.cs.utexas.edu/users/EWD/
transcriptions/EWD13xx/EWD1305.html
– Philip Guo (CACM, 2014)
– Typeset by FoilTEX –
Id
– Typeset by FoilTEX –
Id
– Typeset by FoilTEX –
Id
– Typeset by FoilTEX –
Id
Testfragen
Die folgende Grammatik G über dem Alphabet
Σ = {w, f, u, i} soll Ausdrücke mit den Konstanten w, f und
den binären Operatoren u, i beschreiben:
G = (Σ, {E}, {E → w | f | EiE | EuE}, E).
Begründen Sie, daß G mehrdeutig ist.
Punkte: 3
Gesucht ist eine zu G äquivalente eindeutige kontextfreie
Grammatik G0, für deren Ableitungsbäume gilt: der
Operator u ist linksassoziativ, der Operator i ist
– Typeset by FoilTEX –
Id
rechtsassoziativ, der Operator u bindet stärker als der
Operator i.
Wie sieht unter diesen Bedingungen der abstrakte
Syntaxbaum für f iwuf iw aus?
– Typeset by FoilTEX –
Id
w | f }, E).
Punkte: 3
• G3 = (Σ, {E, A, B}, {E → B | BuE, B → A | BiA, A →
w | f }, E).
Untersuchen Sie, ob G1, G2, G3 die gewünschten
Eigenschaften erfüllen. (Falls nein: begründen, falls ja:
konkreten Syntaxbaum für f iwuf iw angeben.)
Punkte: 8
• Welches ist die Bedeutung der Aussageform {V }P {N }
im Hoare-Kalkül?
Punkte: 9
• G1 = (Σ, {E, A}, {E → A | AiE | EuA, A → w | f }, E).
Geben Sie eine wahre und eine falsche Aussage dieser
Form an.
• G2 = (Σ, {E, A, B}, {E → B | BiE, B → A | BuA, A →
– Typeset by FoilTEX –
Id
Id
falsch (bzw. wahr ).
• Wodurch wird eine kontextfreie Grammatik zu einer
Attributgrammatik erweitert?
Nach welcher Regel bestimmt man, ob ein Ausdruck f(x)
korrekt getypt ist? (Ohne Berücksichtigung von Vererbung
oder Generizität.)
• Geben Sie einen regulären Ausdruck für die Spursprache
dieses Programms an.
while (P) { A; if (Q) { B; } C; }
Das Spur-Alphabet ist {A, B, C, P0, P1, Q0, Q1}, dabei
bedeuten
A : die Anweisung A wird ausgeführt,
P0 (bzw. P1): der Ausdruck P wird ausgewertet und ergibt
– Typeset by FoilTEX –
– Typeset by FoilTEX –
Id
• Wenn f den Typ . . .
• und x den Typ . . .
hat
hat,
• dann ist der Typ von f(x) . . .
.
Wie werden die folgenden Operationen für Typen in
Programmiersprachen realisiert?
Punkte: 6
• Vereinigung:
• Kreuzprodukt:
– Typeset by FoilTEX –
Punkte: 4
Id
• Potenz (vier verschiedene Realisierungen)
procedure Main is
X : Integer := 3; Y : Integer := 2;
procedure P (X : Integer) is
procedure Q (Y : Integer) is
procedure R (X : Integer) is
begin Put_Line (Integer’Image (X+Y)); end R
begin if Y > 0 then P(X-1); else R(X+Y); end i
begin if X > 0 then Q(X-1); else P(X-Y); end if;
begin P (X-1); end Main;
Zeichnen
Punkte:
2 Sie die Frames mit allen Einträgen und
Verweisen zu dem Zeitpunkt direkt vor dem ersten Aufruf
von Put_Line.
Punkte: 1
–
–
–
–
In Java gibt es keine direkte Realisierung der Vereinigung,
was wird stattdessen empfohlen?
Für das Ada-Programm:
with Ada.Text_Io; use Ada.Text_Io;
– Typeset by FoilTEX –
Id
– Typeset by FoilTEX –
Id
betrachten wir den Aufruf p(a[0], a[1]).
Geben Sie die Ausführungsschritte sowie die resultierende
Speicherbelegung an, falls zur Parameterübergabe benutzt
wird:
Punkte: 1
• Wertübergabe
Wie wird auf die Werte von X und Y zugegriffen, die in
Integer’Image(X+Y) benötigt werden?
Für folgende Deklaration:
Punkte: 2
VerweisÜbergabe
int a [] = { 1,2,0 }; void p (int x, int y) { •a[y]
= x;
x = y; }
– Typeset by FoilTEX –
Id
– Typeset by FoilTEX –
Id
• p (new C(), new C());
Für die Deklarationen:
class C { }
class D extends C { }
static void p (Object x, C
y) { System.out.println ("1"); }
static void p (D
x, C
y) { System.out.println ("2"); }
static void p (C
x, Object y) { System.out.println ("3"); }
Beschreiben Sie, wie die Überladung für die folgenden
Aufrufe aufgelöst wird:
Punkte: 7
• p (new D(), new D());
– Typeset by FoilTEX –
Id
– Typeset by FoilTEX –
Id
Herunterladen