Erstes Teilprojekt:
Codegenerierung für Tasskaf
Wie in der Vorlesung befassen wir uns im Projekt auch
zuerst mit der Codeerzeugung. Dafür benötigen
wir aber die Ergebnisse der vorhergehenden Phasen,
nämlich der lexikalischen, syntaktischen und
semantischen Analyse. Diese Phasen sind in einem
Frontend zusammengefaßt. Das Frontend erhält
als Eingabe ein Tasskaf-Programm (als Standardeingabe)
und erzeugt
eine Zwischendarstellung (IR), z.B. einen dekorierten
abstrakten Syntaxbaum. Dieser Teil des Projekts
besteht nun darin ein Backend (d.h. die Codeerzeugung)
zu implementieren.
Die Zwischendarstellung des Frontends für
Tasskaf haben wir anhand von Diagrammen
beschrieben (Postscript).
Schnittstelle des Frontends
In der Datei tasskaf.c findet ihr
ein Beispiel, wie eure Funktion main
aussehen koennte. Sie ruft die Schnittstelle
des Frontends, nämlich die Funktion get_tree
auf.
#include
#include "parstree.h"
void codegen(NODE*);
int main(int argc, char** argv)
{ classpt=get_tree();
codegen(classpt); /* generate JVM-Code (in Jasmin-Syntax) */
}
Eure Aufgabe besteht darin, die Funktion codegen
zu programmieren. Dazu ist es ratsam, zuerst eine Funktion
zu programmieren, die über die Zwischendarstellung
läuft und diese einfach per printf
ausgibt. Übrigens erzeugt das Frontend immer
eine Datei tkaf.gdl, die eine Beschreibung
der Zwischendarstellung enthält.
Mit dem Tool VCG könnt ihr euch so die
Zwischendarstellung graphisch auf dem
Bildschirm anzeigen lassen.
xvcg tkaf.gdl
Die Übersetzungschemata für TassKaf
solltet ihr als Grundlage für codegen
verwenden.
Auf den Rechnern in den Studentenrechnerrämen
findet ihr das Frontend frontend.a
und die zugehoerigen C-Dateien
im Verzeichnis ~diehl/COMP/project1/source/
und einige Beispielprogramme in der Sprache Tasskaf
im Verzeichnis ~diehl/COMP/project1/test/.
Am besten setzt ihr einen Link auf die Datei frontend.a
oder das ganze Verzeichnis. Solltet ihr frontend.a
kopieren, so müßt ihr anschließend
die Kopie mit
ranlib frontend.a
auf den neusten Stand bringen.
(Im Verzeichnis ~diehl/COMP/project1/linux findet ihr
auch eine Version des Archivs für Linux. Diese ist
mit folgenden Einschränkungen zu verwenden: euer Codegenerator
muß auch auf den Rechnern im Rechnerraum laufen, die Anpassung
der Headerdateien an Linux müßt ihr selbst machen und
sollten Fehler in frontend.a enthalten sein, dann
wird die Linux-Version in der Regel mit mehrtägiger
Verspätung korrigiert.)
Die Übersetzungsschema werdet ihr nacheinander
als Teil der Übungsaufgaben entwickeln und könnt sie
dann in eueren Codegenerator einbauen. D.h. also
ihr fangt am besten mit der Übersetzung von
Ausdrücken an.
Was die Java-Virtual Machine ist und wie ihre Instruktionen
aussehen, könnt ihr aus folgenden Dokumenten ersehen:
- In der formalen Notation der Vorlesung habe ich die
Befehle, die für die Übersetzung von
Tasskaf wichtig sind, sowie die Syntax von
Tasskaf in diesem Dokument (Postscript)
beschrieben.
- Eine informalere, aber vollständige Beschreibung
von SUN findet ihr hier (Postscript)
Die textuelle Darstellung die ihr erzeugt, soll als
Eingabe für den JASMIN-Assembler verwendet werden.
Daher solltet ihr euch dessen
Dokumentation
näher anschauen und die Beispielprogramme
im Verzeichnis ~diehl/COMP/jasmin/examples/.
Unter anderem nimmt uns JASMIN das
Erstellen der Konstantentabelle ab, so daß man in
JASMIN-Programmen Konstanten, Methodensignaturen
und Typen als Zeichenketten direkt hinschreiben
kann. Auch die Adreßberechnung für Sprungadressen
erfolgt durch JASMIN, wir können daher einfach
Zeichenketten (Labels) als Sprungadressen verwenden.
Das Archiv frontend.a enthält auch
die Funktion newlabel(), die einen
neuen Label erzeugt:
int nextlabel=0;
char* itoa(int n)
/* converts integer to string, e.g. 107 --> "107" */
{char *string = (char *)malloc(10);
sprintf(string, "%d", n);
return(string);
}
char* newlabel()
/* generates a new label to be used as a marker
in the generated code */
{ return strappend("Label",itoa(nextlabel++)); }
Tools
Der Assembler JASMIN, sowie Java-Compiler und
Java-Byte-Code Interpreter sind im Verzeichnis
~diehl/COMP/bin installiert.
Damit stehen euch folgende Kommandos zur Verfügung:
jasmin dings.j
Übersetzt den von euch erzeugten JASMIN-Assembler-Code
in Java-Byte-Code, den es in sogenannten Klassendabeien
mit der Endung .class ablegt.
Angenommen, ihr habt die Definition der Klasse Dings übersetzt,
so könnt ihr sie jetzt mit dem Interpreter ausführen:
java Dings
Wenn ihr euren Compiler z.B. tasskaf nennt, dann
koennt ihr das Übersetzen und Ausführen der
Beispielprogramme mit dem folgenden Shell-Skript automatisieren:
#!/usr/bin/tcsh
rm *.jasmin
echo compiling
tasskaf < $1.tkaf
echo assembling
jasmin *.jasmin
echo executing
java $1
Testen des erzeugten Codes
Solange dein Compiler noch keine Methoden, Objekte und
Klassen übersetzen kann, mußt du zum Testen
des von deinem Compiler erzeugten Code einen Trick
anwenden. Du kannst
ihn in die folgende Datei einfügen.
Gib der Datei am besten den Namen test.jasmin.
.class public Test
.super java/lang/Object
;
; standard initializer
.method public ()V
aload_0
invokenonvirtual java/lang/Object/()V
return
.end method
.method public static main([Ljava/lang/String;)V
Hier kannst du den Code einfügen, den dein
Compiler erzeugt. Er sollte als Ergebnis in der
obersten Zelle des Kellers eine ganze Zahl
als Wert hinterlassen.
; push System.out onto the stack
getstatic java/lang/System/out Ljava/io/PrintStream;
swap
; call the PrintStream.println() method.
invokevirtual java/io/PrintStream/println(I)V
; done
return
.end method
This page is maintained by Stephan Diehl. For questions and suggestions send email to diehl@cs.uni-sb.de.
Last updated April 24 1997