Informatik II - Institute of Computer Science, Göttingen

Werbung
6. Sprachen, Compiler und Theorie
Literatur (1/3)
Bücher
Michael L. Scott : „Programming Language Pragmatics”, MKP 2000,
ISBN 1-55860-578-9
http://www.cs.rochester.edu/u/scott/pragmatics/
Uwe Schöning: „Theoretische Informatik kurzgefaßt“, 2001, ISBN
3827410991
Rechenberg & Pomberger: „Informatik-Handbuch“, Hanser Verlag, ISBN
3-446-21842-4
Drachenbuch
Informatik II
SS 2004
Teil 6: Sprachen, Compiler und Theorie
1 - Einführung und Übersicht
Alfred V. Aho, Ravi Sethi, Jeffrey D. Ullman:
„Compilers - Principles, Techniques and Tools“.
Addison-Wesley 1988, ISBN 0-201-10088-6
Alfred V. Aho, Ravi Sethi, Jeffrey D. Ullman: „Compilerbau.“
Oldenbourg Verlag 1999, Teil 1: ISBN 3-486-25294-1, Teil 2: ISBN 3-48625266-6
Wikipedia:
http://en.wikipedia.org/wiki/Compilers:_Principles,_Techniques_and_Tools
Prof. Dr. Dieter Hogrefe
Dipl.-Inform. Michael Ebner
Lehrstuhl für Telematik
Institut für Informatik
Einführung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6. Sprachen, Compiler und Theorie
6.1-2
6. Sprachen, Compiler und Theorie
Literatur (2/3)
Literatur (3/3)
Skripte
Bücher
Klassiker der Automatentheorie von Hopcroft/Ullman/Motwani
Hopcroft, Motwani, Ullman : „Introduction to Automata Theory, Languages,
and Computation“, 2001, http://www-db.stanford.edu/~ullman/ialc.html
Hopcroft, Motwani, Ullman: „Einführung in die Automatentheorie, Formale
Sprachen und Komplexitätstheorie“, Pearson Studium 2002, ISBN
3827370205
Asteroth, Baier: „Theoretische Informatik: Eine Einführung in
Berechenbarkeit, Komplexität und formale Sprachen mit 101
Beispielen“, Pearson Studium 2002, ISBN 3-8273-7033-7
(insbesondere für Nebenfächler geeignet, da kaum
Mathematikkenntnisse vorausgesetzt werden.)
Compilerbau-Skript von Prof. Dr. Goltz, Universität Braunschweig
http://www.cs.tu-bs.de/ips/ss04/cb/skript_cp.ps.gz
Informatik-Skripte von Prof. Dr. Waack, Universität Göttingen
http://www.num.math.uni-goettingen.de/waack/lehrmaterial/
Folien
Informatik II - SS2003 Folien dienen als Grundlage und wurden
übersetzt und ev. teilweise ergänzt. Es wird aber auch komplett neue
Teile geben!!!
http://user.informatik.uni-goettingen.de/~info2/SS2003/
Übersetzerbau I – Prof. Dr. Goos, Universität Karlsruhe
http://www.info.uni-karlsruhe.de/lehre/2003WS/uebau1/
WWW: Wikipedia
http://en.wikipedia.org/wiki/Compilers:_Principles,_Techniques_and_To
ols
http://de.wikipedia.org/wiki/Compiler
Erfahrungsberichte von Studentenseite sind erwünscht
Einführung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.1-3
Einführung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.1-4
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Weitere Quellen
Einführung
Katalog von Konstruktionswerkzeugen für Compiler
http://www.first.gmd.de/cogent/catalog/
Inhalte
Grundlegende Konzepte von Programmiersprachen
Organisation von Compilern für moderne Programmiersprachen
Einführung in die Theorie von formalen Sprachen und Automaten
ANTLR, ANother Tool for Language Recognition: http:/www.antlr.org
Konferenzen und Journale
ACM Transactions on Programming Languages and Systems
ACM SIGPLAN Conference on Programming Language Design and
Implementation
ACM SIGPLAN Conference on Programming Language Principles
Als Grundlage dient das Buch “Programming Language Pragmatics”
von Michael L. Smith
Einführung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.1-5
6. Sprachen, Compiler und Theorie
Einführung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.1-6
6. Sprachen, Compiler und Theorie
Abstraktionen...
Sprachen als Abstraktion
Die menschliche Sprache ist ein Werkzeug für die Abstraktion von
Gedanken
Eliminiere Details welche unnötig zum Lösen eines speziellen
Problems sind
„Wenn es mir warm ist, dann schalte ich den Ventilator ein.“
Komplexität wird versteckt
Eine einfache Absicht wird mitgeteilt, wobei aber die kognitiven und
neurologischen Bedingungen, durch welche die Absicht aufkam, höchst
wahrscheinlich für jeden zu komplex sind um sie zu Verstehen
Die Bedeutung dieser Aussage ist dem Verständnis des Individuums
welches es äußert und den Individuen die es hören überlassen
Baue oft auf anderen auf
Erlaubt das Lösen von zunehmend komplexeren Problemen
(teile und herrsche, divide and conquer)
Komplexität moderner Software ist ohne Beispiel (Präzedenzfall)
Programmiersprachen sind ein Werkzeug zum Abstrahieren von
Berechnungen
Abstraktion ist ein grundlegender Bestandteil zum Handhaben von
diesen komplexen Problemen
if (temperatur() > 30.0) { schalte_ventilator_ein(); }
Abstraktion
Abstraktum
Digitale Logik
Computerarchitektur
Assemblersprache
Betriebssystem
Computerkommunikation
Transistoren
Digitale Logik
Maschinensprache
Allokation von Ressourcen (Zeit, Speicher, etc.)
(Physikalische) Netzwerke, Protokolle
Beinhaltet eine komplexe aber konkrete Sequenz von Aktionen:
Einführung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.1-7
lese Thermostat; konvertiere den Ablesewert zu einer IEEE Fliesskomazahl nach
der Celsiusskala; Vergleiche den Wert mit 30.0; wenn größer dann sende ein
Signal an eine PCI Karte, welche ein Signal an ein Relais sendet, welches den
Ventilator einschaltet
Die Bedeutung dieses Ausdrucks ist festgelegt durch die formale Semantik
der Programmiersprache und der Implementierung der Funktionen
temperatur() und schalte_ventilator_ein().
Einführung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.1-8
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Wie abstrahieren Programmiersprachen Berechnungen? (1/4)
Biete eine Notation für den Ausdruck von Algorithmen welche
2.
Verberge unterliegende (systemnahe) Details der Zielarchitektur
Befehlsnamen der Assemblersprache, Registernamen,
Argumentordnung, etc.
Abbildung von Sprachelementen auf die Assemblersprache
Arithmetische Ausdrücke,
Bedingungen,
Konventionen für Prozeduraufrufe, etc.
wie der Algorithmus in einer Maschinensprache implementiert wird,
wie Hilfsalgorithmen, z.B. Hash-Tabellen, Listen, implementiert werden,
es dem Programmierer erlaubt seine eigene Abstraktion
(Unterprogramme, Module, Bibliotheken, Klassen, etc.) zu bauen um
die Weiterführung des Konzepts „Komplexitätsmanagement durch
Schichtenbildung“ zu ermöglichen.
if (a < b + 10) {
do_1();
} else {
do_2();
}
RC
SPA
MI
P
.L1:
.L2:
add
cmp
bge
call
ba
call
…
%l1,10,%l2
%l0,%l2
.L1; nop
do_1; nop
.L2; nop
do_2; nop
L1:
L2:
addi
bge
call
b
call
…
$t2,$t1,10
$t0,$t2,L1
do_1
L2
do_2
S
Einführung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.1-9
6. Sprachen, Compiler und Theorie
Einführung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
Wie abstrahieren Programmiersprachen Berechnungen? (4/4)
Biete Grundbefehle (primitives), Unterprogramme und
Laufzeitunterstützung für übliche (lästige) Programmierpflichten
Biete Merkmale welche eine besondere Art von Algorithmus oder
Softwareentwicklung unterstützen (encourage) oder durchsetzen
(enforce)
Lesen und schreiben von Dateien
Handhabung von Zeichenfolgen (Vergleiche, Erkennung von
Teilzeichenfolge, etc.)
Dynamische Allokation von Speicher (new, malloc, etc.)
Rückgewinnung von unbenutztem Speicher (garbage collection)
Sortieren
etc.
Strukturiertes Programmieren
Unterprogramme
Verschachtelte (Nested ???)
Variablenbereiche ( scopes??)
Schleifen
Beschränkte Formen des „goto“
Befehls (statement??)
Einführung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.1-10
6. Sprachen, Compiler und Theorie
Wie abstrahieren Programmiersprachen Berechnungen? (3/4)
3.
SPARC
(meistens) unabhängig von der Maschine ist auf welcher der
Algorithmus ausgeführt wird,
Fähigkeiten (features) auf höchster Ebene bietet und die
Aufmerksamkeit des Programmierers mehr auf den Algorithmus
fokussiert und weniger auf
MIPS
1.
Wie abstrahieren Programmiersprachen Berechnungen? (2/4)
6.1-11
Objekt-Orientierte Programmierung
Klassen
Vererbung
Polymorphismus
Einführung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.1-12
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Kategorien von Programmiersprachen
Imperative Sprachen (1/2)
Alle Sprachen fallen in eine der beiden folgenden Kategorien:
Die von Neumann Sprachen
Imperative Sprachen erfordern die schrittweise Beschreibung durch
Programmierer wie ein Algorithmus seine Aufgabe erledigen soll.
Analogie aus der realen Welt: „Ein Rezept ist eine Art von imperativem
Programm, welches einem Koch sagt wie ein Gericht zuzubereiten ist.“
Deklarative Sprachen erlauben die Beschreibung durch
Programmierer was ein Algorithmus erledigen soll ohne exakt zu
beschreiben wie es getan werden soll.
schließen Fortran, Pascal, Basic und C ein
stellen eine Reflektion der von Neumann Computerarchitektur dar, auf
welcher die Programme laufen
Führen Befehle aus welche den Zustand des Programms
(Variablen/Speicher) ändern
Manchmal auch Berechnung durch Seiteneffekte genannt
Analogie aus der realen Welt: „Das Pfandgesetz ist ein deklaratives
Programm welches Einzelhändlern mitteilt das sie ein Recyclingprogramm
für Einwegflaschen und Dosen des eigenen Sortiments aufstellen müssen,
ohne exakt mitzuteilen wie dies zu erfolgen hat.
Beispiel: Aufsummieren der ersten n Ganzzahlen in C
for(sum=0,i=1;i<=n;i++) { sum += i; }
Einführung
Einführung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.1-13
6. Sprachen, Compiler und Theorie
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6. Sprachen, Compiler und Theorie
Imperative Sprachen (2/2)
Deklarative Sprachen (1/2)
Die objekt-orientierten Sprachen
Die funktionalen Sprachen
schließen Smalltalk, Eiffel, C++, Java und Sather ein
Sind ähnlich der von Neumann Sprachen mit der Erweiterung von
Objekten
Objekte
enthalten ihren eigenen internen Zustand (Klassenvariablen, member
variables) und Funktionen welche auf diesem Zustand operieren
(Methoden)
Berechnung ist organisiert als Interaktion zwischen Objekten (ein Objekt ruft
die Methoden eines anderen Objektes auf)
Die meisten objekt-orientierten Sprachen bieten Konstrukte (facilities)
basierend auf Objekten welche objekt-orientierte Programmierung
fördern
Kapselung (encapsulation), Vererbung (inheritance) und Polymorphismus
(polymorphism)
Wir werden uns darüber später genauer unterhalten
schließen Lisp/Scheme, ML, Haskell (Gofer) ein
Sind eine Reflektion von Church‘s Theorie der rekursiven Funktionen
(lambda calculus)
Berechnung werden ausgeführt als Rückgabewerte von Funktionen
basierend auf der (möglicherweise rekursiven) evaluation von anderen
Funktionen
Mechanismus ist als Reduktion bekannt
Keine Seiteneffekte
Erlaubt gleichungsbasiertes Problemlösen (equational reasoning),
einfachere formale Beweise von Programmkorrektheit, etc.
Beispiel: Aufsummieren der ersten n Ganzzahlen in SML
fun sum (n) = if n <= 1 then n else n + sum(n-1)
Einführung
Einführung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.1-14
6.1-15
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.1-16
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Deklarative Sprachen (2/2)
Eine historische Perspektive: Maschinensprachen
Die logischen Sprachen
schließen Prolog, SQL und Microsoft Excel/OpenOffice OpenCalc ein
Sind eine Reflektion von der Theorie der Aussagenlogik
(propositional logic)
Berechnung ist ein Versuch einen Wert zu finden welcher eine Menge
von logischen Beziehungen erfüllt
Die ersten Maschinen wurden direkt in einer Maschinensprache
oder Maschinencode programmiert
Langweilig, aber Maschinenzeit war teurer als Programmiererzeit
Der meist verwendete Mechanismus um diesen Wert zu finden ist bekannt
als Resolution (resolution) und Vereinheitlichung (unification)
Beispiel: Aufsummieren der ersten n Ganzzahlen in Prolog
sum(1,1).
sum(N,S) :-
N1 is N-1, sum(N1,S1), S is S1+N.
MIPS Maschinencode für ein Programm zum
Berechnen des GGT von zwei Ganzzahlen
Einführung
Einführung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.1-17
6. Sprachen, Compiler und Theorie
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.1-18
6. Sprachen, Compiler und Theorie
Eine historische Perspektive: Assemblersprachen (1/2)
Eine historische Perspektive: Assemblersprachen (2/2)
Programme wurden immer Komplexer
Beispiel:
zu schwierig, zeitintensiv und teuer um Programme in Maschinencode
zu schreiben
Assemblersprachen wurden entwickelt
Für den Menschen lesbar ☺
Ursprünglich wurde eine eins-zu-eins Beziehung zwischen Instruktionen
der Maschinensprache und Instruktionen der Assemblersprache
bereitgestellt
Schließlich wurden „makro“ Einrichtungen hinzugefügt um
Softwareentwicklung durch anbieten von primitiven Formen von CodeWiederverwendung weiter zu beschleunigen
Der Assembler war das Programm welches ein Assemblerprogramm in
Maschinencode übersetzte mit welchem die Maschine laufen konnte
Assembler
Einführung
Einführung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.1-19
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.1-20
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Eine historische Perspektive: höhere Sprachen (1/2)
Eine historische Perspektive: höhere Sprachen (2/2)
Programme wurden immer Komplexer
Beispiel:
es war zu schwierig, zeitintensiv und teuer um Programme in Assemblersprache
zu schreiben
es war zu schwierig von einer Maschine zu einer anderen zu wechseln, welche
eine andere Assemblersprache hatte
Es wurden höhere Programmiersprachen entwickelt
Mitte der 1950er wurde Fortran entworfen und implementiert
es erlaubte numerische Berechnungen in einer Form ähnlich von mathematischen
Formeln auszudrücken
Der Compiler war das Programm welches ein höheres Quellprogramm in ein
Assemblerprogramm oder Maschinenprogramm übersetzte.
Ursprünglich konnten gute Programmierer schnellere Assemblerprogramme schreiben
als der Compiler
Andere höhere Programmiersprachen folgen Fortran in den späten 50er und
frühen 60er
int gcd (int i, int j) {
while (i != j) {
if (i > j)
i = i – j;
else
Compiler
j = j – i;
}
printf(“%d\n”,i);
}
Lisp: erste funktionale Sprache, basierte auf der Theorie der rekursiven Funktionen
Algol: erste block-strukturierte Sprache
Einführung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.1-21
6. Sprachen, Compiler und Theorie
Einführung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6. Sprachen, Compiler und Theorie
Ausführung von Programmen höherer Sprachen
Entwurf eines Compilers
Kompilation
Programm wird in Assemblersprache oder direkt in Maschinensprache
übersetzt
Kompilierte Programme können so erstellt werden, dass sie relativ
schnell in der Ausführung sind
Fortran, C, C++
Interpretation
Programm wird von einem anderem Programm gelesen und Elemente
der Quellsprache werden einzeln ausgeführt
Ist langsamer als kompilierte Programme
Interpreter sind (normalerweise) einfacher zu implementieren als
Compiler, sind flexibler und können exzellent Fehlersuche (debugging)
und Diagnose unterstützen
Java, Pyhton, Perl, etc.
Compiler sind gut untersuchte, aber auch sehr komplexe
Programme
Daher sollte man nicht davon ausgehen, dass Compiler immer fehlerfrei
arbeiten!!!
Die Komplexität wird durch die Aufteilung der Compilerarbeiten in
unabhängige Abschnitte oder Phasen bewältigt
Typischerweise analysiert eine Phase eine Repräsentation von
einem Programm und übersetzt diese Repräsentation in eine
andere, welche für die nächste Phase besser geeignet ist
Das Design dieser Zwischenrepräsentationen eines Programms
sind kritisch für die erfolgreiche Implementierung eines Compilers
Einführung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.1-22
6.1-23
Einführung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.1-24
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Der Kompilationsprozess (-phasen)
Lexikalische Analyse
Scanner (lexikalische Analyse)
Lese Programm und konvertiere Zeichenstrom in Marken
(tokens).
Parser (syntaktische Analyse)
Lese Tokenstrom und generiere Parserbaum (parse tree).
Semantische Analyse
Traversiere Parserbaum, überprüfe nicht-syntaktische
Regeln.
Zwischencodegenerierung
Traversiere Parserbaum noch mal, gebe Zwischencode
aus.
Optimierung
Untersuche Zwischencode, versuche ihn zu verbessern.
Zielcodegenerierung
Übersetze Zwischencode in Assembler-/Maschinencode
Optimierung Maschinenebene
Untersuche Maschinencode, versuche ihn zu verbessern.
Eine Programmdatei ist nur eine Sequenz von Zeichen
Falsche Detailebene für eine Syntaxanalyse
Die lexikalische Analyse gruppiert Zeichensequenzen in Tokens
Tokens sind die kleinste „Bedeutungseinheit“ (units of meaning) im
Kompilationsprozess und sind die Grundlage (foundation) fürs
Parsen (Syntaxanalyse)
Die Compilerkomponente zum Ausführen der lexikalischen Analyse
ist der Scanner, welcher oftmals ausgehend von höheren
Spezifikationen automatisch generiert wird
Mehr über Scanner in der nächsten Vorlesung
Einführung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.1-25
6. Sprachen, Compiler und Theorie
Syntaktische Analyse
Ein GGT Programm in C
Token
int
int
int
{
i
)
(
j
=
j
j
–
}
“%d\n”
)
gcd
i
j
while
!=
{
i
)
i
;
=
i
printf
,
;
Die lexikalische Analyse erzeugt einen Strom von Tokens
Falsche Detailebene für die semantische Analyse und
Codegenerierung
Die Syntaxanalyse gruppiert eine Zeichenfolge von Tokens in
Parserbäume, was durch die kontextfreie Grammatik gelenkt wird,
die die Syntax der zu kompilierenden Sprache spezifiziert
(
,
)
(
j
if
>
i
–
else
j
;
(
I
}
conditional -> if ( expr ) block else block
Parserbäume repräsentieren die Phrasenstruktur eines
Programmes und sind die Grundlage für die semantische Analyse
und Codegenerierung
Die Compilerkomponente zum Ausführen der syntaktischen Analyse
ist der Parser, welcher oftmals ausgehend von höheren
Spezifikationen automatisch generiert wird
Mehr über kontextfreie Grammatiken und Parser später
Einführung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.1-26
6. Sprachen, Compiler und Theorie
Beispiel für lexikalische Analyse
int gcd (int i, int j) {
while (i != j) {
if (i > j)
i = i – j;
else
j = j – i;
}
printf(“%d\n”,i);
}
Einführung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.1-27
Einführung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.1-28
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Beispiel Syntaxanalyse
Semantische Analyse
conditional
Token
if
>
i
–
else
j
;
(
j
=
j
j
–
}
i
)
i
;
=
i
(
expr
id
comp
id
i
>
j
if
block
)
Bestimmt die Bedeutung eines Programms basierend auf der
Repräsentation des Parserbaumes
Setzt Regeln durch, welche nicht durch die Syntax der
Programmiersprache verwaltet werden
block
else
statement
id
=
j
statement
id
=
expr
i
id
op
id
i
-
j
Konsistente Verwendung von Typen, z.B.
expr
int a; char s[10]; s = s + a; illegal!
id
op
id
j
-
i
Jeder Bezeichner (identifier) muss vor der ersten Verwendung deklariert
sein
Unterprogrammaufrufe müssen die richtige Argumentanzahl und
Argumenttyp haben
etc.
Bringt die Symboltabelle auf den aktuellen Stand, welche neben
anderen Dingen den Typ von Variablen, deren Größe und den
Gültigkeitsbereich in welchen die Variablen erklärt wurden notiert
Einführung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.1-29
6. Sprachen, Compiler und Theorie
Einführung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.1-30
6. Sprachen, Compiler und Theorie
Zwischencodegenerierung
Zielcodegenerierung
Parserbäume sind die falsche Detailebene für die Optimierung und
Zwischencodegenerierung
Zwischencodegenerierung verwandelt den Parsebaum in eine
Sequenz von Anweisungen (statements) der Zwischensprache
welche die Semantik des Quellprogramms verkörpert
Die Zwischensprache ist genauso Mächtig, aber einfacher, wie die
höhere Sprache
z.B. die Zwischensprache könnte nur einen Schleifentyp (goto) haben,
wogegen die Quellsprache mehrere haben könnte (for, while, do, etc.)
Das Endziel eines Compilerprozesses ist die Generierung eines
Programms welches der Computer ausführen kann
Dies ist die Aufgabe der Zielcodegenerierung
Schritt 1: durchlaufe (traverse) die Symboltabelle, weise Variablen
einen Platz im Speicher zu
Schritt 2: durchlaufe (traverse) den Parsebaum oder Programm in
der Zwischensprache um arithmetische Operationen, Vergleiche,
Sprünge und Unterprogrammaufrufe auszugeben, sowie Lasten und
Vorräte von Variablenreferenzen
Eine einfache Zwischensprache macht es einfacher nachfolgende
Compilerphasen zu implementieren
Einführung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.1-31
Einführung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.1-32
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Optimierung
Warum Programmiersprachen und Compiler studieren?
Zwischencode und Zielcode ist typischerweise nicht so effizient wie er sein
könnte
Einschränkungen erlauben es dem Codegenerator sich auf die Codeerzeugung
zu konzentrieren und nicht auf die Optimierung
Ein Optimierer kann aufgerufen werden um die Qualität des Zwischencodes
und/oder Zielcodes nach jeder dieser Phasen zu verbessern
Die Compilerkomponente zur Verbesserung der Qualität des generierten
Codes wird Optimierer (optimizer) genannt.
Optimierer sind die kompliziertesten Teile eines Compilers
Optimierungsalgorithmen sind oftmals sehr ausgefeilt, benötigen erheblich
viel Speicher und Zeit für die Ausführung und erzeugen nur kleine
Verbesserungen der Programmgröße und/oder Leistung der Laufzeit
Zwei wichtige Optimierungen
Registerzuteilung – entscheide welche Programmvariablen zu einem bestimmten
Zeitpunkt der Programmausführung in Registern gehalten werden können
Unbenutzten Code eliminieren – entferne Funktionen, Blöcke, etc., welche
niemals vom Programm ausgeführt würden
Nach Aussage von Michael Scott (siehe Literaturangabe)
Verstehe schwer verständliche Spracheigenschaften
Wähle zwischen alternativen Wegen um etwas auszudrücken
Mache guten Gebrauch von Debuggern, Assemblern, Linkern und
andere verwandte Werkzeuge
Simuliere nützliche Eigenschaften (features) welche in einer Sprache
fehlen
Nach Aussage von Kevin Scott (vorheriger Dozent)
Compiler sind große und komplexe Programme: studieren dieser
Programme hilft dir „große Software“ besser zu verstehen
Viele Programme enthalten „kleine Programmiersprachen“
Unix shells, Microsoft Office Anwendungen, etc.
Es ist nützlich etwas über Sprachdesign und –implementierung zu wissen,
so dass Sie kleine Sprachen in die eigene Software einbauen können
Einführung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.1-33
6. Sprachen, Compiler und Theorie
Einführung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.1-34
6. Sprachen, Compiler und Theorie
Weitere Fragen zum Nachdenken
Plan für nächste Vorlesungen
Was macht eine Programmiersprache erfolgreicher als andere?
Werden Programmiersprachen mit der Zeit besser?
An welchen Eigenschaften (features) mangelt es deiner bevorzugten
Sprache um Sie
mächtiger,
zuverlässiger,
einfacher in der Verwendung zu machen?
Die nächsten Vorlesungen (Kapitel 2 vom Buch)
lexikalische Analyse
syntaktische Analyse
Automatentheorie und automatische Generierung von Scannern und
Parsern
Reguläre und kontextfreie Grammatiken
Nachfolgende 5 Vorlesungen
Namen, Geltungsbereiche und Binden (Kapitel 3)
Kontrollfluss (Kapitel 6)
Unterprogramme und Kontrolle über Abstraktion (Kapitel 8)
Zusammenbauen eines lauffähigen Programms (Kapitel 9)
Objekt-orientierte Programmierung (Kapitel 10)
Einführung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.1-35
Einführung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.1-36
6. Sprachen, Compiler und Theorie
Der Kompilationsprozess (-phasen)
Informatik II
SS 2004
Scanner (lexikalische Analyse)
Lese Programm und konvertiere Zeichenstrom in Marken
(tokens).
Parser (syntaktische Analyse)
Lese Tokenstrom und generiere Parserbaum (parse tree).
Semantische Analyse
Teil 6: Sprachen, Compiler und Theorie
2 – Lexikalische Analyse
Prof. Dr. Dieter Hogrefe
Dipl.-Inform. Michael Ebner
Lehrstuhl für Telematik
Institut für Informatik
Traversiere Parserbaum, überprüfe nicht-syntaktische
Regeln.
Zwischencodegenerierung
Traversiere Parserbaum noch mal, gebe Zwischencode
aus.
Optimierung
Untersuche Zwischencode, versuche ihn zu verbessern.
Zielcodegenerierung
Übersetze Zwischencode in Assembler-/Maschinencode
Optimierung Maschinenebene
Untersuche Maschinencode, versuche ihn zu verbessern.
Lexikalische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6. Sprachen, Compiler und Theorie
6.2-2
6. Sprachen, Compiler und Theorie
Lexikalische Analyse
Beispiel für lexikalische Analyse
Ein GGT Programm in C
Die lexikalische Analyse gruppiert Zeichensequenzen in Tokens
(Marken) bzw. Symbole
Tokens sind die kleinste „Bedeutungseinheit“ (units of meaning) im
Kompilationsprozess und sind die Grundlage (foundation) fürs
Parsen (Syntaxanalyse)
Die Compilerkomponente zum Ausführen der lexikalischen Analyse
ist der Scanner, welcher oftmals ausgehend von höheren
Spezifikationen automatisch generiert wird
int gcd (int i, int j) {
while (i != j) {
if (i > j)
i = i – j;
else
j = j – i;
}
printf(“%d\n”,i);
}
Lexikalische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.2-3
Token
int
int
int
{
i
)
(
j
=
j
j
–
}
“%d\n”
)
gcd
i
j
while
!=
{
i
)
i
;
=
i
printf
,
;
(
,
)
(
j
if
>
i
–
else
j
;
(
I
}
Lexikalische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.2-4
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
2 Fragen
Wie beschreiben wir die lexikalische Struktur? (1/2)
Wie beschreiben wir die lexikalische Struktur einer
Programmiersprache?
1. Versuch: Liste aller Tokens
if else long int short char ; , : ( ) { } …
Mit anderen Worten, was sind die Tokens (Symbole)
Wie implementieren wir den Scanner nachdem wir wissen was die
Tokens sind?
Aber was ist mit den Konstanten (Ganzzahlen, Fliesskommazahlen,
Zeichenketten)?
Es können nicht alle aufgelistet werden, es gibt ~8 Milliarden 32-bit integer
und floating-point Konstanten und eine unendliche Anzahl von
Zeichenfolgenkonstanten
Das gleiche Problem gilt für Bezeichner (Variablen, Funktionen und
benutzerdefinierte Typnamen)
Lösung: Wir brauchen einen Weg um kurz und prägnant Klassen von
Tokens zu beschreiben, welche eine große Anzahl von verschiedenen
Werten abdecken können
Lexikalische Analyse
Lexikalische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.2-5
6. Sprachen, Compiler und Theorie
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.2-6
6. Sprachen, Compiler und Theorie
Wie beschreiben wir die lexikalische Struktur? (2/2)
Abkürzungen von regulären Ausdrücken
2. Versuch: Reguläre Ausdrücke
Zeichenfolgen
Muster (patterns) welche zum Auffinden von passendem Text
verwendet werden können
Werden mit folgenden Ausdrücken rekursiv ausgedrückt
r=‘c1c2c3...cn‘ ist äquivalent zu
r=c1.c2.c3.....cn
Zeichenbereiche
Ein Zeichen
Der leeren Zeichenfolge ε
Der Verkettung zweier regulärer Ausdrücke
r=[c1-cn] ist äquivalent zu
r=c1|c2|c3|...|cn für die aufeinander folgende Reihe von n Zeichen
beginnend mit c1 und endend mit cn
z.B. r=[a-d] ist äquivalent zu r=a|b|c|d
r1.r2 ist der Wert von r1 gefolgt vom Wert von r2
Der Alternative zweier regulärer Ausdrücke
Kleenesche Hülle +
r1|r2 ist der Wert von r1 oder der Wert von r2
r+ ist ein oder mehrere Vorkommen des Wertes von r
Der Kleenesche Hülle * (ode einfach Hülle oder Stern)
Formal definiert als r+ = r.r*
r* ist kein oder mehrere Vorkommen des Wertes von r1
Runde Klammern können zum Gruppieren von regulären Ausdrücken
verwendet werden, um Zweideutigkeiten bei Kombinationen
auszuschließen
Das Symbol . steht für jeden Charakter außer „newline“
z.B. bedeutet r1.r2|r3 nun (r1.r2)|r3 oder r1.(r2|r3)???
Lexikalische Analyse
Lexikalische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.2-7
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.2-8
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Lexikalische Analyse: Reguläre Ausdrücke bei der Arbeit
Ein GGT Programm in C
int gcd (int i, int j) {
while (i != j) {
if (i > j)
i = i – j;
else
j = j – i;
}
printf(“%d\n”,i);
}
Reguläre Ausdrücke
digit=[0-9]
letter=[a-z]|[A-Z]
punct=\|%
INT=‘int’
WHILE=‘while’
IF=‘if’
ID=letter.(letter|digit)*
LPAREN=(
RPAREN=)
COMMA=,
SEMI=;
LBRACE={
RBRACE=}
EQ==
MINUS=GT=>
SC=“.(letter|digit|punct)*.”
Ein genauerer Blick auf die lexikalische Analyse
Wie behandelt der lexikalische Analysator Leerzeichen,
Kommentare und Konflikte zwischen regulären Ausdrücken?
Tokens
INT
INT
INT
LBRACE
ID:i
RPAREN
LPAREN
ID:j
EQ
ID:j
ID:j
MINUS
RBRACE
SC:“%d\n”
RPAREN
ID:gcd
ID:i
ID:j
WHILE
NEQ
LBRACE
ID:i
RPAREN
ID:i
SEMI
EQ
ID:i
ID:printf
COMMA
SEMI
LPAREN
COMMA
RPAREN
LPAREN
ID:j
IF
GT
ID:i
MINUS
ELSE
ID:j
SEMI
LPAREN
ID:i
RBRACE
Leerzeichen
int
gcd
(int
i, int
j) {
Kommentare einer Programmiersprache
/* gcd */ int gcd (int i, int j) {
Konflikte zwischen regulären Ausdrücken
Gegeben:
WHILE=‘while’
ID=letter.(letter|digit)*
Beide reguläre Ausdrücke decken die Zeichenfolge „while“ ab. Welcher
Ausdruck soll aber nun gewählt werden?
Lexikalische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.2-9
6. Sprachen, Compiler und Theorie
Lexikalische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6. Sprachen, Compiler und Theorie
Handhabung von Leerzeichen
Handhabung von Kommentaren (1/2)
Leerzeichen können als Token durch folgende Regel erkannt
werden
Alternative 1: Präprozessoren
Spezielles Programm welches eine Datei einliest, Kommentare entfernt,
andere Operationen wie Makro-Expansion ausführt und eine
Ausgabedatei schreibt, welche vom lexikalischen Analysator gelesen
wird.
Quellprogramme können auch Steueranweisungen enthalten, die nicht
zur Sprache gehören, z.B. Makro-Anweisungen. Der lexikalische
Analysator behandelt die Steueranweisungen und entfernt sie aus dem
Tokenstrom.
Präprozessor-Anweisungen in C und C++
WS=(\n|\r|\t|\s)*
\n ist ein „escape“ Zeichen für „newline“ (neue Zeile)
\r ist ein „escape“ Zeichen für „carriage return“ (Wagenrücklauf)
\t ist ein „escape“ Zeichen für „tab“ (Tabulator)
\s ist ein „escape“ Zeichen für „space“ (Leerzeichen)
Das Leerzeichentoken WS ist normalerweise unwichtig für die
Syntax einer Programmiersprache, weshalb es einfach vom
Tokenstrom gelöscht werden kann
z.B. #include und #define
Lexikalische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.2-10
6.2-11
Lexikalische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.2-12
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Handhabung von Kommentaren (2/2)
Handhabung von Konflikten
Gegeben sind zwei reguläre Ausdrücke r1 und r2, welche eine
Teileingabe p=‘c1..ck‘ finden. Welche soll nun ausgewählt werden?
Alternative 2: Kommentartoken
In Abhängigkeit von der Komplexität von Kommentaren ist eine
Beschreibung via regulärer Ausdrücke vielleicht möglich
Alternative 1: Längster Fund
Zeilenkommentare (single line comments) können mit regulären Ausdrücken
gefunden werden
SLC=‘//’.*.$
$ ist ein spezielles Symbol, welches das Ende einer Zeile bedeutet
Nehme solange Eingabezeichen hinzu bis weder r1 noch r2 passen. Entferne
ein Zeichen und entweder r1 oder r2 muss passen. Die Teileingabe p ist der
längste Fund und wenn nur einer von r1 oder r2 passt, dann wähle ihn.
Beispiel:
r1=‘while’
r2=letter.(letter|digit)*
Eingabe
int while48; …
Wenn p=‘while’, beide, r1 und r2 passen
Wenn p=‘while48;’ weder r1 noch r2 passen
Wenn p=‘while48’ nur r2 passt, wähle r2 aus
Findet Texte wie
// Dies ist ein Kommentar
Einige Kommentare sind zu kompliziert um durch reguläre Ausdrücke
gefunden zu werden
Willkürlich verschachtelte Kommentare
/* level 1 /* level 2 */ back to level 1 */
Wird Normalerweise vom Präprozessor behandelt
Alternative 2: Regelpriorität
Wenn der längste Fund immer noch in einem Konflikt endet, dann wähle den
erste regulären Ausdruck aus der lexikalischen Definition der Sprache
Lexikalische Analyse
Lexikalische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.2-13
6. Sprachen, Compiler und Theorie
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6. Sprachen, Compiler und Theorie
Weitere spezielle Probleme
Implementierung eines lexikalischen Analysators
Reservierte Schlüsselwörter
Wie übertragen wir reguläre Ausdrücke in einen
lexikalischen Analysator?
Schlüsselwörter dürfen nicht in Bezeichnern (Namen) verwendet
werden
Konvertiere reguläre Ausdrücke zu einem deterministischen
endlichen (finite) Automaten (DFA)
Groß-/Kleinschreibung
intern nur eine Repräsentation verwenden, weshalb eine Anpassung
notwendig ist
Textende
Das Textende muss dem Syntaxanalysator mitgeteilt werden, weshalb
ein eind-of-text Symbol (eot) eingefügt werden muss
Vorgriff (lookahead) um mehrere Zeichen
Warum??? DFAs sind einfacher zu simulieren als reguläre
Ausdrücke
Schreibe ein Programm zum Simulieren eines DFAs
Der DFA erkennt die Tokens im Eingabetext und wird der
lexikalische Analysator
Wenn ein Token erkannt wurde, dann kann eine
benutzerdefinierte Aktion ausgeführt werden
z.B. überprüfe, ob der Wert einer Ganzzahlkonstante in eine 32-bit
integer passt
gelesene aber nicht verwendete Zeichen müssen für nächsten Test
berücksichtigt werden
Lexikalische Fehler
Die Verletzung der Syntax (z.B. falscher Wertebereich) wird gemeldet
und trotzdem an den Syntaxanalysator weitergegeben
Die Konvertierung von regulären Ausdrücken zu DFAs und
das Schreiben eines Programms zum Simulieren des DFA
kann entweder von Hand vorgenommen werden oder von
einem anderen Programm, welches lexikalischer
Analysegenerator genannt wird.
Lexikalische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.2-14
6.2-15
Regular
Expressions
+
Actions
Lexical Analyzer
Generator
Lexical analyzer
source code
High-level language
compiler
Lexical analyzer
Lexikalische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.2-16
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Endliche Automaten
Ein Beispiel eines endlichen Automaten
Formal, ein endlicher Automat M ist ein Quintupel M=(Q,Σ,q,F,δ),
wobei
Q ist eine endliche Menge von Symbolen genannt Zustände (states)
Σ ist eine endliche Menge von Eingabesymbolen genannt Alphabet
q ist der Startzustand
F ist eine endliche Menge von finalen oder akzeptierenden
Zuständen. F ist eine, möglicherweise leere, Teilmenge von Q.
δ ist eine Übergangsfunktion
L(M), oder die Sprache von M, ist die Menge von endlichen
Zeichenketten von Symbolen aus dem Alphabet Σ welche vom
Automaten M akzeptiert werden
Q={q1,q2,q3,q4,q5}
Σ={a,b}
q=q1
F={q4}
δ=
{((q1,a),q2),((q1,b),q3),
((q2,a),q4),((q2,b),q2),
((q3,a),q4),((q3,b),q5),
((q4,a),q5),((q4,b),q5),
((q5,a),q5),((q5,b),q5)}
b
a
q2
a,b
a
q1
q4
b
Eingabe:
a,b
q5
a
q3
b
abba a Nicht akzeptiert!
Welche Sprache akzeptiert M?
(ab*a)|ba
Lexikalische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.2-17
6. Sprachen, Compiler und Theorie
Lexikalische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.2-18
6. Sprachen, Compiler und Theorie
Zwei Arten von endlichen Automaten:
Deterministisch und Nichtdeterministisch
Ein Beispiel eines nichtdeterministischen Automaten (NFA)
Deterministische endliche Automaten
Die Übergangsfunktion ist formal definiert als
δ:Q x Σ -> Q
Ein Eingabesymbol und ein Zustand ergeben den einzigen nächsten
Zustand
Nichtdeterministische endliche Automaten (NFA)
Q={q1,q2,q3,q4,q5}
Σ={a,b}
q=q1
F={q4}
δ=
{((q1,a),{q2,q3}),((q1,b),{q3}),
((q2,a),{q4}),((q2,b),{q2}),
((q3,a),{q4}),((q3,b),{q5}),
((q4,a),{q5}),((q4,b),{q5}),
((q5,a),{q5}),((q5,b),{q5})}
Die Übergangsfunktion ist formal definiert als
δ:Q x Σ -> φQ (Potenzmenge von Q)
Ein Eingabesymbol und ein Zustand ergeben eine Menge von
möglichen nächsten Zuständen. Die Menge kann auch leer sein.
Abgesehen von den Übergangsfunktionen sind DFAs und NFAs
gleich
b
a
q2
q1
a,b
Eingabe:
a,b
a
q4
q3
a,b
q5
a
b
abba a Nicht akzeptiert!
Welche Sprache akzeptiert M?
(ab*a)|ba
Gleiche wie zuvor beim DFA…
Lexikalische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.2-19
Lexikalische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.2-20
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Eine interessante Sache über endliche Automaten
Eine Nebenbemerkung zu endlichen Automaten
Auch wenn es so aussieht als ob Nichtdeterminismus einem
endlichen Automaten mehr Ausdruckskraft verleiht, sind NFAs und
DFAs formal äquivalent
Jeder NFA kann in einen DFA umgewandelt werden und ungekehrt
Warum machen wir dann aber die Unterscheidung?
Es ist einfacher reguläre Ausdrücke in NFAs umzuwandeln
Es ist einfacher DFAs zu simulieren
MESI cache coherence protocol
Endliche Automaten sind auch für
andere Dinge als lexikalische
Analyse nützlich
(Courtesy: John Morris, University of Western Australia)
Die meisten Systeme, welche
Transaktionen zwischen einer
endlichen Anzahl von Zuständen
vornehmen, können mit endlichen
Automaten modelliert werden
Beispiele
Beschreibung, Simulation,
Überprüfung und Implementierung
von Protokollen
Bauen von schnellen,
zustandsbasierten Schaltungen
(siehe Kapitel 2)
Vending machine automata
25¢
25 ¢
0¢
25 ¢
50 ¢
75¢
25 ¢
50 ¢
50¢
50 ¢
Lexikalische Analyse
6.2-21
6. Sprachen, Compiler und Theorie
Lexikalische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
Beispiel: Reguläre Ausdrücke nach NFA
Regulärer Ausdruck
c
є
Alternative: r1|r2
Verkettung: r1.r2
r1
є
r2
r1
є
є
r1:
r1=a.b
r2=c.d
r3=r1|r2
r=r3*
є
Leere Zeichenkette: є
a
r=(‘ab’|’cd’)*
Faktor:
NFA
Charakter: c
є
c
r2:
r
d
є
є
r3:
є
r2
є
є
є
b
r4:
є
є
Lexikalische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.2-22
6. Sprachen, Compiler und Theorie
Bau des lexikalischen Analysators:
Reguläre Ausdrücke nach NFA
Kleenesche Hülle: r*
vend
25 ¢
50 ¢
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
25 ¢
6.2-23
є
є
a
є
b
c
є
d
a
є
b
c
є
d
a
є
b
c
є
d
є
є
є
є
є
Lexikalische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.2-24
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Theoretische Ergebnisse 1
Bau des lexikalischen Analysators:
NFA nach DFA
Definitionen
Endliche Automaten akzeptieren oder erkennen Sprachen
Reguläre Ausdrücke erzeugen Sprachen
L(M) ist die akzeptierte Sprache vom endlichen Automaten M
L(R) ist die erzeugte Sprache vom regulären Ausdruck R
L(R) and L(M) sind Mengen von endlichen Zeichenketten von Symbolen der
Alphabete ΣR und ΣM
LR ist die Menge { L(r):alle reguläre Ausdrücke r }
LN ist die Menge { L(n):alle nichtdeterministische endliche Automaten n }
Regulärer Ausdruck
LR ist eine Untermenge von LN
Nichtdeterministische endliche Automaten akzeptieren alle von regulären
Ausdrücken erzeugten Sprachen
Warum? Wir haben gezeigt wie beliebige reguläre Ausdrücke zu einem NFA
konvertiert werden können
Beschreiben LR und LN die gleichen Mengen?
Es stellt sich heraus, dass die Antwort ja ist
Beweis durch zeigen das LN eine Untermenge von LR ist oder das jeder
nichtdeterministische endliche Automat in einen regulären Ausdruck
umgewandelt werden kann
Siehe jedes gute theoretische Informatik Buch für Details:
Introduction to Automata Theory, Languages, and Computation by Hopcroft and Ullman
Introduction to the Theory of Computation by Michael Sipser
Lexikalische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
NFA
r=(‘ab’|’cd’)*
Konvertiere NFA nach DFA
є
unter Verwendung der
є q3
Konstruktion von
є
q1
q2
Untermengen
є q7
Beschrifte jeden DFA
Zustand als die vom
vorherigen Zustand in
einem Schritt erreichbare DFA
Menge von Zuständen
a
Wenn irgendein NFA
{q1,q2,q3,
Zustand in der Menge der
erreichbaren Zustände ein q7,q12}
Endzustand ist, dann ist der
c
ganze DFA Zustand ein
Endzustand
6.2-25
6. Sprachen, Compiler und Theorie
a
c
q4
q8
є
є
q5
q9
b
d
q6
q10
є
q11
є
q12
є
a
{q4,q5}
{q8,q9}
b {q2,q3,q6,
q7,q11,q12}
c
a
{q2,q3,q7,
d
q10,q11,q12}
c
Lexikalische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.2-26
6. Sprachen, Compiler und Theorie
Theoretische Ergebnisse 2
Einige Bemerkungen zu DFAs
Definitionen
Erinnerung, LN ist die Menge { L(n):alle nichtdeterministische endliche
Automaten n }
LD ist die Menge { L(d): alle deterministischen endlichen Automaten d }
LN ist eine Untermenge von LD und LR ist eine Untermenge von LD
Deterministische endliche Automaten akzeptieren alle Sprachen die
auch von nichtdeterministischen endlichen Automaten akzeptiert
werden
Neben Transitivität, akzeptieren DFAs auch alle durch reguläre
Ausdrücke generierte Sprachen
Warum? Wir haben gezeigt wie jeder NFA zu einem DFA und jeder
reguläre Ausdruck zu einem NFA konvertiert werden kann
Ein DFA M gebaut unter Verwendung der Konstruktion von
Untermengen kann nicht minimal sein
Mit anderen Worten, es könnte einen Automaten M‘ geben wobei
L(M)=L(M‘) und M‘ hat weniger Zustände als M
Minimale DFAs sind besser geeignet für Implementierungszwecke
Weniger Zustände benötigen weniger Speicher und führen generell zu
schnelleren Simulationen
Die meisten automatischen Werkzeuge zum Konvertieren von NFAs
nach DFAs führen einen Optimierungsprozess aus um die Anzahl
der DFA Zustände zu reduzieren
Beschreiben LN und LD die gleichen Mengen?
Es stellt sich heraus, dass die Antwort ja ist
Beweis durch zeigen das LD eine Untermenge von LN ist oder das jeder
DFA in einen NFA umgewandelt werden kann
Noch mal, siehe jedes gute theoretische Informatik Buch für Details
Das Finden eines minimalen DFAs ist ein sehr hartes Problem (auch
NP-vollständig bezeichnet), weshalb Optimierer keinen minimalen DFA
garantieren können
Praktisch gesehen ist das Ok, obwohl weniger Zustände immer besser
ist ☺
Lexikalische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.2-27
Lexikalische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.2-28
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Bau des lexikalischen Analysators: DFA zu Code
Bau des lexikalischen Analysators: Letzter Schritt
a
DFAs können effizient Simuliert
werden indem ein tabellenbasierter
Algorithmus verwendet wird
void dfa (char *in) {
s = in;
state = start_state;
while(1) {
c = *s++;
state = table[state][c];
if (final[state)]) {
printf(“Accepted %s\n”,in);
break;
}
}
}
b
q2
a
q3
c
q1
a
c
d
q4
q5
c
Tabelle
a
b
c
d
q1
q2
q6
q4
q6
q2
q6
q3
q6
q6
q3
q2
q6
q4
q6
q4
q6
q6
q6
q5
q5
q2
q6
q4
q6
q6
q6
q6
q6
q6
DFA Simulatorcode wird der Kern des lexikalischen Analysators
Wenn der DFA in einem Endzustand ist
Führe mit dem letzten, passenden regulären Ausdruck, entsprechend
dem längsten Fund und/oder der Regelpriorität, die verbundene,
benutzerdefinierte Aktion aus
Merke aktuelle Stelle im Eingabestrom und gebe Token an
Tokenkonsument (parser) weiter
Lexikalische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.2-29
6. Sprachen, Compiler und Theorie
import java.io.IOException;
%%
%public
%class Scanner
%type
void
%eofval{
return;
%eofval}
%{
public static void main (String args []) {
Scanner scanner = new Scanner(System.in);
try {
scanner.yylex();
} catch (IOException e) { System.err.println(e); }
}
%}
comment
space
digit
integer
real
IF
THEN
ELSE
=
=
=
=
=
=
=
=
("#".*)
[\ \t\b\015]+
[0-9]
{digit}+
({digit}+"."{digit}*|{digit}*"."{digit}+)
("if")
"then"
else
%%
{space}
break;
}
{comment}
break;
}
{integer}
break;
{ System.out.println("space");
{ System.out.println("comment");
{ System.out.println("Integer CONSTANT\t" + yytext());
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
Die nächsten Vorlesungen (Kapitel 2 vom Buch)
break;
}
{real}
{ System.out.println("REAL
CONSTANT\t" + yytext());
{ System.out.println("IF
Token\t" + yytext());
{ System.out.println("THEN
Token\t" + yytext());
{ System.out.println("ELSE
Token\t" + yytext());
break;
}
{IF}
break;
}
{THEN}
break;
}
{ELSE}
break;
}
\n
{ System.out.println("NL");
}
{ System.out.println("ADD");
break;
}
"-"
{ System.out.println("SUB");
break;
}
"*"
{ System.out.println("MUL");
break;
}
"/"
{ System.out.println("DIV");
break;
}
"%"
syntaktische Analyse
Automatentheorie und automatische Generierung Parsern
Reguläre und kontextfreie Grammatiken
Nachfolgende 5 Vorlesungen
Namen, Geltungsbereiche und Binden (Kapitel 3)
Kontrollfluss (Kapitel 6)
Unterprogramme und Kontrolle über Abstraktion (Kapitel 8)
Zusammenbauen eines lauffähigen Programms (Kapitel 9)
Objekt-orientierte Programmierung (Kapitel 10)
break;
"+"
Plan für nächste Vorlesungen
{ System.out.println("MOD");
break;
}
"("
{ System.out.println("LPAR");
break;
}
")"
{ System.out.println("RPAR");
break;
}
.
{ System.out.println("error" + "+" + yytext() + "+");
break;
}
Lexikalische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.2-30
6. Sprachen, Compiler und Theorie
Eine reale JLex lexikalische Spezifikation für einen Kalkulatorsprache
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
Lexikalische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.2-31
Lexikalische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.2-32
6. Sprachen, Compiler und Theorie
Pumping Lemma für reguläre Sprachen (1/2)
„
Informatik II
SS 2004
Das Pumping Lemma
ist eine Methode, um
heraus zu finden, ob
eine Sprache nicht
regulär.
Teil 6: Sprachen, Compiler und Theorie
2a – Lexikalische Analyse
Prof. Dr. Dieter Hogrefe
Dipl.-Inform. Michael Ebner
Lehrstuhl für Telematik
Institut für Informatik
Lexikalische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Pumping Lemma für reguläre Sprachen (2)
„
Beweis
Satz:
Sei L eine reguläre Sprache. Dann gibt es eine Zahl (Konstante) n,
derart dass alle Wörter (Zeichenreihen) w in L mit |w | ≥ n gilt, dass
wir in w drei Wörter w = xyz zerlegen können, für die gilt:
…
…
…
6.2-34
„
Jede Zeichenreihe, deren Länge nicht kleiner ist als die Anzahl der
Zustände, muss bewirken, dass ein Zustand zweimal durchlaufen wird
(Schubfachschluss).
|y | ≥ 1 (oder y ≠ ε)
|xy | ≤ n,
Für alle k ≥ 0 gilt, dass die Zeichenreihe xy kz auch in L enthalten ist.
Lexikalische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.2-35
Lexikalische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.2-36
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Beispiele
„
„
Rückblick
Sind diese Sprachen (nicht) regulär?
…
w = anbn
…
w= ab|c
„
„
…
Die Anwendung des Pumping Lemmas ist ein kreativer Vorgang, da
es kein „mechanisches“ Vorgehen für den Einsatz gibt.
…
Reguläre Sprachen, reguläre Ausdrücke, (deterministische und
nichtdeterministische) endliche Automaten
Wichtige Algorithmen
…
vergleiche Ableitungsregeln aus der Mathematik (Analysís)
…
„
Konvertierung von regulären Ausdrücken zu nichtdeterministischen
endlichen Automaten (NFA) (inklusive Beweise)
Konvertierung von nichtdeterministischen endlichen Automaten zu
deterministischen endlichen Automaten (DFA)
Tabellenbasierte Simulation von DFAs
Lexikalische Analyse und Scanner
…
…
Verwenden reguläre Ausdrücke zur Definition der lexikalischen Struktur
(Symbole/Token) einer Sprache
Verwenden die Theorie der regulären Sprachen zur Erzeugung eines
Scanners ausgehend von der Beschreibung der lexikalischen Struktur
einer Programmiersprache anhand von regulären Ausdrücken
Lexikalische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.2-37
Lexikalische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Reguläre Ausdrücke (1/3)
„
…
…
…
…
„
„
Reguläre Ausdrücke (2/3)
Werden mit folgenden Ausdrücken rekursiv ausgedrückt:
…
„
Ein Zeichen c aus dem Alphabet Σ, oder
der leeren Zeichenfolge ε, oder
der Verkettung zweier regulärer Ausdrücke, r1 . r2, oder
der Alternative zweier regulärer Ausdrücke, r1 | r2, oder
der Kleenesche Hülle * (ode einfach Hülle oder Stern), r1*.
Zeichenfolgen
…
„
r=‘c1c2c3...cn‘ = c1.c2.c3.....cn
Zeichenbereiche
…
…
Ein regulärer Ausdruck ist gedacht um Zeichenketten aus Zeichen
aus einem Alphabet Σ zu erzeugen
Die Menge aller durch einen regulären Ausdruck R erzeugte
Zeichenketten wird die Sprache von R genannt und wird
symbolisiert durch L(R)
…
r=[c1-cn] = c1|c2|c3|...|cn
Kleenesche Hülle +
r+ = r.r*
Lexikalische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.2-38
6.2-39
Lexikalische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.2-40
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Reguläre Ausdrücke (3/3)
Endliche Automaten (1/5)
Reguläre Ausdrücke
Erzeugt…
‘if’|’then’|’else’
Die Zeichenketten if, then, or else.
a.(a|b|c)*.a
„
Formal, ein endlicher Automat M ist ein Quintupel M=(Q,Σ,q0,F,δ),
wobei
…
…
Alle Zeichenketten mit a’s, b’s und c’s,
welche mit einem a beginnen und enden.
…
…
a.(a|b|c)*.(b|c).a
Alle Zeichenketten mit a’s, b’s, und c’s,
welche mit einem a beginnen und einem
einzelnen a enden.
(a|b|c)*.a.b.a.(a|b|c)*
Alle Zeichenketten mit a’s, b’s und c’s,
welche die Teilzeichenkette aba enthalten.
(b|c)*.a.(b|c)*.a.(b|c)*.a.(b|c)*
Alle Zeichenketten mit a’s, b’s und c’s,
welche exakt drei a’s beinhalten.
…
„
„
Q ist eine endliche Menge von Symbolen genannt Zustände (states)
Σ ist eine endliche Menge von Eingabesymbolen genannt Alphabet
q0 ist der Startzustand
F ist eine endliche Menge von finalen oder akzeptierenden
Zuständen. F ist eine, möglicherweise leere, Teilmenge von Q.
δ ist eine Übergangsfunktion
Ein endlicher Automat ist geeignet um Zeichenketten aus Zeichen
aus dem Alphabet Σ zu akzeptieren
L(M), oder die Sprache von M, ist die Menge von endlichen
Zeichenketten von Symbolen aus dem Alphabet Σ welche vom
Automaten M akzeptiert werden
Lexikalische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.2-41
Lexikalische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Endliche Automaten (2/5)
„
Endliche Automaten (3/5)
Deterministische endliche Automaten (DEA/DFA)
…
Übergänge sind deterministisch
„
„
…
6.2-42
„
Übergang von einzelnem Zustand zu einzelnem Zustand
δD:Q x Σ -> Q
„
„
Übergangsfunktionen können als eine Tabelle oder
Zustandsübergangsdiagramm geschrieben werden
„
„
Tabelle
Beispiel DFA
Q={q1,q2,q3,q4,q5}
Σ={a,b}
q0=q1
F={q4}
δ=
…
…
…
…
…
q1
q2
q3
q4
q5
{((q1,a),q2),((q1,b),q3),
((q2,a),q4),((q2,b),q2),
((q3,a),q4),((q3,b),q5),
((q4,a),q5),((q4,b),q5),
((q5,a),q5),((q5,b),q5)}
q2
q4
b
q3
a,b
q5
a
b
Lexikalische Analyse
6.2-43
a,b
a
q1
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
b
q3
q2
q5
q5
q5
b
a
Zustandsübergangsdiagramm
a
q2
q4
q4
q5
q5
Lexikalische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.2-44
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Endliche Automaten (4/5)
„
Endliche Automaten (5/5)
Nichtdeterministische endliche Automaten (NEA/NFA)
…
„
„
…
„
Übergänge sind nichtdeterministisch
„
Übergang von einzelnem Zustand zu einer Menge von möglichen
Zuständen
δD:Q x Σ -> P(Q)
( P(Q) Potenzmenge von Q )
„
„
Das Alphabet ist erweitert um Übergänge der leeren Zeichenkette є zu
erlauben
„
Tabelle
Beispiel NFA
Q={q1,q2,q3,q4,q5}
Σ={a,b,є}
q0=q1
F={q4}
δ=
{
((q1,є),{q2,q3}),
((q2,a),{q5}),((q2,b),{q2,q4}),
((q3,a),{q4}),((q3,b),{q5}),
((q4,a),{q5}),((q4,b),{q5}),
((q5,a),{q5}),((q5,b),{q5})
}
a
{q5}
{q5}
{q4}
{q5}
{q5}
є
{q2,q3}
{q5}
{q5}
{q5}
{q5}
q1
q2
q3
q4
q5
a
b
q2
є
a,b
b
a,b
q4
q1
Zustandsübergangsdiagramm
є
6.2-45
6. Sprachen, Compiler und Theorie
b
…
…
„
„
„
Wir können jeden regulären Ausdruck in einen NFA konvertieren und
umgekehrt
c
Wir können jeden NFA in einen DFA konvertieren und umgekehrt
r1
Alternative: r1|r2
Verkettung: r1.r2
є
є
r2
є
є
r1
є
r2
є
Kleenesche Hülle: r*
Lexikalische Analyse
6.2-47
є
Leere Zeichenkette: є
Gegeben ist ein beliebiger NFA MN und DFA MD, mit L(MN) = L(MD)
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
NFA
Charakter: c
Gegeben ist beliebiger regulärer Ausdruck R und ein NFA MN, mit
L(R)=L(MN)
…
6.2-46
Regulärer Ausdruck
Es gibt einen regulären Ausdruck R so dass gilt L(R) = L(X), oder
Es gibt einen DFA MD so dass gilt L(MD) = L(X), oder
Es gibt einen NFA MN so dass gilt L(MN) = L(X)
Die Sprachen der regulären Ausdrücke, DFA Sprachen und NFA
Sprachen sind alle regulär
…
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
Reguläre Ausdrücke nach NFA (1/2)
Eine Sprache L(X) ist Regulär wenn:
…
Lexikalische Analyse
6. Sprachen, Compiler und Theorie
Reguläre Sprachen
„
q5
a
q3
Lexikalische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
b
{q5}
{q2,q4}
{q5}
{q5}
{q5}
є
є
r
є
Lexikalische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.2-48
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Reguläre Ausdrücke nach NFA (2/2)
NFAs nach DFAs (1/2)
„
Definition:
…
r=‘ab’|’cd’
Faktor:
„
„
…
…
…
r1:
r1=‘ab’
r2=‘cd’
r=r1.r2
a
b
r2:
Gegeben NFA M=(Q,Σ,q,F,δ) und DFA MD=(QD,Σ,qD,FD,δD)
…
c
d
d
є
…
…
…
є
r3:
b
є
„
c
є
a
є
b
c
є
d
є-FZ(s) ist die Menge aller Zustände, welche in s beinhaltet sind, plus
aller von den Zuständen in s erreichbaren Zustände unter
ausschließlicher Verwendung des є Überganges
QD=P(Q), z.B., QD ist die Menge aller Untermengen von Q
FD = {S:∀S ∈QD wobei S∩F ≠ {} }
qD= є-FZ (q)
δD({q1,q2,…,qk},a) = є-FZ(δ(q1,a)∪ δ(q2,a)∪… ∪(δ(qk,a))
є
є
Lexikalische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.2-49
6. Sprachen, Compiler und Theorie
NFAs nach DFAs (2/2)
„
b
NFA
q2
є
a,b
q4
q1
є
q3
…
a
b
a,b
Schritt 1: Der Startzustand
„
Schritt 2: Zustand {q1,q2,q3}
…
q5
…
a,b
a
{q4,q5}
a,b
„
Schritt 3: Zustand {q4,q5}
…
b
{q2,q4,q5}
b
δD({q1,q2,q3},b) =
є-FZ(δ(q1,b)∪δ(q2,b)∪δ(q3,b)) =
є-FZ({q2,q4}∪{q2,q4}∪ {q5}) =
{q2,q4,q5}
{q5}
a
{q1,q2,q3}
δD({q1,q2,q3},a) =
є-FZ(δ(q1,a)∪δ(q2,a)∪δ(q3,a)) =
є-FZ({q5}∪{q5}∪ {q4}) =
{q4,q5}
a
b
DFA
qD= є-FZ({q1}) = {q1,q2,q3}
„
…
Schritt 4: Zustand {q2,q4,q5}
…
…
Lexikalische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.2-51
Lexikalische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.2-50
6. Sprachen, Compiler und Theorie
Der Kompilationsprozess (-phasen)
Informatik II
SS 2004
Scanner (lexikalische Analyse)
Lese Programm und konvertiere Zeichenstrom in Marken
(tokens).
Parser (syntaktische Analyse)
Lese Tokenstrom und generiere Parserbaum (parse tree).
Semantische Analyse
Teil 6: Sprachen, Compiler und Theorie
3 – Syntaktische Analyse
Prof. Dr. Dieter Hogrefe
Dipl.-Inform. Michael Ebner
Lehrstuhl für Telematik
Institut für Informatik
Traversiere Parserbaum, überprüfe nicht-syntaktische
Regeln.
Zwischencodegenerierung
Traversiere Parserbaum noch mal, gebe Zwischencode
aus.
Optimierung
Untersuche Zwischencode, versuche ihn zu verbessern.
Zielcodegenerierung
Übersetze Zwischencode in Assembler-/Maschinencode
Optimierung Maschinenebene
Untersuche Maschinencode, versuche ihn zu verbessern.
Syntaktische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Lexikalische Analyse
„
„
„
Der Kompilationsprozess (-phasen)
Die lexikalische Analyse gruppiert Zeichensequenzen in Tokens
(Marken) bzw. Symbole
Tokens sind die kleinste „Bedeutungseinheit“ (units of meaning) im
Kompilationsprozess und sind die Grundlage (foundation) fürs
Parsen (Syntaxanalyse)
Die Compilerkomponente zum Ausführen der lexikalischen Analyse
ist der Scanner, welcher oftmals ausgehend von höheren
Spezifikationen automatisch generiert wird
Scanner (lexikalische Analyse)
Lese Programm und konvertiere Zeichenstrom in Marken
(tokens).
Parser (syntaktische Analyse)
Lese Tokenstrom und generiere Ableitungsbaum (parse
tree).
Semantische Analyse
6.3-3
Traversiere Parserbaum, überprüfe nicht-syntaktische
Regeln.
Zwischencodegenerierung
Traversiere Parserbaum noch mal, gebe Zwischencode
aus.
Optimierung
Untersuche Zwischencode, versuche ihn zu verbessern.
Zielcodegenerierung
Übersetze Zwischencode in Assembler-/Maschinencode
Optimierung Maschinenebene
Untersuche Maschinencode, versuche ihn zu verbessern.
Syntaktische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.3-2
Syntaktische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.3-4
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Syntaktische Analyse
„
„
„
Die lexikalische Analyse erzeugt einen Strom von Symbolen
(Tokens)
Falsche Detailebene für die semantische Analyse und
Codegenerierung
Die Syntaxanalyse gruppiert eine Zeichenfolge von Tokens in
Ableitungsbäume (Struktur-/Parser-/Syntaxbäume), was durch
die kontextfreie Grammatik gelenkt wird, die die Syntax der zu
kompilierenden Sprache spezifiziert
…
„
„
Beispiel Syntaxanalyse
conditional -> if ( expr ) block else block
Ableitungsbäume repräsentieren die Phrasenstruktur eines
Programms und sind die Grundlage für die semantische Analyse
und Codegenerierung
Die Compilerkomponente zum Ausführen der syntaktischen Analyse
ist der Parser, welcher oftmals ausgehend von höheren
Spezifikationen automatisch generiert wird
conditional
Token
if
>
i
–
else
j
;
(
j
=
j
j
–
}
i
)
i
;
=
i
(
expr
id
comp
id
i
>
j
if
block
)
statement
statement
6.3-5
…
…
…
„
…
…
„
digit=[0-9]
letter=[a-z]
id=letter.(letter|digit)*
Kann Identitäten von id durch
Substitution entfernen:
id=[0-9].([a-z]|[0-9])*
id ist ein regulärer Ausdruck
„
id
j
-
i
i
id
op
id
i
-
j
6.3-6
Eine kontextfreie Grammatik (KFG/CFG) ist eine rekursive Definition einer
Sprache mit:
…
Einem Alphabet Σ von Symbolen
…
Eine Menge von Produktionen (oder Regeln) der Form
Identitäten:
…
…
…
„
digits=[0-9]+
sum=expr.’+’.expr
expr=(‘(‘.sum.’)’) | digits
Kann nicht Identitäten von expr
durch Substitution entfernen:
…
…
expr ist durch Rekursion definiert
expr ist kein regulärer Ausdruck
symbol -> symbol symbol … symbol
…
Ein Startsymbol
…
Eine Menge von nicht-terminalen Symbolen aus dem Alphabet Σ, welche auf
der linken oder rechten Seite einer Produktionsregel erscheinen darf
(convention: written in all capital letters)
…
Eine Menge von terminalen Symbolen aus dem Alphabet Σ, welche nur auf der
rechten Seite einer Produktionsregel erscheinen darf. (convention: written in all
lower case letters)
…
Die Menge aller von einer CFG G erzeugten Strings wird die Sprache von G
genannt und wird symbolisiert durch L(G)
Syntaktische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
op
Kontextfreie Grammatiken (1/4)
Warum können wir nicht reguläre Ausdrücke zum Beschreiben der
Syntax einer Programmiersprache verwenden?
Betrachte die folgenden Beschreibungen:
Identitäten:
id
Syntaktische Analyse
„
„
j
expr
expr
6. Sprachen, Compiler und Theorie
Syntaxbeschreibung
„
=
=
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6. Sprachen, Compiler und Theorie
„
id
id
Syntaktische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
block
else
6.3-7
Syntaktische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.3-8
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Kontextfreie Grammatiken (2/4)
„
Kontextfreie Grammatiken (3/4)
Kurzschreibweisen:
…
„
Alternativen
„
„
„
„
„
s->a1..an|b1..bn|…|z1..zn =
s->a1..an
s->b1..bn
…
s->z1..zn
…
…
…
„
…
Wenn eine CFG G zum Parsen von Programmiersprachen
verwendet wird, dann gilt
Beispiel:
Kleenesche * Hülle
„
„
„
„
L(G) ist die Menge von gültigen Quellprogrammen, und
die terminalen Symbole sind die Tokens, welche vom Scanner
zurückgeliefert werden
Klammergrammatik
expr -> LPAREN sum RPAREN
expr -> INT
sum -> expr PLUS expr
s->s1*
s->s1’
s1’->s1 s1’
s1’->є
Terminale: {PLUS,LPAREN,RPAREN,INT}
… Nichtterminale: {sum,expr}
… Startsymbol: {expr}
… Σ = Terminale ∪ Nichtterminale
…
Syntaktische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.3-9
Syntaktische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Kontextfreie Grammatiken (4/4)
„
Ableitungen (1/4)
Eine CFG G erzeugt Zeichenketten durch:
„
…
Beginne mit dem Startsymbol
…
Ersetze ein nichtterminales Symbol sk auf der rechten Seite mit der
rechten Seite dieses Nichtterminals
„
„
„
…
…
…
Grammatik:
expr -> ( sum )
expr -> INT
sum -> expr + expr
s ⇒ s1 s2 … sn
„
Gegeben: sk -> k1…km
Dann: s ⇒ s1…sk…sn ⇒ s1…k1…km…sn
Wiederhole bis nur noch Terminal auf der linken Seite sind
Jeder Schritt in diesem Prozess wird Ableitung (derivation) genannt
und jede Zeichenkette von Symbolen entlang dieses Weges wird
Satzform genannt.
Die abschließende Satzform, welche nur Terminalsymbole enthält, wird
ein Satz (sentence) der Grammatik oder auch das Ergebnis (yield) des
Ableitungsprozesses genannt
Mögliche Ableitungen:
expr ⇒ ( sum )
⇒ ( expr + expr )
⇒ ( INT + expr )
⇒ (INT + ( sum ) )
⇒ (INT + ( expr + expr ) )
⇒ (INT + ( INT + expr ) )
⇒ (INT + (INT + INT ) )
Syntaktische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.3-10
6.3-11
Syntaktische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.3-12
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Ableitungen (2/4)
„
Rechtsseitige Ableitungen (rightmost derivations)
…
…
„
…
„
„
Eine Ableitung (oder Herleitung) ist eine Operationenfolge von
Ersetzungen, welche zeigen wie eine Zeichenkette von Terminalen
(Tokens), ausgehend vom Startsymbol einer Grammatik, abgeleitet
werden kann
„
Unter der Annahme es gibt eine Produktion X -> y, eine einzelne
Ersatzoperation oder ein Ableitungsschritt, dann können diese
beschrieben werden durch αXβ⇒αγβ, für beliebige Zeichenketten von
Grammatiksymbolen α, β und γ
„
Kurzschreibweisen:
Ersetze jeweils das äußerste rechte Nichtterminalsymbol in jedem
Ableitungsschritt
Wird manchmal auch die kanonische Ableitung genannt
Linksseitige Ableitungen (leftmost derivations)
…
„
Ableitungen (3/4)
Ersetze jeweils das äußerste linke Nichtterminalsymbol in jedem
Ableitungsschritt
Siehe vorherige Folie
Andere Ableitungsreihenfolgen sind möglich
…
Die meisten Parser suchen nach entweder einer rechtsseitigen oder
linksseitigen Ableitung
…
…
α ⇒* β bedeutet β kann abgeleitet werden von α in 0 oder mehr Schritten
α ⇒+ β bedeutet β kann abgeleitet werden von α in 1 oder mehr Schritten
α ⇒n β bedeutet β kann abgeleitet werden von α in genau n Schritten
Syntaktische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.3-13
6. Sprachen, Compiler und Theorie
Beispiel Ableitungen
„
Linksseitige Ableitungen (leftmost derivations):
…
…
Grammatik:
expr -> ( sum ) | INT
sum -> expr + expr
Für jeden Ableitungsschritt αXβ⇒αγβ, muss X das äußerte linke
Nichtterminal im String von Symbolen αXβ sein
Wird verwendet in LL(k) bzw. top-down parsen
Linksseitige Ableitung:
„
expr ⇒ ( sum )
⇒
( expr + expr )
⇒
( INT + expr )
⇒
(INT + ( sum ) )
⇒
(INT + ( expr + expr ) )
⇒
(INT + ( INT + expr ) )
⇒
(INT + (INT + INT ) )
Rechtsseitige Ableitungen (rightmost derivations):
…
…
…
Für jeden Ableitungsschritt αXβ⇒αγβ, muss X das äußerte rechte
Nichtterminal im String von Symbolen αXβ sein
Wird verwendet in LR(k) bzw. bottom-up parsen
Wird manchmal auch die kanonische Ableitung genannt
Syntaktische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.3-14
6. Sprachen, Compiler und Theorie
Ableitungen (4/4)
„
Syntaktische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.3-15
„
Eingabe:
(INT + (INT + INT))
Rechtsseitige Ableitung:
expr ⇒ ( sum )
⇒ ( expr + expr )
⇒ ( expr + ( sum ) )
⇒ (expr + ( expr + expr) )
⇒ (expr + ( expr + INT ) )
⇒ (expr + ( INT + INT ) )
⇒ (INT + (INT + INT ) )
Syntaktische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.3-16
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Ableitungen und Ableitungsbäume (1/2)
„
„
„
„
Ableitungen und Ableitungsbäume (2/2)
Ein Ableitungsbaum ist eine graphische Repräsentation des
Ableitungsprozesses
expr
expr
⇒
( sum)
⇒
( expr + expr )
expr
Innere Knoten von Ableitungsbäumen entsprechen den
Nichtterminalsymbolen der Grammatik (Produktionen auf der
linken Seite)
⇒
( INT + expr )
INT
⇒
(INT + ( sum ) )
Die meisten Parser konstruieren einen Ableitungsbaum während
des Ableitungsprozesses für eine spätere Analyse
⇒
(INT + ( expr + expr ) )
expr
⇒
(INT + ( INT + expr ) )
INT
⇒
(INT + (INT + INT ) )
Blätter eines Ableitungsbaumes entsprechen den
Terminalsymbolen (Token) der Grammatik
(
sum
)
+
expr
(
sum
)
+
expr
Syntaktische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.3-17
Syntaktische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6. Sprachen, Compiler und Theorie
„
Mehrdeutigkeiten (2/2)
Eine Grammatik gilt als Mehrdeutig, wenn ein Satz mit (mind.) zwei
verschiedenen Ableitungsbäumen abgeleitet werden kann
Beispiel – linksseitige versus rechtsseitige Ableitung:
…
„
Berühmteres Beispiel – “dangling else”
…
…
Grammatik:
Programmfragment: if a then if b then s1 else s2
Kann interpretiert werden als:
„
„
expression -> identifier | number | - expression | ( expression ) |
expression operator expression
operator -> + | - | * | /
…
„
Eingabe: slope * x + intercept
„
1) if a then { if b then s1 else s2}
2) if a then { if b then s1 } else s2
Mehrdeutigkeit kann manchmal durch die Auswahl eines
akzeptierenden Ableitungsbaumes aus mehreren gehandhabt
werden
…
Zum Beispiel, obige Interpretation #1 wird von den meisten Parsern für
Sprachen die die „dangling else“ Mehrdeutigkeit haben ausgewählt
Generell ist Mehrdeutigkeit jedoch ein Zeichen dafür, dass die
Grammatik „schlecht“ spezifiziert wurde und umgeschrieben werden
sollte um Mehrdeutigkeiten zu beseitigen
Syntaktische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.3-18
6. Sprachen, Compiler und Theorie
Mehrdeutigkeiten (1/2)
„
INT
6.3-19
Syntaktische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.3-20
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Grammatiken und Parser
„
„
Kontextfreie Grammatiken erzeugen durch den Ableitungsprozess
Strings (oder Sätze)
Die kontextfreien Sprachen sind definiert durch
…
…
„
„
„
„
Kellerautomat (1/4)
LCF={L(G): Alle kontextfreien Grammatiken G}
Mit anderen Worten: Die Menge aller Sprachen von allen kontextfreien
Grammatiken
Ein Parser für eine kontextfreie Grammatik erkennt Strings in der
Grammatiksprache
Parser können automatisch aus einer kontextfreien Grammatik
generiert werden
Parser zum Erkennen von allgemeinen kontextfreien Sprachen
können langsam sein
Parser, die nur eine Untermenge von kontextfreien Sprachen
erkennen können, können so gestaltet werden, dass sie schneller
sind
Syntaktische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.3-21
Syntaktische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Kellerautomat (2/4)
„
„
„
Kellerautomat (3/4)
Kontextfreie Grammatiken können von Kellerautomaten (Push
Down Automata, PDA) erkannt werden
PDAs sind eine Erweiterung der endlichen Automaten um ein
„einfaches“ Gedächtnis (Hilfsband)
Eigenschaften eines Kellerautomaten:
…
…
…
…
„
Das Hilfsband heißt auch Kellerstapel oder einfach Stapel (engl.
stack ).
…
…
Das Eingabeband kann sich nur in eine Richtung bewegen.
Es existiert ein "Hilfsband", welches sich in beide Richtungen bewegen
kann.
Der Automat liest im ersten Schritt die jeweils erste Zelle beider Bänder.
Als Reaktion des Automaten kann entweder das Hilfsband vorwärts
bewegt und ein Zeichen in die nächste Zelle geschrieben werden oder
das Symbol gelöscht und das Hilfsband eine Zelle zurück bewegt
werden.
„
„
„
„
Ein Element kann immer nur oben auf den Stapel gelegt (bzw. an das
Ende des Bandes geschrieben) werden (= push ).
Immer nur das oberste (letzte) Element kann wieder vom Stapel entfernt
werden (= pop ).
Die erste Zelle des Hilfsbandes enthält eine spezielle
Kennzeichnung, um anzuzeigen, wann der Stapel leer ist. Ein
Kellerautomat kann bei leerem Stapel nicht weiterarbeiten.
Kellerautomaten arbeiten eigentlich nicht-deterministisch,
nichtdeterministische Kellerautomaten sind aber in deterministische
überführbar
ε-Bewegungen sind erlaubt
Eine Eingabe wird genau dann erlaubt, wenn es möglich ist, eine
Konfiguration zu erreichen, bei der die gesamte Eingabe gelesen
wurde und der Stapel leer ist.
Syntaktische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.3-22
6.3-23
Syntaktische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.3-24
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Kellerautomat (4/4)
„
PDA-Übergangsfunktionen
Ein Kellerautomat (=pushdown automaton, PDA) ist ein
Septupel P = {Q, Σ, Γ, δ, q0, Z0, F } mit:
…
…
…
…
…
…
…
Q
Σ
Γ
δ
q0
Z0
F
„
Die Ausgabe von δ besteht aus einer endlichen Menge von Paaren (p, γ),
wobei p für den neuen Zustand und γ für die Zeichenreihe der Stacksymbole steht, die X auf dem oberen Ende des Stacks ersetzt.
Wenn γ = ε, dann wird das oberste Stacksymbol wird gelöscht. (pop-Operation)
Wenn γ = X, dann bleibt der Stack unverändert.
… Wenn γ = YZ, dann wird X durch Z ersetzt und Y zuoberst auf dem Stack
abgelegt. (push-Operation)
…
Zustandsmenge, |Q | < ∞
Eingabealphabet, |Σ| < ∞
Stackalphabet, |Γ| < ∞
Übergangsfunktion (ZustandsÜF)
δ(q,a,X) mit q ∈ Q, a ∈ {Σ, ε}, X ∈ Γ
Anfangszustand
Startsymbol (für Stack)
Endzustände, F ⊆ Q
…
„
„
Da PDAs nicht-deterministisch arbeiten, kann die Ausgabe von δ eine
Menge an Paaren ergeben, z.B.
δ(q, a, X) = { (p, YZ), (r, ε) }
Die Paare müssen dabei als Einheit betrachtet und behandelt werden.
Wenn sich der PDA im Zustand q befindet, X das oberste Stacksymbol
ist und die Eingabe a gelesen wird, kann
…
…
in den Zustand p gewechselt und X durch YZ ersetzt werden, oder
in den Zustand r gewechselt und X vom Stack entfernt werden.
Syntaktische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.3-25
Syntaktische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Beispiel PDA: Palindrome
„
Schreibkonventionen für PDAs
Formelle Beschreibung:
P = ({q0,q1,q2},{0,1},{0,1,Z0}, δ, q0, Z0, {q2})
…
…
…
…
…
δ(q0, 0, Z0) = {(q0,0 Z0)}
δ(q0, 1, Z0) = {(q0,1 Z0)}
δ(q0, 0, 0) = {(q0,00)}
δ(q0, 0, 1) = {(q0,01)}
δ(q0, 1, 0) = {(q0,10)}
δ(q0, 1, 1) = {(q0,11)}
δ(q0, ε, Z0)= {(q1, Z0)}
δ(q0, ε, 0) = {(q1, 0)}
δ(q0, ε, 1) = {(q1, 1)}
δ(q1, 0, 0) = {(q1, ε)}
δ(q1, 1, 1) = {(q1, ε)}
δ(q1, ε, Z0)= {(q2, Z0)}
„
„
„
Æ lesen und push
„
„
Æ lesen und push
a, b, ... ∈ Σ
p, q, ... ∈ Q
w, z, ... = Zeichenreihen aus Σ (Terminale)
X, Y, ... = Γ
α, β, γ, ... = Zeichenreihen aus Γ (Nichtterminale)
Æ Wechsel nach q1, ohne Stack
zu verändern
Æ lesen, vergleichen, pop
Æ Z0 erreicht, akzeptiert
Syntaktische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.3-26
6.3-27
Syntaktische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.3-28
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Beschreibung der Konfiguration eines PDA (1/2)
„
„
Beschreibung der Konfiguration eines PDA (2/2)
Im Gegensatz zum endlichen Automaten, bei denen lediglich der
Zustand (neben dem Eingabesymbol) für einen Übergang von
Bedeutung ist, umfasst die Konfiguration eines PDA sowohl den
Zustand als auch den Inhalt des Stacks.
Die Konfiguration wird daher durch das Tripel (q, w, γ) dargestellt,
wobei
…
…
…
q
w
γ
für den Zustand,
für die verbleibende Eingabe,
für den Inhalt des Stacks steht.
„
„
Sei P = {Q, Σ, Γ, δ, q0, Z0, F } ein PDA.
Angenommen, δ(q, a, X) enthält (p, α).
Dann gilt für alle Zeichenreihen w aus Σ* und β aus Γ*:
(q, aw, X β) ⊢ (p, w, αβ)
D.h., der Automat kann vom Zustand q in den Zustand p übergehen, indem
er das Symbol a (das ε sein kann) aus der Eingabe einliest und X auf dem
Stack durch α ersetzt. (Die restliche Eingabe w und der restliche Inhalt des
Stacks β beeinflussen die Aktion des PDA nicht!)
(Das obere Ende des Stacks steht am linken Ende von γ.)
Syntaktische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.3-29
6. Sprachen, Compiler und Theorie
…
„
„
„
…
Eingabe wird von links-nach-rechts
(1. L) abgearbeitet
… linksseitige Ableitung (2. L)
… “top down” oder “prädiktive”
(voraussagende) Parser genannt
„
…
…
Eingabe wird von links-nach-rechts
(1. L) abgearbeitet
… rechtsseitige Ableitung (2. R)
… “bottom up” oder “schiebe-reduziere“
(shift-reduce) Parser genannt
„
Sei P = {Q, Σ, Γ, δ, q0, Z0, F } ein PDA.
Dann ist die Sprache N(P ), die von P durch Endzustand akzeptiert wird,
{w | (q0, w, Z0) ⊢* (q, ε, ε) für einen beliebigen Zustand q.
N(P) ist die Menge der Eingabezeichenreihen w, die P einlesen kann
und bei der er gleichzeitig den Stack leeren kann.
6.3-31
“k” steht für die Anzahl von Symbolen
(token) für die in der Eingabe
vorausgeschaut werden muss um
eine Entscheidung treffen zu können
LL(k) – welche nächste Produktion auf
der rechten Seite ist bei einer
linksseitigen Ableitung zu wählen
… LR(k) – ob zu schieben oder reduzieren
…
Syntaktische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
LR(k) parsers
…
Sei P = {Q, Σ, Γ, δ, q0, Z0, F } ein PDA.
Dann ist die Sprache L(P ), die von P durch Endzustand akzeptiert wird,
{w | (q0, w, Z0) ⊢*p (q, ε, β) für einen Zustand q in F und eine
Stackzeichenreihe α.
Akzeptanz durch leeren Stack
…
LL(k) Parser
…
Akzeptanz durch Endzustand
Akzeptanz durch leeren Stack
Zwar unterscheiden sich die Sprachen, die die jeweiligen PDAs
akzeptieren, aber sie sind jeweils ineinander überführbar.
Akzeptanz durch Endzustand
…
„
Klassen von Grammatiken und Parsern
Es gibt zwei Ansätze, wann ein PDA eine Eingabe akzeptiert:
…
6.3-30
6. Sprachen, Compiler und Theorie
Akzeptanzzustände von PDAs
„
Syntaktische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
Syntaktische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.3-32
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Top-down versus
Bottom-up Syntaxanalyse (2/2)
Top-down versus Bottom-up Syntaxanalyse (1/2)
„
Top-down oder LL-Syntaxanalyse
…
…
„
Baue den Ableitungsbaum von der Wurzel aus bis hinunter zu den
Blättern auf
Berechne in jedem Schritt voraus welche Produktion zu verwenden ist
um den aktuellen nichtterminalen Knoten des Ableitungsbaumes
aufzuweiten (expand), indem die nächsten k Eingabesymbole betrachtet
werden
id_list -> id id_list_tail
id_list_tail -> , id id_list_tail
id_list_tail -> ;
„
„
Bottom-up oder LR-Syntaxanalyse
…
…
Grammatik:
Beispiel Strings:
A;
A, B, C;
Baue den Ableitungsbaum von den Blättern aus bis hinauf zu der
Wurzel auf
Ermittle in jedem Schritt, ob eine Kollektion von Ableitungsbaumknoten
zu einem einzelnen Vorgängerknoten zusammengefasst werden kann
oder nicht
Syntaktische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.3-33
Syntaktische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Syntaxanalyse durch rekursiven Abstieg (1/4)
„
„
„
„
Syntaxanalyse durch rekursiven Abstieg (2/4)
Rekursiver Abstieg ist ein Weg um LL (top-down) Parser zu
implementieren
„
Rekursiver Abstieg ist ein Weg um LL(1)-Parser zu implementieren:
…
Es ist einfach von Hand zu schreiben
…
Es wird kein Parsergenerator benötigt
„
Jedes nichtterminale Symbol in der Grammatik hat einen
Prozeduraufruf
Erinnerung: LL(1)-Parser machen linksseitige Ableitungen, unter
Verwendung von höchstens 1 Symbol in der Vorausschau, um zu
entscheiden welche rechte Seite einer Produktion verwendet wird, um
ein linksseitiges Nichtterminal in einer Satzform zu ersetzen.
LL(1)-Parser Beispiel:
…
Grammatikfragment:
…
Wenn die Satzform “n1 … nk factor sm … sn” lautet, dann sollte die
nächste Satzform folgende sein:
„
Es muss im Stande sein die nächste, anzuwendende, linksseitige
Ableitung zu bestimmen (predict), indem nur die nächsten k
Symbole angeschaut werden
…
6.3-34
„
„
factor -> ( expr ) | [ sexpr ]
“n1 … nk ( expr ) sm … sn” oder
“n1 … nk [ sexpr ] sm … sn”
k ist üblicherweise 1
Syntaktische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.3-35
Syntaktische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.3-36
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Syntaxanalyse durch rekursiven Abstieg (3/4)
Syntaxanalyse durch rekursiven Abstieg (4/4)
Grammatik für eine
Kalkulatorsprache
Ableitungsbaum für
Beispieleingabe:
read A
read B
sum := A + B
write sum
write sum / 2
Beispieleingabe:
read A
read B
sum := A + B
write sum
write sum / 2
Syntaktische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.3-37
Syntaktische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
LL-Syntaxanalyse
„
Probleme mit der LL-Syntaxanalyse (1/4)
Finde zu einer Eingabe von Terminalsymbolen (tokens) passende
Produktionen in einer Grammatik durch Herstellung von
linksseitigen Ableitungen
„
Linksrekursion
…
Produktionen von der Form:
„
„
„
„
Für eine gegebene Menge von Produktionen für ein Nichtterminal,
X->y1|…|γn, und einen gegebenen, linksseitigen Ableitungsschritt
αXβ ⇒ αγiβ, müssen wir im Stande sein zu bestimmen welches γi
zu wählen ist indem nur die nächsten k Eingabesymbole
angeschaut werden
Anmerkung:
…
Für eine gegebene Menge von linksseitigen Ableitungsschritten,
ausgehend vom Startsymbol S ⇒ αXβ, wird der String von Symbolen
α nur aus Terminalen bestehen und repräsentiert den passenden
Eingabeabschnitt zu den bisherigen Grammatikproduktionen
…
Wenn eine Grammatik linksrekursive Produktionen enthält, dann kann
es dafür keinen LL Parser geben
„
…
A -> Aα
A -> β
LL Parser würden in eine Endlosschleife eintreten, wenn versucht wird eine
linksseitige Ableitung in solch einer Grammatik vorzunehmen
Linksrekursion kann durch das Umschreiben der Grammatik
ausgeschlossen werden
„
„
A -> βA’
A’ -> αA’ | є
Syntaktische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.3-38
6.3-39
Syntaktische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.3-40
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Probleme mit der LL-Syntaxanalyse (2/4)
„
Linksrekursion: Nicht formale Rechtfertigung
…
Originalgrammatik:
„
„
…
…
A -> Aα
A -> β
Ableitungen:
„
…
„
Umgeschriebene Grammatik:
„
A ⇒ Aα ⇒ Aαα ⇒ Aααα ⇒*
βααα…
„
Probleme mit der LL-Syntaxanalyse (3/4)
Gemeinsame Präfixe
…
A -> βA’
A’ -> αA’ | є
Tritt auf wenn zwei verschiedene Produktionen mit der gleichen linken
Seite mit den gleichen Symbolen anfangen
„
…
A ⇒ βA’ ⇒ βαA’ ⇒ βααA’ ⇒*
βααα…
„
Linksrekursion: Beispiel
…
Grammatik:
„
„
…
Produktionen der Form:
…
Ableitungen:
…
id_list -> id_list_prefix ;
id_list_prefix -> id_list_prefix , id | id
A -> bα
A -> bβ
LL(1) Parser kann nicht entscheiden welche Regel auszuwählen ist, wenn A
in einem linksseitigen Ableitungsschritt zu ersetzen ist, weil beide rechten
Seiten mit dem gleichen Terminalsymbol anfangen
Kann durch Faktorisierung ausgeschlossen werden:
„
„
A -> bA’
A’ -> α | β
Linksrekursion kann durch das Umschreiben der Grammatik
ausgeschlossen werden
„
„
id_list -> id id_list_tail
id_list_tail -> , id id_list_tail | ;
Syntaktische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.3-41
Syntaktische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Probleme mit der LL-Syntaxanalyse (4/4)
„
Bau eines Top-Down Parsers mit rekursivem Abstieg (1/2)
Gemeinsame Präfixe
…
„
…
„
Beispiel:
„
stmt -> id := expr
stmt -> id ( argument_list )
Für jedes Nichtterminal in einer Grammatik wird ein Unterprogramm
erzeugt, welches einem einzelnen linksseitigen Ableitungsschritt
entspricht, wenn es aufgerufen wird
…
Gemeinsame Präfixe können durch das Umschreiben der Grammatik
ausgeschlossen werden
„
„
6.3-42
Beispiel:
„
„
factor -> ( expr )
factor -> [ sexpr ]
void factor (void) {
switch(next_token()) {
stmt -> id stmt_list_tail
stmt_list_tail -> expr | ( argument_list )
case ‘(‘:
expr(); match(‘)’); break;
case ‘[‘:
„
„
Der Ausschluss von Linksrekursion und gemeinsame Präfixe
garantiert nicht das eine Grammatik LL wird
Wenn wir keinen LL Parser für eine Grammatik finden können, dann
müssen wir einen mächtigere Technik verwenden
…
sexpr(); match(‘]’); break;
}
„
Schwieriger Teil:
…
z.B., LALR(1) – Grammatiken
Herausbekommen welches Token den ‚case‘ Arm vom switch Befehl
benennt
Syntaktische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.3-43
}
Syntaktische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.3-44
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Bau eines Top-Down Parsers mit rekursivem Abstieg (2/2)
„
PREDICT-Mengen (Vorhersagemengen)
…
…
…
PREDICT Mengen teilen uns mit, welche rechte Seite einer Produktion bei
einer linken Ableitung auszuwählen ist, wenn mehrere zur Auswahl stehen
PREDICT-Mengen dienen somit als Grundlage für Ableitungstabellen
(Parse-Tabellen) bzw. sind eine andere Teildarstellungsform für die
Tabellen
Wird in Form von FIRST-, FOLLOW- und NULLABLE-Mengen definiert :
„
„
„
„
Sei A ein Nichtterminal und α beliebig, dann gilt
PREDICT(A->α) = FIRST(α) ∪ FOLLOW(A) wenn NULLABLE(α)
PREDICT(A->α) = FIRST(α) wenn nicht NULLABLE(α)
FIRST-Mengen
„
Sei α eine beliebige Folge von Grammatiksymbolen (Terminale
und Nichtterminale)
„
FIRST(α) ist die Menge aller Terminalsymbolen a mit denen ein
aus α abgeleiteter String beginnen kann:
FIRST(α) ist { a: α ⇒* aβ}
„
Gilt α ⇒* є, dann ist auch є in FIRST(α)
NULLABLE-Mengen
…
…
Sei X ein Nichtterminal
NULLABLE(X) ist wahr wenn gilt X ⇒* є (X kann den leeren String
ableiten)
Syntaktische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.3-45
Syntaktische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Berechnung von FIRST-Mengen (1/2)
Berechnung von FIRST-Mengen (2/2)
Für alle Grammatiksymbole X wird FIRST(X) berechnet, indem die
folgenden Regeln solange angewandt werden, bis zu keiner FIRSTMenge mehr ein neues Terminal oder є hinzukommt:
„
6.3-46
„
Folglich gilt:
…
Elemente aus FIRST(Y1) gehören immer auch zu FIRST(X)
…
Ist є nicht aus Y1 ableitbar (NICHT NULLABLE), dann brauch nichts
mehr hinzugefügt werden
1.
Wenn X ein Terminal ist, dann ist FIRST(X)={X}
2.
Wenn X → ε eine Produktion ist, dann füge ε zu FIRST(X) hinzu
…
Ist є aus Y1 ableitbar (NULLABLE), dann muss auch FIRST(Y2) zu
FIRST(X) hinzugefügt werden
Wenn X Nichtterminal und X → Y1Y2Y3 KYk
nehme a zu FIRST(X) hinzu, falls
…
Ist є aus Y2 ableitbar (NULLABLE), dann muss auch FIRST(Y3) zu
FIRST(X) hinzugefügt werden
usw.
3.
eine Produktion ist, dann
(a) a für irgendein i in FIRST(Yi) und
(b) ein ε in allen FIRST(Y1), ..., FIRST(Yi-1) enthalten ist (Y1...Yi-1 sind alle
NULLABLE)
…
…
є wird nur zu FIRST(X) hinzugefügt, wenn es in allen Mengen
FIRST(Y1), ... ,FIRST(Yk) enthalten ist
Syntaktische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.3-47
Syntaktische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.3-48
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
FOLLOW-Mengen
Berechnung von FOLLOW-Mengen
„
Sei A ein Nichtterminal
„
FOLLOW(A) ist die Menge aller Terminalsymbole a, die in einer
Satzform direkt rechts neben A stehen können ( sei S Startregel;
α, β beliebig):
„
Follow(A) wird für alle Nichtterminale A berechnet, indem die
folgenden Regeln solange angewandt werden, bis keine FollowMenge mehr vergrößert werden kann:
1.
Sei S das Startsymbol und $ die Endemarkierung, dann nehme $ in
FOLLOW(S) auf
FOLLOW(A) ist { a:S ⇒* αAaβ }
„
Achtung: Zwischen A und a können während der Ableitung
Symbole gestanden haben, die aber verschwunden sind, weil aus
Ihnen є abgeleitet wurde!
„
Gibt es eine Satzform, in der A das am weitesten rechts stehende
Symbol ist, dann gehört auch $ (die Endemarkierung) zu
FOLLOW(A)
2.
3.
Wenn es eine Produktion A → αBβ gibt, dann wird jedes
Element von FIRST(β ) mit Ausnahme von ε auch in
FOLLOW(B) aufgenommen.
Wenn es Produktionen A → αB oder A → αBβ gibt und FIRST(β )
enthält (d.h. β ⇒*ε ), dann gehört jedes Element von FOLLOW(A)
auch zu FOLLOW(B)
Syntaktische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.3-49
6. Sprachen, Compiler und Theorie
S -> s$
B -> є
A -> B
S -> A B S
B -> b
A -> a
Schritt 1: i=0
NULLABLE
FIRST
FOLLOW
A
False
{a}
{}
B
True
{b, є}
{}
S
False
{s}
{$}
S
A
True
{a,b,є}
{b,s}
B
True
{b, є}
S
False
{s,a,b}
True
{a,b,є}
{b,s,a}
S -> A B S B -> b
A -> a
B
True
{b, є}
{s,a,b}
S
False
{s,a,b}
{$}
FOLLOW
A
True
{a,b,є}
{b}
B
True
{b, є}
{s}
A->B
{a,b,є,s}
False
{s,a}
{$}
A->a
{a}
B->є
{a,b,s}
PREDICT
FIRST
FOLLOW
B->b
{b, є}
A
True
{a,b,є}
{b,s,a}
S->s$
{s,a}
B
True
{s,a,b}
{s}
{b, є}
S->ABS
{$}
S
False
{s,a,b}
{$}
„
„
{a,b,s}
Syntaktische Analyse
6.3-51
FOLLOW
A
NULLABLE
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
FIRST
A -> B
FIRST
Schritt 4: i=3
NULLABLE
B -> є
S -> s$
NULLABLE
Schritt 3: i=2
FOLLOW
6.3-50
Beispiel für PREDICT-Mengen
Schritt 2: i=1
FIRST
Syntaktische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6. Sprachen, Compiler und Theorie
Beispiel für NULLABLE-, FIRST- und FOLLOW-Mengen
NULLABLE
ε
PREDICT-Mengen zeigen uns welche
Menge von look-ahead Symbolen die
rechte Seite einer Produktion selektiert
Diese Grammatik ist NICHT LL(1), da
es duplizierte Symbole in den
PREDICT-Mengen für alle drei
Nichtterminale gibt
…
Siehe Hervorhebungen (dick, rot)
Syntaktische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.3-52
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
LL(k) Eigenschaften
„
Ableitungsbäume und Parser mit rekursivem Abstieg (1/2)
Satz: Jede kontextfreie Grammatik G ist genau dann LL(1), wenn für
alle Alternativen A ⇒ α1| α2 | ... | αn gilt
1.
2.
…
„
FIRST(α1), ..., First(αn) paarweise disjunkt,
falls αi ⇒* є gilt, dann FIRST1(αj) ∩ FOLLOW1(A) = Ø für 1 ≤ j ≤ n, j ≠ i
In Worten:
„
„
„
Aus α1, α2 , ... und αn sind jeweils keine Strings ableitbar, wo zwei mit dem
gleichen Nichtterminal anfangen
Der leere String є kann nicht sowohl aus αi und αj für i ≠ j abgeleitet werden
Falls αi ⇒* є gilt, dann beginnt kein aus αi ableitbarer String mit einem
Terminal aus FOLLOW(A)
Die Beispielparser auf die wir bisher geschaut haben sind nur
Erkenner
…
„
Sie bestimmen, ob eine Eingabe syntaktisch korrekt ist, aber bauen
keinen Ableitungsbaum
Wie konstruieren wir dann einen Ableitungsbaum?
…
In Parser mit rekursivem Abstieg machen wir für jede nichtterminale
Funktion:
„
„
„
Konstruktion eines korrekten Ableitungsbaumknoten für sich selbst und
Verbindungen zu seinen Kindern
Geben den konstruierten Ableitungsbaumknoten an den Aufrufer zurück
Satz: Sei G kontextfreie Grammatik, k ≥ 0. G ist genau dann LL(k),
wenn gilt:
Sind A ⇒ β, A ⇒ ζ verschiedene Produktionen, dann
Firstk(βα) ∩ FIRSTk(ζα) = Ø für alle α, σ mit S ⇒* σ A α
Syntaktische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.3-53
Syntaktische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Ableitungsbäume und Parser mit rekursivem Abstieg (2/2)
„
Beispiel: Jedes nichtterminale Unterprogramm konstruiert einen
Ableitungsbaumknoten
node *factor (void) {
…
…
factor -> ( expr )
factor -> [ sexpr ]
6.3-54
Parsergeneratoren und Syntaxanalyse
„
„
switch(next_token()) {
Parsergeneratoren erzeugen ausgehend von der kontextfreien
Grammatik einen Parser
An Produktionen dürfen semantische Aktionen angehängt sein
…
case ‘(‘:
node = factor_node(expr());
…
match(‘)’); break;
Wenn ein Parser eine Produktion erkannt hat, dann wird die
semantische Aktion aufgerufen
Wird hauptsächlich dazu verwendet einen Ableitungsbaum explizit zu
konstruieren
case ‘[‘:
node = factor_node(sexpr());
„
Nicht alle Symbole werden zu
einem Ableitungsbaumknoten
…
„
Beispiele: ‘(‘, ‘)’, ‘[‘, ‘]’
Diese Art von Ableitungsbaum
}
wird „Abstrakter Syntaxbaum“
(abstract syntax tree, AST) genannt
match(‘]’); break;
}
return node;
„
Die Ausgabe eines Parsergenerators ist ein Programm in einer
Hochsprache (z.B. C, C++, oder Java) welches einen Symbolstrom
(token stream) von einem Lexer (für die lexikalische Analyse)
entgegen nimmt und welches einen Ableitungsbaum für die
nachfolgenden Compilerphasen produziert
Syntaktische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.3-55
Syntaktische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.3-56
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
ANTLR als Beispiel eines Parsergenerators
Rückblick
„
ANTLR Grammatikspezifikation
(parser.g)
lexikalischer
Analysator
(scanner.class)
Eingabe
10+(27-5);
(44-2)-(1-10);
„
Kontextfreie Grammatiken (KFG) und Sprachen (KFS),
Kellerautomat
Wichtige Algorithmen:
…
…
ANTLR
„
java parser.class
Syntaktische Analyse und Parser
…
(java antlr.Tool parser.g)
…
…
symbols.java
parser.java
…
Ausgabe
=32
=51
Auflösung von Linksrekursion und gemeinsame Präfixe
FIRST, FOLLOW, NULLABLE und PREDICT Mengen für kontextfreie
Grammatiken
Die Syntax einer Programmiersprache wird mit KFGs spezifiziert
Konstruktion eines Parsers mit rekursivem Abstieg anhand von KFGs
Automatische Generierung von Parsern anhand von KFGs
Parser erzeugen Ableitungsbäume für die Analyse und weitere
Verarbeitung in den nachfolgenden Compilerphasen
javac parser.java
Syntaktische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.3-57
6. Sprachen, Compiler und Theorie
Ausblick
„
„
„
„
Namen, Bindungen und Gültigkeitsbereiche (Kapitel 3)
Objektlebenszeit und Speichermanagement
Kontrollfluss (Kapitel 6)
Zusammenführung (Bau eines ausführbaren Programms) (Kapitel 9)
Syntaktische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.3-59
Syntaktische Analyse
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.3-58
6. Sprachen, Compiler und Theorie
Namen, Bindungen und Gültigkeitsbereiche (1/3)
„
Namen
…
Informatik II
Ein mnemonischer Zeichenname wird verwendet um irgendetwas
anderes zu repräsentieren oder zu benennen (Mnemonic ist die
Bezeichnung für Ausdrücke deren Bedeutung vorwiegend durch die verwendete
Buchstabenfolge leicht behalten werden kann.)
„ Normalerweise Bezeichner (identifier)
SS 2004
…
Teil 6: Sprachen, Compiler und Theorie
Ist essentiell für Abstraktion
„
4 – Namen, Bindungen und Gültigkeitsbereiche
Erlaubt es Programmierern Werte zu bezeichnen damit die Notwendigkeit
zur direkten Manipulation von Adressen, Registernamen, etc. vermieden
wird
…
Beispiel: Es ist nicht notwendig zu wissen ob die Variable foo im Register $t0 oder
an der Speicherstelle 10000 gespeichert wird
Prof. Dr. Dieter Hogrefe
Dipl.-Inform. Michael Ebner
„
Erlaubt es Programmierern einen einfachen Namen für ein potenziell
komplexes Programmstück stehen zu lassen
Lehrstuhl für Telematik
Institut für Informatik
„
Beide Fälle verringern die konzeptuelle Komplexität
…
Beispiel: foo = a*a + b*b + c*c + d*d;
Namen, Bindungen und Gültigkeitsbereiche
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Namen, Bindungen und Gültigkeitsbereiche (2/3)
„
Namen, Bindungen und Gültigkeitsbereiche (3/3)
„
Bindungen
…
„
„
…
Gültigkeitsbereiche (Scope)
…
Ist eine Assoziation zwischen zwei Dingen
„
…
Ein Variablenname zu einem Wert
Ein Variablenname zu einer spezifischen Speicherstelle
Ein Typ und seine Repräsentation oder Layout im Speicher
Die Bindezeit ist die Zeit zu der eine solche Assoziation gemacht wird
…
Ist der Textbereich eines Programms in welchem eine Bindung aktiv ist
Java Beispiel:
public void foo (int a) {
Global Scope
int b;
while(a < n) {
int c;
Method Scope
c = a + a;
b = a * c;
Block Scope
a++;
}
}
Verbessert die Abstraktion durch die Kontrolle über die Sichtbarkeit von
Bindungen
Namen, Bindungen und Gültigkeitsbereiche
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.4-2
6.4-3
Namen, Bindungen und Gültigkeitsbereiche
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.4-4
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Bindezeitpunkte (1/8)
„
„
Wir unterscheiden 7 Zeitpunkte für die Entscheidung über eine
Bindung
„
Zeitpunkt des Sprachentwurfs
…
Entscheidungen welche vom Designer der Programmiersprache
gemacht wurden
…
Typische Beispiele:
Sprache
…
…
„
Bindezeitpunkte (2/8)
Entwurf
Implementierung (mit Compilern)
„
Programm
…
…
…
…
…
Programmierung (Schreiben des Programms)
Kompilation
Linken
Laden
Ausführen
Binden von Kontrollstrukturen (Bedingungen, Schleifen, etc.) zu Ihrer
abstrakten Bedeutung
…
„
„Befehle in einem while Schleifenblock werden ausgeführt bis die Bedingung nicht
mehr länger wahr ist“
Binden von primitiven Datentypnamen (int, float, char, etc.) zu Ihrer
geforderten Repräsentation
…
…
„Variablen vom Typ int beinhalten vorzeichenbehaftete Ganzzahlen“
„Variablen vom Typ int beinhalten vorzeichenbehaftete 32-bit Werte“
Namen, Bindungen und Gültigkeitsbereiche
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.4-5
Namen, Bindungen und Gültigkeitsbereiche
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Bindezeitpunkte (3/8)
„
Bindezeitpunkte (4/8)
„
Zeitpunkt der Sprachimplementierung
Zeitpunkt des Programmierens
…
…
…
…
Entscheidungen welche vom Compiler bzw. vom
Compilerprogrammierer gemacht wurden
„
Mit anderen Worten, Angelegenheiten der Sprachimplementierung die nicht
spezifisch während des Sprachentwurfs definiert wurden
„
„
„
Binden von primitiven Datentypen zu deren Repräsentationsgenauigkeit
(Anzahl der Bits)
…
Entscheidungen des Programmierers
Typische Beispiele:
„
Typische Beispiele:
„
…
…
„bytes sind 8-bits, shorts sind 16-bits, ints sind 32-bits, longs sind 64-bits“
Binden von Dateioperationen zur betriebssystemspezifischen
Implementierung dieser Operationen
…
Entscheidungen des Compilers
Typische Beispiele:
„
open() ist mit einem SYS_open Systemaufruf implementiert
Binden eines Algorithmus zu den Befehlen der Programmiersprache mit denen
der Algorithmus implementiert ist
Binden von Namen zu Variablen, welche für einen Algorithmus erforderlich sind
Binden von Datenstrukturen zu Sprachdatentypen
Zeitpunkt der Kompilation
„
„
„
Binden von höheren Konstrukten zu Maschinencode (Optimierung
eingeschlossen)
Binden von statisch definierten Datenstrukturen zu einem spezifischen
Speicherlayout
Binden von benutzerdefinierten Datentypen zu einem spezifischen
Speicherlayout
Namen, Bindungen und Gültigkeitsbereiche
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.4-6
6.4-7
Namen, Bindungen und Gültigkeitsbereiche
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.4-8
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Bindezeitpunkte (5/8)
„
Zeitpunkt des Verbindens (linken)
…
Entscheidungen des Linkers
…
Typische Beispiele:
„
„
„
„
Bindezeitpunkte (6/8)
„
Zeitpunkt der Programmausführung
Linker binden Programmmodule zusammen
Binden von Objekten (Unterprogramme und Daten) zu einem spezifischen
Platz in einer ausführbaren Datei
Binden von Namen, welche Objekte in anderen Modulen referenzieren, zu
deren tatsächlichen Ortsreferenz
…
Entscheidungen welche während der Programmausführung gemacht
werden
…
Typische Beispiele:
Entscheidungen des Laders
…
Typische Beispiele:
„
„
Binden von konkreten Werten zu Programmvariablen
„
Binden von Referenzen von dynamisch zugeteilten Objekten zu
Speicheradressen
Binden von Namen zu Objekten in Sprachen mit dynamischen
Gültigkeitsbereichen
…
Zeitpunkt des Ladens
…
„
Lader holen ausführbare Dateien in den Speicher
„
„a = a + 1;“
Binden von virtuellen Adressen in der ausführbaren Datei zu den
physikalischen Speicheradressen
…
In modernen Betriebssystemen nicht mehr wirklich notwendig, da das
Betriebssystem virtuelle Adresse zu physikalischen Adressen bindet in dem es
virtuellen Speicher (einschließlich der notwendiger Hardware) verwendet
Namen, Bindungen und Gültigkeitsbereiche
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.4-9
Namen, Bindungen und Gültigkeitsbereiche
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Bindezeitpunkte (7/8)
„
…
„
Bindezeitpunkte (8/8)
Ähnliche Bindeentscheidungen können zu mehreren
Bindezeitpunkten durchgeführt werden
…
„
Statisches Binden (static binding)
…
Linkentscheidungen können zur Linkzeit, Ladezeit (ein Typ des
dynamischen Linken) oder Laufzeit (ein anderer Typ des dynamischen
Linkens) auftreten
Optimierungsentscheidungen können zur Compilezeit, Linkzeit,
Ladezeit und sogar zur Laufzeit (dynamische Optimierung) auftreten
Dynamisches Binden (dynamic binding)
„
Frühe Bindezeitpunkte
…
…
Bezieht sich auf alle Bindeentscheidungen die zur Laufzeit gemacht werden
Verbunden mit größerer Effizienz
„
„
C bindet Variablennamen an die referenzierten Objekte zur Compilezeit
„
…
Bezieht sich auf alle Bindeentscheidungen die vor der Laufzeit gemacht werden
„
Bindeentscheidungen können zu verschiedenen Bindezeitpunkten
in verschiedenen Sprachen getroffen werden
…
Wenn wir in C sagen „foo=bar;“, dann wissen wir genau ob foo und bar
global oder lokal sind oder nicht, von welchem Typ sie sind, ob ihre Typen
für Zuweisungen kompatibel sind oder nicht, etc.
Kompilierte Sprachen laufen typischerweise viel schneller, weil die meisten
Bindeentscheidungen zur Compilezeit getroffen wurden
Ist eine Bindeentscheidung aber erst einmal getroffen worden, dann verlieren wir auch
einiges an Flexibilität
Späte Bindezeitpunkte
…
Verbunden mit größerer Flexibilität
Interpretierte Sprachen erlauben es die meisten Bindeentscheidungen zur Laufzeit zu
treffen, was eine größere Flexibilität erlaubt
…
Wir können in Perl sagen „$foo=$bar;“, und wenn der Name $bar nicht
schon an ein Objekt gebunden ist, dann wird eines erzeugt, und dann zu
$foo zugewiesen
Namen, Bindungen und Gültigkeitsbereiche
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
„
„
Perl (und gilt eigentlich für alle interpretierten Sprachen) bindet
Variablennamen an die referenzierten Objekte zur Laufzeit
„
6.4-10
6.4-11
„
Zum Beispiel, die meisten interpretierten Sprachen erlauben es einem Programm Fragmente
eines anderen Programms dynamisch zu generieren und auszuführen
Da Bindeentscheidungen zur Laufzeit getroffen werden, können interpretierte Sprachen
langsam sein
Namen, Bindungen und Gültigkeitsbereiche
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.4-12
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Zusammenfassung Namen und Bindungen
„
Gültigkeitsbereiche
Namen
…
„
Ein mnemonischer Zeichenname wird verwendet um irgendetwas
anderes zu repräsentieren oder zu benennen
„
„
Beispiel: Variable foo kann die Speicherstelle 10000 referenzieren
Textueller Bereich eines Programms in welchem eine Bindung aktiv
ist
Es gibt grundsätzlich zwei Varianten:
…
Statische Gültigkeitsbereiche (static scopes)
„
„
Bindungen
…
„
„
…
Ist eine Assoziation zwischen zwei Dingen
„
Bindezeit
…
Bindungen zwischen Namen und Objekten hängen vom Programmfluss zur
Laufzeit ab
Nähere Ausführung
…
Die Bindezeit ist die Zeit zu der die Entscheidung über eine solche
Assoziation gemacht wird
„
Dynamische Gültigkeitsbereiche (dynamic scopes)
„
Ein Name und das was er referenziert
Es kann zur Compilezeit genau festgestellt werden welcher Name welches
Objekt an welchen Punkten im Programm referenziert
Der Prozess durch den eine Menge von Bindungen aktiv wird wenn die
Kontrolle in einen Gültigkeitsbereich eintritt
„
Zum Beispiel die Allokation von Speicher um Objekte darin zu halten
Beispiel: Ist der Wert von foo in einem Register oder im Speicher?
(Entscheidung wird zur Compilezeit gemacht)
Namen, Bindungen und Gültigkeitsbereiche
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.4-13
Namen, Bindungen und Gültigkeitsbereiche
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Gültigkeitsbereiche
„
…
„
Static scope: Verschachtelte Unterprogramme
Referenzierende Umgebung (referencing environment)
…
„
Die Menge von aktiven Bindungen zu einem gegebenen Zeitpunkt in
der Programmausführung
Wird durch die Regeln für Gültigkeitsbereiche einer
Programmiersprache festgelegt
Statische Gültigkeitsbereiche
…
Bindungen zwischen Namen und Objekten könne zur Compilezeit
festgestellt werden
Einfache Varianten
…
Komplexe Varianten
…
„
„
6.4-14
Frage:
…
„
Welches Objekt wird von X im
Funktionsblock von F1 referenziert?
Regel über den nächsten
Gültigkeitsbereich
(closest nested scope )
…
Referenzen von Variablen
referenzieren das Objekt im
naheliegendsten Gültigkeitsbereich
Frühe Versionen von BASIC hatten einen, globalen Gültigkeitsbereich
Moderne Programmiersprachen erlauben verschachtelte Unterprogramme
und Module weshalb kompliziertere Regeln für Gültigkeitsbereiche
erforderlich sind
Namen, Bindungen und Gültigkeitsbereiche
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.4-15
Namen, Bindungen und Gültigkeitsbereiche
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.4-16
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Ein Problem welches nicht von verschachtelten Unterprogrammen
behandelt wird (1/2)
„
„
„
Ein Problem welches nicht von verschachtelten Unterprogrammen
behandelt wird (2/2)
Geheimnisprinzip (information hiding) für komplexe abstrakte
Datentypen (ADT)
Für einfache ADTs könnten Funktionen mit statischen lokalen
Variablen funktionieren
Siehe Beispiel auf nächster Folie:
…
Die Variable name_nums behält seinen Wert über Aufrufe von
gen_new_name bei
…
Dies ist zu einfach für ADTs mit mehreren Funktionen die sich einen
globalen Zustand teilen müssen
Namen, Bindungen und Gültigkeitsbereiche
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.4-17
Namen, Bindungen und Gültigkeitsbereiche
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Module
„
Ein Modul Beispiel
Ein Modul erlaubt es eine Sammlung von Objekten zu kapseln, so
dass
„
Objekte innerhalb eines Moduls sich gegenseitig sehen können
Objekte innerhalb des Moduls nach außen nicht sichtbar sind, es sei
denn sie werden explizit exportiert
Objekte von außerhalb nach innen nicht sichtbar sind, es sei denn sie
werden explizit importiert
„
…
…
…
„
Abstraktion eines Stacks in
Modula
Wir exportieren die push
und pop Funktionen
Außerhalb des Moduls nicht
sichtbar
…
…
„
Top des Stackzeigers „top“
Stack array „s“
Module mit geschlossenem Gültigkeitsbereich
…
„
6.4-18
Betrifft Module in welche Namen explizit importiert werden müssen um
innerhalb des Moduls sichtbar zu sein
Module mit offenem Gültigkeitsbereich
…
Betrifft Module für die es nicht explizit erforderlich ist Namen von
außerhalb zu importieren um sichtbar zu sein
Namen, Bindungen und Gültigkeitsbereiche
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.4-19
Namen, Bindungen und Gültigkeitsbereiche
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.4-20
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Dynamische Gültigkeitsbereiche
„
Bindungen zwischen Namen und Objekten hängen vom
Programmfluss zur Laufzeit ab
…
„
Statische vs. dynamische Gültigkeitsbereiche
„
…
Reihenfolge in welcher Unterprogramme aufgerufen werden ist wichtig
„
Die Regeln für dynamische Gültigkeitsbereiche sind normalerweise
einfach
…
Statischer Gültigkeitsbereich
Die aktuelle Bindung zwischen Name und Objekt ist diejenige die
während der Ausführung als letzte angetroffen wurde (sprich diejenige
die am kürzlichsten gesetzt wurde)
Dynamischer Gültigkeitsbereich
…
„
Programm gibt 1 aus
Programm gibt 1 oder 2 aus in
Abhängigkeit des gelesenen
Wertes in Zeile 8
Warum?
…
Ist die Zuweisung zu „a“ in
Zeile 3 eine Zuweisung zu dem
globalen „a“ von Zeile 1 oder
dem Lokalen „a“ von Zeile 5?
Namen, Bindungen und Gültigkeitsbereiche
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.4-21
Namen, Bindungen und Gültigkeitsbereiche
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Vorteile von dynamischen Gültigkeitsbereichen
„
Ein Problem von dynamischen Gültigkeitsbereichen
Was sind die Vorteile von dynamischen Gültigkeitsbereichen?
…
…
6.4-22
„
Problem: unvorhersagbare referenzierende Umgebungen
„
Globale Variable max_score wird verwendet von scaled_score()
max_score wird umdefiniert in foo()
scaled_score() wird von foo() aufgerufen
Ahhhhh
Es erleichtert die Anpassung von Unterprogrammen
Beispiel:
begin --nested block
print_base: integer := 16
print_integer(n)
„
Die Variable print_base kontrolliert die Basis welche print_integer für
die Ausgabe von Zahlen verwendet
„
print_integer kann früh in einem globalen Gültigkeitsbereich mit einem
Standardwert belegt werden und kann temporär in einem globalen
Gültigkeitsbereich auf eine andere Basis überschrieben werden
„
„
„
Namen, Bindungen und Gültigkeitsbereiche
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.4-23
Namen, Bindungen und Gültigkeitsbereiche
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.4-24
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Vermischte Gültigkeitsbereiche (mixed scoping)
„
Zusammenfassung für Gültigkeitsbereiche
Perl unterstützt beide Arten, dynamische wie statische
Gültigkeitsbereiche
Dynamic Scoping
„
Static Scoping
$i = 1;
$i = 1;
sub f {
sub f {
local($i) = 2;
my($i) = 2;
return g();
return g();
}
}
sub g { return $i; }
sub g { return $i; }
print g(), f();
print g(), f();
Ausgabe:
1 2
Ausgabe:
1 1
Statische Gültigkeitsbereiche
…
Wird von den meisten, kompilierten Hochsprachen verwendet
…
Bindungen von Namen zu Variablen können zur Compilezeit festgestellt
werden
Effizient
„
…
„
C, C++, Java, Modula, etc.
Dynamische Gültigkeitsbereiche
…
Wird von vielen interpretierten Sprachen verwendet
…
Bindungen von Namen zu Variablen können eine Feststellung zur
Laufzeit benötigen
Flexibel
„
…
Ursprüngliches LISP, APL, Snobol und Perl
Namen, Bindungen und Gültigkeitsbereiche
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.4-25
6. Sprachen, Compiler und Theorie
Ausblick
„
„
„
„
Namen, Gültigkeitsbereiche und Bindungen (Kapitel 3)
Speichermanagement und Implementierung
Kontrollfluss (Kapitel 6)
Zusammenführung (Bau eines ausführbaren Programms) (Kapitel 9)
Namen, Bindungen und Gültigkeitsbereiche
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.4-27
Namen, Bindungen und Gültigkeitsbereiche
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.4-26
6. Sprachen, Compiler und Theorie
Inhalt
Lebensdauer von Objekten
Speichermanagement
Weiterführende Spracheigenschaften und Bindungen
„
„
Informatik II
„
…
SS 2004
…
Implementierung von statischen Gültigkeitsbereichen für verschachtelte
Unterprogramme
Implementierung von Unterprogrammreferenzen
Teil 6: Sprachen, Compiler und Theorie
5 – Speichermanagement und Implementierung
Prof. Dr. Dieter Hogrefe
Dipl.-Inform. Michael Ebner
Lehrstuhl für Telematik
Institut für Informatik
Speichermanagement und Implementierung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Objektlebensdauer (1/3)
„
…
…
…
…
…
„
„
Objekt wird erzeugt
Bindungen zum Objekt werden erzeugt
Referenzen zu den Variablen, Unterprogrammen und Typen werden
durch Bindungen gemacht
Deaktivierung und Reaktivierung von temporär nicht verwendbaren
Bindungen
Vernichtung von Bindungen
Vernichtung des Objekts
Lebensdauer
des Objekts Bar
int b;
b = b + 1; ...
Deaktiviere Bindung von b zu Bar
}
Reaktiviere Bindung von b zu Bar
}
Beispiel: Zeit während der eine Java Referenz ein Objekt im Speicher
referenziert
Beispiel: Zeit während der ein Objekt im Speicher „lebt“
„
Anmerkung: Das durch foo() erzeugte Objekt Bar ist nicht unbedingt nach
der Rückkehr aus dem Unterprogramm zerstört. Es kann nach der Rückkehr
von foo() nicht länger referenziert werden, aber es wird wahrscheinlich erst
bei der „garbage collection“ zu einem späteren Zeitpunkt in der
Programmausführung zerstört werden.
Speichermanagement und Implementierung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
Bar b = new Bar();
while(1) {
Binde Namen b an Objekt Bar
Lebensdauer von Objekten: Zeit zwischen Erzeugung und
Vernichtung eines Objekts
…
Beispiel:
public void foo (void) {
Lebensdauer von Bindungen: Zeit zwischen Erzeugung und
Vernichtung einer Bindung
…
„
Objektlebensdauer (2/3)
Schlüsselereignisse während der Lebensdauer eines Objektes
…
6.5-2
6.5-3
Speichermanagement und Implementierung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.5-4
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Objektlebensdauer (3/3)
„
Statische Allokation
Die Lebenszeit eines Objekts korrespondiert mit einem von drei
Hauptmechanismen der Speicherallokation
…
…
Globale Variablen
…
Konstante Variablen welche während der Programmausführung sich
nicht ändern sollten
…
Der Programmcode (Unterprogramme, etc.)
…
Vom Compiler produzierte Informationen zum Debuggen
Falls eine Sprache rekursive Unterprogrammaufrufe nicht untersützt,
dann auch lokale Variablen, Unterprogrammargumente,
Rückgabewerte, vom Compiler generierte temporäre Daten, etc.
„
Objekte werden zur Compilezeit oder Laufzeit zu festen Speicherplätzen
allokiert
Stack Allokation
„
„
Objekte werden zur Laufzeit wie benötigt allokiert, wobei eine last-in, first-out
Ordnung gilt
…
…
Was wird statisch allokiert?
Statische Allokation
„
…
„
„
Beispiel: Lokales
Heap Allokation
„
…
Objekte werden zur Laufzeit in einer beliebigen Reihenfolge allokiert und
freigegeben
…
Beispiel: dynamisch allokierte Objekte
Beispiel: Statische Klassenvariablen
Beispiel: “i=%d\n” ist konstant in printf(“i=%d\n”,i);
Ausnahme: dynamisch verbundene Unterprogramme
Speichermanagement und Implementierung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.5-5
Speichermanagement und Implementierung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Beispiel: Statische Allokation von Lokalem
„
„
Allokation über einen Stack (1/2)
Keine Rekursion
bedeutet das es zu
einer Zeit nur eine
aktive Instanz bzw.
Aktivierung einer
Instanz von jedem
gegebenen
Unterprogramm
geben kann
„
„
Daher können wir für
eine einzelne,
mögliche Aktivierung
für jedes
Unterprogramm eines
Programms den
Speicher statisch
reservieren
„
Fall eine Sprache Rekursion erlaubt, dann kann jedes
Unterprogramm mehrere simultane Aktivierungen haben
Beispiel:
public int foo (int n) {
int a, b, c;
a = random(); b = random();
if (n > 0) { c = foo(n-1); }
c = c * (a + b);
}
Wir können n Aktivierungen von foo() haben und jede benötigt
Speicherplatz um die eigenen Kopien von a, b, c,
Übergabeargument n und jeden temporären, vom Compiler
generierten Wert zu speichern
Speichermanagement und Implementierung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.5-6
6.5-7
Speichermanagement und Implementierung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.5-8
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Allokation über einen Stack (2/2)
„
„
„
Allokation über einen Heap
„
Die Lösung für das
Rekursionsproblem ist die
Allokation über einen
Stack (stack allocation)
„
Wir wissen wie Code für Globales, Lokales, Konstanten,
Temporäres, etc. allokiert wird
Was bleibt übrig:
…
Dynamisch allokierte Objekte
Warum können diese nicht statisch allokiert werden?
…
Warum können diese nicht auf einem Stack allokiert werden?
…
„
„Push“ Stack um Platz für
Lokales (locals) für
Unterprogrammaufrufe zu
reservieren
„
Weil sie dynamisch erzeugt werden
Ein Objekt, welches dynamisch von einem Unterprogramm erzeugt wurde,
könnte die Aktivierung des Unterprogramms überleben
…
„Pop“ Stack um Platz für
Lokales (locals) bei der
Rückkehr von einem
Unterprogramm wieder
freizugeben
„
Heaps lösen dieses Problem
…
„
Beispiel: Objekt wird einem Globalen zugewiesen oder von dem Unterprogramm
zurückgegeben
Ein Heap ist eine Speicherregion in welcher Speicherblöcke jederzeit
willkürlich allokiert und wieder freigegeben werden können
Wie sind Heaps implementiert?
…
Wie handhaben wir Anfragen zur Allokation und Freigabe?
Speichermanagement und Implementierung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.5-9
Speichermanagement und Implementierung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Heap-Management (1/4)
„
„
„
„
Heap-Management (2/4)
Heap
Heap
Allokationsanforderung
Allokationsanforderung
Wir bekommen eine Allokationsanforderung für n Bytes vom Speicher
Der Heap hat verwendete (dunkle) und freie (helle) Bereiche
Wie wählen wir einen freien Bereich um eine Allokationsanforderung
zu befriedigen?
Einfache Antwort:
…
…
Finde den ersten freien Bereich welcher groß genug ist der Allokation zu
entsprechen (wird first fit genannt)
Problem: interne Fragmentierung
„
Wenn wir n Bytes anfordern und der erste, verfügbare freie bereich hat n+k
Bytes, dann verschwenden wir k Bytes durch die Allokation im ersten Bereich
„
Eine bessere Antwort (vielleicht):
…
…
Finde den ersten Bereich, welcher von der Größe am nächsten zur
Allokationsanforderung ist (wird best fit genannt)
Problem: Zeitaufwendiger
„
„
Muss alle freie Blöcke finden um den Besten zu finden
Es kann immer noch interne Fragmentierung geben, aber hoffentlich
weniger als bei first fit
Speichermanagement und Implementierung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.5-10
6.5-11
Speichermanagement und Implementierung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.5-12
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Heap-Management (3/4)
„
Heap
Heap
Allokationsanforderung
Allokationsanforderung
Ein anderes Problem: externe Fragmentierung
…
Wir bekommen eine Allokationsanforderung für n Bytes und der Heap
hat mehr als n Bytes frei, aber
„
…
„
Heap-Management (4/4)
„
…
kein einzelner freier Bereich ist n Bytes groß oder größer
…
Explizit:
„
Wir haben genügend freien Speicher, aber wir können die
Allokationsanforderung nicht befriedigen
Der Programmierer muss dem Heap-Manager mitteilen dass ein Bereich
nicht länger vom Programm verwendet wird
…
…
Mögliche Lösungen:
…
Wie handhaben wir die Freigabe?
Automatisch:
„
Vereinigung von Bereichen: wenn zwei benachbarte Bereiche mit j und
k Bytes frei sind, dann vereinige diese zu einem einzelnen, freien
Bereich mit j+k Bytes
Ist eine Verbesserung, aber kann nicht alle externen Fragmentierungen
eliminieren
Beispiel: verwende in C free(p) um den Bereich freizugeben auf den p zeigt
„
Das Laufzeitsystem bestimmt welche Objekte auf dem Heap lebendig
(sprich immer noch an Namen gebunden sind) oder tot (sprich nicht länger
zu irgendeinem Namen gebunden sind) sind und gibt die toten Objekte
automatisch frei
Wird Garbage Collection (Speicherbereinigung) genannt
Speichermanagement und Implementierung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.5-13
Speichermanagement und Implementierung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Speicherbereinigung (Garbage Collection) (1/2)
„
Speicherbereinigung (Garbage Collection) (2/2)
Warum verwenden wir Speicherbereinigung?
…
„
…
„
Verhindert:
„
Speicherlöcher (memory leak): Programmierer können die Freigabe von
dynamisch allokiertem Speicher vergessen
Dangling pointers: Programmierer können ein Objekt freigeben bevor alle
Referenzen darauf zerstört sind
Warum Speicherbereinigung nicht verwenden?
…
Teuer: Festzustellen welche Objekte lebendig und welche tot sind
kostet Zeit
…
Schlecht für Echtzeitsysteme: Können normalerweise nicht
garantieren wann die Speicherbereinigung laufen wird und wie lange es
dauern wird
…
Schwierig zu implementieren: Das Schreiben einer
Speicherbereinigung ist schwierig und macht den Compiler und die
Laufzeit einer Sprache komplizierter
…
Sprachdesign: Einige Sprachen wurden nicht mit dem Gedanken an
eine Speicherbereinigung entworfen, was es schwierig machte eine
Speicherbereinigung zuzufügen
Reduzieren den Programmieraufwand und resultiert in zuverlässigeren
Programmen
Speichermanagement und Implementierung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.5-14
6.5-15
Speichermanagement und Implementierung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.5-16
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Weiterführende Spracheigenschaften und Bindungen
„
„
Implementierung von statischen Gültigkeitsbereichen (1/2)
Wie implementieren wir statische Gültigkeitsbereiche in Sprachen
die verschachtelte Unterprogramme erlauben?
Wie implementieren wir Referenzen auf Unterprogramme?
„
Problem:
…
void a (void) {
int foo1;
Von c(), wie
referenzieren wir
nichtlokale Variablen
in a() und b()?
void b (void) {
int foo2;
void c (void) {
int foo3 = foo1 + foo2;
}
void d (void) {
}
}
void e (void) {
}
}
Speichermanagement und Implementierung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.5-17
Speichermanagement und Implementierung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Implementierung von statischen Gültigkeitsbereichen (2/2)
„
Lösung: statische Links
…
…
…
…
Implementierung von Referenzen auf Unterprogramme - 1
„
Jede Aktivierung eines
Unterprogramms speichert einen
Zeiger zum nächsten, umgebenden
Gültigkeitsbereich in seinem
Stackrahmen
c() bekommt seine eigenen Lokalen
von seinem eigenen Stackrahmen
c() bekommt die Nichtlokalen in b()
durch die einmalige
Dereferenzierung seines statischen
Links
c() bekommt die Nichtlokalen in a()
durch die Dereferenzierung seines
statischen Links zu b() und dann
b()‘s statischen Link zu a()
Große Frage:
…
„
Wie wenden wir Gültigkeitsbereichsregeln in Sprachen an wo
Unterprogramme als Wert übergeben werden können?
Zwei Antworten:
…
Flache Bindung (shallow binding):
„
„
…
Referenzierende Umgebung wird sofort festgestellt bevor das referenzierte
Unterprogramm aufgerufen wird
Ist normalerweise der Standard in Sprachen mit dynamischen
Gültigkeitsbereichen
Tiefe Bindung (deep binding):
„
Referenzierende Umgebung wird festgestellt wenn die Referenz auf das
Unterprogramm erzeugt wird
Speichermanagement und Implementierung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.5-18
6.5-19
Speichermanagement und Implementierung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.5-20
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Tiefe vs. flache Bindung
„
Flache Bindung (shallow)
…
„
Implementierung von Referenzen auf Unterprogramme - 2
„
Nötig für die line_length
Zuweisung in
print_selected_records um
das print_person
Unterprogramm zu erreichen
…
„
Nötig für die threshold
Zuweisung im
Hauptprogramm um das
older_than Unterpogramm
zu erreichen
Ein Zeiger auf den Code des Unterprogramms und ein Zeiger auf die
referenzierende Umgebung des Unterprogramms
Warum benötigen wir einen Zeiger auf die referenzierende
Umgebung?
…
Tiefe Bindung (deep)
…
Zum Abschluss
Wir müssen einen Weg für das Unterprogramm haben mit welcher es
Zugriff auf seine nichtlokalen, nichtglobalen Variablen hat
„
„
Für Sprachen mit dynamischen Gültigkeitsbereichen schließt dies Variablen
in den umschließenden, dynamisch verschachtelten Unterprogrammen ein
(Unterprogramme die andere aufrufen)
Für Sprachen mit statischen Gültigkeitsbereichen schließt dies Variablen in
den umschließenden, statisch verschachtelten Unterprogrammen ein
Speichermanagement und Implementierung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.5-21
Speichermanagement und Implementierung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Zusammenfassung
„
Ausblick
Lebensdauer von Objekten
…
„
Die Zeitperiode während der ein Name an ein Objekt (Variable,
Unterprogramm, etc.) gebunden ist
„
„
„
„
Namen, Gültigkeitsbereiche und Bindungen (Kapitel 3)
Speichermanagement und Implementierung
Kontrollstrukturen (Kapitel 6)
Zusammenführung (Bau eines ausführbaren Programms) (Kapitel 9)
Speichermanagement
…
„
6.5-22
Statische Allokation, Stacks und Heaps
Weiterführende Spracheigenschaften und Bindungen
…
Implementierung von statischen Gültigkeitsbereichen für verschachtelte
Unterprogramme
…
Implementierung von Unterprogrammreferenzen
„
„
Links auf Stackrahmen ablegen
Ein Zeiger auf den Code des Unterprogramms und ein Zeiger auf die
referenzierende Umgebung des Unterprogramms (flache und tiefe Bindung)
Speichermanagement und Implementierung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.5-23
Speichermanagement und Implementierung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.5-24
6. Sprachen, Compiler und Theorie
Rückblick
„
„
Informatik II
„
Lebensdauer von Objekten
Speichermanagement
Weiterführende Spracheigenschaften und Bindungen
…
SS 2004
…
Implementierung von statischen Gültigkeitsbereichen für verschachtelte
Unterprogramme
Implementierung von Unterprogrammreferenzen
Teil 6: Sprachen, Compiler und Theorie
6 – Kontrollstrukturen
Prof. Dr. Dieter Hogrefe
Dipl.-Inform. Michael Ebner
Lehrstuhl für Telematik
Institut für Informatik
Kontrollstrukturen
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Was fehlt uns noch?
„
„
Kontrollfluss (control flow)
Kontrollfluss
…
„
Das Offensichtliche: Programme machen ihre Arbeit durch
ausführen von Berechnungen
„
Kontrollfluss (control flow) spezifiziert die Reihenfolge in welcher
Berechnungen ausgeführt werden
„
Sprachen stellen eine große Vielfalt von
Kontrollflussmechanismen (control flow mechanism) bereit
welche es dem Programmierer erlauben den Kontrollfluss zu
spezifizieren
Spezifikation der Reihenfolge in welcher Elemente einer höheren
Programmiersprache ausgeführt werden
Kontrollflussmechanismen
…
…
Anweisungen (statements), Schleifen, Unterprogrammaufrufe,
Rekursion, etc.
Übersetzung zu ausführbarem Code
Kontrollstrukturen
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.6-2
6.6-3
Kontrollstrukturen
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.6-4
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Kontrollfluss und Kontrollflussmechanismen
Wichtige Fragen
Iterationen (Wiederholungen)
„
…
…
„
Führt eine Gruppe von Berechnungen mehrmals aus (repeatedly)
Eine von sieben Kategorien von Kontrollflussmechanismen
„
Wie implementieren Sprachen Iterationen?
„
Schleifen: C, C++, Java
for(i=0;i<N;i++) {
do_something(i);
Einige Sprachen verwenden andere
Mechanismen um das gleiche Ziel
zu erreichen
„
Wie lauten die Kategorien von Kontrollflussmechanismen
Welche Eigenschaften stellen Sprachen zur Verfügung um die
Kontrollflussmechanismen einer gegebenen Kategorie zu
implementieren?
Wie übersetzen Compiler Kontrollflussmechanismen in
ausführbaren Code?
Rekursion: ML
fun foo i N =
}
if i < N then
do_something i
Iteratoren: Icon, CLU
foo i + 1 N
every do_something(0 to N-1)
foo 0 N
Kontrollstrukturen
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.6-5
Kontrollstrukturen
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Kategorien von Kontrollflussmechanismen
„
„
„
„
Wähle, basierend auf einer Laufzeitbedingung, welche von mehreren
Berechnungen ausgeführt werden soll
Bestimmt für ein gegebenes Paar von Berechnungen welches
zuerst ausgeführt wird
Zwei Typen von Berechnungen für welche wir die Reihenfolge
betrachten wollen
…
Iteration (iteration)
…
„
Bestimmt für ein gegebenes Paar von Berechnungen welches zuerst ausgeführt
wird
Auswahl (selection)
…
„
Sequentialität (sequencing)
Sequentialität (sequencing)
…
Ausdrücke (expressions)
„
Führt eine Gruppe von Berechnungen mehrmals aus
„
Rekursion (recursion)
…
Prozedurale Abstraktion (procedural abstraction)
…
…
„
„
Berechnungen welche die Werte von Variablen ändern
Beispiel:
…
Erlaubt es Berechnungen „zur gleichen Zeit“ auszuführen
…
Keine Festlegung (Nondeterminancy)
…
„
Reihenfolge zwischen Berechnungen wird unspezifiziert gelassen
zweistellige Ausdrücke: foo + bar
Evaluieren wir zuerst die Unterausdrücke foo oder bar bevor wir die Addition
ausführen?
Zuweisungen (assignments)
„
Nebenläufigkeit (concurrency)
…
„
…
Erlaubt es einer Gruppe von Berechnungen zu bennen, möglicherweise zu
parametrisieren und auszuführen wann immer der Name referenziert wird
Berechnungen die einen Wert erzeugen
Beispiel:
…
Erlaubt es Berechnungen durch sich selbst zu definieren (Allows computations to be
defined in terms of themselves)
„
foo = bar + 1;
bar = foo + 1;
Welche von diesen beiden Zuweisungen evaluieren wir zuerst?
Kontrollstrukturen
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.6-6
6.6-7
Kontrollstrukturen
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.6-8
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Was genau ist eine Ausdruck (expression)?
„
Evaluation von Ausdrücken und Seiteneffekte
Berechnungen welche einen Wert erzeugen
„
Evaluation von Ausdrücken kann zusätzlich zu den Werten auch
Seiteneffekte erzeugen
Beispiele:
…
Variablenreferenzen
…
Konstantenreferenzen
…
1, 2, 3, ‘a’, ‘b’, ‘c’, …
…
„
„
…
Holt den Wert der Variablen aus dem Speicher
„
Operatoren oder Funktionen angewandt auf eine Sammlung von
Unterausdrücken
„
Funktionsaufrufe
…
„
…
„
foo(a,b+10)
Arithmetische Operationen
…
Ausdrücke ohne Seiteneffekte werden „referentially transparent”
genannt
…
foo + bar
int foo (void) { a = 10; return a; }
… foo() + 20 …
Evaluation von „foo()+20“ ergibt den Wert 30 UND als einen
Seiteneffekt die Zuweisung des Wertes 10 an die Globale a
Solche Ausdrücke können als mathematische Objekte behandelt
werden und entsprechend durchdacht
Kontrollstrukturen
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.6-9
Kontrollstrukturen
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Priorität und Assoziativität
„
„
„
Priorität (Precedence)
„
Zwei Wege um die Reihenfolge zu spezifizieren in welcher
Unterausdrücke von komplexen Ausdrücken evaluiert werden
Prioritätsregel
…
…
Beispiel:
…
…
Ähnlich dem mathematischen Konzept mit dem gleichen Namen
Spezifiziert ob Operatoren von der gleichen Prioritätsgruppe zur Linken
oder Rechten zuerst evaluieren
-a * c
Wie ist die Reihenfolge der Evaluierung?
„
Spezifiziert wie Operationen gruppieren wenn Klammern abwesend sind
…
Assoziativität
…
(-a) * c oder –(a * c)???
In C, -, unäre Negierung (unary negation), hat höhere Priorität als *
(Multiplikation), weshalb die erste Klammerung korrekt ist
„
Prioritätsregeln variieren stark von Sprache zu Sprache
„
Frage:
…
…
…
Wie wird in C int i = 0; int *ip = &i; ++*ip++; ausgewertet?
++( ) auf den Wert von *ip++. Der Wert ist der Inhalt der Variablen, auf die ip
verweist. Wenn ip abgerufen wurde, wird ip im nachhinein um eins erhöht
(Zeigerarithmetik).
Daher ist am Ende i = 1 und der Zeiger ip wurde auch um eins erhöht (und
zeigt somit höchstwahrscheinlich ins Nirvana, da kein Bezug zu dieser
Speicherstelle besteht)
Kontrollstrukturen
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.6-10
6.6-11
Kontrollstrukturen
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.6-12
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Assoziativität (Associativity)
„
„
Die Assoziativität ist in Sprachen einheitlicher
Elementare arithmetische Operatoren assoziieren von links nach
rechts
…
…
Operatoren werden von links nach rechts gruppiert und evaluiert
Beispiel (Subtraktion):
„
„
Einige arithmetische Operatoren assoziieren aber von rechts nach
links
…
Beispiel (Potenzieren):
„
„
9 – 3 – 2 evaluiert eher zu (9 – 3) -2 als 9 - (3 - 2)
4**3**2 evaluiert eher zu 4**(3**2) als (4**3)**2
In Sprachen die Zuweisungen in Ausdrücken erlauben, assoziieren
Zuweisungen von rechts nach links
…
Beispiel:
„
„
a = b = a + c evaluiert zu a = (b = a + c)
a + c wird berechnet und b zugewiesen, danach wird b zu a zugewiesen
Kontrollstrukturen
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.6-13
Kontrollstrukturen
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Arbeiten mit Prioritäten und Assoziativität
„
Mehr zur Evaluierungsordnung von Ausdrücken (1/2)
Regeln für Prioritäten und Assoziativität variieren stark von Sprache
zu Sprache
…
„
„
„
Prioritäten und Assoziativität können nicht immer eine
Evaluierungsreihenfolge festlegen
…
In Pascal:
„
Beispiel:
„
„if A < B und C < D then ...“
Könnte zu „if A < (B and C) < D then...“ evaluiert werden
Upps!
„
„
„
„
… Leitfaden/Richtlinie:
„
„
Wenn f(b) die Variablen c oder d modifiziert, dann hängt der Wert des
ganzen Ausdruckes davon ab, ob f(b) zuerst ausgeführt wird oder nicht
Verbesserung des Codes
…
„
a – f(b) – c * d
Mit Prioritäten ergibt sich a – f(b) – (c * d) und weiter mit Assoziativität (a –
f(b)) - (c * d)
Aber welches wird zuerst ausgeführt: a-f(b) oder (c*d)?
Warum kümmert uns das?
Seiteneffekte
…
Im Zweifelsfall lieber Klammern verwenden, speziell
wenn jemand oft zwischen verschiedenen Sprachen
wechselt!
Wir wollen (c*d) zu erst berechnen, so dass wir das berechnete
Ergebnis nicht speichern und wiederherstellen müssen bevor und
nachdem f(b) aufgerufen wird
Nochmals: Im Zweifelsfall Klammern setzen!
Kontrollstrukturen
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.6-14
6.6-15
Kontrollstrukturen
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.6-16
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Mehr zur Evaluierungsordnung von Ausdrücken (2/2)
„
Zuweisungen
Boolesche Ausdrücke
„
…
Ausdrücke die eine logische Operation ausführen und entweder zu wahr (true)
oder falsch (false) evaluieren
… Beispiele:
„
„
„
…
„
„
…
„
„
(a < b) && (c < d)
Wenn (a < b) zu falsch evaluiert wird dann gibt es keinen Bedarf mehr (c <d )
auszuwerten
Siehe Regel R1 aus Kapitel 2, Boolesche Algebra und Gatter
Weisst den Wert, der durch den Ausdruck „ a +b“ berechnet wird, der
Variablen c zu
Zuweisungen sind der fundamentale Mechanismus um
Seiteneffekte zu erzeugen
Beispiel:
„
Beispiel: c = a + b
„
Die Evaluation von booleschen Ausdrücken kann durch die „short
circuiting“ Technik optimiert werden
…
„
a<b
a && b || c oder a & b | c
Berechnungen welche den Wert einer Variablen beeinflussen
Werte die Variablen zugewiesen werden können zukünftige
Berechnungen beeinflussen
Zuweisungen sind unerlässlich für das imperative
Programmiermodel
Dies wird wichtig bei Code nach folgendem Muster:
…
…
if (unwahrscheinliche Bedingung && teure Funktion() ) ...
Wir wollen die Auswertung einer teuren Funktion() verhindern, wenn eine
unwahrscheinliche Bedingung zu falsch ausgewertet wird
Kontrollstrukturen
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.6-17
Kontrollstrukturen
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Was genau ist eine Variable? (1/2)
„
Was genau ist eine Variable? (2/2)
Die Interpretation eines Variablennamens hängt von dem Kontext ab
in welchem er auftritt
„
Zwei Wege um eine Variable zu behandeln
…
Wertemodell
„
„
„
Beispiele:
…
„
d=a
„
Die Referenz zu der Variablen „a“ auf der „rechten Seite“ einer Zuweisung
benötigt einen Wert
…
…
…
„
„
Wird ein r-value-context genannt und das „a“ wird r-value genannt
Variablen sind benannte Referenzen für Werte
Nur die Interpretation als l-value ist möglich
…
Die Referenz zu der Variablen „a“ auf der „linken Seite“ einer Zuweisung
bezieht sich auf a‘s Speicherort
…
Variablen sind benannte Container für Werte
Beide Interpretationen als l-value und r-value von Variablen sind möglich
Modell wird verwendet von Pascal, Ada, C, etc.
Referenzmodell
a=b+c
„
6.6-18
„
Variablen in einem r-value-context müssen „dereferenziert“ werden um einen
Wert zu erzeugen
Modell wird verwendet von Clu
Wird ein l-value-context genannt und das „a“ wird l-value genannt
Wertemodell
Kontrollstrukturen
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.6-19
Referenzmodell
Kontrollstrukturen
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.6-20
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Zuweisungsfolgen
„
Zuweisungsfolgen (assignment sequencing ) ist in den meisten
Sprachen einfach
…
Zuweisungen werden in der Reihenfolge ausgeführt in der sie im
Programmtext auftreten
„
„
Wie initialisieren oder wie weisen wir initiale Werte Variablen zu?
„
Verwende den Zuweisungsoperator um initiale Werte zur Laufzeit
zuzuweisen
…
Beispiel:
…
„
Zuweisungsfolgen: Initialisierung (1/2)
a = 10; b = a; Å Es wird zuerst die 10 dem a zugewiesen und danach wird a dem
b zugewiesen
Probleme:
„
Ausnahmen
…
„
„
…
…
„
Zuweisungsausdrücke
Beispiel: a = b = a * c
Erinnere dich an die Auswertereihenfolge bei Ausdrücken: In den meisten
Programmiersprachen gilt die Assiziation von rechts nach links
Ineffizienz: Wenn wir den initialen Wert einer Variablen zur Compilezeit
kennen, dann kann der Compiler diesen Wert dem Speicher zuweisen ohne
eine Initialisierung zur Laufzeit zu benötigen
Programmierfehler: Wenn Variablen kein initialer Wert bei der Deklaration
zugewiesen wird, dann könnte ein Programm eine Variable verwenden bevor
sie irgendeinen (sinnvollen) Wert enthält
Initialisierung
Kombinationen mit dem Zuweisungsoperator
Kontrollstrukturen
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.6-21
Kontrollstrukturen
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Zuweisungsfolgen: Initialisierung (2/2)
„
Zuweisungsfolgen: Kombinationen
Verwende den Zuweisungsoperator um initiale Werte zur Laufzeit
zuzuweisen
…
„
Lösungen:
„
…
…
„
„
„
Sprachen können einen Defaultwert für jede Deklaration eines eingebauten
(built-in) Typs spezifizieren
…
Ist fehleranfällig und schwierig zu schreiben, da Text wiederholt wird
Kann zu ineffizientem kompilierten Code führen
Lösungen: Kombinationen mit dem Zuweisungsoperator
…
Beispiele:
„
Mache es zu einem Laufzeitfehler, wenn eine Variable verwendet wird bevor ihr
ein Wert zugewiesen wurde
„
…
Mache es zu einem Compilerfehler wenn eine Variable verwendet werden könnte
bevor ihr ein Wert zugewiesen wurde
a = a + 1;
b.c[3].d = b.c[3].d * e;
Probleme:
…
„
Statische Wertkontrollen
…
Beispiele:
„
Beispiel für C: static char s[] = “foo”
Der Compiler kann den Elementen des Arrays s die Werte zur Compilezeit
zuweisen, was uns 4 Zuweisungen zur Laufzeit erspart (eine für jedes Zeichen
plus dem NULL (String-)Terminator)
siehe auch C++ Konstruktorinitialisierung
Dynamische Wertkontrollen
…
„
…
Defaultwerte (Standardwerte/Ausgangswerte/...)
…
„
Gibt es einen effizienteren Weg um komplexe Zuweisungen zu
handhaben?
Statische Initialisierung:
…
a += 1;
b.c[3].d *= e;
Zuweisungen werden mit Operatoren für Ausdrücke kombiniert
„
„
Vermeidet sich wiederholenden Code
Erlaubt es dem Compiler auf einfacherem Wege effizienteren Code zu
generieren
Kontrollstrukturen
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.6-22
6.6-23
Kontrollstrukturen
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.6-24
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Sequentialität: Zusammenfassung
„
Ausdrücke
…
…
…
„
Auswahl (selection) (1/4)
„
Prioritäten und Assoziativität kontrollieren die Reihenfolge
Es müssen Seiteneffekte bei Unterausdrücken beachtet werden
Logische Ausdrücke können von der short-circuit Auswertung profitieren
„
Wähle, basierend auf einer Laufzeitbedingung, welche von
mehreren Berechnungen ausgeführt werden soll
Am häufigsten Ausgeführt vom if..then..else Sprachkonstrukt
…
Zuweisungen
…
…
…
Beispiel:
„
„
Die Folge des Auftretens im Programmtext bestimmt die Reihenfolge
Zuweisungen zur Compilezeit erlauben die Vermeidung von
Zuweisungen zur Laufzeit
Zusammengesetzte Zuweisungsoperatoren kombinieren
Ausdrucksauswertung und Zuweisung um effizienter sein zu können
if ((a < b) && (c < d)) { do_something(); }
Wenn beide bedingte Anweisungen „a<b“ und „c<d“ zu wahr ausgewertet
werden, dann führe die Berechnung, welche durch das Unterprogramm
do_something() referenziert wird, aus
Kontrollstrukturen
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.6-25
Kontrollstrukturen
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Auswahl (selection) (2/4)
„
Auswahl (selection) (3/4)
Short circuiting
…
…
„
„
„
„
Angenommen wir haben Code der ähnlich wie dieser aussieht:
j := … (* something complicated *)
IF j = 1 THEN
clause_A
ELSIF j IN 2, 7 THEN
clause_B
ELSIF j in 3..5 THEN
clause_C
ELSE
clause_D
END
Zur Erinnerung: Kann verwendet werden um unnötige
Ausdrucksauswertungen zu verhinden
Beispiel:
„
if ( (a < b) && (c < d) ) { do_something(); }
Wenn (a < b) falsch ist, dann kann do_something() nicht ausgeführt werden,
egal was (c < d) ergibt
Siehe Regel R1 aus Kapitel 2, Boolesche Algebra und Gatter
Short circuiting wird Code generieren der die Auswertung von (c < d)
genauso ausläßt (skipped) wie die Ausführung von do_something(), wenn (a
< b) falsch ist
„
Problem:
…
Ist kompliziert zu schreiben
Kontrollstrukturen
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.6-26
6.6-27
Kontrollstrukturen
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.6-28
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Auswahl (selection) (4/4)
„
Iteration
„
Lösung: case/switch Befehle
„
„
…
Beispiel:
CASE …
1:
| 2,7:
| 3..5:
ELSE
END
Führt eine Gruppe von Berechnungen mehrmals aus
Sprachen bieten für Iterationen Schleifenkonstrukte an
„
clause_A
clause_B
clause_C
clause_D
…
„
Die Schleife wird solange ausgeführt bis sich eine boolesche Bedingung
ändert
Anmerkung:
…
Ist einfacher zu schreiben und zu verstehen
Die Schleife wird für jeden Wert aus einer endlichen Menge (Aufzählung)
ausgeführt
Logikgesteuerte Schleifen
„
…
„
Aufzählungsgesteuerte Schleifen
…
Der imperative Stil der Programmierung favorisiert Schleifen gegenüber
Rekursion
Iteration und Rekursion können beide verwendet werden um eine
Gruppe von Berechnungen wiederholt auszuführen
Alle Arten von Schleifen können auf die beiden Konstrukte Selektion
(if..then..end) und Sprung (goto) zurückgeführt werden. Wird oft in
Zwischensprachen zur Codegenerierung verwendet.
Kontrollstrukturen
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.6-29
Kontrollstrukturen
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Aufzählungsgesteuerte Schleifen: Probleme (1/3)
„
Aufzählungsgesteuerte Schleifen: Fragen (2/3)
Beispiel von FORTRAN I, II und IV
„
Allgemeine Form von Schleifen:
do 10 i = 1, 10, 2
...
10: continue
FOR j := first TO last BY step DO
…
END
…
Die Variable i wird die Indexvariable genannt und nimmt hier die Werte 1, 3, 5,
7, 9 an
… Die Statements zwischen der ersten und letzte Zeile werden der Schleifenrumpf
(loop body) genannt und wird hier für jeden der fünf Werte von i einmal
ausgeführt
„
Probleme:
Der Schleifenrumpf wird immer mindestens einmal ausgeführt
… Statements im Schleifenrumpf könnten i ändern und somit würde auch das
Verhalten der Schleife verändert werden
… Goto Statements können in oder aus der Schleife springen
…
„
Fragen die zu dieser Schleifenart zu stellen sind:
3.
Kann j, first und/oder last im Schleifenrumpf verändert werden?
Wenn ja, welchen Einfluss hat dies auf die Steuerung?
Was passiert wenn first größer als last ist?
Welchen Wert hat j wenn die Schleife beendet wurde?
4.
Kann die Kontrolle von außerhalb in die Schleife hineinspringen?
1.
2.
…
„
6.6-30
Goto-Sprünge in die Schleife hinein, wobei i nicht vernünftig initialisiert wird, werden
wahrscheinlich in einem Laufzeitfehler enden
Die Schleife wird beendet wenn der Wert von i die obere Grenze überschreitet.
Dies könnte einen (unnötigen) arithmetischen Überlauf veranlassen, wenn die
obere Grenze in der Nähe des größten, zulässigen Wertes von i liegt
Kontrollstrukturen
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.6-31
Kontrollstrukturen
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.6-32
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Aufzählungsgesteuerte Schleifen: Antworten (3/3)
„
„
Können der Schleifenindex oder die Grenzen verändert werden?
…
Ist bei den meisten Sprachen verboten
Algol 68, Pascal, Ada, Fortran 77 und 90, Modula-3
„
Was passiert wenn first größer als last ist?
„
„
„
Iteratoren
…
…
Die meisten Sprachen werten first und last aus bevor die Schleife ausgeführt wird
… Falls first größer als last ist, dann wird der Schleifenrumpf niemals ausgeführt
„
Welchen Wert hat der Schleifenindex j am Ende der Schleife?
„
…
Ist in einigen Sprachen nicht definiert, z.B. Fortran IV oder Pascal
… In den meisten Sprachen gilt der zuletzt definierte Wert
… Einige Sprachen machen die Indexvariable zu einer lokalen Variablen der Schleife,
weswegen die Variable außerhalb des Gültigkeitsbereiches der Schleife nicht sichtbar ist
„
Beispiel:
“every write (1 + upto(‘ ‘, s))” in ICON schreibt jede Position in den String s
welcher ein Leerzeichen folgt
… upto(‘ ‘,s) erzeugt jede Position in s gefolgt von einem Leerzeichen
„
…
Nein, für die meisten Sprachen
Viele Sprachen erlauben aber den Sprung von innen nach außen
… Viele Sprachen bieten Anweisungen (break; exit; last, etc,) an, die einen frühzeitige
Abbruch der Schleife ohne expliziten Sprung erlauben
Die “FOR j := first TO last BY step DO … END” Schleife kann auch geschrieben
werden als
“every j := first to last by step do { … }” in ICON
…
Kann die Kontrolle von außerhalb in die Schleife hineinspringen?
…
Alle bisher betrachteten Schleifen iterieren über eine arithmetische Folge
(1,3,5,7)
Aber wie iterieren wir über eine frei wählbare Menge von Objekten?
Antwort: Iteratoren
„
Iteratoren sind Ausdrücke die mehrere Werte generieren und welche Ihre
enthaltende Ausdrücke und Statements bestimmen können um diese
mehrmals auszuwerten oder auszuführen
Ein anderes Beispiel:
…
…
„
“write(10 + 1 to 20)” schreibt 10 + j für jedes j zwischen 1 und 20
1 bis 20 erzeugt die Folge 1 bis einschließlich 20
Siehe auch Standard Template Library (STL) von C++
Kontrollstrukturen
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.6-33
Kontrollstrukturen
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Logikgesteuerte Schleifen
„
Rekursion
Beispiele:
…
„
„
„
…
for(Vor-Anweisung; Bedingung; Nach-Anweisung ) Block
Nachprüfende Schleife
„
…
„
Mit anderen Worten, komplexe Berechnungen werden mit Begriffen von
einfacheren Berechnungen ausgedrückt
Ähnlich dem Prinzip der mathematischen Induktion
Ist die bevorzugte Methode der wiederholenden
Programmausführung in funktionalen Sprachen
…
„repeat Anweisung until Bedingung“
„do Anweisung while Bedingung“
Diese Art von Schleife werden oft falsch verwendet und sollten daher
vermieden werden
(da mindest ein Durchlauf erfolgt!)
…
Eigentlich ist es die meiste Zeit der einzigste Weg um Berechnungen in
funktionalen Sprachen wiederholt auszuführen
Warum?
„
Prüfung in der Mitte einer Schleife
„
Erlaubt es Berechnungen durch sich selbst zu definieren
…
„while Bedingung do Anweisung“
Die C for-Schleife ist eine vorprüfende, logikgesteuerte Schleife und nicht
eine aufzählungsgesteuerte Schleife!
…
…
„
Vorprüfende Schleife
„
…
„loop Anweisung when Bedingung exit Anweisung end“
Weil für die Alternative, nämlich Iteration (Schleifen), die Ausführung von
Anweisungen mit Seiteneffekten (wie Zuweisungen) verbunden ist, was in
rein funktionalen Sprachen verboten ist
Dies ist nicht wirklich eine Einschränkung da Rekursion streng
genommen genauso Mächtig ist wie Iteration und umgekehrt
Kontrollstrukturen
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.6-34
6.6-35
Kontrollstrukturen
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.6-36
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Rekursion und Iteration
„
Verbesserte Durchführung von Rekursion
„
Informell gesprochen, die Schleife
“FOR j := first TO last BY step DO … END”
wird durch Rekursion zu:
fun loop j step last =
if j <= last then
…
loop j + step step last
fun loop j step last =
if j <= last then
…
loop j + step step last
„
Gegebene Schleife
„
Der rekursive Aufruf der Schleife „loop“ ist die letzte ausgeführte
Berechnung der Funktion „loop“
„
Geschickte Compiler werden Endrekursionen durch eine Schleife
ersetzen
…
Es gibt mit der rekursiven Emulation von Iteration aber ein Problem:
sie ist langsam!
…
…
Wird Endrekursion (tail recursion) genannt
Argumente für den Aufruf der Endrekursion werden ausgewertet und in
den entsprechenden Lokalen platziert und ein Sprung zurück zum
Anfang der Funktion wird gemacht anstatt einen rekursiven Aufruf zu
machen
Dies kann zu einer signifikanten Steigerung der Leistung führen
Kontrollstrukturen
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.6-37
Kontrollstrukturen
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Evaluationskonzepte von Funktionsargumenten
„
Ausblick
Wie werden Argumente für Funktionen ausgewertet?
…
„
…
„
Die Argumente einer Funktion werden ausgewertet bevor die Funktion die
Steuerung erhält?
„
Wird Applicative-Order Evaluation (eager evaluation, call-by-value) bezeichnet
Ist der Standard in den meisten Sprachen
Die Argumente einer Funktion werden nur dann ausgewertet, wenn sie
auch benötigt werden?
„
„
„
6.6-38
„
„
„
Namen, Gültigkeitsbereiche und Bindungen (Kapitel 3)
Speichermanagement und Implementierung
Kontrollfluss (Kapitel 6)
Zusammenführung (Bau eines ausführbaren Programms)
(Kapitel 9)
Wird Normal-Order Evaluation (lazy evaluation‚ call by need, delayed evaluation)
bezeichnet
Kann zu einer besseren Leistung führen wenn an eine Funktion übergebene
Argumente manchmal nicht gebraucht werden
Beispiel:
void foo (int a, int b, int c) {
if (a + b < N) { return c; } else { return a + b; }
foo(a,b,expensive_function())
…
In einigen Fällen wird „c“ nicht benötigt, und der Wert von c könnte von einerteuer zu
berechnenden Funktion bestimmt werden
Kontrollstrukturen
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.6-39
Kontrollstrukturen
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.6-40
6. Sprachen, Compiler und Theorie
Der Kompilationsprozess (-phasen)
Informatik II
Scanner (lexikalische Analyse)
Lese Programm und konvertiere Zeichenstrom in Marken
(tokens). Theorie: Reguläre Ausdrücke, endlicher Automat
Parser (syntaktische Analyse)
Lese Tokenstrom und generiere Ableitungsbaum (parse
tree). Theorie: Kontextfreie Grammatiken, Kellerautomat
SS 2004
Traversiere Parserbaum, überprüfe nicht-syntaktische
Regeln.
Semantische Analyse
Teil 6: Sprachen, Compiler und Theorie
Zwischencodegenerierung
Traversiere Parserbaum noch mal, gebe Zwischencode
aus.
Optimierung
Untersuche Zwischencode, versuche ihn zu verbessern.
Zielcodegenerierung
Übersetze Zwischencode in Assembler-/Maschinencode
Optimierung Maschinenebene
Untersuche Maschinencode, versuche ihn zu verbessern.
7 – Zusammenführung
Prof. Dr. Dieter Hogrefe
Dipl.-Inform. Michael Ebner
Lehrstuhl für Telematik
Institut für Informatik
Zusammenführung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Die Organisation eines typischen Compilers
„
„
Schreiben des Programms
Frontend
…
„
Führt Operationen aus
welche von der zu
kompilierenden Sprache
abhängen und nicht von
der Zielmaschine
Backend
…
Führt Operationen aus
welche etwas Wissen
über die Zielmaschine
haben müssen
Ein kleines Programm,
geschrieben in Pascal,
welches den größten
gemeinsamen Teiler
(ggT) von zwei
Ganzzahlen berechnet
program gcd (input, output);
var i, j : integer;
begin
read(i,j);
while i <> j do
if i > j then i := i – j
else j :- j – i;
writeln(i)
end.
Zusammenführung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.7-2
6.7-3
Zusammenführung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.7-4
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Vom Text des Quellcodes zu den Tokens
Von den Tokens zum Ableitungsbaum
Programmquelltext
Programmquelltext
program gcd (input, output);
var i, j : integer;
begin
read(i,j);
while i <> j do
if i > j then i := i – j
else j :- j – i;
writeln(i)
end.
Tokens
program
gcd
(
input
,
output
)
;
var
i
,
j
:
integer
;
begin
read
(
i
,
j
)
;
while
i
<>
j
do
if
i
Ableitungsbaum und Symboltabelle
program gcd (input, output);
var i, j : integer;
begin
read(i,j);
while i <> j do
if i > j then i := i – j
else j :- j – i;
writeln(i)
end.
…
Zusammenführung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
Zusammenführung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.7-5
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Zwischencode
„
„
„
Nicht optimierende Compiler
„
Der Ableitungsbaum wird zu
einem Kontrollflussgraphen
konvertiert
Die Knoten des
Kontrollflussgraphen sind
grundlegende Blöcke und
enthalten eine pseudoAssemblersprache
Die Kontrolle kann einen
grundlegenden Block nur vom
Anfang betreten und kann in
nur am Ende wieder
verlassen
„
„
Der Kontrollflussgraph wird
zum Zielcode der
Zielmaschine konvertiert
Der Zielcode ist eine andere
pseudo-Assemblersprache
Der Kontrollfluss wird
ausführlich gemacht durch:
…
…
„
Bezeichnen der Anfänge
der grundlegenden Blöcke
Konvertieren der
Kontrollflusskanten zu
Sprung- (branch), Aufruf(call) und
Rückkehrinstruktionen
Virtuelle Register werden
durch reale Register ersetzt
Zusammenführung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.7-6
6.7-7
Zusammenführung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.7-8
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Zielcode
„
Der Zielcode ist beinahe
Assemblercode
…
…
…
„
Vom Zielcode zum Assemblercode
„
Normalerweise einfach:
…
Der Kontrollfluss ist
ausführlich
Der Code referenziert nur
reale Registernamen
Anweisungen zum
Speicherreservieren sind
vorhanden
…
„
r10 := r8 + r9 -> add $10, $8, $9
r10 := r8 + 0x12 -> addi $10, $8, 0x12
Manchmal auch zu einer Folge von Instruktionen erweitert:
…
r14 := 0x12345abc ->
„
„
lui $14, 0x1234
ori $14, 0x5abc
Zielcode ist einfach zu
Assemblercode zu
übersetzen
Zusammenführung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
Zusammenführung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.7-9
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Binden (linking)
Optimierende Compiler
„
„
Beim Binden
werden mehrere
durch den
Assembler erzeugte
Objektdateien zu
einer einzelnen,
ausführbaren
Datei kombiniert,
welche durch ein
Betriebssystem
lauffähig ist
„
„
„
Optimierung ist ein komplexer
Prozess
Verbessert die Qualität des
generierten Codes auf Kosten
von zusätzlicher Compilezeit
Optimierer sind schwierig zu
schreiben und einige
Optimierungen verbessern das
fertige Programm vielleicht nicht
Praxistip: Die jeweilige
Einstellung der Optimierungstiefe
eines Compilers genau auf
korrekte Funktion kontrollieren,
da diese öfters fehleranfällig sind
(lieber erstmal auf Optimierung
verzichten und erst am Ende
austesten!)
Zusammenführung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.7-10
6.7-11
Zusammenführung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.7-12
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Peephole-Optimierung
„
„
„
Sehe dir den Zielcode an, wenige Instruktionen gleichzeitig, und
versuche einfache Verbesserungen zu machen
Versucht kurze, sub-optimale Folgen von Instruktionen zu finden
und ersetzt diese Sequenzen mit einer „besseren“ Sequenz
Sub-Optimale Sequenzen werden durch Muster (patterns)
spezifiziert
…
„
Peephole-Optimierungstypen (1/3)
Redundante load/store Instruktionen beseitigen
„
r2
i
r3
r4
Meistens heuristische Methoden — Es gibt keinen Weg um zu
überprüfen ob das Ersetzen eines sub-optimalen Musters tatsächlich
das endgültige Programm verbessern wird
:=
:=
:=
:=
r1 + 5
r2
i
r3 x 3
wird zu
r2 := r1 + 5
i := r2
r4 := r2 x 3
Konstantenfaltung (constant folding)
„
r2 := 3 x 2
Einfach und ziemlich wirksam
wird zu
r2 := 6
Entfernung gemeinsamer Teilausdrücke (common subexpression elimination)
„
r2 := r1 x r5
r2 := r2 + r3
r3 := r1 x r5
wird zu
r4 := r1 x r5
r2 := r4 + r3
r3 := r4
Zusammenführung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.7-13
Zusammenführung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Peephole-Optimierungstypen (2/3)
„
„
„
Algebraische Vereinfachung (strength reduction)
r2 := 4
wird zu r3 := r1 + 4
und
r2 := …
r3 := r1 + 4
r2 := …
r1 := r2 x 2
r1 := r2 / 2
wird zu
r1 := r2 + r2
r1 := r2 >> 1
oder r1 := r2 << 1
und auch
r2 := 4
r3 := r1 + r2
r3 := *r3
„
Peephole-Optimierungstypen (3/3)
Fortpflanzung von Konstanten (constant propagation)
r2 := 4
r3 := r1 + r2
r2 := …
6.7-14
wird zu r3 := r1 + 4
r3 := *r3
und
r3 := *(r1+4)
Fortpflanzung von Zuweisungen (copy propagation)
r2 := r1
r3 := r1 + r2
r2 := 5
r2 := r1
wird zu r3 := r1 + r1
r2 := 5
und
r3 := r1 + r1
r2 := 5
„
Beseitigung von unnötigen Instruktionen
r1 := r1 + 0
r1 := r1 - 0
r1 := r1 * 1
wird zu
Zusammenführung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.7-15
(wird komplett beseitigt)
Zusammenführung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.7-16
6. Sprachen, Compiler und Theorie
6. Sprachen, Compiler und Theorie
Komplexe Optimierungen
„
Es ist für den Optimierer erforderlich den Datenfluss zwischen
Registern und Speicher zu „verstehen“
…
…
…
„
Wird durch Datenflussanalyse (data flow analysis) bestimmt
„
„
Beispiel für komplexe Optimierung
Schleifeninvarianter Code
(Loop Invariant Code Motion)
…
Beispiel: Finde die Variablenmenge welche einen grundlegenden Block auf
dem Weg zu einem anderen Block „durchfliesst“ und von diesem anderen
Block verwendet wird (lebendige Variablen)
Ist wichtig für Optimierungen welche datenverändernde Instruktionen
einfügen, löschen oder bewegen
Der ursprüngliche Programmdatenfluss kann nicht geändert werden!
Bewege Berechnungen,
dessen Werte während allen
Schleifeniterationen gleich
bleiben (invariant sind), aus
der Schleife raus
L1:
r1 := *(sp + 100)
r2 := *r1
…
r3 := r2 < 100
if r3 goto L1
L0:
r1 := *(sp + 100)
L1:
r2 := *r1
…
r3 := r2 < 100
if r3 goto L1
Es ist für den Optimierer erforderlich die Struktur des
Kontrollflussgraphen (control flow graph) zu „verstehen“
…
…
Wird durch Kontrollflussanalyse bestimmt
Ist wichtig für die Leistungsoptimierung von Schleifen oder
schleifenähnlichen Strukturen in dem Kontrollflussgraphen
Zusammenführung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.7-17
6. Sprachen, Compiler und Theorie
Zusammenführung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.7-18
6. Sprachen, Compiler und Theorie
Was haben Sie in diesem Kapitel gelernt?
Ausblick
Compilerbau (Kapitel 6)
„
Programmiersprachen sind Abstraktionsmechanismen, welche:
…
…
„
„
ein Rahmenwerk zum Lösen von Problemen und erzeugen neuer
Abstraktionen bieten
Schirmen den Programmierer von niederen Detailebenen (low-level
details) der Zielmaschine (Assemblersprache, Verbinden (linken), etc.)
ab
Compiler sind komplexe Programme welche eine höhere
Programmiersprache in eine Assemblersprache umwandeln um
danach ausgeführt zu werden
Compilerprogrammierer handhaben die Komplexität des
Kompilationsprozesses durch:
…
…
Betriebssysteme (Kapitel 5)
Maschinenorientierte Programmierung (Kapitel 4)
von-Neumann-Rechner (Kapitel 3)
aufteilen des Compilers in unterschiedliche Phasen
verwenden, ausgehend von der Spezifikation, eine Theorie für den Bau
von Compilerkomponenten
Speicher
Zahlen und logische Schaltungen (Kapitel 2)
Kommunikation (Kapitel 7)
von-Neumann-Rechner
Zusammenführung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.7-19
Zusammenführung
Dipl.-Inform. Michael Ebner, Prof. Dr. Dieter Hogrefe
Informatik II - SS 2004
6.7-20
Herunterladen