Phasen des Compilers mit Beispiel, Prozess und Schritten

⚡ Intelligente Zusammenfassung

Die Phasen des Compilers beschreiben, wie ein Compiler Quellcode in Maschinencode umwandelt. Dies geschieht in sechs Schritten: lexikalische Analyse, Syntaxanalyse, semantische Analyse, Zwischencodegenerierung, Codeoptimierung und Codegenerierung, unterstützt durch Symboltabellenverwaltung und Fehlerbehandlung.

  • 🔤 Lexikalische Analyse: In der ersten Phase wird der Quellcode gescannt und die Zeichen werden zu Token gruppiert, wodurch die Symboltabelle gefüllt wird.
  • 🌳 Syntaxanalyse: Tokens werden anhand von Grammatikregeln geprüft und in einem Syntaxbaum angeordnet.
  • Semantische Analyse: Der Compiler überprüft die Typkompatibilität und -bedeutung mithilfe des Syntaxbaums und der Symboltabelle.
  • 🔁 Fortgeschrittener Code: Zur einfachen Übersetzung wird eine maschinenunabhängige Darstellung, wie beispielsweise ein Drei-Adressen-Code, generiert.
  • Optimierung: Redundanter und unerreichbarer Code wird entfernt, um das Programm schneller und kleiner zu machen.
  • Code Generation: In der letzten Phase wird der optimierte Code in den Zielmaschinencode umgewandelt, wobei Register und Speicher zugewiesen werden.

Was sind die Phasen des Compiler-Designs?

Compiler arbeitet in verschiedenen Phasen. Jede Phase transformiert das Quellprogramm von einer Darstellung in eine andere. Jede Phase übernimmt Eingaben aus der vorherigen Phase und gibt ihre Ausgabe an die nächste Phase des Compilers weiter.
Es gibt 6 Phasen in einem Compiler. Jede dieser Phasen hilft bei der Konvertierung der Hochsprache in den Maschinencode. Die Phasen eines Compilers sind:

  1. Lexikalische Analyse
  2. Syntaxanalyse
  3. Semantische Analyse
  4. Zwischencodegenerator
  5. Code Optimierer
  6. Code Generator
Phasen des Compilers
Phasen des Compilers

Alle diese Phasen konvertieren den Quellcode, indem sie ihn in Token aufteilen, Parse-Bäume erstellen und den Quellcode in verschiedenen Phasen optimieren.

Phase 1: Lexikalische Analyse

Die lexikalische Analyse ist die erste Phase, in der der Compiler den Quellcode scannt. Dieser Vorgang kann Zeichen für Zeichen von links nach rechts erfolgen und diese Zeichen in Token gruppieren.
Hierbei wird der Zeichenstrom aus dem Quellprogramm durch die Identifizierung der Token in sinnvolle Sequenzen gruppiert. Es führt den Eintrag der entsprechenden Tickets in die Symboltabelle durch und übergibt diesen Token an die nächste Phase.
Die Hauptfunktionen dieser Phase sind:

  • Identifizieren Sie die lexikalischen Einheiten in einem Quellcode
  • Klassifizieren Sie lexikalische Einheiten in Klassen wie Konstanten und reservierte Wörter und geben Sie sie in verschiedene Tabellen ein. Kommentare im Quellprogramm werden ignoriert
  • Identifizieren Sie ein Token, das nicht Teil der Sprache ist

Beispiel:
x = y + 10

Tokens

X Kennzeichnung
= Aufgabenverwalter
Y Kennzeichnung
+ Additionsoperator
10 Nummer

Phase 2: Syntaxanalyse

Bei der Syntaxanalyse geht es darum, die Struktur im Code zu entdecken. Es bestimmt, ob ein Text dem erwarteten Format folgt oder nicht. Das Hauptziel dieser Phase besteht darin, sicherzustellen, dass der vom Programmierer geschriebene Quellcode korrekt ist oder nicht.
Die Syntaxanalyse basiert auf den Regeln, die auf der spezifischen Programmiersprache basieren, indem der Analysebaum mithilfe von Token erstellt wird. Es bestimmt auch die Struktur der Ausgangssprache und die Grammatik oder Syntax der Sprache.
Hier ist eine Liste der in dieser Phase ausgeführten Aufgaben:

  • Erhalten Sie Token vom lexikalischen Analysator
  • Überprüft, ob der Ausdruck syntaktisch korrekt ist oder nicht
  • Melden Sie alle Syntaxfehler
  • Konstruieren Sie eine hierarchische Struktur, die als Parse-Baum bezeichnet wird.

