Danke, sieht interessant aus. Werde ich mir mal genauer anschauen.
Bevor Du das anschaust, klick Dich mal zur Please login to see this link. durch und lies am Ende folgende Aussage:
Quote
So far, I’ve been implementing a compiler and writing posts as I go. This system worked really well for a while, but now it’s starting to work less well; I realized that some decisions I made in earlier stages made this stage harder to complete, so I had to go back and change them. I think I’m likely to run into more problems like that in later posts. So I’m going to take a break, finish building the compiler (whatever I decide “finished” means), and then come back and write the rest of this series. I probably won’t post another update for six months. So basically…I’m going to keep posting at about the same rate I have been.
Da die letzte Veröffentlichung schon eine ganze Weile her ist, kann man davon ausgehen, daß der Kurs nicht weiterfortgeführt und auch nicht an die erwähnten neuen Erkenntnisse angepaßt wird. Er ist daher mit Vorsicht zu genießen und liefert auch nicht die Lösungen für die wirklich schweren Probleme.
Das Buch "Compiler Construction" von Wirth in der überarbeiteten Auflage von 2005 kann man sich in der englischen Ausgabe kostenlos im Internet herunterladen. Es behandelt als reales Beispiel die Übersetzung einer (umfangreichen) Untermenge der Sprache Oberon in Befehle für einen RISC-Prozessor. Der Compiler-Sourcecode dazu ist ebenfalls frei erhältlich. Diese zusammen böten prinzipiell ein gutes Anschauungsmaterial, wenn Wirth nicht die Eigenschaft hätte, seinen Code nur äußerst spartanisch zu kommentieren, kryptische Variablennamen zu verwenden und mehrere Befehle in eine Zeile zu quetschen, um nachher sagen zu können: Schaut her, ich habe den kürzesten und kompaktesten Compiler... Mit anderen Worten: Wirth beweist, daß man auch in seiner Sprache schlecht lesbaren Code schreiben kann. 
Mein "Problem" mit den meisten Büchern zum Thema (und auch Vorlesungen an der Uni damals) ist, dass sie sich in Grammatiken, Parser und Lexer ergehen und die Codegenerierung oft nur als "Ja, gibt es auch noch...ist aber trivial, das kann jeder Depp" abtun.
Dies entspricht leider auch meiner Erfahrung. Die genannten Bücher habe ich mir damals[tm] ebenfalls angesehen und auch eine Vorlesung zum Thema besucht, die aber nicht über den Lexer/Scanner hinausgekommen ist. Dabei ist es genau umgekehrt: Das vollständige, reine Parsen eines Programms mit Test auf syntaktische Korrektheit (= Frontend) ist trivial. Die Codeerzeugung hingegen äußerst kompliziert, und man wird das Gefühl nicht los, daß die verantwortlichen Lehrenden sich gerne darum herumdrücken. Mein Fazit am Ende war: Vergiß die Literatur und mach es selber frei nach dem Motto "Learning by doing". Letztlich ist ein Compiler auch nur ein Programm, d. h. man geht in der Entwicklung genau so vor wie bei anderen Programmen auch. Zuallererst muß man wissen, was man überhaupt will. Aus "Ich möchte irgendwie ein Spiel schreiben mit irgendeiner Figur, die irgendwas macht." wird ja auch nie ein fertiges Spiel. Falls Du, ogd, also Interesse daran hast, einen eigenen Compiler zu schreiben, solltest Du zunächst die folgenden Fragen beanworten:
1.) Auf welchem Computer soll der fertige Compiler laufen? PC oder C64? Dies bestimmt von vornherein den Umfang des Compilers (z. B. mögliche Codeoptimierungen) und die Vorgehensweise: direkte Übersetzung ohne Zwischencode (sehr wenig Speicherverbrauch) <=> Zwischencode für Prozeduren/Funktionen (geringfügiger Speicherverbrauch, teilweise Optimierungen möglich) <=> Zwischencode für das ganze Programm (immenser Speicherverbrauch, auf Retrorechnern nicht zu erreichen).
2.) Wie sieht die Quellsprache aus? Ist sie Pascalartig? Herzlichen Glückwunsch. Einen Compiler für eine solche Sprache zu erstellen, ist einigermaßen realistisch, Handelt es sich um Basic? Dann kommt man schnell an die Grenzen der Kompilierbarkeit, denn Basic verwendet zu viele Elemente, die erst während der Laufzeit entschieden werden können, und eignet sich daher von vornherein nicht gut als Sprache zum Kompilieren.
Die Wahl der Quellsprache bestimmt auch, wie kompliziert das Parsen ausfällt: Kann ein Programmtext in einem Durchlauf geparst werden oder braucht man mehr als einen Durchgang? Hierbei muß man unterscheiden in zusätzliche Durchgänge, um Programmadressen (z. B. für Sprünge) zu ermitteln. Dies kannmit Hilfe des Zwischencodes durchgeführt werden. Oder handelt es sich um Deklarationen, bei denen die Verwendung eines Bezeichners vor der Deklaration stattfinden kann? Dieser Fall ist schwer zu behandeln. Beispiel:
10 GOSUB 1000
100 a(50) = 0
...
1000 DIM a(40)
Der Compiler müßte in Zeile 100 einen Fehler ausspucken, da auf ein Element 50 zugegriffen werden soll, jedoch im späteren Programmcode nur ein Feld mit 41 Elementen erzeugt wird.
Besonders lustig wird es in Basic bei folgendem Code:
10 IF A=0 THEN GOSUB 900
100 a(30) = 0
200 FOR I=1 TO 30 : a(i) = 0: NEXT
300 FOR I=1 TO max: a(i) = 0: NEXT
400 GOTO 10
...
900 A=1
910 PRINT"Welche Größe? ==> ";
1000 GET X$
1010 IF X$="1" THEN DIM a(10):max = 10:RETURN
1020 IF X$="2" THEN DIM a(20):max = 20:RETURN
1030 IF X$="3" THEN DIM a(30):max = 30:RETURN
...
1999 GOTO 1000
Display More
Damit sich solche Scherze nicht auswirken auf "normalen" Basiccode, in dem ein Array nur einmal dimensioniert wird mit einer Konstanten, muß man im Compiler einige Verrenkungen vornehmen.
3.) Wie lautet die Zielsprache? Wird in P-Code kompiliert? Das wäre relativ einfach. Assembler hingegen ist recht schwierig, weil z. B. die 8 Bit-Prozessoren nicht über die Adressierungsarten verfügen, die man für ein Hochsprachenprogramm benötigt.
4.) Soll Zwischencode verwendet werden und falls ja, wie sieht dieser aus? Üblicherweise nimmt man entweder einen Code für eine Stackmaschine, die dann bereits dem auszuwerfenden P-Code nahekommt, oder man verwendet eine 3-Adreß-Codierung (aufwendig). Letztere erlaubt einige Optimierungen am Code, ist aber schwerer in der Handhabung. Stackmaschinen-Befehle lassen sich hingegen auch relativ leicht auf eine Registermaschine übertragen (vorausgesetzt man unterscheidet zwischen Evaluationsstack und Datenstack), erzeugen aber keinen optimalen Code.
Solltest Du am Anfang noch keine Ahnung haben, wie der Compiler intern aufgebaut sein soll (Unterscheidung Frontend - Backend? Welcher Zwischencode? etc), folge einfach den Ratschlägen von EgonOlsen71:
1.) Schreib ein Programm in der Programmiersprache Deiner Wahl auf dem PC, welches einen Programmtext in Deiner Quellsprache akzeptiert.
2.) Schreib darauf aufbauend einen Interpreter für Deine Sprache. Dabei lernt man mit Variablenadressen umzugehen, Bezeichnerdeklarationen umzusetzen, Stackallokationen durchzuführen usw. (Hinweis: Es ist relativ leicht, einen Interpreter für Pascal zu schreiben, wenn man zusätzlich ein Flag definiert, welches festhält, ob ein Code ausgeführt werden darf. Zwar wird hierbei auch nicht auszuführender Code wiederholt geparst (= übersprungen), doch war selbst damals[tm] auf meinem Amiga1200 die Ausführungsgeschwindigkeit eines alten Pascal-Programms aus Schulzeiten schneller als original auf dem AppleII.)
3.) Schreib einen Codegenerator auf Basis des Interpreters. Vom Interpreter zum Compiler ist es nur ein kleiner Schritt.
4.) Schreib Deinen Compiler neu in der Quellsprache und übersetze ihn mit sich selber. Wenn das dadurch entstandene Kompilat sich nicht vom Vorgänger unterscheidet, darfst Du Dir gratulieren. Du hast einen Please login to see this link. geschrieben.
Kurz gesagt: Viel Spaß! 