Ein Compiler (auch Kompilierer; von ‚zusammentragen‘ bzw. ‚aufhäufen‘) ist ein Computerprogramm, das Quellcodes einer bestimmten Programmiersprache in eine Form übersetzt, die von einem Computer (direkter) ausgeführt werden kann. Daraus entsteht ein mehr oder weniger direkt ausführbares Programm. Davon zu unterscheiden sind Interpreter, etwa für frühe Versionen von BASIC, die keinen Maschinencode erzeugen.

Teils wird zwischen den Begriffen Übersetzer und Compiler unterschieden. Ein Übersetzer überführt ein Programm aus einer formalen Quellsprache in ein semantisches Äquivalent in einer formalen Zielsprache. Compiler sind spezielle Übersetzer, die Programmcode aus höheren Programmiersprachen, in ausführbare Maschinensprache einer bestimmten Rechnerarchitektur oder einen Zwischencode überführen. Diese Trennung zwischen den Begriffen Übersetzer und Compiler wird nicht in allen Fällen vorgenommen.

Der Vorgang der Übersetzung durch den Compiler wird als Kompilierung oder Umwandlung bezeichnet. Das Gegenteil, also die Rückübersetzung von Maschinensprache in Quelltext einer bestimmten Programmiersprache, wird Dekompilierung und entsprechende Programme Decompiler genannt.

Terminologie Ein Übersetzer ist ein Programm, das als Eingabe ein in einer Quellsprache formuliertes Programm akzeptiert und es in ein semantisch äquivalentes Programm in einer Zielsprache übersetzt.Michael Eulenstein: Generierung portabler Compiler. Das portable System POCO. (= Informatik-Fachberichte 164) Springer Verlag: Berlin, u. a., 1988, S. 1; Hans-Jochen Schneider (Hrsg.): Lexikon Informatik und Datenverarbeitung. 4. Auflage. Oldenbourg Verlag: München, Berlin, 1998, 900; Manfred Broy: Informatik. Eine grundlegende Einführung. Band 2: Systemstrukturen und Theoretische Informatik. 2. Auflage. Springer Verlag: Berlin, Heidelberg, 1998, S. 173. Es wird also insbesondere gefordert, dass das erzeugte Programm die gleichen Ergebnisse wie das gegebene Programm liefert. Als Ausnahme wird oft die Quell-Sprache Assembler angesehen – ihr Übersetzer (in Maschinencode) heißt „Assembler“ und wird i. A. nicht als „Compiler“ bezeichnet. Die Aufgabe des Übersetzers umfasst ein großes Spektrum an Teilaufgaben, von der Syntaxanalyse bis zur Zielcodeerzeugung. Eine wichtige Aufgabe besteht auch darin, Fehler im Quellprogramm zu erkennen und zu melden.

Das Wort „Compiler“ stammt vom Englischen „to compile“ (dt. zusammentragen, zusammenstellen) ab und heißt im eigentlichen Wortsinn also „Zusammentrager“. In den 1950er-Jahren war der Begriff noch nicht fest in der Computerwelt verankert.Carsten Busch: Mataphern in der Informatik. Modellbildung – Formalisierung – Anwendung. Springer Fachmedien: Wiesbaden, 1998, S. 171. Ursprünglich bezeichnete Compiler ein Hilfsprogramm, das ein Gesamtprogramm aus einzelnen Unterprogrammen oder Formelauswertungen zusammentrug, um spezielle Aufgaben auszuführen. (Diese Aufgabe erfüllt heute der Linker, der jedoch auch im Compiler integriert sein kann.) Die einzelnen Unterprogramme wurden noch „von Hand“ in Maschinensprache geschrieben. Ab 1954 kam der Begriff „algebraic compiler“ für ein Programm auf, das die Umsetzung von Formeln in Maschinencode selbständig übernahm. Das „algebraic“ fiel im Laufe der Zeit weg.Axel Rogat: , Kapitel 1.11: ; Thomas W. Parsons: Introduction to Compiler Construction. Computer Science Press: New York, 1992, S. 1.

