import mathe.FormattedOut; // aus meinem mathe-package
/**
* Realisiert eine Registermaschine, wie sie in der Vorlesung
* AlgoDat beschrieben wurde.
*
* Keine öffentlichen Felder mehr, dafür auch weniger
* Sicherheitsüberprüfungen während des Programmlaufs.
*
* @author Christian Semrau, 17.12.1999
*
* Christian.Semrau@Student.uni-magdeburg.de
*/
class ChS_Registermaschine2 {
// Alle Befehle als Strings
private static final String[] kommandos = {
"END", "GOTO", "IFGOTO", "LOAD",
"CLOAD", "STORE", "ADD", "CADD",
"SUB", "CSUB", "MULT", "CMULT",
"DIV", "CDIV", "NOP"}; // NOP = No Operation
// man wird sich wohl denken koennen, dass IFGOTO
// der bedingte Sprungbefehl ist
// ach ja, noch was zu IFGOTO: diese Registermaschine kennt
// keinen Befehl IF c0==10 GOTO 2
// es gibt nur IF c0==0 GOTO 2 <-> IFGOTO 2
// die Opcodes (Operator-Codes) der einzelnen Befehle,
// dh jeder Befehl kriegt eine Nummer, die statt des Textes
// gespeichert wird
private static final int
END = 0, GOTO = 1, IFGOTO = 2, LOAD = 3,
CLOAD = 4, STORE = 5, ADD = 6, CADD = 7,
SUB = 8, CSUB = 9, MULT =10, CMULT =11,
DIV =12, CDIV =13, NOP =14;
// welche sind Registerbefehle (fuer Ueberpruefung des Programms)
// (Ausnahme: IFGOTO gehoert nicht in diese Liste)
private static final int[] REGBEF = {LOAD,STORE,ADD,SUB,MULT,DIV};
// welche sind No-Operand-Befehle (haben keinen Operanden)
private static final int[] NOOPBEF = {END,NOP};
/* HIER beginnt die Beschreibung der Registermaschine: */
/**
* die Opcodes, jeder Befehl wird durch eine Zahl dargestellt
*/
private int[] befehl;
/**
* die Operanden, dh die Zahlen hinter den Befehlen
*/
private int[] param;
/**
* der Befehlszeiger, die Werte reichen von 1(=Start) bis Programmlänge
*/
private int b;
/**
* die Speicherregister (0=Akku)
*/
private int[] c;
/**
* die Anzahl der bereits ausgeführten Befehle
*/
private int t;
/**
* Lädt ein Programm und die Speicherbelegung.
*
* Dem Objekt wird das Programm als String-Feld übergeben, zusammen
* mit der initialen Speicherbelegung. Der Befehlszähler zeigt
* standardmäßig auf den ersten Befehl (Zeile 1).
* Operanden und Registerinhalte sind nichtnegative ganze Zahlen.
*
* @param programm das Programm, wie unter parse(String[]) beschrieben
* @param speicher die Speicherbelegung, wie unter setzeRegister(int[]) beschrieben
*
* @exception NumberFormatException siehe parse und setzeRegister
* @exception IllegalArgumentException siehe parse und setzeRegister
* auch wenn ein illegaler Registerzugriff oder Sprung im Programm ist
* oder das Programm nicht mit END
endet
*
* "Alles was schiefgehen kann, wird schiefgehen." Murphys Gesetz
*
* @see #parse(java.lang.String[])
* @see #setzeRegister(int[])
*/
public ChS_Registermaschine2(String[] programm, int[] speicher)
throws NumberFormatException, IllegalArgumentException {
parse(programm);
setzeRegister(speicher);
check();
}
/**
* True, wenn das Programm beendet ist (der aktuelle Befehl ist END), false, wenn nicht.
* @return boolean
*/
public boolean beendet() {
return (befehl[b-1]==END);
}
/**
* Gibt die Text-Darstellung des Befehls in Zeile i zurück.
*
* @return String
* @param i die Zeile des Befehls, der disassembliert werden soll
* @exception IllegalArgumentException wenn i auf eine nicht existierende Zeile zeigt
*/
private String befehlToText(int i)
throws IllegalArgumentException {
int nr;
try{
nr = befehl[i-1];
}catch(ArrayIndexOutOfBoundsException e){
throw new IllegalArgumentException(
"Befehl "+(i)+" existiert nicht (1.."+befehl.length+").");
}
String s;
s = kommandos[nr];
s = FormattedOut.left(s,6); // nur Kosmetik, kann ggf. weggelassen werden
for (int n=0; n
* oder ein Sprungbefehl eine nicht existierende Zeile enthält
* oder das Programm nicht mit END
endet
*/
private void check()
throws IllegalArgumentException {
for (int i = 0; i=c.length)
throw new IllegalArgumentException(
"Moeglicher Zugriff ausserhalb des reservierten Bereichs "+
"(Zeile "+(i+1)+" auf Register "+param[i]+")");
}else
if (befehl[i]==GOTO||befehl[i]==IFGOTO){
if (param[i]<1||param[i]>befehl.length)
throw new IllegalArgumentException(
"Moeglicher Sprung in nicht existierende Zeile "+
"(Zeile "+(i+1)+" nach Zeile "+param[i]+")");
}
}
if (befehl[befehl.length-1]!=END)
throw new IllegalArgumentException(
"Die letzte Anweisung des Programms muss END sein.");
}
/**
* True, wenn der Befehl mit dem Opcode opc
ein Registerbefehl ist.
* @return boolean
* @param b der Opcode, der überprüft werden soll
*/
private boolean isRegBef(int opc) {
for (int n=0; n
*
* Setzt den Befehlszähler b
und die Anzahl der
* ausgeführten Befehle t
zurück.
*
* Befehl und Operand (Zahl) müssen durch Leerzeichen getrennt sein.
* END
und NOP
brauchen keine Operanden.
* Gross-/Kleinschreibung ist egal.
* Läßt die Register unverändert.
*
* @param programm das Programm
* @exception IllegalArgumentException
* wenn ein Befehl nicht bekannt ist
* @exception NumberFormatException
* wenn ein Operand keine nichtnegative ganze Zahl ist
*/
void parse(String[] programm)
throws IllegalArgumentException, NumberFormatException {
if (programm.length==0)
throw new IllegalArgumentException(
"Wie soll ich ein leeres Programm ausfuehren !?");
String bef; int op;
befehl = new int[programm.length];
param = new int[programm.length];
for(int i=0; i=0) {
bef = programm[i].substring(0,p).toUpperCase();
// bef ist der Teil vor dem ersten Leerzeichen
try {
String ops = programm[i].substring(programm[i].lastIndexOf(" ")+1);
// ops ist der Teil hinter dem letzten Leerzeichen
op = new Integer(ops).intValue();
// Umwandlung in eine Zahl
} catch(NumberFormatException e) {
throw new NumberFormatException(
"Keine nichtnegative ganze Zahl: ("+(i+1)+") "+programm[i]);
}
if (op<0)
throw new NumberFormatException(
"Keine nichtnegative ganze Zahl: ("+(i+1)+") "+programm[i]);
} else { // p<0, dh kein Leerzeichen in der Zeile
bef = programm[i].toUpperCase();
op = 0;
}
boolean known = false;
for(int j=0; jspeicher sind.
* Mehr Register existieren dann nicht!
*
* @param speicher die Speicherregister (ohne Befehlszähler)
* @exception IllegalArgumentException
* wenn speicher ein leeres Feld ist
* @exception NumberFormatException
* wenn ein Registerinhalt kleiner als 0 ist
*/
void setzeRegister(int[] speicher)
throws IllegalArgumentException, NumberFormatException {
if (speicher.length==0)
throw new IllegalArgumentException(
"Es muss mindestens ein Register (den Akku) geben!");
c = new int[speicher.length];
for (int i=0; i