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: 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