Folien zu Kapitel 1

informatik.uni.hamburg.de

Folien zu Kapitel 1

Folienkopien

zur

Vorlesung

1 Einleitung

1.1 Ein Blick auf den Übersetzungsprozeß

Übersetzung

objektorientierter Sprachen

1.2 Aufgaben eines Compilers

1.3 Aufgaben eines Compilerbauers

1.4 Struktur eines Compilers

1.5 T-Diagramme

Martin Lehmann

Wintersemester 2007/2008

1.6 Grobe Historie des Compilerbaus

1.7 Zusammenfassung


Beispiel einer Übersetzung:

Zielarchitektur: Einfache Registermaschine

Aufgabe: Berechnung des größten gemeinsamen Teilers

zweier natürlicher Zahlen.

Register Hauptspeicher

Seien a, b ∈ N :

ggT(a, b) =






a,

ggT(a − b, b),

ggT(a, b − a),

falls

falls

falls

a = b

a > b

a < b

R0 0

R1 1

R2 2

M

.

.

Formulierung in einer algorithmischen Sprache:

ggT (a, b: natural) =

begin

while a ≠ b do

if a > b then

a := a – b

else

b := b – a;

return a

end;

a

b

Programm

.

.


Schritte bei der Übersetzung der Schleife:

2. Bildung des Strukturbaums:

1. Bildung der Lexeme

hier: nur für den Schleifenkörper

Symbol Klasse

while Schlüsselwort

a Bezeichner

≠ Vergleichsoperator

b Bezeichner

do Schlüsselwort

if Schlüsselwort

a Bezeichner

> Vergleichsoperator

b Bezeichner

then Schlüsselwort

a Bezeichner

:= Zuweisungsoperator

a Bezeichner

– Additionsoperator

b Bezeichner

else Schlüsselwort

b Bezeichner

:= Zuweisungsoperator

b Bezeichner

– Additionsoperator

a Bezeichner

; Trennsymbol

Grammatikfragment für Quellsprache:

.

Anweisung ::= "while" Ausdruck "do" Anweisung

| "if" Ausdruck "then" Anweisung

| "if" Ausdruck "then" Anweisung

"else" Anweisung

| Zuweisung

| . . .

Ausdruck

Operator

Vergleichsoperator

.

::= Ausdruck Operator Ausdruck

| Variable

| Konstante

| . . .

::= Additionsoperator

| Multiplikationsoperator

| Vergleichsoperator

| . . .

::= "=" | "≠" | "" | "≥"

Bemerkung: Formatierungszeichen wurden entfernt.


Ausschnitt aus Strukturbaum:

3. Transformation des Strukturbaums, Attributierung:

while : Schleife, Ende

Anweisung

Vergleich : ≠

if : Else, Ifende

while

Ausdruck

do

Anweisung

. . .

Variable

: a

Variable

: b

Ausdruck

Operator

Ausdruck

Vergleich : > Zuweisung Zuweisung

.

Variable

Vergleichsoperator

Variable

Variable

: a

Variable

: b

Variable

: a

Summe

: –

a


b

Variable

: a

Variable

: b


4. Einfache schablonengesteuerte Codeerzeugung:

Erzeugter Code:

Codeerzeugung mittels Schablonensatz:

Vergleich: ≠ Load R?, A

Sub R?, B

jzero M?

A B

Vergleich: < Load R?, A

Sub R?, B

jnpos M?

A B

M

Summe: + Load R?, A

Add R?, B

Schleife: load R1, a

sub R1, b

jzero Ende

load R1, a

sub R1, b

jnpos Else ; jump on not positive

load R1, a

sub R1, b

store R1, a

jump Ifende

Else: load R1, b

sub R1, a

store R1, b

Ifende: jump Schleife

Ende:

A B

Bemerkung: Es wird angenommen, daß das

analysierte Programm korrekt ist,

daher keine Berücksichtigung möglicher

Fehlrechnungen.

Bemerkung: In der Regel werden Codeschablonen umgebungsunabhängig

eingesetzt. Der erzeugte

Code bedarf daher der nachträglichen

Glättung.


5a. Codeoptimierung, hier: Gucklochoptimierung:

5b. Codeoptimierung, hier: Flußgraphbetrachtung:

Ersetzen von Befehlen und Befehlsfolgen durch vermutlich

aufwandsärmere:

Schleife: load R1, a

sub R1, b

jzero Ende

load R1, a ; Berechnung schon

sub R1, b ; erfolgt

jnpos Else

load

sub

R1, a

R1, b

load R1, a ; Berechnung schon

sub R1, b ; erfolgt

store R1, a

jump Ifende ; Vermeidung von

; Sprungkaskaden

jump Schleife

store

R1, a

Else: load R1, b ; Ersetzen dieser

