Die Zwischendarstellung (englisch Intermediate Representation, kurz IR) ist das Herzstück moderner Compiler. Sie sitzt zwischen dem Frontend, das den Quellcode analysiert, und dem Backend, das den Zielcode erzeugt. Statt direkt Quellsprache in Maschinensprache zu übersetzen, arbeitet der Compiler mit einer plattformunabhängigen Darstellung, an der alle Optimierungen und Analysen stattfinden.

Die Compiler-Pipeline

Quellcode
  → Frontend: Lexikalische Analyse → Parser → Semantische Analyse
  → Zwischendarstellung (IR)
  → Optimierung (mehrere Passes)
  → Backend: Codegenerierung
  → Zielcode (Assembly / Maschinensprache)

Die lexikalische Analyse, der Parser mit dem Syntaxbaum und die semantische Analyse bilden zusammen das Frontend und sind Quellcode-spezifisch. Das Backend mit der Codegenerierung ist Zielplattform-spezifisch. Die IR dazwischen ist von beiden unabhängig.

Warum eine Zwischendarstellung?

  • Wiederverwendung: Optimierungen werden einmal auf der IR implementiert und wirken für alle Quellsprachen und alle Zielplattformen.
  • Retargeting: Statt M Quellsprachen × N Zielarchitekturen = M·N Compiler zu pflegen, genügen M Frontends + N Backends. Für jede neue Sprache kommt nur ein Frontend dazu, für jede neue CPU nur ein Backend.
  • Stabilität: Analyse und Optimierung sind unabhängig von den Eigenheiten einzelner Sprachen oder Prozessoren.

Bekannte Formen von Zwischendarstellungen

  • Abstrakter Syntaxbaum (AST): Die höchste, sprachnahe Form — im Grunde der Syntaxbaum des Frontends.
  • Drei-Adress-Code (Three-Address Code, TAC): Jede Anweisung enthält höchstens eine Operation, zum Beispiel t1 = a + b und t2 = t1 * c. Das klassische Lehrbuchformat des „Dragon Book".
  • SSA (Static Single Assignment): Jede Variable wird im Programmtext genau einmal zugewiesen; an Verzweigungs-Zusammenflüssen vermitteln spezielle Phi-Funktionen. SSA wurde 1988 von Rosen, Wegman und Zadeck eingeführt und ist die Grundlage moderner Optimierer (unter anderem LLVM).
  • LLVM IR: Eine typisierte SSA-basierte IR mit menschenlesbarem Format (.ll) und Binärform (.bc).
  • Stackbasierte IR: Bytecode für die JVM oder .NET CIL arbeitet auf einem Operanden-Stack — die Grundlage interpretierter und JIT-übersetzter Sprachen.

Zusätzlich strukturiert der Kontrollflussgraph (CFG) die IR: Grundblöcke (Basic Blocks) sind lineare Anweisungsfolgen, Kanten bilden Sprünge und Verzweigungen ab.

Optimierung auf der IR

Fast alle Compiler-Optimierungen laufen als Passes über die IR: Konstantenfaltung (Konstanten werden zur Compilezeit ausgerechnet), Toter-Code-Eliminierung (unbenutzte Zuweisungen entfallen), Eliminierung gemeinsamer Teilausdrücke und viele mehr. Auch die Registerallokation und die Codegenerierung arbeiten auf der IR — ein Beleg dafür, wie zentral diese Schicht ist.

Zusammenfassung

Die Zwischendarstellung ist die plattformunabhängige Mittelschicht zwischen Frontend und Backend. Sie erlaubt gemeinsame Optimierungen, einfaches Retargeting und eine saubere Trennung der Verantwortlichkeiten — vom Syntaxbaum bis zur Codegenerierung.