[ Inhalt ] [ Index ]

Next: Grundlagen Up: Einleitung Previous: Einleitung

Compiler im Überblick

Was ist nun ein Compiler?

Welche Aufgaben muß ein Compiler erfüllen?

Was ist der Unterschied zu einem Interpretierer?

Welche Designentscheidungen muß man treffen?

Diese Fragen wollen wir in diesem Abschnitt kurz anreißen.

Komponenten eines Compilers

Man kann das Thema Compilerbau grob in vier Teilbereiche gliedern, die wir uns, soweit es die Zeit erlaubt, alle ansehen werden:

Das Zusammenspiel dieser Teilprogramme zeigt das folgende Bild:

tex2html_wrap1777

Das Thema Scanner   beschäftigt sich mit der Frage, wie man aus den einzelnen Zeichen des Quelltextes die einzelnen Programmsymbole extrahiert.

Der Parser   überprüft dann diese Symbolfolge auf ihre syntaktische Korrektheit. Ein Programm kann sehr wohl syntaktisch korrekt sein - damit ist noch lange nicht gesagt, daß der Compiler es auch übersetzen kann: denken Sie an Typkonflikte, undeklarierte Variablen, fehlende Parameter, etc.

Diese Kontextbedingungen   müssen zusätzlich geprüft werden, ehe man mit der Übersetzung beginnen kann. Man sagt auch, daß die statische Semantik   geprüft werden muß.

Das letzte Thema, die Codeerzeugung ist das am wenigsten formalisierte. Hier ist noch sehr viel Kreativität nötig, um wirklich guten, effizienten Code zu generieren. Es ist in vielen Fällen relativ einfach, die Anweisungen und Ausdrücke einer Programmiersprache in für einen Computer verständliche Häppchen zu zerlegen. Wenn es aber harte Anforderungen bzgl. Laufzeitverhalten oder Speicherbedarf gibt, wird die Aufgabe sehr viel komplizierter.

Compiler vs. Interpretierer

Ein Compiler
erzeugt aus einem Quellprogramm  , das in einer Quellsprache   geschrieben ist, ein Zielprogramm   in einer Zielsprache  . Statt Zielprogramm findet man auch oft die Bezeichnung Objektprogramm  . Der Compiler ist in einer Implementierungssprache   geschrieben.

Graphisch kann man einen Compiler durch ein T-Diagramm   beschreiben:

tex2html_wrap1789

Das erzeugte Programm wird dann auf die Zielmaschine   geladen und ausgeführt. Dabei findet die Interpretation der Befehle direkt durch die Hardware/das Betriebssystem der Zielmaschine statt.

Ein Interpreter  
ist ein Programm, das auf der Zielmaschine ausgeführt wird, als Eingabe - wie der Compiler - ein Quellprogramm erwartet und dieses Programm direkt interpretiert und unmittelbar ausführt.

Vorteile eines Interpretierers:

Nachteile eines Interpretierers:

Geschwindigkeit des ausgeführten Programms

Entwurfsziele

Man sieht, daß sich diese Ziele zum Teil widersprechen:

Effizienz tex2html_wrap_inline1801 kompakter Code
gute Fehlerdiagnose tex2html_wrap_inline1801 kleiner Compiler
kurze Übersetzungszeit tex2html_wrap_inline1801 Effizienz

Bootstrapping

 

Angenommen auf einer SUN-Workstation existiert ein C-Compiler. Wir möchten einen C-Compiler (1) für eine Intel-Maschine in C schreiben. Dann gehen wir wie folgt vor:

Im ersten Schritt erzeugen wir mit dem SUN-Compiler (0) einen C-Compiler (2), der auf SUN läuft und 586-Code erzeugt. Damit übersetzen wir (1) noch einmal und erhalten (3), einen C-Compiler der auf Intel läuft.

tex2html_wrap1807

Ein guter Test ist nun das folgende Vorgehen:

tex2html_wrap1809

(4) ist ein Compiler, der auf Intel von einem auf SUN generierten Compiler erzeugt wurde.

Wir stecken (1) noch einmal in (4) und erhalten (5):

tex2html_wrap1811

Wenn (4) und (5) identisch sind, haben wir ein gutes Indiz, daß unser Compiler korrekt arbeitet.

Zwischensprachen

Will man n Quellsprachen für m Maschinen übersetzen, so benötigt man prinzipiell n*m Compiler. Die Verwendung einer gemeinsamen Zwischensprache erlaubt die Reduktion auf nur n+m Programme.

Ein weiterer Vorteil ist die einfache Mischbarkeit verschiedener
Sprachen:

tex2html_wrap1822




Next: Grundlagen Up: Einleitung Previous: Einleitung

Prof. Dr. Reinhard Völler