Eine virtuelle Maschine ist ein Rechner, der physisch nicht existiert. Seine Bestandteile werden durch ein Programm simuliert. Es muss alle Bestandteile eines physischen Rechners nachbilden.
Register
Speicher
Steuerschleife
Befehlssatz
Je nach Arbeitsweise unterscheidet man zwischen
Dreiadressmaschine
Eine beispielsweise arithmetische Operation wird durch einen Befehl mit 3 Parametern realisiert, den beiden Summanden und dem Ziel, auf dem das Ergebnis der Operation abgelegt wird. Zwischenergebnisse komplexer Ausdrücke werden in temporären Variablen abgelegt.
Zweiadressmaschine ähnlich der Dreiadressmaschine, jedoch überschreibt das Ergebnis einen der beiden Operanden, so dass der 3. Parameter entfällt.
Stackmaschine.
Operanden und Ergebnisse werden auf einem Kellerspeicher abgelegt. Auch die Variablen der Prozeduren werden im Keller angelegt. Sie werden durch eine Relativadresse, die relativ zum Anfang der Variablenbereiches (Adresse der 1. Variablen) gebildet wird adressiert.
Die virtuelle Maschine zum Modellcompiler wurde als Stackmaschine realisiert. Der Befehlssatz ist in dem Headerfile code.h enthalten. Bei genauerer Betrachtung lassen sich 4 Befehlsgruppen erkennen.
Keller-Befehle
Push-Befehle schreiben Werte oder Adressen in den Keller. Als Operand ist immer die Relativadresse der betreffenden Variable anzugeben. Handelt es sich um eine zur aktuellen Prozedur globale Variable, so ist die Prozedurnummer der Prozedur, die die Variablendefinition enthält, zusätzlich anzugeben. Der PuConst Befehl kellert eine zu indizierende Konstante aus dem Konstantenblock. Der storeVal Befehl entfernt aus dem Keller einen zu speichenden Wert und die Zieladresse und speichert den Wert auf die Adresse.
Arithmetische und Vergleichsbefehle
Die arithemetischen und Vergleichsbefehle entnehmen dem Stack ein (unäre Operatoren odd und - ) bzw. zwei (binäre Operatoren) Operanden und speichern das Ergebnis wieder im Stack. Bei Vergleichsbefehlen oder dem Befehl odd ist das Ergebnis ein Wahrheitswert.
Sprungbefehle
- unbedingter Sprung(jmp): Das Sprungziel wird als Differenz zwischen dem aktuellen Programmcounter und dem Sprungziel angegeben. Der aktuelle Programmcounter zeigt hinter die Relativadresse des Sprungbefehls.
- bedingter Sprung (jnot): Das Sprungziel wird ebenfalls als Differenz angegeben, zusätzlich wird ein Wert ausgekellert, der als Wahrheitswert interpretiert wird.
- Unterprogramm: call hat als Parameter die Prozedurnummer der zu rufenden Prozedur (siehe Sematikroutinen/Namensliste). Die virtuelle Maschine hält eine Prozedurtabelle, in der ua. Die Anfangsadressen der Prozeduren abgelegt sind. Der call -Befehl legt den aktuellen Programmcounterwert auf den Stack und schreibt die Startadresse der Prozedur, die aus der Prozedurtabelle durch Indizierung mit der Prozedurnummer ermittelt wird in den Programmcounter. Der erste Befehl der aufgerufenen Prozedur ist immer entryProc. Seine Parameter sind die Codelänge, die vom Codelader ausgewertet wird, die Variablenlänge und die Prozedurnummer. Dieser Befehl richtet die Prozedur, ihre Variablen und den Stackpointer ein. Über retProc wird die Prozedur schließlich verlassen.
Ein-Ausgabebefehle
putVal: Ausgabe eines Wertes aus dem Keller, der Wert wird aus dem Keller entfernt.
getVal: Eingabe eines Wertes, der Wert wird auf eine Adresse geschrieben, die vom Stack geholt wird.
Die virtuelle Maschine arbeitet mit folgenden Datenstrukturen:
Speicherbereich für den Stack: Wird beim Start angelegt, während der Programmabarbeitung überwacht und bei Bedarf vergrößert.
Speicherbereich für den Code und die Konstanten: Wird beim Laden des Zwischencodefiles angelegt.
Prozedurtabelle: wird nach dem Laden des Zwischencodefiles angelegt. Sie enthält die Anfangsadressen der Prozeduren sowie ein zunächst leeres Feld für die Anfangsadresse des Variablenbereiches, das durch entryProc beim Aufruf der Prozedur belegt wird.
Die Einträge der Prozedurtabelle sind nach Prozedurnummer aufsteigend geordnet, so dass die Prozedurtabelle durch die Prozedurnummer indiziert werden kann.
Register der VM:
Register |
Variable der VM |
---|---|
ProgrammCounter |
pC |
Stackpointer |
pS |
Prozedurtabelle |
pInfProc |
KonstantenPointer |
pConst |
Aktuelle Prozedur |
iCProc |
Der Ladevorgang
Datenstruktur
nach dem Laden
Situation nach dem Laden, nach
entryProc des Hauptprogramms |
Programmbeispiel |
![]() |
var a,b,Max; |
Nach dem Laden wird entryProc des Hauptprogramms ausgeführt, danach
ergibt sich die dargestellte Situation. Die Prozedurtabelle (pInfProc)
ist ausgefüllt, der Stack ist angelegt, ebenso die Variablen des
Hauptprogramms (a,b,Max). Stackpointer und Programmcounter sind mit den
entsprechenden Werten belegt.