Die semantische Analyse ist die dritte Phase der Compiler-Vorderseite (Frontend). Nachdem der Parser aus dem Tokenstrom einen Syntaxbaum gebaut hat, prüft die semantische Analyse, ob der Code nicht nur formal richtig, sondern auch in seiner Bedeutung korrekt ist. Sie beantwortet Fragen wie: „Ist diese Variable deklariert?“, „Passen die Datentypen zusammen?“ oder „Wird die Funktion mit der richtigen Anzahl von Argumenten aufgerufen?“. Erst wenn diese Prüfungen bestanden sind, kann der Übersetzer eine Zwischendarstellung erzeugen.

Syntaxfehler versus Semantikfehler

Die Abgrenzung ist wichtig: Syntax beschreibt die Grammatik, also die erlaubte Form von Anweisungen. Semantik beschreibt die Bedeutung. Ein Syntaxfehler verletzt die Grammatik, ein Semantikfehler verletzt die Bedeutung:

int x = "Hallo";   // Typfehler: String kann nicht int zugewiesen werden
y = x + 1;          // Semantikfehler: y ist nicht deklariert
z = f(1, 2, 3);     // Semantikfehler: f erwartet nur 2 Parameter

Den ersten Fehler findet der Parser nicht — grammatikalisch ist die Zeile korrekt. Erst die semantische Analyse meldet ihn.

Aufgaben der semantischen Analyse

  • Symboltabelle und Namensauflösung: Jede Verwendung eines Bezeichners wird mit seiner Deklaration verbunden. Dazu verwaltet der Compiler einen Stapel von Gültigkeitsbereichen (Scopes); beim Betreten eines Blocks kommt ein neuer Scope dazu, beim Verlassen wird er entfernt (lexikalisches Scoping).
  • Typ-Prüfung (Type Checking): Die Datentypen von Ausdrücken werden anhand der Operatoren und Operationen geprüft — die Grundlage jedes Typsystems. Bei int + int ist das Ergebnis int, bei int + string meldet der Compiler einen Typfehler.
  • Signatur-Prüfung: Anzahl und Typ der Argumente eines Funktionsaufrufs werden gegen die Deklaration geprüft.
  • Mehrfachdeklarationen erkennen: Zwei Variablen mit gleichem Namen im selben Scope sind ein Fehler.
  • Zuweisungsprüfungen: Konstanten lassen sich nicht ändern, auf nicht lesbare Werte darf nicht zugegriffen werden.

Wie arbeitet die semantische Analyse?

Klassisch wird der abstrakte Syntaxbaum einmal durchlaufen (Tree Walk). Donald Knuth formalisierte 1968 das Konzept der attributierten Grammatik: Jeder Knoten trägt Attribute, die entweder abgeleitet (synthesized, von unten nach oben) oder geerbt (inherited, von oben nach unten) berechnet werden. So wandert die Typinformation durch den Baum: Aus den Typen der Blätter wird der Typ jedes Teilausdrucks bestimmt, bis schließlich der Typ der gesamten Anweisung feststeht.

Das Ergebnis ist ein annotierter Syntaxbaum mit Typ- und Scope-Informationen — die saubere Eingabe für die nachfolgende Zwischendarstellung.

Statische und dynamische Prüfung

Die semantische Analyse ist Teil der statischen Analyse: Sie läuft zur Übersetzungszeit, bevor das Programm startet. Sprachen wie C, C++, Java und Rust prüfen Typen überwiegend statisch. Interpretierte Sprachen wie Python verschieben viele Prüfungen in die Laufzeit — ein Grund, warum Interpreter manche Fehler erst beim Ausführen melden.

Zusammenfassung

Die semantische Analyse ist die letzte Phase des Compiler-Frontends. Sie ergänzt den Syntaxbaum um Bedeutung: Sie löst Namen auf, prüft Typen, Signatur und Gültigkeitsbereiche und meldet Fehler, die kein Parser finden kann. Ihr Ergebnis fließt direkt in die Zwischendarstellung des Compilers.