Beispiel

Jeder Bezeichner/jede Zahl ist ein Ausdruck
Wenn x ein Bezeichner und y+10 ein Ausdruck ist, dann ist x= y+10 eine Anweisung.
Betrachten Sie den Parse-Baum für das folgende Beispiel

(a+b)*c

Beispiel einer Syntaxanalyse

Im Analysebaum

  • Innerer Knoten: Datensatz mit einem Operatorfeld und zwei Dateien für untergeordnete Elemente
  • Blatt: Datensätze mit 2/mehr Feldern; eine für Token und andere Informationen über den Token
  • Stellen Sie sicher, dass die Programmbestandteile sinnvoll zusammenpassen
  • Sammelt Typinformationen und prüft die Typkompatibilität
  • Überprüft, ob Operanden in der Quellsprache zulässig sind

Phase 3: Semantische Analyse

Die semantische Analyse überprüft die semantische Konsistenz des Codes. Es verwendet den Syntaxbaum der vorherigen Phase zusammen mit der Symboltabelle, um zu überprüfen, ob der angegebene Quellcode semantisch konsistent ist. Außerdem wird geprüft, ob der Code eine angemessene Bedeutung vermittelt.
Der semantische Analysator sucht nach Typkonflikten, inkompatiblen Operanden, einer mit falschen Argumenten aufgerufenen Funktion, einer nicht deklarierten Variable usw.
Die Funktionen der Phase der semantischen Analyse sind:

  • Hilft Ihnen, gesammelte Typinformationen zu speichern und in einer Symboltabelle oder einem Syntaxbaum zu speichern
  • Ermöglicht die Durchführung einer Typprüfung
  • Im Falle einer Typ-Nichtübereinstimmung, bei der es keine genauen Typ-Korrekturregeln gibt, die die gewünschte Operation erfüllen, wird ein semantischer Fehler angezeigt
  • Sammelt Typinformationen und prüft die Typkompatibilität
  • Überprüft, ob die Quellsprache die Operanden zulässt oder nicht

Beispiel

float x = 20.2;
float y = x*30;

Im obigen Code wandelt der Semantikanalysator die Ganzzahl 30 vor der Multiplikation in Float 30.0 um

Phase 4: Mittelstufe Code Generation

Sobald die semantische Analysephase abgeschlossen ist, generiert der Compiler Zwischencode für die Zielmaschine. Dieser repräsentiert ein Programm für eine bestimmte Zielgruppe.tract-Maschine.
Der Zwischencode liegt zwischen der Hochsprache und der Maschinensprache. Dieser Zwischencode muss so generiert werden, dass er leicht in den Zielmaschinencode übersetzt werden kann.
Funktionen auf Zwischenebene Code Generation:

  • Es sollte aus der semantischen Darstellung des Quellprogramms generiert werden
  • Enthält die während des Übersetzungsprozesses berechneten Werte
  • Hilft Ihnen, den Zwischencode in die Zielsprache zu übersetzen
  • Ermöglicht Ihnen, die Rangfolge der Ausgangssprache beizubehalten
  • Es enthält die richtige Anzahl von Operanden der Anweisung

Beispiel

Zum Beispiel,

total = count + rate * 5

Der Zwischencode mit Hilfe der Adresscode-Methode lautet:

t1 := int_to_float(5)
t2 := rate * t1
t3 := count + t2
total := t3

Phase 5: Code Optimierung

Die nächste Phase ist die Codeoptimierung oder der Zwischencode. In dieser Phase werden unnötige Codezeilen entfernt und die Anweisungsfolge so angeordnet, dass die Ausführung des Programms beschleunigt wird, ohne Ressourcen zu verschwenden. Das Hauptziel dieser Phase besteht darin, den Zwischencode zu verbessern, um einen Code zu generieren, der schneller ausgeführt wird und weniger Platz einnimmt.
Die Hauptfunktionen dieser Phase sind:

  • Es hilft Ihnen, einen Kompromiss zwischen Ausführungs- und Kompilierungsgeschwindigkeit zu finden
  • Verbessert die Laufzeit des Zielprogramms
  • Erzeugt optimierten Code noch in Zwischendarstellung
  • Entfernen von nicht erreichbarem Code und Entfernen nicht verwendeter Variablen
  • Entfernen von Anweisungen, die nicht geändert werden, aus der Schleife

Ejemplo:
Betrachten Sie den folgenden Code

