Station - Ein Code-Erzeuger für strukturierte MiniPython-Programme
Aufgabe des Code-Erzeugers
Der Code-Erzeuger hat die Aufgabe, strukturierte MiniPython-Programme in Programme einer (maschinennahen) Sprache zu übersetzen. Die Arbeitsweise des Code-Erzeugers soll am folgenden Beispiel-Programm verdeutlicht werden.
Der Code-Erzeuger verarbeitet als Quellcode das zugehörige strukturierte MiniPython-Programm:
Aus diesem Qhellcode soll der Code-Erzeuger ein Bonsaiassembler-Programm erzeugen
Die erzeugung dieses Assemblercodes erfolgt (hier) in zwei Schritten. Zunächst wird ein Programm einer Hilfsassemblersprache erzeugt (s.u.).
Dieser Zwischencode wird anschließend in BonsaiAssembler-Code umgewandelt.
Die Assemblerhilfssprache
Der Befehlsumfang der Hilfsassemblersprache ist derselbe wie bei der Bonsai-Assemblersprache. Es werden nur die 5 Befehle inc
, dec
, jmp
, tst
und hlt
benutzt.
Bei den Befehlen inc
, dec
und tst
werden Variablenbezeichner statt Registeradressen benutzt. Jede Variable steht dabei für ein Register. Die genaue Adresse des Registers spielt vorerst noch keine Rolle.
Am Ende des Programms werden alle im Programm benutzten Variablen mit ihren Startwerten aufgelistet.
Mit dieser Notation wird angezeigt, welche Register im Programm verwendet werden und mit welchen Variablen auf die Registerwerte zugegriffen wird.
Im vorliegenden Beispiel wird z.B. das erste Register (mit einer noch zu vergebenden Adresse - z.B. der Adresse 0) von der Variablen x verwaltet. Der Anfangswert dieses Registers ist die Zahl 0.
Auch die Adressierung beim jmp
-Befehl unterscheidet sich in der Hilfsassemblersprache von der BonsaiAssemblersprache.
Eine Angabe wie z.B. jmp (-5)
bedeutet: Gehe 5 Zeilen im Programm zurück. Entsprechend bedeutet eine Angabe wie z.B. jmp (+5)
: Gehe 5 Zeilen im Programm weiter vorwärts. Die mit Klammern gekennzeichneten Adressen sind hier also relative Sprungadressen.
Durch die Verwendung relativer Sprungadressen müssen die einzelnen Befehle eines Hilfsassemblerprogramms nicht durchnummeriert werden.
Beachte, dass die Hilfsassemblersprache auch Kommentare (# ...) zulässt.
Die Arbeitsweise des Code-Erzeugers
Die Aufgabe des Code-Erzeugers ist es, die Bausteine eines strukturierten MiniPython-Programms mit Hilfe der Befehle der Hilfsassemblersprache zu modellieren. Hierzu werden Code-Schnipsel für die einzelnen Bausteine erzeugt (vgl. auch Erzeugung von Hilfsassembler-Code). Wir verdeutlichen dies anhand einfacher Beispiele
Wir betrachten zunächst Zuweisungen der Form a = b
:
Die Übersetzung solcher Zuweisungen könnte nach folgendem Verfahren ablaufen.
{a: III; b: IIII} eine Hilfsvariable h erzeugen {a: III; b: IIII; h: } Register a leeren {a: ; b: IIII; h: } transportiere den Inhalt von Register b in Register a und das Hilfsregister h {a: IIII; b: ; h: IIII} transportiere den Inhalt von Register h zurück in Register b {a: IIII; b: IIII; h: }
Das entsprechende Code-Schnipsel sieht dann so aus:
Als nächstes betrachten wir Bedingungen der Form a != 0
:
Das Ergebnis bei der Auswertung einer Bedingung ist einer der beiden Wahrheitswerte True
und False
. Dieses Ergebnis wird in ein Hilfsregister abgelegt und mit einer Hilfsvariablen zugänglich gemacht. Zur Codierung der Wahrheitswerte benutzen wir die Zuordnung True -> 1
und False -> 0
. Zu beachten ist, dass die´Hilfsvariable h zunächst auf einen festen Anfangswert (hier: 0) initialisiert wird.
Etwas aufwendiger sind Code-schnipsel zu Fallunterscheidungen und Wiederholungen. Zur Verdeutlichung betrachten wir Wiederholungen der Form:
Mit bed wird hier die Bedingung beschrieben, mit anw die Anweisungssequenz des Schleifenkörpers.
Wir setzen voraus, dass bereits Assembler-Code für die Bedingung und für die Anweisungssequenz vorliegen. Mit c_bed wird der Assembler-Code für die Bedingung beschrieben, mit c_anw der Assembler-Code für die Anweisungssequenz.
Bei der Übersetzung einer Wiederholung werden jetzt die bereits existierenden Code-Schnipsel benutzt, um das Code-Schnipsel für die gesamte Wiederholungsanweisung zu erzeigen.
Implementierung des Code-Erzeugers
Der Code-Erzeuger wird durch ein Objekt der Klasse UebersetzerWhileList
realisiert. Dieses Objekt verfügt insbesondere über eine Methode uebersetzen
, die letztlich für die Erzeugung des Zielcodes zuständig ist. Die genauen Details können dem Quelltext uebersetzerWhileList.txt entnommen werden.
Testen lässt sich der Code-Erzeuger mit fogendem testprogramm:
Aufgabe 1
Probiere das selbst einmal aus. Übersetze verschiedene strukturierte MiniPython-Programme.