mirror of
https://github.com/MartinThoma/LaTeX-examples.git
synced 2025-04-25 06:18:05 +02:00
Abschnitt 'Compilerbau' begonnen.
This commit is contained in:
parent
e9af39c3a1
commit
ff9e624576
6 changed files with 162 additions and 4 deletions
|
@ -9,3 +9,4 @@ in dem Erstellen dieses Skripts steckt:
|
||||||
|01.02.2014 | 11:15 - 11:45 | Thoma | Haskell Class Hierachy
|
|01.02.2014 | 11:15 - 11:45 | Thoma | Haskell Class Hierachy
|
||||||
|01.02.2014 | 16:00 - 17:00 | Thoma | Abschnitt über Rekursion hinzugefügt
|
|01.02.2014 | 16:00 - 17:00 | Thoma | Abschnitt über Rekursion hinzugefügt
|
||||||
|04.02.2014 | 13:00 - 14:00 | Thoma | Viel zu Haskell ergänzt; Funktionen höherer Ordnung beschrieben
|
|04.02.2014 | 13:00 - 14:00 | Thoma | Viel zu Haskell ergänzt; Funktionen höherer Ordnung beschrieben
|
||||||
|
|14.02.2014 | 08:30 - 09:30 | Thoma | Abschnitt über Compilerbau begonnen
|
|
@ -34,7 +34,7 @@ unterscheiden.
|
||||||
\centering
|
\centering
|
||||||
\begin{tabular}{|l|l||l|l||l|l||l|l|}
|
\begin{tabular}{|l|l||l|l||l|l||l|l|}
|
||||||
\hline
|
\hline
|
||||||
\textbf{Dez.} & \textbf{Zeichen} & \textbf{Dez.} & \textbf{Zeichen} & \textbf{Dez.} & \textbf{Zeichen} & \textbf{Dez.} & \textbf{Zeichen} \\ \hline\hline
|
\textbf{Dez.} & \textbf{Z.} & \textbf{Dez.} & \textbf{Z.} & \textbf{Dez.} & \textbf{Z.} & \textbf{Dez.} & \textbf{Z.} \\ \hline\hline
|
||||||
0 & ~ & 31 & ~ & 64 & @ & 96 & ' \\ \hline
|
0 & ~ & 31 & ~ & 64 & @ & 96 & ' \\ \hline
|
||||||
1 & ~ & ~ & ~ & 65 & A & 97 & a \\ \hline
|
1 & ~ & ~ & ~ & 65 & A & 97 & a \\ \hline
|
||||||
2 & ~ & ~ & ~ & 66 & B & 98 & b \\ \hline
|
2 & ~ & ~ & ~ & 66 & B & 98 & b \\ \hline
|
||||||
|
|
|
@ -1,7 +1,126 @@
|
||||||
\chapter{Compilerbau}
|
\chapter{Compilerbau}
|
||||||
\index{Compilerbau|(}
|
\index{Compilerbau|(}
|
||||||
|
|
||||||
TODO
|
Wenn man über Compiler redet, meint man üblicherweise \enquote{vollständige Übersetzer}:
|
||||||
|
|
||||||
\index{Compilerbau|)}
|
\begin{definition}\xindex{Compiler}%
|
||||||
|
Ein \textbf{Compiler} ist ein Programm $C$, das den Quelltext eines Programms
|
||||||
|
$A$ in eine ausführbare Form übersetzen kann.
|
||||||
|
\end{definition}
|
||||||
|
|
||||||
|
Jedoch gibt es verschiedene Ebenen der Interpretation bzw. Übersetzung:
|
||||||
|
\begin{enumerate}
|
||||||
|
\item \textbf{Reiner Interpretierer}: TCL, Unix-Shell
|
||||||
|
\item \textbf{Vorübersetzung}: Java-Bytecode, Pascal P-Code, Python\footnote{Python hat auch \texttt{.pyc}-Dateien, die Python-Bytecode enthalten.}, Smalltalk-Bytecode
|
||||||
|
\item \textbf{Laufzeitübersetzung}: JavaScript\footnote{JavaScript wird nicht immer zur Laufzeit übersetzt. Früher war es üblich, dass JavaScript nur interpretiert wurde.}
|
||||||
|
\item \textbf{Vollständige Übersetzung}: C, C++, Fortran
|
||||||
|
\end{enumerate}
|
||||||
|
|
||||||
|
Zu sagen, dass Python eine interpretierte Sprache ist, ist in etwa so korrekt
|
||||||
|
wie zu sagen, dass die Bibel ein Hardcover-Buch ist.\footnote{Quelle: stackoverflow.com/a/2998544, danke Alex Martelli für diesen Vergleich.}
|
||||||
|
|
||||||
|
Reine Interpretierer lesen den Quelltext Anweisung für Anweisung und führen
|
||||||
|
diese direkt aus.
|
||||||
|
|
||||||
|
\todo[inline]{Bild}
|
||||||
|
|
||||||
|
Bei der \textit{Interpretation nach Vorübersetzung} wird der Quelltext analysiert
|
||||||
|
und in eine für den Interpretierer günstigere Form übersetzt. Das kann z.~B.
|
||||||
|
durch
|
||||||
|
\begin{itemize}
|
||||||
|
\item Zuordnung Bezeichnergebrauch - Vereinbarung\todo{?}
|
||||||
|
\item Transformation in Postfixbaum
|
||||||
|
\item Typcheck, wo statisch möglich
|
||||||
|
\end{itemize}
|
||||||
|
geschehen. Diese Vorübersetzung ist nicht unbedingt maschinennah.
|
||||||
|
|
||||||
|
\todo[inline]{Bild}
|
||||||
|
|
||||||
|
Die \textit{Just-in-time-Compiler}\xindex{Compiler!Just-in-time}\index{JIT|see{Just-in-time Compiler}} (kurz: JIT-Compiler) betreiben
|
||||||
|
Laufzeitübersetzung. Folgendes sind Vor- bzw. Nachteile von Just-in-time Compilern:
|
||||||
|
\begin{itemize}
|
||||||
|
\item schneller als reine Interpretierer
|
||||||
|
\item Speichergewinn: Quelle kompakter als Zielprogramm\todo{Was ist hier gemeint?}
|
||||||
|
\item Schnellerer Start des Programms
|
||||||
|
\item Langsamer (pro Funktion) als vollständige Übersetzung
|
||||||
|
\item kann dynamisch ermittelte Laufzeiteigenschaften berücksichtigen (dynamische Optimierung)
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
Moderne virtuelle Maschinen für Java und für .NET nutzen JIT-Compiler.
|
||||||
|
|
||||||
|
Bei der \textit{vollständigen Übersetzung} wird der Quelltext vor der ersten
|
||||||
|
Ausführung des Programms $A$ in Maschinencode (z.~B. x86, SPARC) übersetzt.
|
||||||
|
|
||||||
|
\todo[inline]{Bild}
|
||||||
|
|
||||||
|
\section{Funktionsweise}
|
||||||
|
Üblicherweise führt ein Compiler folgende Schritte aus:
|
||||||
|
\begin{enumerate}
|
||||||
|
\item Lexikalische Analyse
|
||||||
|
\item Syntaktische Analyse
|
||||||
|
\item Semantische Analyse
|
||||||
|
\item Zwischencodeoptimierung
|
||||||
|
\item Codegenerierung
|
||||||
|
\item Assemblieren und Binden
|
||||||
|
\end{enumerate}
|
||||||
|
|
||||||
|
\subsection{Lexikalische Analyse}\xindex{Analyse!lexikalische}%
|
||||||
|
In der lexikalischen Analyse wird der Quelltext als Sequenz von Zeichen betrachtet.
|
||||||
|
Sie soll bedeutungstragende Zeichengruppen, sog. \textit{Tokens}\xindex{Token},
|
||||||
|
erkennen und unwichtige Zeichen, wie z.~B. Kommentare überspringen. Außerdem
|
||||||
|
sollen Bezeichner identifiziert und in einer \textit{Stringtabelle}\xindex{Stringtabelle}
|
||||||
|
zusammengefasst werden.
|
||||||
|
|
||||||
|
\begin{beispiel}
|
||||||
|
\todo[inline]{Beispiel erstellen}
|
||||||
|
\end{beispiel}
|
||||||
|
|
||||||
|
\section{Syntaktische Analyse}\xindex{Analyse!syntaktische}%
|
||||||
|
In der syntaktischen Analyse wird überprüft, ob die Tokenfolge zur
|
||||||
|
kontextfreien Sprache\todo{Warum kontextfrei?} gehört. Außerdem soll die
|
||||||
|
hierarchische Struktur der Eingabe erkannt werden.\todo{Was ist gemeint?}
|
||||||
|
|
||||||
|
Ausgegeben wird ein \textbf{abstrakter Syntaxbaum}\xindex{Syntaxbaum!abstrakter}.
|
||||||
|
|
||||||
|
\begin{beispiel}[Abstrakter Syntaxbaum]
|
||||||
|
TODO
|
||||||
|
\end{beispiel}
|
||||||
|
|
||||||
|
\section{Semantische Analyse}\xindex{Analyse!semantische}%
|
||||||
|
Die semantische Analyse arbeitet auf einem abstrakten Syntaxbaum und generiert
|
||||||
|
einen attributierten Syntaxbaum\xindex{Syntaxbaum!attributeriter}.
|
||||||
|
|
||||||
|
Sie führt eine kontextsensitive Analyse durch. Dazu gehören:
|
||||||
|
\begin{itemize}
|
||||||
|
\item \textbf{Namensanalyse}: Beziehung zwischen Deklaration und Verwendung\todo{?}
|
||||||
|
\item \textbf{Typanalyse}: Bestimme und prüfe Typen von Variablen, Funktionen, \dots \todo{?}
|
||||||
|
\item \textbf{Konsistenzprüfung}: Wurden alle Einschränkungen der Programmiersprache eingehalten?\todo{?}
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
\begin{beispiel}[Attributeriter Syntaxbaum]
|
||||||
|
TODO
|
||||||
|
\end{beispiel}
|
||||||
|
|
||||||
|
\section{Zwischencodeoptimierung}
|
||||||
|
Hier wird der Code in eine sprach- und zielunabhängige Zwischensprache transformiert.
|
||||||
|
Dabei sind viele Optimierungen vorstellbar. Ein paar davon sind:
|
||||||
|
\begin{itemize}
|
||||||
|
\item \textbf{Konstantenfaltung}: Ersetze z.~B. $3+5$ durch $8$.
|
||||||
|
\item \textbf{Kopienfortschaffung}: Setze Werte von Variablen direkt ein
|
||||||
|
\item \textbf{Code verschieben}: Führe Befehle vor der Schleife aus, statt in der Schleife \todo{?}
|
||||||
|
\item \textbf{Gemeinsame Teilausdrücke entfernen}: Es sollen doppelte Berechnungen vermieden werden \todo{Beispiel?}
|
||||||
|
\item \textbf{Inlining}: Statt Methode aufzurufen, kann der Code der Methode an der Aufrufstelle eingebaut werden.
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
\section{Codegenerierung}
|
||||||
|
Der letzte Schritt besteht darin, aus dem generiertem Zwischencode den
|
||||||
|
Maschinencode oder Assembler zu erstellen. Dabei muss folgendes beachtet werden:
|
||||||
|
\begin{itemize}
|
||||||
|
\item \textbf{Konventionen}: Wie werden z.~B. im Laufzeitsystem Methoden aufgerufen?
|
||||||
|
\item \textbf{Codeauswahl}: Welche Befehle kennt das Zielsystem?
|
||||||
|
\item \textbf{Scheduling}: In welcher Reihenfolge sollen die Befehle angeordnet werden?
|
||||||
|
\item \textbf{Registerallokation}: Welche Zwischenergebnisse sollen in welchen Prozessorregistern gehalten werden?
|
||||||
|
\item \textbf{Nachoptimierung}\todo{?}
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
\index{Compilerbau|)}
|
Binary file not shown.
|
@ -2,6 +2,43 @@
|
||||||
Im folgenden werden einige Begriffe definiert anhand derer
|
Im folgenden werden einige Begriffe definiert anhand derer
|
||||||
Programmiersprachen unterschieden werden können.
|
Programmiersprachen unterschieden werden können.
|
||||||
|
|
||||||
|
\begin{definition}\xindex{Programmiersprache}\xindex{Programm}%
|
||||||
|
Eine \textbf{Programmiersprache} ist eine formale Sprache, die durch eine
|
||||||
|
Spezifikation definiert wird und mit der Algorithmen beschrieben werden
|
||||||
|
können. Elemente dieser Sprache heißen \textbf{Programme}.
|
||||||
|
\end{definition}
|
||||||
|
|
||||||
|
Ein Beispiel für eine Sprachspezifikation ist die \textit{Java Language Specification}.\footnote{Zu finden unter \url{http://docs.oracle.com/javase/specs/}} Obwohl es kein guter Stil ist, ist auch
|
||||||
|
eine Referenzimplementierung eine Form der Spezifikation.
|
||||||
|
|
||||||
|
Im Folgenden wird darauf eingegangen, anhand welcher Kriterien man
|
||||||
|
Programmiersprachen unterscheiden kann.
|
||||||
|
|
||||||
|
\section{Abstraktion}
|
||||||
|
Wie nah an den physikalischen Prozessen im Computer ist die Sprache?
|
||||||
|
Wie nah ist sie an einer mathematisch / algorithmischen Beschreibung?
|
||||||
|
|
||||||
|
\begin{definition}\xindex{Maschinensprache}\xindex{Befehlssatz}%
|
||||||
|
Eine \textbf{Maschinensprache} beinhaltet ausschließlich Instruktionen, die direkt
|
||||||
|
von einer CPU ausgeführt werden können. Die Menge dieser Instruktionen
|
||||||
|
sowie deren Syntax wird \textbf{Befehlssatz} genannt.
|
||||||
|
\end{definition}
|
||||||
|
|
||||||
|
\begin{beispiel}[Maschinensprachen]
|
||||||
|
\begin{bspenum}
|
||||||
|
\item \xindex{x86}x86:
|
||||||
|
\item \xindex{SPARC}SPARC:
|
||||||
|
\end{bspenum}
|
||||||
|
\end{beispiel}
|
||||||
|
|
||||||
|
\begin{definition}\xindex{Assembler}%
|
||||||
|
\textbf{Assembler} TODO
|
||||||
|
\end{definition}
|
||||||
|
|
||||||
|
\begin{beispiel}[Assembler]%
|
||||||
|
TODO
|
||||||
|
\end{beispiel}
|
||||||
|
|
||||||
\section{Paradigmen}
|
\section{Paradigmen}
|
||||||
Die grundlegendste Art, wie man Programmiersprachen unterscheiden
|
Die grundlegendste Art, wie man Programmiersprachen unterscheiden
|
||||||
kann ist das sog. \enquote{Programmierparadigma}, also die Art wie
|
kann ist das sog. \enquote{Programmierparadigma}, also die Art wie
|
||||||
|
|
|
@ -5,7 +5,8 @@ in der Klausur als Nachschlagewerk zu dienen; es soll jedoch auch
|
||||||
vorher schon für die Vorbereitung genutzt werden können und nach
|
vorher schon für die Vorbereitung genutzt werden können und nach
|
||||||
der Klausur als Nachschlagewerk dienen.
|
der Klausur als Nachschlagewerk dienen.
|
||||||
|
|
||||||
Ein Link auf das Skript ist unter \href{http://martin-thoma.com/programmierparadigmen/}{\path{martin-thoma.com/programmierparadigmen}}
|
Ein Link auf das Skript ist unter \\
|
||||||
|
\href{http://martin-thoma.com/programmierparadigmen/}{\path{martin-thoma.com/programmierparadigmen}}\\
|
||||||
zu finden.
|
zu finden.
|
||||||
|
|
||||||
\section*{Anregungen, Verbesserungsvorschläge, Ergänzungen}
|
\section*{Anregungen, Verbesserungsvorschläge, Ergänzungen}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue