Eigene Programmiersprache Teil 1

Werbung
Eigene Programmiersprache erster Teil
Aufgabe 1 Code Generierung für arithmetische Ausdrücke
Als erstes sollen Sie die Klassen ILSample.java und ILSample2.java studieren. In
diesen Klassen wird zur Laufzeit Java-Bytecode generiert, genau genommen eine
Klasse mit einer Methode, die ein vorgegebenes Interface implementiert.
Der Bytecode wird mit der Library BCEL (Byte Code Engineering Library) generiert.
Die Methode buildClass ist so konstruiert, dass eine Klasse erstellt wird, die das
beim Aufruf mitgegebene Interface implementiert. Die eigentliche CodeGenerierungsmethode wird in einem Objekt mitgegeben, das das Interface
ICodeGenStart implementiert (Generierung in der start() Methode).
Innerhalb der Methode werden Funktionen der BCEL Bibliothek aufgerufen. BCEL
ermöglicht dem Programmierer Java Class-Dateien zu erstellen.
Mehr Informationen unter: http://jakarta.apache.org/bcel/
Sie sollten folgende Klassen aus der BCEL verstehen:
ConstantPoolGen
Generiert man in BCEL eine Klasse, wird ihr automatisch ein so genannter
Konstanten-Pool angehängt. In diesem Konstanten-Pool können beliebig Konstanten
gespeichert werden. Einige Bytecode Operationen beziehen ihre Werte aus diesem
Konstanten-Pool.
InstructionList
In der Instruktionsliste werden die Instruktionsobjekte abgelegt. Die
Instruktionsobjekte und die Reihenfolge in der Sie in der Instruktionsliste abgelegt
wurden definieren die Funktion der Methode.
Aufgabe: Generieren Sie Code für die Berechnung von arithmetischen Ausdrücken
(Expressions).
Hinweise:
•
•
•
Konstante Werte im Ausdruck müssen zuerst im Konstanten-Pool abgelegt und
die passende Instruktion dazu generiert werden.
Nehmen Sie die Klasse ILSample und ILSample2 als Vorlagen.
Ihr Parser muss in der codeGen-Methode übergebenen start-Methode aufgerufen
werden.
Statt den Wert direkt zu berechnen, soll Code für den Ausdruck generiert werden und
dann nachträglich berechnet werden (durch Aufruf der generierten Methode). Das
Gerüst für den Aufruf sieht folgendermassen aus:
public static void main(String[] args) throws Exception
Scanner.init("4.2 + 3.2*2");
CodeGen.init();
Scanner.scan();
ICalculator calculator = (ICalculator)
CodeGen.buildClass(ICalculator.class, new Calculator ());
// Die generierte Methode wird aufgerufen.
System.out.println("\Result: " + calculator.calc(0));
}
Wobei die Calculator Klasse das ICodeGenStart Interface implementiert. In der
start Methode wird dann einfach expr()aufgerufen, das den Parse Vorgang
startet. Beim Parsen wird dann der Java Byte Code generiert.
class Calculator implements ICodeGenStart {
…
Die BCEL Bibliothek ist eine interne Bibliothek und deshalb werden vom Compiler
Warnungen generiert. Sie können Sie aber mit der Compiler Option
-XDignore.symbol.file ausschalten.
Aufgabe 2 Code Generierung mit Variablen
Jetzt wollen wir einen Schritt weiter gehen und Code für Ausdrücke mit Variablen
generieren. Erstellen Sie dafür eine Klasse Programm und folgendes Interface;
public interface IProgram {
double main(double arg);
}
und passen Sie Ihren Aufruf an:
…
IProgram program = (IProgram)
CodeGen.buildClass(IProgram.class,
new Program ());
// Die generierte Methode wird aufgerufen.
System.out.println("\nProgram Result: " + program.main(49));
Anbei die Grammatik unserer (ersten) Programmiersprache.
expr = term {("+" | "-”) term}
term = factor {("*" | "/") factor}
factor = number | ident | "(" expr ")"
assignement = ident "=" expr ";"
statement = assignment
statementSequence = statement {statement}
program = statementSequence
Assignement: einer lokalen Variablen wird ein Ausdruck zugewiesen, z.B. a = 6+2.
Zusätzlich sollen in Ausdrücken (expr) ebenfalls Variablen zugelassen werden, z.B. i
=i -1
Statement: Eine Anweisung ist ein Assignment (wird später noch erweitert).
Program: besteht aus einer oder mehreren Anweisungen.
Eine Zuweisung besteht aus einem Variablennamen (dem ein Speicherplatz
zugewiesen wurde) und einem Ausdruck. Damit der Parser weiss, welcher
Speicherplatz für welche Variabel reserviert wurde, wird eine Liste geführt.
Beispiel-Programm
x = arg0;
a = 1;
b = 2;
c = 3;
value = a*x*x + b*x + c;
Die Parameter seien in den vordefinierten Variablen arg0, arg1, … und der
Rückgabe Wert in value gespeichert.
Hinweis:
•
•
Die Methode local der Klasse CodeGen liefert die Nummer des Slots der
benannten lokalen Double-Variablen oder generiert bei Bedarf eine neue SlotNummer; diese können für die entsprechenden Load und Store Operation
verwendet werden.
Vergessen Sie nicht, dass am Schluss der Methode ein DRETURN stehen muss
und der berechnete Wert (in der Variablen "value") auf dem Stack abgelegt sein
muss.
Beispiele:
Zuweisung a = expr()
// Erzeugen einer neuen Variablen a
int slot = CodeGen.local("a");
// Store-Instruktion, die das oberste
// Stack-Element in a speichert.
CodeGen.il.append(new DSTORE(slot));
a kommt in einem Ausdruck vor, z.B a+2:
int slot = CodeGen.local("a"); // Adresse von a
// Load-Instruktion, die den Wert von a auf den Stack pushed
CodeGen.il.append (new DLOAD(slot));
Herunterladen