sub R1, a ; zwei Befehle durch

; neg R1

; liegt außerhalb der

; Gucklochoptimierung

store R1, b

Ifende: jump Schleife ; Marke wird nicht

; mehr benötigt.

Ende:

load

sub

store

Problem: Lohnt der Aufwand?

R2, b

R2, a

R2, b


Zielcode für die Schleife auf einer Mehrregistermaschine:

Aufgaben eines Compilers:

Schleife: load R1, a

sub R1, b

jzero Ende

Fehlerangaben

jnpos

store

jump

Else

R1, a

Schleife

Quelltext

Compiler

Verletzungen von

Implementationsgrenzen

Else: load R2, b

sub R2, a

store R2, b

Zielcode

jump

Schleife

Ende:

Eigenschaften des Zielcodes:

1. Bedeutungstreue Realisierung des Quelltextes.

Bemerkungen:

2. Ökonomische Nutzung der Ressourcen des

Zielrechners.

(i)

(ii)

Die algorithmische Formulierung zur Berechnung

des größten gemeinsamen Teilers ist

nicht vorbildlich.

Der erzeugte Code ist nicht optimal.

Eigenschaft der Beanstandungen:

Genaue Angabe, in welchen Teilen der Quelltext

die Sprachdefinition oder die Implementationsbeschränkungen

verletzt.


Aufgaben eines Compilerbauers:

Aufgabenunterteilung:

Compiler

1. Erstellung von Compilern.

2. Verbesserung von Compilern.

3. Verbesserung der Erstellung von Compilern.

4. Beschreibung von Compilern.

5. Entwurf von Programmiersprachen.

6. Entwurf von Rechnern.


Analyse Synthese

Analyse Analyse Synthese

der Form des Inhalts



Lexikalische Syntax- Semantik- Code-

Aufbereitung analyse analyse erzeugung


Bemerkung: Gegeben seien eine Beschreibung der

Quellsprache S, eine Beschreibung der

Zielsprache T und Randbedingungen;

wieweit darf die in einem Compiler

implementierte Sprache S' von der

Originalsprache S abweichen?

Aufbereitung der Eingabe

Lexikalische Analyse

Syntaxanalyse

Analyse der statischen Semantik

Speicherplatz-Zuweisung

Erzeugung eines Universalcodes

Verbesserung des Universalcodes

Erzeugung zielnahen Codes

Verbesserung des zielnahen Codes

Aufbereitung der Ausgabe


Abstraktes Compilermodell:

Zweiteilung eines Compilers:

Quelltext

Lexikalische Analyse

Zwischentext-1

Code

Quell- für Zieltext

abstrakte code

Maschine

Syntaktische Analyse

Zwischentext-2

Semantische Analyse

sprachabhängiger maschinenabhängiger

Teil Teil

Zwischentext-3

Optimierung

Analyse: Analyse:

Hauptaufgabe trivial

Zwischentext-4

Codeerzeugung

Zieltext

Codeerzeugung: Codeerzeugung:

trivial Beschreibung mittels

eines kleinen

Schablonensatzes


Das n Sprachen, m Maschinen Problem,

auch UNCOL – Problem:

Beispiele zur Struktur von Compilern:

Front-ends Back-ends

(i) Phasen des Gier-Algol-Compilers:

Sprache

1

Maschine

1

1 Übertragung in Hardware-Repräsentation

2 Ersetzung der Bezeichner durch Zahlen

Sprache

2

Sprache

3

Darstellung

des

semantischen

Inhalts

Maschine

2

.

3 Syntaxanalyse

4 Aufbau der Symboltabelle

5 Speicherzuweisung für Variable

6 Typprüfung und Überführung in

Polnische Notation

7 Codeerzeugung

.

Maschine

m–1

8 Endgültige Adreßfestlegung

Sprache

n

Maschine

m

9 Umordnung der Programmteile auf

Trommel

Bemerkung: Bisher ist jeder Versuch einer allgemeinen

Lösung gescheitert.


(ii)

Aufbau des Fortran-Übersetzers von Backus

und Mitarbeitern:

(iii)

Gliederung des York Ada-Compilers

Phasengröße Phasenaufgabe

Zeilen Quellcode

(C-Code)

Klassifizierung der Anweisungen,

5500 Instr. Übersetzung arithmetischer

Formeln, Teilausgabe nach Datei 1.

Übersetzung von Indizes

6000 Instr. innerhalb von Schleifen,

Ausgabe nach Datei 2.

2500 Instr. Zusammenführen von Datei 1

und Datei 2.

3000 Instr. Flußanalyse.

Abbildung des übersetzten

5000 Instr. Textes auf Maschine mit

3 Indexregistern (IBM 704).

2000 Instr. Endbehandlung.

Lexikalische und 5.221

syntaktische Analyse

davon lexikalische Analyse 461

Analyse der statischen 40.178

Semantik

davon

Deklarationsbearbeitung 10.835

Ausdrucksbearbeitung 14.831

Codeerzeugung 31.248

davon

maschinenunabhängig 24.319

maschinenabhängig 5.376

Laufzeitunterstützung 17.813

davon

allgemein 3.514

Bibliothekscode 14.399


Darstellung von Compilern als T-Diagramme:

Die Erstellung eines Compilers für die Sprache S läßt sich

als iterativer Vorgang betrachten.

Quellsprache

Name

Zielsprache

1. Definiere Folge von Teilsprachen.

S 0 < S 1 < S

Implementationssprache

2. Schreibe Übersetzer.

S

3

Z

S

4

Z

S 1

S 1

2

Z

Z

Einsatz:

S 0

S 0

1

Z

Quell- N

Zielprogramm

Q

Z programm

Z

I

Um den gewünschten Übersetzer 4 zu erhalten,

sind 1, 2 und 3 zu schreiben.


Situation des eigenständigen "bootstrap":

Drei Perioden des Compilerbaus:

Gegeben:

Q

1

Q

ZC

Q

2 3

ZC

ZC

ZC

Q

Interpreter für

Zwischencode

Periode 1: 1945 – 1960

Hauptaugenmerk: Codeerzeugung.

Es galt für einfache syntaktische und semantische

Konstrukte hervorragenden Zielcode zu erzeugen. Es

galt zu demonstrieren, daß übersetzte Hochsprachenprogramme

bezüglich Speicherplatz und Laufzeit den

Assemblerprogrammen ebenbürtig sind. Das leuchtende

Beispiel für exzellenten Code ist der frühe

Fortran-Compiler (1954).

Vorgehen:

Periode 2: 1960 – 1975

Hauptaugenmerk: Syntaxanalyse.

Q

1a

Q

Manuelle

Anpassung

Q

M

Q

1a

Q

2

ZC

3a

ZC

M

M

Q

ZC

cpz

ZC

3a

ZC

M

Q

M

comp

M

M

gewünschter

Compiler

Diese Zeit war geprägt von dem Wissen, daß die

Leistungsfähigkeit von Rechnern exponentiell

zunimmt. Daher galt es, programmierfreundliche

mächtige Notationen automatisch zu analysieren. Die

Güte des erzeugten Codes wurde als zweitrangig

betrachtet. Wichtig war die Produktivität des

Programmierers.

Periode 3: 1975 – heute

Hauptaugenmerk: Codeoptimierung.

Die Zahl der strukturunterschiedlichen Rechner

reduziert sich erheblich. Die Investitionen in

Codeverbesserungen sind daher dauerhaft.


Beispiel zur Codeoptimierung:

Übersetzung als allgemeine Texttransformation:

Umbenennung der Register:

ursprünglich:

mov [mem01], R2

mul R2, "6", R2

mov R2, [mem02]

mov [mem03], R2

add R2, "7", R2

mov R2, [mem04]

Text Q

in

Quellsprache

Beispiele:

Compiler

Text Z

in

Zielsprache

geändert:

mov [mem01], T1

mul T1, "6", T1

mov T1, [mem02]

mov [mem03], T2

add T2, "7", T2

mov T2, [mem04]

{mov T2, R2} // eventuell ?

Pascal Intel 8086-Code

C Assemblercode

Fortran Fortran

Pascal C

Postscript Druckseite

Bemerkung: Diese Art der Codeverbesserung wird

heutzutage von der Hardware ausgeführt,

Ti sind verborgene Hardware-Register.

HTML Webseite


Übersetzerarten:

Zur Interpretation:

Assembler

Makro-Assembler

Compiler

Präprozessor

Disassembler

Decompiler

Interpreter

Quellcode

Zwischencode Interpretation

Bemerkung: Ein Decompiler wird eingesetzt, um aus

Objektcode einen Hochsprachentext zu

gewinnen, der den compilierten Algorithmus

beschreibt. Dies kann sinnvoll sein,

um verloren gegangene Quelltexte zu

rekonstruieren oder um Malware zu

analysieren. Der Einsatz eines Decompilers

ist eine Form des Reverse Engineering.

Objektcode Ausführung


Automatisierung der Compilererstellung:

Beschreibung

der

Quellsprache

Q

Beschreibung

der

Zielsprache

Z

Beschreibung

der

Implementationssprache

I

C G

O E

M N

P – E

I R

L A

E T

R O

R

Q → Z

I

Bemerkung: Für die einzelnen Teile eines

Compilers kennt man zugkräftige

Beschreibungsmittel.

Weitere Magazine dieses Users
Ähnliche Magazine