a = intofloat(10)
b = c * a
d = e + b
f = d

Kann werden

b =c * 10.0
f = e+b

Phase 6: Code Generation

Code Die Generierung ist die letzte Phase eines Compilers. Sie erhält Eingaben aus den Codeoptimierungsphasen und erzeugt als Ergebnis den Seitencode oder Objektcode. Ziel dieser Phase ist die Speicherzuweisung und die Generierung von verschiebbarem Maschinencode.
Außerdem werden Speicherplätze für die Variable zugewiesen. Die Anweisungen im Zwischencode werden in Maschinenanweisungen umgewandelt. In dieser Phase wird der Optimierungs- oder Zwischencode in die Zielsprache umgewandelt.
Die Zielsprache ist der Maschinencode. Daher werden in dieser Phase auch alle Speicherplätze und Register ausgewählt und zugewiesen. Der in dieser Phase generierte Code wird ausgeführt, um Eingaben entgegenzunehmen und erwartete Ausgaben zu generieren.

Beispiel

a = b + 60.0
Würde möglicherweise in Register übersetzt.

MOVF a, R1
MULF #60.0, R2
ADDF R1, R2

Symboltabellenverwaltung

Eine Symboltabelle enthält für jeden Bezeichner einen Datensatz mit Feldern für die Attribute des Bezeichners. Diese Komponente erleichtert es dem Compiler, den Bezeichnerdatensatz zu durchsuchen und ihn schnell abzurufen. Die Symboltabelle hilft Ihnen auch bei der Scope-Verwaltung. Die Symboltabelle und der Fehlerhandler interagieren mit allen Phasen und die Symboltabelle wird entsprechend aktualisiert.

Fehlerbehandlungsroutine

Im Compiler-Designprozess können in allen unten aufgeführten Phasen Fehler auftreten:

  • Lexikalischer Analysator: Falsch geschriebene Token
  • Syntaxanalysator: Fehlende Klammer
  • Zwischencodegenerator: Nicht übereinstimmende Operanden für einen Operator
  • Code Optimierer: Wenn die Anweisung nicht erreichbar ist
  • Code Generator: Wenn der Speicher voll ist oder nicht die richtigen Register zugewiesen sind
  • Symboltabellen: Fehler bei mehreren deklarierten Bezeichnern

Die häufigsten Fehler sind ungültige Zeichenfolgen beim Scannen, ungültige Tokensequenzen beim Typ, Bereichsfehler und Parsing bei der semantischen Analyse.
Der Fehler kann in jeder der oben genannten Phasen auftreten. Nachdem Fehler gefunden wurden, muss sich die Phase mit den Fehlern befassen, um mit dem Kompilierungsprozess fortzufahren. Diese Fehler müssen dem Fehlerhandler gemeldet werden, der den Fehler behandelt, um den Kompilierungsprozess durchzuführen. Im Allgemeinen werden die Fehler in Form einer Nachricht gemeldet.

Häufig gestellte Fragen

Die Analysephase (Frontend) zerlegt den Quellcode durch lexikalische, syntaktische und semantische Analyse. Die Synthesephase (Backend) erstellt das Zielprogramm durch Zwischencodegenerierung, Optimierung und erneute Codegenerierung.

Ein Compiler übersetzt das gesamte Quellprogramm in Maschinencode, bevor es ausgeführt wird. Ein Interpreter übersetzt und führt den Code Zeile für Zeile aus, was die Fehlersuche erleichtert, aber zur Laufzeit in der Regel langsamer ist.

Der Drei-Adress-Code ist eine Zwischenrepräsentation, bei der jede Anweisung höchstens drei Operanden hat, z. B. t1 = a + b. Er ist einfach zu optimieren und leicht in Zielmaschinencode zu übersetzen.

Künstliche Intelligenz und maschinelles Lernen unterstützen moderne Compiler bei intelligenteren Optimierungsentscheidungen, beispielsweise bei der Auswahl von Schleifentransformationen, Inlining und Registerzuweisung. Sie prognostizieren, welche Optimierungen die Leistung eines bestimmten Programms und Zielsystems verbessern.

Ja. Die KI kann jede Phase anhand von Beispielen erklären. tracErklären Sie, wie eine Beispielanweisung von Tokens in Maschinencode umgewandelt wird, und beantworten Sie anschließende Fragen. Dies erleichtert Studierenden das Erlernen des Compilerbaus.

Fassen Sie diesen Beitrag mit folgenden Worten zusammen: