Was ist ein Compiler?

Frau, die von zu Hause aus am Computer arbeitet

Autoren

Josh Schneider

Staff Writer

IBM Think

Ian Smalley

Staff Editor

IBM Think

Was ist ein Compiler?

Ein Compiler ist ein Computerprogramm, das Code aus einer Programmiersprache (der Quellsprache) in eine andere Programmiersprache (die Zielsprache) umwandelt.

Compiler werden verwendet, um High-Level-Quellcode in Low-Level-Zielcode (wie Assemblersprache, Objektcode oder Maschinencode) umzuwandeln, während die Programmfunktionalität erhalten bleibt.

Der Compiler ist ein unverzichtbares Tool für die moderne, praktische Computerprogrammierung. Er ermöglicht es Programmierern, in einer lesbaren höhere Programmiersprache zu arbeiten und ihren Quellcode anschließend in einen ausführbaren Zielcode umzuwandeln. Compiler unterstützen Softwareentwickler auch dabei, effiziente ausführbare Programme mit verbesserter Sicherheit, Stabilität und Portabilität zu erstellen. Dies liegt daran, dass Compiler dabei helfen, Fehler zu identifizieren und zu beheben, wodurch portable ausführbare Anwendungen entstehen. 

Obwohl alle Compiler hochsprachigen Code in niedrigsprachigen, ausführbaren Code umwandeln, werden für verschiedene Programmiersprachen und Anwendungen unterschiedliche Compiler verwendet. Ein Cross-Compiler wird beispielsweise verwendet, um Code für einen anderen Typ von CPU oder Betriebssystem zu erstellen als den, auf dem er ausgeführt wird.

Wenn der ideale Compiler nicht verfügbar ist oder noch nicht erstellt wurde, wird ein temporärer Bootstrap-Compiler verwendet, um einen dauerhafteren Compiler zu kompilieren, der besser für die Kompilierung einer bestimmten Programmiersprache optimiert ist.

Eine kurze Liste weiterer verwandter Software umfasst:

  • Decompiler funktionieren wie Reverse-Compiler und wandeln Low-Level-Code in High-Level-Sprachen um.
  • Quelltext-zu-Quelltext-Compiler (oder Transpiler) konvertieren hochsprachigen Code in andere hochsprachige Sprachen.
  • Code-Umschreiber wandeln formale Codeausdrücke in verschiedene Formen um, ohne die Sprache zu verändern.
  • Compiler-Compiler dienen zur Erstellung generischer und wiederverwendbarer Compiler oder Compiler-Komponenten, die für projektspezifische Zwecke integriert werden können.  

Die neuesten Tech-News – von Experten bestätigt

Bleiben Sie mit dem Think-Newsletter über die wichtigsten – und faszinierendsten – Branchentrends in den Bereichen KI, Automatisierung, Daten und darüber hinaus auf dem Laufenden. Weitere Informationen finden Sie in der IBM Datenschutzerklärung.

Vielen Dank! Sie haben ein Abonnement abgeschlossen.

Ihr Abonnement wird auf Englisch geliefert. In jedem Newsletter finden Sie einen Abmeldelink. Hier können Sie Ihre Abonnements verwalten oder sich abmelden. Weitere Informationen finden Sie in unserer IBM Datenschutzerklärung.

Funktionsweise von Compilern

In der Praxis kann die Verwendung eines Compilers so einfach sein wie die Eingabe eines Befehls in eine Befehlszeile in einem beliebigen Linux-System (oder einem gleichwertigen System), wobei die ausführbare Compiler-Datei und die zu kompilierenden Quelldateien angegeben werden. Dieser Befehl weist das System an, den Quellcode zu verarbeiten, ihn in einen Zielmaschinencode zu kompilieren und die erforderlichen Objektdateien zu erzeugen, um ein ausführbares Programm zu erstellen. 

Open-Source-Compiler wie die GNU Compiler Collection (GCC) – eine robuste C-Compiler-Sammlung, die häufig verwendet wird, um C-Code in C-Programme zu kompilieren – oder das alternative Clang sind auf Repositorys wie GitHub verfügbar. Andere Compiler können frei installiert oder von einer Vielzahl von Händlern erworben werden. Sie können auch in gängige integrierte Entwicklungsumgebungen (IDEs) eingebunden werden, die verschiedene Dienstprogramme für die Softwareentwicklung bündeln, darunter Texteditoren, API-Dokumentation und Debugging-Tools.     

Unabhängig vom verwendeten Compiler umfasst der Prozess der Code-Kompilierung die Überprüfung des Quellcodes auf verschiedenen Ebenen der Analyse, Optimierung und schließlich der Codegenerierung. Der Quellcode durchläuft nacheinander die verschiedenen Analyseebenen und wird in jedem Schritt des Prozesses ausgewertet.

Wenn der Compiler irgendwelche Probleme mit dem ursprünglichen Quellcode erkennt, gibt er möglicherweise eine Fehlermeldung zurück, die Entwickler auffordert, identifizierte Fehler zu beheben, bevor sie mit dem Kompilieren des restlichen Codes fortfahren. Im Allgemeinen führen Compiler die folgenden Schritte durch:

  1. Lexikalische Analyse: Im ersten Schritt der Kompilierung durchläuft der Quellcode den Lexer des Compilers, ein Programm, das Zeichen in sinnvolle Spracheinheiten wie Schlüsselwörter, Bezeichner und bekannte Operatoren umwandelt. Diese Einheiten werden zusammenfassend als Token bezeichnet. Dieser Schritt bereitet im Wesentlichen den Quellcode für den nächsten Schritt vor, indem er aussagekräftige und wichtige Elemente des Quellcodes in Tokens umwandelt, mit denen der Compiler arbeiten kann. 
  2. Syntaxanalyse: Im zweiten Schritt des Kompilierungsprozesses werden die Tokens vom Lexer an den Parser des Compilers weitergeleitet. Ein Parser ist ein Programm, das Code auf syntaktische Fehler überprüft und sicherstellt, dass der Quellcode den Regeln der Quellsprache entspricht. Wenn der Parser während der Analyse keine Fehler feststellt, erzeugt er eine abstrakte Darstellung der gesamten Codestruktur, die als abstrakter Syntaxbaum (Abstract Syntax Tree, AST) bezeichnet wird.
  3. Semantische Analyse: Nach der Überprüfung der Codesyntax führt ein Compiler eine semantische Analyse des geparsten Codes durch, um die beabsichtigte Funktion des Quellcodes abzuleiten. In diesem Schritt führt der Compiler Überprüfungen auf logische Fehler wie nicht deklarierte Variablen oder falsche Verwendung von Operatoren durch.
  4. Optimierung: Die Optimierung ist zwar nicht unbedingt erforderlich, um funktionierenden Code zu erzeugen, aber sie ist ein optionaler Schritt, der bei vielen Compilern üblich ist, um die Gesamtleistung des kompilierten Codes zu verbessern. Durch die Optimierung kann unnötiger Code identifiziert und entfernt werden. Das Ergebnis sind schnellere, effizientere und stabilere Programme sowie eine Verkürzung des abschließenden Debugging-Prozesses. 
  5. Code-Generierung: Im letzten Schritt des Prozesses konvertiert der Compiler die AST in maschinenlesbaren Code. Die endgültige Ausgabe der Codegenerierung ist ein Assemblercode, der dann in Binärcode umgewandelt und vom Computersystem ausgeführt werden kann. 
AI Academy

KI-Bereitschaft mit Hybrid Cloud

Das Programm, das von führenden IBM Experten geleitet wird, soll Führungskräften dabei helfen, das nötige Wissen zu erwerben, um die Prioritäten für KI-Investitionen zu setzen, die zu mehr Wachstum führen.

Dreistufige Compiler-Struktur

Einige Compiler halten sich möglicherweise nicht strikt an die vorstehende Struktur. Obwohl einige Compiler mehr oder weniger Schritte enthalten können, lassen sich alle Phasen der Kompilierung einer von drei Stufen zuordnen: einem Frontend, einem Middleend und einem Backend.

Diese dreistufige Struktur ermöglicht Compilern einen modularen Ansatz. Es ermöglicht die Kombination mehrerer Frontends für verschiedene Sprachen mit Backends für verschiedene CPUs, wobei die Optimierungsfunktionen verschiedener anwendbarer Middle-Ends gemeinsam genutzt werden.

Die drei Phasen eines Compilers lassen sich wie folgt unterteilen:

  1. Front-End: Das Front-End eines Compilers umfasst Aspekte der lexikalischen Analyse, Syntaxanalyse und semantischen Analyse. In dieser Phase werden Syntax und Semantik gemäß den Regeln der Quellsprache überprüft und Fehler im Quellcode identifiziert und lokalisiert. Unter der Annahme, dass keine Fehler gefunden werden, konvertiert das Front-End des Compilers den Quellcode in eine Zwischendarstellung (IR) – eine temporäre Konvertierung des Quellcodes auf niedrigerer Ebene – für das mittlere Ende. 
  2. Middle-End: Der mittlere Abschnitt eines Compilers führt verschiedene Code-Optimierungen auf der IR durch, unabhängig davon, welche CPU-Architektur vom gesamten Kompilierungsprozess angestrebt wird. Durch die Optimierung des Quellcodes unabhängig vom Zielmaschinencode kann der Compiler allgemeine Optimierungen vornehmen, die die Code-Performance über mehrere Versionen hinweg verbessern. Diese Verbesserungen können unabhängig von der spezifischen unterstützten Sprache oder Hardwarearchitektur vorgenommen werden. 
  3. Backend: Die Backend-Phase nutzt die Ausgabe der Middle-End-Phase und führt möglicherweise weitere CPU-spezifische Optimierungen und Konvertierungen durch. In dieser letzten Phase des Kompilierungsprozesses gibt der Compiler zielabhängigen Assemblercode aus, einschließlich Registerzuweisungen und Befehlsplanung. Die Backend-Phase resultiert in der Regel in Maschinencode, der auf die Zielbetriebssysteme und die Hardware spezialisiert ist. 

Vorteile der Verwendung eines Compilers

Compiler sind zwar nicht explizit notwendig, um brauchbaren Code zu erzeugen, aber die große Vielfalt und Komplexität sowohl der Codierung als auch der Maschinenumgebungen machen Compiler zu einer praktischen Notwendigkeit für die Erstellung ausführbarer Software. Dies sind die vier Hauptvorteile der Verwendung von Softwarecompilern.

Erleichtern der Codierung in Hochsprachen

Höhere Programmiersprachen verwenden eine Syntax und Schlüsselwörter, die denen der gesprochenen Sprachen näher sind, was die Bedienung für Entwickler wesentlich erleichtert. Compiler wandeln diesen menschenlesbaren Code in den komplexeren Maschinencode um, der zum Ausführen optimierter Anwendungen erforderlich ist.

Einige Beispiele für hochrangige Sprachen sind die folgenden Sprachen:

  • Python (für Webentwicklung, Data Science und andere Bereiche)
  • Java (verwendet für Android-Entwicklung, Unternehmensanwendungen und andere)
  • C++ (verwendet für Spieleentwicklung, Betriebssysteme und andere)
  • JavaScript (für die dynamische und interaktive Webentwicklung)
  • PHP (für serverseitige Skripte in der Webentwicklung)
  • C# (verwendet für Windows-Anwendungen, Unity Engine Spieleentwicklung)
Wiederholungen reduzieren

Compiler tragen zur Verbesserung der Effizienz bei, indem sie High-Level-Code in ausführbaren Maschinencode umwandeln. Die Ausgabe des Compilers wird mit einer .exe-Dateierweiterung gespeichert, die dann direkt von einem Computer ausgeführt werden kann. Dank des Compilers wird das Schreiben eines ausführbaren Programms zu einer einmaligen Aufgabe.

Nach der Fertigstellung kann der kompilierte Code so oft wie nötig ausgeführt werden. Dieser Prozess trägt dazu bei, dass Programme im Allgemeinen schneller und effizienter ausgeführt werden, da bestimmte Anwendungen oder Teile von Anwendungen getrennt von Laufzeitsoftwareaufgaben ausgeführt werden können.

Portabilität verbessern

Nicht alle Systeme können alle Arten von Programmcode ausführen. Compiler werden verwendet, um die von Entwicklern bevorzugten Codetypen in die Codetypen zu konvertieren, die Systeme für ihren Betrieb benötigen. Auf diese Weise verbessern Compiler die Portabilität von Programmen, indem sie Software in eine Vielzahl kompatibler Sprachen konvertieren, die sich leicht speichern, übertragen und auf verschiedenen Betriebssystemen und Hardwarearchitekturen ausführen lassen.

Fördern der Gesamtoptimierung

Während des Kompilierungsprozesses können Compiler eingesetzt werden, um Softwarefehler und -mängel zu identifizieren und zu beheben, was zu stabileren und besser optimierten Programmen führt. Compiler können auch zur Verbesserung der Softwaresicherheit beitragen, indem sie Speicherfehler wie Pufferüberläufe verhindern und Warnungen ausgeben, wenn potenzielle Speicherprobleme erkannt werden. 

Compiler vs. Interpreter

Während Compiler verwendet werden, um Quellcode in ausführbaren Maschinencode umzuwandeln, sind Interpreter eine andere Art von Programm, die ähnliche Funktionen bieten können, jedoch über einen anderen Mechanismus.

Anstatt den Quellcode zu konvertieren, führen Interpreter den Quellcode entweder direkt aus oder verwenden einen Zwischencode, der als Bytecode bekannt ist. Dabei handelt es sich um eine plattformunabhängige Low-Level-Darstellung des Quellcodes. Bytecode dient als Vermittler zwischen menschenlesbarem Quellcode und Maschinencode, konzipiert für die Ausführung durch eine virtuelle Maschine (VM) statt direkt auf der Hardware eines Computers. 

Theoretisch kann jede Programmiersprache entweder mit einem Compiler oder einem Interpreter ausgeführt werden. Einzelne Programmiersprachen eignen sich jedoch in der Regel besser für die Kompilierung oder Interpretation.