Ende der 1950er-Jahre wurde der Begriff des Compilers im englischsprachigen Raum noch kontrovers diskutiert. So hielt das Fortran-Entwicklerteam noch jahrelang am Begriff „translator“ (deutsch „Übersetzer“) fest, um den Compiler zu bezeichnen. Diese Bezeichnung ist sogar im Namen der Programmiersprache Fortran selbst enthalten: Fortran ist zusammengesetzt aus Formula und Translation, heißt also in etwa Formel-Übersetzung. Erst 1964 setzte sich der Begriff Compiler auch im Zusammenhang mit Fortran gegenüber dem Begriff Translator durch. Nach Carsten Busch liegt eine „besondere Ironie der Geschichte darin“, dass der Begriff Compiler im Deutschen mit „Übersetzer“ übersetzt wird.Zur Übersetzung des englischen „compiler“ mit dem deutschen „Übersetzer“ siehe u. a.: Hans-Jürgen Siegert, Uwe Baumgarten: Betriebssysteme. Eine Einführung. 6. Auflage. Oldenbourg Verlag: München, Wien, 2007, S. 352; Christoph Prevezanos: Computer-Lexikon 2011. Markt+Technik Verlag: München, 2010, S. 940; Christoph Prevenzanos: Technisches Schreiben. Für Informatiker, Akademiker, Techniker und den Berufsalltag. Hanser Verlag: München, 2013, S. 130. Einige deutsche Publikationen verwenden jedoch auch den englischen Fachbegriff Compiler anstelle von Übersetzer.So beispielsweise Alfred V. Aho, Monica S. Lam, Ravi Sethi, Jeffrey D. Ullman: Compiler. Prinzipien, Techniken und Werkzeuge. 2. Auflage. Pearson Studium: München, 2008.

In einem engeren Sinne verwenden einige deutschsprachige Publikationen den Fachbegriff Compiler jedoch nur, wenn die Quellsprache eine höhere Programmiersprache ist als die Zielsprache.Siehe dazu Hans-Jochen Schneider (Hrsg.): Lexikon Informatik und Datenverarbeitung. 4. Auflage. Oldenbourg Verlag: München, Berlin, 1998: Artikel „Compiler“, S. 158, und Artikel „Übersetzer“, S. 900. Typische Anwendungsfälle sind die Übersetzung einer höheren Programmiersprache in die Maschinensprache eines Computers, sowie die Übersetzung in Bytecode einer virtuellen Maschine. Zielsprache von Compilern (in diesem Sinne) kann auch eine Assemblersprache sein. Ein Übersetzer zur Übertragung von Assembler-Quellprogrammen in Maschinensprache wird als Assembler oder Assemblierer bezeichnet.Hartmut Ernst, Jochen Schmidt; Gert Beneken: Grundkurs Informatik. Grundlagen und Konzepte für die erfolgreiche IT-Praxis. Eine umfassende, praxisorientierte Einführung. 5. Auflage. Springer: Wiesbaden, 2015, S. 409.

Geschichte Bereits für die erste entworfene höhere Programmiersprache, den Plankalkül von Konrad Zuse, plante dieser – nach heutiger Terminologie – einen Compiler. Zuse bezeichnete ein einzelnes Programm als Rechenplan und hatte schon 1944 die Idee für ein sogenanntes Planfertigungsgerät, welches automatisch aus einem mathematisch formulierten Rechenplan einen gestanzten Lochstreifen mit entsprechendem Maschinenplan für den Zuse-Z4-Computer erzeugen sollte.Hans Dieter Hellige: Geschichten der Informatik. Visionen, Paradigmen, Leitmotive. Springer, Berlin 2004, ISBN 3-540-00217-0, S. 45, 104, 105.

Konkreter als die Idee von Zuse eines Planfertigungsgeräts war ein Konzept von Heinz Rutishauser zur automatischen Rechenplanfertigung. In einem Vortrag vor der Gesellschaft für Angewandte Mathematik und Mechanik (GAMM) wie auch 1951 in seiner Habilitationsschrift an der ETH Zürich beschrieb er, welche zusätzlichen Programmierbefehle (Instruktionen) und Hardware-Ergänzungen an der damals an der ETHZ genutzten Z4 nötig seien, um den Rechner ebenfalls als Hilfsmittel zur automatischen Programmerstellung einzusetzen.Stefan Betschon: Der Zauber des Anfangs. Schweizer Computerpioniere. In: Franz Betschon, Stefan Betschon, Jürg Lindecker, Willy Schlachter (Hrsg.): Ingenieure bauen die Schweiz. Technikgeschichte aus erster Hand. Verlag Neue Zürcher Zeitung, Zürich 2013, ISBN 978-3-03823-791-4, S. 381–383.Friedrich L. Bauer: My years with Rutishauser.Stefan Betschon: Die Geschichte der Zukunft. In: Neue Zürcher Zeitung. 6. Dezember 2016, S. 11.

mini|hochkant|Grace Hopper (1984)

Ein früher Compiler wurde 1949 von der Mathematikerin Grace Hopper konzipiert. Bis zu diesem Zeitpunkt mussten Programmierer direkt Maschinencode erstellen. (Der erste Assembler wurde zwischen 1948 und 1950 von Nathaniel Rochester für eine IBM 701 geschrieben.) Um diesen Prozess zu vereinfachen, entwickelte Grace Hopper eine Methode, die es ermöglichte, Programme und ihre Unterprogramme in einer mehr an der menschlichen als der maschinellen Sprache orientierten Weise auszudrücken. Am 3. Mai 1952 stellte Hopper den ersten Compiler A-0 vor, der Algorithmen aus einem Katalog abrief, Code umschrieb, in passender Reihenfolge zusammenstellte, Speicherplatz reservierte und die Zuteilung von Speicheradressen organisierte. Anfang 1955 präsentierte Hopper bereits einen Prototyp des Compilers B-0, der nach englischen, französischen oder deutschen Anweisungen Programme erzeugte. Hopper nannte ihren Vortrag zum ersten Compiler „The Education of a Computer“ („Die Erziehung eines Computers“).

Die Geschichte des Compilerbaus wurde von den jeweils aktuellen Programmiersprachen (vgl. Zeittafel der Programmiersprachen) und Hardwarearchitekturen geprägt. Weitere frühe Meilensteine sind 1957 der erste Fortran-Compiler und 1960 der erste COBOL-Compiler. Viele Architekturmerkmale heutiger Compiler wurden aber erst in den 1960er Jahren entwickelt.

Früher wurden teilweise auch Programme als Compiler bezeichnet, die Unterprogramme zusammenfügen.F. L. Bauer, J. Eickel: Compiler Construction: An Advanced Course. Springer, 1975. Dies geht an der heutigen Kernaufgabe eines Compilers vorbei, weil Unterprogramme heutzutage mit anderen Mitteln eingefügt werden können: Entweder im Quelltext selbst, beispielsweise von einem Präprozessor (siehe auch Precompiler) oder bei übersetzten Komponenten von einem eigenständigen Linker.

Arbeitsweise Die prinzipiellen Schritte bei der Übersetzung eines Quellcodes in einen Zielcode lauten:

Syntaxprüfung Es wird geprüft, ob der Quellcode ein gültiges Programm darstellt, also der Syntax der Quellsprache entspricht. Festgestellte Fehler werden protokolliert. Ergebnis ist eine Zwischendarstellung des Quellcodes.

Analyse und Optimierung Die Zwischendarstellung wird analysiert und optimiert. Dieser Schritt variiert im Umfang je nach Compiler und Benutzereinstellung stark. Er reicht von einfacheren Effizienzoptimierungen bis hin zu Programmanalyse.

Codeerzeugung Die optimierte Zwischendarstellung wird in entsprechende Befehle der Zielsprache übersetzt. Hierbei können weitere, zielsprachenspezifische Optimierungen vorgenommen werden. Beachte: Moderne Compiler führen mittlerweile (meist) keine Codegenerierung mehr selbst durch. C++ bei eingeschalteter globaler Optimierung: Die Codegenerierung erfolgt beim Linken. C#: Die Codegenerierung erfolgt aus, während der Kompilierung erzeugtem, Common-Intermediate-Language-Code während der Laufzeit durch den JIT- oder NGEN-Compiler der .NET-Umgebung. gleiches gilt für andere Sprachen, die die Common Language Infrastructure nutzen wie F# und VB.NET, siehe Liste von .NET-Sprachen. Java: Die Codegenerierung erfolgt aus, während der Kompilierung erzeugtem, Java-Byte-Code während der Laufzeit durch den Java-JIT-Compiler. Codegenerierung während der Runtime ermöglicht: modulübergreifende Optimierungen, exakte Anpassungen an die Zielplattform (Befehlssatz, Anpassung an die Fähigkeiten der CPU), Nutzung von Profiling-Informationen.

Aufbau eines Compilers Der Compilerbau, also die Programmierung eines Compilers, ist eine eigenständige Disziplin innerhalb der Informatik.

Moderne Compiler werden in verschiedene Phasen gegliedert, die jeweils verschiedene Teilaufgaben des Compilers übernehmen. Einige dieser Phasen können als eigenständige Programme bzw. Softwarekomponenten realisiert werden, z. B. Precompiler oder Präprozessor. Sie werden sequentiell ausgeführt. Im Wesentlichen lassen sich zwei Phasen unterscheiden: das Frontend (auch Analysephase), das den Quelltext analysiert und daraus einen attributierten Syntaxbaum erzeugt, sowie das Backend (auch Synthesephase), das daraus den Programmcode der Zielsprache erzeugt.

Frontend (auch „Analysephase“) Im Compiler-Frontend wird der Code analysiert, strukturiert und auf Fehler geprüft. Es ist selbst wiederum in Phasen gegliedert. Sprachen wie modernes C++ erlauben aufgrund von Mehrdeutigkeiten in ihrer Grammatik keine Aufteilung der Syntaxanalyse in lexikalische Analyse, syntaktische Analyse und semantische Analyse. Ihre Compiler sind entsprechend komplex.

Lexikalische Analyse