Compilerbau

Diese Seiten befinden sich im Aufbau!

Software

  1. Zur Einführung: das Tool dataGen erleichtert die schematisch Erzeugung von Klassen, die abstrakte Syntaxbäume u.ä. representieren

    Beispiels-programm und Klassen-struktur aus der Vorlesung: prog.java, slp.java

  2. Lexikalische Analyse für MiniJava.

    Zur Entwicklung des Parsers soll folgende Tabelle von Tokens verwendet werden: Klasse mit Tokens für den Lexer

    Der Rumpf des zu erstellenden Lexer files ist ebenfalls vorgegeben. Daraus wir mittels folgender Instruktion ein .java file erstellt: jflex MJLex.x (genauer /soft/bin/jflex).

    Für die Ausführung des lexers, ist der CLASSPATH wie folgt zu ändern: export CLASSPATH=$CLASSPATH:/soft/IFI/lang/java-cup/java-cup-v11a.jar

  3. Zum Parsing verwenden wir den Parser Generator java-cup (java-CUP .jar file).
  4. Abstrakte Syntax: Zur Definition der Baumstruktur bieten sich algebraische Datentypen an, wie sie aus Sprachen wie Haskell bekannt sind. Das Tool dataGen nimmt solche Datenstrukturen als Input und erzeugt eine entsprechende Java Klassenhierarchie. Nicht-Terminalsymbole werden zu abstrakten Klassen, Terminalsymbole zu konkreten Klassen. Das Makefile im StraightLine Parser zeigt die Verwendung von dataGen in einem Compiler.
  5. Zwischensprache: Der Code für die Kanonisierung des Zwischencodes, wie in Vorlesung 8 vorgestellt, ist hier verfügbar, zusammen mit den Hilfspaketen List.java und Utils.java. Zum Einbinden in den eigenen Code, sollte für jeden Methodenrumpf this.body folgendes Codestück ausgeführt werden:
        LinkedList blks = IntmTrafo.intmTrafo(this.body); 
        this.canon_body = blks;
         

    Interpreter: Um das Testen des MiniJava Compilers zu vereinfachen, ist hier ein Interpreter für die Zwischensprache verfügbar. Als Eingabe nimmt der Interpreter eine Folge von Funktionsdefinitionen, die den Rümpfen der Methoden in MiniJava entsprechen. Im Kopf der Funktionsdefinition muss der Name (mit beginnendem "L"!) und die Parameterliste angegeben sein. In dieser Liste kennzeichnet das Schlüsselwort REG ein (abstraktes) Register und LOC eine Location auf dem Frame. Das erste Argument der Parameterliste, muss ein Register mit dem THIS Objekt sein. Als Beispiel, hier die Struktur der Factorial Funktion im Zwischencode:

    FCT LFactorial$main(REG t1, REG t77) =
    {
    ...
    }
         
    Links zu weiteren Beispielen finden sich am Ende der Web page.

    Zum Ausdrucken des Codes kann der pretty-printing Visitor in PPIntm verwendet werden (neue Version im package IntmTrafo. Diese Funktion muss für jeden Methodenrumpf in der Symboltabelle aufgerufen werden. Der Kopf der Funktionsdefinition muss separat aus der weiteren Information in der Symboltabelle erzeugt werden.

    Wichtige Konventionen:

    • Registernamen müssen mit t beginnen, zB: t33
    • Funktionsnamen und labels müssen mit L beginnen, zB: Lfact
    • Das Resultatregister muss t2 sein (oder mit -r name setzen), der Framepointer muss t32 sein (oder mit -f name setzen).
    • Der this-pointer muss t1 heissen und der erste Parameter der Funktion sein (oder mit -t name setzen).
    • Als "calling convention" werden vor dem Aufruf einer Funktion werden sämtliche Register abgespeichert. D.h. es ist (noch) nicht nötig die Funktion procEntryExit1 aus der Vorlesung zu implementieren. In der Endversion der Zwischensprachengenerierung müssen sämtliche callee-save Register durch den erzeugten Code gesichert werden. Dann ist eine einfachere "calling convention" im Interpreter zu verwenden.
    • Kein Sprung in einen Basisblock (dies kann durch Fusion von basic blocks bei der Erzeugung von Traces passieren). D.h. im Zwischencode muss vor jeder Label Definition ein JUMP oder CJUMP stehen (als Ende des vorherigen Basisblocks). Ab Version 1.3 nicht mehr nötig.

    Weitere nützliche Informationen:

    • Laufzeitwerte werden im Interpreter als A int für Adressen und I int für integers repräsentiert.
    • Der Stack startet bei Adresse 8000 und wächst nach unten (zu kleineren Adressen), der Heap startet bei Adresse 9000 und wächst nach oben. Mit flag -C werden die aktuellen Werte für jeden Methodenaufruf ausgedruckt.

    Der Interpreter (Name: muHwI) wird mit dem Filenamen des Zwischencodes und den Parametern der L...$main Funktion aufgerufen:

         ./muHwI F3.intm 4
         
    Während der Ausführung druckt der Interpreter Meldungen über die Ausführung bestimmter Kommandos aus (z.B. Funktionsaufrufe mit Parameterwerten). Am Ende wird das Resultat ausgegeben.

    Name für spezielle externe Funktionen, die der Interpreter kennt:

    • L_halloc_obj: Allokierung eines heap objects; Parameter: Grösse
    • L_init_obj: Initialisierung eines heap objects; Parameter: Pointer zum Objekt, Grösse
    • L_halloc_arr: Allokierung eines Arrays; Parameter: Grösse
    • L_init_arr: Initialisierung eines Arrays; Parameter: Pointer zum Objekt, Grösse (Indizierung startet mit 0; Grösse ist im Index -1 abgelegt)
    • L_print: Ausdrucken eines Wertes; Parameter: Wert (Integer oder Adresse)

    Hier die wichtigsten Optionen:

    Usage: muHwI [options] <file>
      -?         --help              show usage information
      -v         --verbose           be verbose
      -T Traces  --defTrace=Traces   default tracing flags
      -C         --callTrace         trace function calls
      -J         --jumpTrace         trace jumps
      -M         --moveTrace         trace moves
      -A         --allocTrace        trace memory allocations
      -P         --ParamTrace        trace parameter passing
      -R         --regMap            print register maps
      -H         --memMap            print memory maps
      -L         --labMap            print label maps
      -D         --debugging         debug interpreter itself
      -f t32     --framepointer=t32  name of frame pointer register
      -s t98     --stackpointer=t98  name of stack pointer register
      -h t99     --heappointer=t99   name of heap pointer register
      -t t1      --thispointer=t1    name of this pointer register
      -o FILE    --output=FILE       output file
    

    Weitere Beispiel für Zwischencode (so wie er von muHwI eingelesen wird):

  6. Instruktionsauswahl: Um sich mit der Zielarchitektur vertraut zu machen, empfehlen wir in folgenden Dokumenten nachzulesen:

    Intel x386:

    MIPS R2000/R3000:

Top level file für Zwischencodetransformation

Bug Alarm:: MJIntmAbsSyn.java aus Vorlesung 7 hatte einen Bug in den kids/build Funktionen für MOVE. Dadurch erzeugt das Canon Modul falschen Zwischencode. Hier ist das korrigierte file für MJIntmAbsSyn.java (Version 1.4). Insbesondere, sind damit keine Fixes in Canon.java nötig.

Aktuelle Version von muHwI (Revision 1.6).


Valid HTML 4.01!
Hans-Wolfgang Loidl
Last modified: Fri Jan 20 16:58:33 2006 Stardate: [-29]5193.32
Valid CSS!