In der Praxis kann die Unterscheidung zwischen Compiler- und Interpretersprachen manchmal verschwimmen – ebenso wie die Unterscheidung zwischen Compilern und Interpretern selbst – da beide Arten von Programmen überlappende Funktionen aufweisen können. Während einige Sprachen eher kompiliert und andere eher interpretiert werden, ist es möglich, einen Compiler für eine Sprache zu schreiben, die üblicherweise interpretiert wird und umgekehrt.

Höhere Programmiersprachen werden in der Regel mit Blick auf eine bestimmte Art der Konvertierung entwickelt – entweder Kompilierung oder Interpretation –, jedoch handelt es sich hierbei eher um Empfehlungen als um strenge Einschränkungen. Beispielsweise wird BASIC häufig als interpretierte Sprache und C als kompilierte Sprache bezeichnet, jedoch existieren Compiler für BASIC ebenso wie C-Interpreter. 

Der Hauptunterschied zwischen Interpretern und Compilern liegt im Timing und in der Optimierung. Beide Programme versuchen, Quellcode in Zielcode umzuwandeln, der zunächst funktionsfähig ist und anschließend optimiert wird.

Je nach Betriebsumgebung kann kompilierter oder interpretierter Code besser geeignet sein, um unter Berücksichtigung der Hardwareleistung, des Arbeitsspeichers und der Speicherkapazität effizient ausgeführt zu werden. Abhängig von den Einschränkungen eines bestimmten Programms, einer Anwendung oder der Hardware kann entweder die Kompilierung, die Interpretation oder eine Kombination aus beidem die besten Ergebnisse erzielen. 

Daher kann die Interpretation die Kompilierung nicht vollständig ersetzen, aber sie kann die Kompilierungsaufgaben durch einen schrittweisen Umstellungsprozess in den Hintergrund verlagern. Compiler verwenden eine Ahead-of-Time-Konvertierungsstrategie (AOT), die den Quellcode vollständig in Zielcode umwandelt, bevor eine ausführbare Datei erstellt wird.

Interpreter hingegen führen entweder Code direkt aus, wenn eine Anwendung dies erfordert, oder verwenden Bytecode als Zwischenform, um den ausführbaren Quellcode für die virtuelle Maschine auszugeben. So bieten Interpreter zwar gewisse Geschwindigkeitsvorteile und Flexibilität, jedoch muss gegen Ende des Ausführungsstacks eine Reihe direkt ausführbarer Maschinenbefehle bereitgestellt werden.

In einigen Fällen, in denen eine geringe Effizienz vorrangig ist, können spezielle Interpreter aufgrund ihrer Fähigkeit zur Just-in-Time-Konvertierung (JIT) gegenüber Compilern vorzuziehen sein. JIT ist eine Strategie, bei der Teile des Quellcodes in Zielcode kompiliert und in einem Speicherpuffer für die sofortige Ausführung gespeichert werden. Die JIT-Interpretation kompiliert Code bei Bedarf und kombiniert dabei die Effizienz einer einmaligen Kompilierung durch einen herkömmlichen Compiler mit der Flexibilität, Code wiederholt auszuführen – oft schneller als Standard-Bytecode-Interpreter.

Da jedoch moderne Trends hin zur JIT-Kompilierung zusammen mit situationsabhängiger Bytecode-Interpretation zunehmen, werden viele Compiler so konzipiert, dass sie sowohl Kompilierungs- als auch Interpretierungsfunktionen bieten. Diese Überschneidung lässt die Grenzen zwischen diesen beiden Kategorien weiter verschwimmen. 

Weiterführende Lösungen
IBM Cloud Infrastructure Center 

IBM Cloud Infrastructure Center ist eine mit OpenStack kompatible Softwareplattform für die Verwaltung der Infrastruktur von Private Clouds auf IBM zSystems und IBM LinuxONE.

Cloud Infrastructure Center erkunden
IT-Infrastrukturlösungen

Entdecken Sie Server, Speicher und Software für die Hybrid-Cloud- und KI-Strategie Ihres Unternehmens.

IT-Infrastrukturlösungen entdecken
Lösungen für Cloud-Infrastrukturen

Finden Sie die richtige Cloud-Infrastrukturlösung für Ihre Geschäftsanforderungen und skalieren Sie Ressourcen nach Bedarf.

Cloud-Lösungen
Machen Sie den nächsten Schritt

Transformieren Sie Ihre Unternehmensinfrastruktur mit der Hybrid Cloud und KI-fähigen Lösungen von IBM. Entdecken Sie Server, Speicher und Software, die für die Sicherung, Skalierung und Modernisierung Ihres Unternehmens entwickelt wurden, oder greifen Sie auf Erkenntnisse von Experten zu, um Ihre generative KI-Strategie zu verbessern.

IT-Infrastrukturlösungen entdecken E-Book herunterladen