1. Kapitel EINFÜHRUNG UND ÜBERBLICK Compilerbau Prof. Dr. Wolfgang Schramm Vorbemerkungen 1/4 1 o o o o o o o o Einführung in die Grundlagen und Techniken des Compilerbaus. Übersetzer transformieren Texte einer Quellsprache, deren Struktur durch eine formale GrammaOk beschrieben ist, in eine Zielsprache. Klassische Anwendung: Übersetzung höherer Programmiersprachen in Maschinensprache. Übersetzung von Programmiersprachen = grundlegendes Problem der InformaOk. Gut verstandene Theorie zu formalen Sprachen und Maschinen, die sie akzepOeren. Techniken der Syntaxanalyse und ihre Verbindungen mit Übersetzungs-­‐akOonen sind ausgefeilt. Klare Zerlegung der Gesamtaufgabe des Übersetzungsprozesses in Teilaufgaben. ImplemenOerung von Programmiersprachen = Allgemeinbildung eines InformaOkers. Vorbemerkungen 2/4 2 o Themengebiete des Compilerbau: ¤ ¤ ¤ ¤ ¤ Programmiersprachen Rechnerarchitektur Theorie (formaler) Sprachen Datenstrukturen und Algorithmen So^ware Engineering Vorbemerkungen 3/4 3 o Einsatzbereiche von Compilerbautechniken ¤ ¤ ¤ ¤ ¤ ¤ ¤ Dokumentstrukturen GrafikspezifikaOonssprachen Kommandosprachen von Betriebssystemen Hardware-­‐Beschreibungssprachen Anfragesprachen für Datenbanksysteme Protokolle in verteilten Systemen Formate für den Datenaustausch Vorbemerkungen 4/4 4 o Vorlesungsinhalte ¤ ¤ ¤ ¤ Methoden des Übersetzerbaus (lexikalische Analyse, Syntaxanalyse, syntaxgesteuerte Übersetzung, Code-­‐OpOmierung). VielseiOgkeit der Anwendbarkeit der Techniken (Übersetzung einer Dokumentbeschreibungssprache nach LATEX = Beispiel für eine vollständige ÜbersetzerimplemenOerung) Einsatz von Werkzeugen (Scanner-­‐ und Parsergeneratoren; Lex/Flex und Yacc/-­‐Bison). Detaillierte Behandlung der ImplemenOerung eines Compilers für eine klassische imperaOve Programmiersprache auf der Basis einer abstrakten Maschine. Programmiersprachen -­‐ GeneraOonen 5 o Maschinensprachen (1. GeneraOon – seit 1945) ¤ ¤ o Assemblersprachen (2. GeneraOon – seit 1950) ¤ ¤ o ¤ Loslösung von der Hardware à problemorienOert ImperaOve/prozedurale/objektorienOerte Sprachen Bsp.: Fortran, Cobol, C, Java 4GL (Sprachen der 4. GeneraOon -­‐ seit 1970) ¤ o Befehle maschinennah (mnemotechnisch) Programme sind schwer lesbar, wenig übersichtlich und fehleranfällig Höhere Programmiersprachen (3. GeneraOon – seit 1954) ¤ o Befehle in Binärform Programme sind (fast) unlesbar, unübersichtlich und fehleranfällig Sprachenfür besondere Anwendungen; Bsp. SQL, PostScript, Maple DeklaraOve Programmiersprachen (5. GeneraOon -­‐ seit 1980) ¤ ¤ Nicht der Lösungsalgorithmus sondern die Problemformulierung mit Hilfe logischer Ausdrücke steht im Vordergrund Die Lösungsfindung ist weitgehend vom System vorgegeben. Bsp: Prolog Höhere Programmiersprachen 6 • Fortran I – 2000 • Common Lisp • Simula 67 • Algol • Scheme • Smalltalk 80 • PL/I • Haskell • CLOS (Common Lisp Object System) • Cobol 68 - 02 • Basic • Prolog • Pascal • ... • Oberon-2 • C++ • C • ObjectPascal • Modula-2 • Delphi • ... • Ada • Eiffel • Java • C# • ... Programmiersprachklassen 7 o ImperaOve Sprachen ¤ o FunkOonale Sprachen ¤ ¤ o ¤ Basieren auf der operaOonellen Sicht der Prädikatenlogik. Ausführungsmechanismus: ResoluOon. ObjektorienOerte Programmiersprachen ¤ ¤ o Keine Trennung zwischen Anweisungen und Ausdrücken. Namen nur für FunkOonen und Ausdrücke nicht aber für Speicherzellen. Logische Programmiersprachen ¤ o Eng an Struktur des von-­‐Neumann-­‐Rechners orienOert. Im Kern imperaOv, ihre Typsysteme unterstützen DatenabstrakOon. Ermöglichen evoluOonäre So^wareentwicklung. Sprachen für spezielle Anwendungsgebiete Beispiele: ¤ Hardware-­‐Beschreibungssprachen. ¤ Kommandosprachen für Betriebssysteme. ¤ Text-­‐ und GrafikspezifikaOonssprachen. o Skriptsprachen ¤ ¤ ¤ InterpreOerte Sprachen mit Operatoren auf höherer Ebene, Kurze, sehr mächOge Befehle / Berechnungen = Skripts Beipiele: Awk, JavaScript. Perl, PHP, Python, Ruby, Tcl Abstammung von Programmiersprachen 8 1957 1960 Fortran I Lisp 1965 Cobol Algol 60 Fortran IV PL/I Algol-W Basic Algol 68 1970 Pascal Simula 67 BCPL C 1975 1980 1985 Fortran 77 Smalltalk 80 Common Lisp CLOS 1990 1995 Ada Modula-2 ObjectPascal Delphi Oberon-2 C++ Ansi-C Fortran 90 Java Ada 9x C# Fortran 95 Aufgabe eines Compilers 9 Quellprogramm in A Compiler Meldungen Zielprogramm in B Grobmodell eines Compilers 10 Quellprogramm Analyse Zwischenprogramm Synthese Zielprogramm Feinmodell eines Compilers 11 Quellprogramm lexikalische Analyse Analyse Syntaxanalyse semantische Analyse Symboltabellenverwaltung Zwischencodeerzeugung Fehlerbehandlung Codeoptimierung Codergenerierung Zielprogramm Synthese Symboltabelle 12 . . . enthält InformaOon über Bezeichner, die vom Programmierer eingeführt werden. Format: Bezeichner Attribute Beispiel: double r; Attribute von r: • Typ: double • Relative Adresse innerhalb des umschließenden Unterprogramms / der Klasse • Gültigkeitsbereich Fehlerbehandlung 13 o Ziel der Fehlerbehandlung ¤ ¤ ¤ Entdeckung aller Fehler Beschreibung der Fehler Behebung der Fehler für eine Fortsetzung der Übersetzung Lexikalische Analyse 14 Eingabe Ausgabe Folge von einzelnen Zeichen – Buchstaben – Ziffern – Leerzeichen – Zeilenende – Operatorsymbole – Interpunktionszeichen Gruppe zusammengehöriger Zeichen – Bezeichner – Schlüsselworte – Operatoren: = <= != . . . – Zahlen – Trennzeichen /* */ – Zeichenketten “ . . . . . “ Aufgabe Erkennen gewisser “Grundsymbole“ im Zeichenstrom Zusätzliche Aktionen – – – – Vorbereiten von Einträgen in die Symboltabelle Entfernen von Kommentaren Entfernen überflüssiger Leerzeichen (Blank Stripping) Fehlerbehandlung lexikalische Elemente, Lexeme, Token SyntakOsche Analyse 1/2 15 Eingabe: Folgen lexikalischer Elemente. Aufgabe: Erkennen hierarchischer Strukturen in Programmen. Ausgabe: Hierarchische Darstellung („Baum“) von Folgen lexikalischer Elemente = Strukturbaum. Beispiel: mitte = (links + rechts) / 2; assignment identifier = Strukturbaum expression expression identifier + / identifier number SyntakOsche Analyse 2/2 16 Komprimierung des Strukturbaums = identifier / + Syntaxbaum identifier Zusätzliche Aktionen – – Ergänzungen in der Symboltabelle Fehlerbehandlung number identifier SemanOsche Analyse 1/2 17 Eingabe: Hierarchische Darstellung des Quellprogramms Aufgabe: Überprüfung der Typverträglichkeiten Überprüfung von Aspekten, die nicht von der syntakOschen Analyse erfassbar sind, z.B.: n DeklaraOon / Verwendung von Bezeichnern. n ÜbereinsOmmung zwischen formalen und aktuellen Parametern. n ÜbereinsOmmung zwischen Dimension eines Feldes und Indizierung des Zugriffs. n Auflösen überladener oder polymorpher OperaOonen. Ausgabe: Geänderter Struktur-­‐ (oder Syntax-­‐) Baum SemanOsche Analyse 2/2 18 Beispiel: mitte = (links + rechts) / 2; Feststellen des Typs der Variablen links und rechts. Überprüfen, ob für die beiden Typen idenOsch sind. Sind beide beispielsweise vom Typ int, dann wird eine ganzzahlige AddiOon durchgeführt. Sind die beiden von unterschiedlichem Typ, wird, falls in der Programmiersprache zugelassen, zuerst eine TypkonverOerung durchgeführt. Dann wird analog weiter verfahren: Feststellen des Typs der AddiOon von links und rechts und von 2. Zwischencode Erzeugung 19 Eingabe: Strukturbaum (Syntaxbaum) Aufgabe: Erzeugen eines “höheren Maschinencodes“ aus dem Syntaxbaum Ausgabe: Zwischencode Beispiel: mitte = (links + rechts) / 2; hilf_1 = links + rechts hilf_2 = hilf_1 div 2 mitte = hilf_2 3-Adress-Code CodeopOmierung 20 Eingabe: Zwischencode Aufgabe: Auffinden von Ineffizienzen im Zwischencode Ausgabe: (OpOmierter) Zwischencode Beispiel: hilf_1 = links + rechts hilf_2 = hilf_1 div 2 mitte = hilf_2 hilf_1 = links + rechts mitte = hilf_1 div 2 Codeerzeugung 21 Eingabe: OpOmierter Zwischencode Aufgabe: Erzeugen von Assembler-­‐ oder Maschinencode für die spezielle Zielmaschine Ausgabe: Maschinencode Beispiel: hilf_1 = links + rechts mitte = hilf_1 div 2 LOAD links ADD rechts DIV 2 STORE mitte 1-Registermaschine “Akkumulator“ Die Systemumgebung des Compilers 22 Vorform des Quellprogramms Präprozessor Quellprogramm Compiler Zielprogramm in Assemblersprache Assembler Programm in verschiebbarem Maschinencode Lader/Binder Programm in absolutem Maschinencode Andere Programmteile, Pro-­‐ gramme aus Bibliotheken in verschiebbarem Maschinencode Aufgaben von Präprozessor, Assembler und Binder/Lader 23 o o o Präprozessor: Erzeugt aus der Vorform des Quellprogramms (enthält Spracherweiterungen wie z.B. Makros, Einbesung von Datenbank-­‐ anfragesprachen) die Eingabe für den Compiler. Assembler: Überführt ein Programm in Assemblersprache in ein „verschiebbares“ Programm in Maschinensprache. D.h. die im Maschinen-­‐ programm verwendeten Adressen sind relaOv zum Programmanfang. Binder und Lader: Bauen eine Menge von verschiebbaren Maschinenprogrammen aus unterschiedlichen Dateien zu einem einzigen ausführbaren Programm zusammen und laden es in den Hauptspeicher. Dabei werden externe Referenzen (links) aufgelöst (Binder) und es werden die relaOven Adressen entsprechend der LadeposiOon in absolute Adressen umgewandelt. Ablauf eines komplexen Übersetzungsvorgangs 24 Programmeinheit1 Assemblercode1 Programmeinheitn Compiler Assemblercoden Assembler relokatierbarer Maschinencoden relokatierbarer Maschinencode1 Linker relokatierbare Einheit ausführbarer Maschinencode im Hauptspeicher Loader Compiler und Interpreter 25 o o Compiler: Übersetzt ein Quellprogramm in ein Zielprogramm, das zu einem beliebigen späteren Zeitpunkt ausgeführt wird. Interpreter: Analysiert das Quellprogramm genauso wie der Compiler. Statt der Überführung in ein Zielprogramm, wird das Quellprogramm direkt ausgeführt. Ausführung von Compiler-­‐Sprachen 26 Programm (höhere Sprache) 1.Describe system Set of Subsystems Set of Interconnections Compiler 1.Describe system Set of Subsystems Set of Interconnections Programm (Maschinensprache) 1.Describe system Set of Subsystems 2.Describe subsystems by their properties 2.Describe subsystems by their properties 2.Describe subsystems by their properties Subsystems and Properties Subsystems and Properties Subsystems and Properties Set of Interconnections 3.Determine potential mismatches 3.Determine potential mismatches List of Potential Mismatches List of Potential Mismatches 3.Determine potential mismatches List of Potential Mismatches 4.Determine actual mismatches 4.Determine actual mismatches 4.Determine actual mismatches List of Mismatches List of Mismatches List of Mismatches Ausführung von Compiler-­‐Sprachen 27 Programm (Maschinensprache) 1.Describe system Set of Subsystems Set of Interconnections 2.Describe subsystems by their properties Subsystems and Properties 3.Determine potential mismatches List of Potential Mismatches 4.Determine actual mismatches List of Mismatches Ausführung von Interpreter-­‐Sprachen 28 Programm (höhere Sprache) 1.Describe system Set of Subsystems Set of Interconnections 2.Describe subsystems by their properties Subsystems and Properties 3.Determine potential mismatches List of Potential Mismatches 4.Determine actual mismatches List of Mismatches Interpreter InterpretaOon -­‐ Arbeitsweise 29 = direktes Ausführen der zu den Anweisungen der höheren Programmiersprache gehörenden AkOonen. 1 Lesen der nächsten Anweisung 2 Bestimmen der auszuführenden Aktion 3 Ausführen dieser Aktion Vor-­‐ und Nachteile von Compilern und Interpretern 30 Compiler ¤ ¤ ¤ ¤ ¤ Compiler können das Programm bei der Übersetzung auf Syntax-­‐ und SemanOk-­‐ Fehler überprüfen, d.h. auf Schreibfehler und Widersprüche gegen die SprachdefiniOon. Anweisungen werden genau einmal (beim Übersetzen) geprü^ und beim Ablauf direkt vom Prozessor ausgeführt. Compiler zu erstellen ist schwierig. Treten zur Laufzeit Fehler auf (z.B. eine Division durch 0), sind diese meist schwer zu lokalisieren. Compiler erzeugen Code, der nur auf einem speziellen Prozessor läu^; Unterschiede z.B. in der Darstellung von Datentypen kann zu unterschiedlichen Ergebnissen des gleichen Programms führen. ¨ Interpreter ¤ ¤ ¤ ¤ ¤ SemanOk-­‐Fehler werden eventuell erst bei der Programmausführung bemerkt, ein Absturz kann die Folge sein. Anweisungen werden bei jedem Durchlauf erneut interpreOert, daher laufen interpreOerte Programme langsamer als übersetzte (Just-­‐In-­‐Time-­‐Compiler helfen). Interpreter sind einfacher und schneller zu entwickeln. Interpreter können genauere Fehlermeldungen geben als Compiler. Interpreter abstrahieren vom zugrundeliegenden Prozessor, Programme liefern auf jedem Rechner idenOsche Ergebnisse. Hybridcompiler 31 Quellprogramm Java-Sprachprozessoren Übersetzer Zwischenprogramm Eingabe Virtuelle Maschine Ausgabe Zusammenspiel von Compiler und Interpreter 32 Quellsprache A Compiler Zielsprache B Quellsprache B Interpreter Abstrakte Maschine für B Maschinensprache X Maschinensprache X Reale Maschine für X Hardware Werkzeuge für den Compilerbau 33 Werkzeuge für die verschiedenen Teilaufgaben: o Scannergenerator (Bsp.: Lex, Flex, JFlex) o Parsergeneratoren (Bsp.: Yacc, Bison, JavaCC, SableCC) o Generator für abstrakte Syntaxbäume o Generator für Asributauswerter o TransformaOon abstrakter Syntaxbäume o Generator für Codegeneratoren Vorlesungsgliederung 34 OrienOert an den Phasen des Compilers: • • • • Lexikalische Analyse SyntakOsche Analyse SemanOsche Analyse – Syntax gesteuerte Übersetzung (Zwischen)code Erzeugung und CodeopOmierung Literaturempfehlungen – eine kleine Auswahl 1/2 35 o A. Aho, M. Lam, R. Sethi, J. Ullman: Compilers – Principles, Techniques and Tools 2nd EdiOon, Pearson InternaOonal 2007; Paperback (Englisch) 83,45 € Deutsche Übersetzung Pearson Verlag 2008 69,95 € Das Standardwerk des Compilerbaus. Hat (in seiner Erstausgabe) gewissermaßen alle weiteren Bücher zum Compilerbau beeinflusst. Sehr umfassend (Theorie + Praxis) und anschaulich, gut verständlich. o o R. GüOng, M. Erwig: Übersetzerbau – Techniken, Werkzeuge, Anwendungen, Springer Verlag 1999, 32,95 € Verständlich geschriebenes, kompaktes Buch, ideal für den Einsatz der Compilerbautechniken in der Praxis. Buch mit dem geringsten Theorieanteil aber mit schönen Beispielen. N. Wirth: Grundlagen und Techniken des Compilerbaus 2. Auflage, Oldenbourg Verlag, München, 2008, 24,80 € Sehr kompaktes Buch. Die Theorie wird sehr knapp behandelt. Schwerpunkt liegt auf der prakOschen Umsetzung, d.h. der ImplemenOerung eines Compilers (mit konkreten Codefragmenten) für eine Teilmenge von Oberon. Literaturempfehlungen – eine kleine Auswahl 2/2 36 o R. Wilhelm, D. Maurer: Übersetzerbau – Theorie, KonstrukOon, Generierung 2. Auflage, Springer Verlag 1997, 32,95 € Gutes Buch mit anderem (ungewöhnlichem) Auyau. Auyau orienOert an den 4 Typen von Programmiersprachen. Behandelt auch die Übersetzung funkOonaler, logischer und objektorienOerter Sprachen. DidakOsch anders mit Theorieanteil, der nicht ganz einfach zu verstehen ist. o O. Mayer: Syntaxanalyse, BI 1978 Ein umfassendes Buch mit hohem Theorieanteil zum Thema Syntaxanalyse. o J. Levine, T. Mason, D. Brown: „ lex & yacc“. O‘Reilly 1995. 29 €. Gute, einfache Einführung in lex und yacc. Geht auch auf die unterschiedlichen „lexe“ und „yaccs“ ein. o Herold: „ lex & yacc. Die Profitools zur lexikalischen und syntakOschen Textanalyse“. Addison-­‐Wesley 2003. 24,95 €. Gute, einfache Einführung in lex und yacc. Wie das Buch von Levine mit etwas zu vielen Redundanzen.