MAL-Homepage Inhaltsverzeichnis



MAL Dokumentation: Erweiterung




Inhalt:

1. EINLEITUNG
2. COMPILIEREN UND LINKEN
2.1. Windows Betriebssysteme
2.2. LINUX und DOS
3. DER GENERATOR MALGEN
4. STACKDATEN LESEN
5. STACKDATEN SCHREIBEN
6. FEHLERMELDUNGEN


1. EINLEITUNG

Eine Besonderheit der Sprache MAL ist ihre Erweiterbarkeit. Neben der Möglichkeit, den Befehlssatz durch Doppelpunktdefinitionen zu erweitern, ist auch die direkte Einbindung neuer Worte in den MAL-Interpreter auf C++-Ebene unterstützt. In gleicher Weise ist es dem Anwender ermöglicht, Verbesserungen an bestehenden MAL-Worten vorzunehmen.

Der Code zu neuen MAL-Worten kann entweder in bestehenden oder neu angelegten Source-Dateien untergebracht werden. Auf C++-Ebene exitstiert zu jedem MAL-Wort eine Prozedur, sowie ein speziell aufgebauter Kommentarblock, der nebst einer Kurzbeschreibung des Wortes auch die Zuordnung des Namens auf MAL-Ebene zum Prozedurnamen auf C++-Ebene enthält. Ein Generatorprogramm (
malgen) durchsucht alle Source-Dateien und bringt die Befehlslisten (Dateien ´liste.voc´, ´proc.voc´) des MAL-Hauptprogramms (Datei ´mal.C´) auf den neuesten Stand.

Um ein neu implementiertes Wort auf MAL-Ebene aufrufbar zu machen, sind also folgende Schritte erforderlich:

  1. Editieren der C++-Prozedur.
  2. Editieren des Kommentarblocks.
  3. Starten des Programms ´malgen´.
  4. Compilieren der veränderten Sourcedatei und der Datei ´mal.C´.
  5. Linken.
Beim Verändern eines bestehenden Wortes genügen folgende Schritte:
  1. Editieren des Sourcecodes.
  2. Compilieren der veränderten Datei.
  3. Linken.

MAL-Homepage Inhaltsverzeichnis


2. COMPILIEREN UND LINKEN

2.1. Windows Betriebssysteme

Unter WIN98, WIN2000 oder WIN-NT wurde MAL mit dem Borland C++-Builder (Version 5.0, deutsch) compiliert. Wenn Sie den Compiler installiert habe, genügt es das Projekt 'mal' zu öffnen und mit der Taste F9 die Compilierung zu starten.

MAL-Homepage Inhaltsverzeichnis


2.2. LINUX und DOS

Die LINUX-Version von MAL wurde unter Redhat 5.0 und Redhat 6.0 compiliert und getestet. Für DOS wurde der GNU-C++-Compiler verwendet. Der Download für den passenden DOS-Compiler wurde aus Platzgründen von der MAL-Homepage entfernt. Die entsprechende Datei (gpp.zip) kann aber auf Anfrage beim
Autor bezogen werden. Expandieren Sie die Datei 'gpp.zip' zum Beispiel in eine Directory 'c:\gpp'. Sie finden dann dort eine Datei 'autoexec.bat' mit den Einstellungen, die der Compiler benötigt. Fügen Sie diese in Ihre 'autoexec.bat'-Datei ein, dann ist der Compiler nach Neustart des System installiert.

Das Compilieren des kompletten MAL-Interpreters geschieht durch Aufruf des Batch-Jobs cmal. Nach fehlerfreier Übersetzung kann mit dem Batch-Job lmal der Interpreter gelinkt werden. Die beiden Batch-Dateien sind je nach Betriebssystem unterschiedlich aufgebaut. Bei UNIX-Betriebssystemen ist die Liste der zu kompilierenden und einzubindenden Dateien jeweils direkt in cmal bzw. lmal angeführt. Unter MS-DOS existieren die Hilfsdateien mal.src mit der Liste der Source-Dateien und mal.lnk mit der Liste der einzubindenen Object-Files.

Hat man aber nur an einer oder an einigen wenigen Dateien Änderungen vorgenommen, so genügt es, diese mit der Option ´-c´ zu Compilieren und anschließend lmal aufzurufen:

Beispiel (für DOS oder LINUX):

gcc -c mathe.C
lmal

MAL-Homepage Inhaltsverzeichnis


3. DER GENERATOR MALGEN

Damit der Interpreter eine in C++ implementierte Prozedur als MAL-Wort erkennt, muß ein entsprechender Verweis in das Vokabular eingetragen werden. Dies geschieht in der Initialisierungsphase des Interpreters. Der Code für die Initialisierung des Vokabulars befindet sich in der Datei liste.voc, die vom Generator ´malgen´ erzeugt wird und mit #include in der Sourcedatei mal.C eingebunden ist. Außerdem werden die Deklarationszeilen der Prozeduren für die Compilation benötigt. Diese befinden sich in der Datei proc.voc, die ebenfalls von malgen erzeugt wird.

Für die Aktualisierung der Help-Datenbank wird von malgen darüber hinaus noch eine Datei help.mal erzeugt. Sie wird bei der Ausführung des Wortes
update_help (Folder: admin) interpretiert.

Das Programm malgen bearbeitet alle Dateien in der Arbeitsdirectory, deren Name die Zeichenfolge ´.c´, ´.C´, ´.h´ oder ´.cpu´ enthält. In diesen Dateien wird nach Zeilen mit der Zeichenfolge /*... am Zeilenanfang gesucht. Diese gelten als Einleitung für den Kommentarblock eines MAL-Wortes auf C++ Ebene.

Beschreibung (Kommentarblock) eines MAL-Wortes:

/*..................................................
MAL-Name C++-Name
Topic
Autor
Eine Zeile Kurzbeschreibung.
Langbeschreibung (Syntax, Legende, Beispiele...) 
..................................................*/
Die Zeichenfolge /*..... am Zeilenanfang kennzeichnet den Anfang und .... das Ende des Kommentarblocks, der im Prinzip an beliebiger Stelle, vorzugsweise aber vor der Definition der entsprechenden C-Routine im Sourcecode steht.

Der Generator malgen erzeugt drei Dateien: Auszug aus liste.voc :
vokabular[wortanz++]=new word_class("breakpoint",breakpoint);
vokabular[wortanz++]=new word_class("make",make);
vokabular[wortanz++]=new word_class("(",kommentar);
vokabular[wortanz++]=new word_class("test_key_codes",test_key_codes);
vokabular[wortanz++]=new word_class("amenue",amenue);
vokabular[wortanz++]=new word_class("leftbound_menu",leftbound_menu);
vokabular[wortanz++]=new word_class("writemask",writemask);
Auszug aus ´proc.voc´:
extern void breakpoint();
extern void make();
extern void kommentar();
extern void test_key_codes();
extern void amenue();
extern void leftbound_menu();
extern void writemask();
Beispiel (Code eines einfachen Wortes auf C++-Ebene):
/*.................................................
testword testprocedure
test
Miller A.
Ausgabe eines Textes am Bildschirm.
->
Es wird der Text ´Das ist ein Testwort´ ausgegeben.
..................................................*/
void testprocedure()
{ printf("Das ist ein Testwort\n"); 
}
Wird der obige Code zum Beispiel in die Datei ´worte.C´ editiert, so kann das Wort testwort folgendermaßen in das Vokabular aufgenommen werden:
malgen
gcc -c mal.C worte.C
lmal

MAL-Homepage Inhaltsverzeichnis


4. STACKDATEN LESEN

Detailbeschreibungen für die hier angeführten Prozeduren befinden sich im Kapitel
Internes.

Jedes Wort, das Eingangsdaten vom Stack erwarted sollte zu Beginn die Funktion need(int) aufrufen. Sie prüft, ob überhaupt genug Einträge am Stack vorhanden sind und übergibt im Fehlerfall den Funktionswert 1 (sonst 0).

Skalare können mit der Funktion pull() vom Stack gelesen werden. Der Stackpointer wird dabei dekrementiert. Analog existieren für das Holen von Strings die Prozeduren spullstring(sstring*) (Für kurze Strings, Typ ´sstring´) oder lpullstring(lstring*) (für lange Strings, Typ ´lstring´).

Mit der Funktion indizieren(int stackptr,int index) kann eine Komponente aus einem Verbund gelesen werden. Der Verbund wird dabei aber nicht vom Stack gelöscht. Der Parameter stackptr ermöglicht es auch, von Verbunden, die nicht am Top of Stack sind, zu indizieren. In der Regel sollte man nach jedem Aufruf von indizieren() die Prozedur codeausfuehren() aufrufen. Sie bewerkstelligt die automatische Ausführung von Codevariablen und das automatische Dereferenzieren von Poolverweisen. Selbstverständlich gibt es auch Fälle, in denen der Aufruf von codeausfuehren() nicht angebracht ist (z. B. im Wort >voc).

maxindex(int sp) oder maxindex() kann verwendet werden, um die Anzahl der Komponenten in einem Verbund zu bestimmen.

Für die Bearbeitung von Realverbunden ist die Verwendung der Klasse vectortyp hilfreich. Ein Realverbund kann mit der Funktion makerealvector() auf ein Objekt vom Typ vectortyp umgewandelt werden. vectortyp stellt den Operator [ ] zum Schreiben und Lesen der Komponenten zur Verfügung. Der Index läuft dabei, wie in MAL üblich, ab 1.

Beispiel:

void liste_realverbund()
{ if (need(1)) return;
keytyp anzahl=maxindex();
vectortyp liste=makerealvector();
for (keytyp i=1;i<=anzahl;i++)
printf("%g\n",liste[i]);
}
Um dieses Beispiel als reguläres MAL-Wort zu verwenden, müßten noch entsprechende Fehlerabfragen eingebaut werden. Sowohl in maxindex() als auch in makerealvector() können Fehler auftreten, wenn kein Realverbund am Stack übergeben wird.

MAL-Homepage Inhaltsverzeichnis


5. STACKDATEN SCHREIBEN

Mit den Prozeduren push(real) oder pushstring(char *) können Zahlen oder Strings am Stack gelegt werden. Verbunde können mit den Prozeduren verbundanfang() und verbundende() erzeugt werden. Sie sind funktionsgleich mit den Worten
[ und ].

Die Prozeduren drop(), swap() oder dup() können genauso wie die gleichnamigen MAL-Worte angewandt werden.

Mit der Prozedur create_realvector(keytyp anzahl) kann ein Objekt der Klasse vectortyp erzeugt werden. Die Komponenten dieses Objekts können dann unter Zuhilfename des Operators [ ] geladen werden.

Beispiel:

void ramp()
{ if (need(1)) return;
keytyp anzahl=(keytyp)pull(); 
vectortyp rampe=create_realvector(anzahl);
for(kreytyp i=0;i<anz;i++) rampe[i+1]=i;
}

MAL-Homepage Inhaltsverzeichnis


6. FEHLERMELDUNGEN

Bei Laufzeitfehlern ist die Prozedur fmeld(char *) für die Ausgabe des Fehlermeldungstextes aufzurufen. Sie setzt die globale Variable fehler auf 1, was die Ausgabe weiterer Fehlermeldungen von Folgefehlern unterdrückt. Außerdem wird nach dem Aufruf von fmeld() die weiter Interpretation unterbrochen und in den Debugging-Modus gewechselt.

Der Aufruf von fmeld() verhindert aber nicht, daß das gerade bearbeitete Wort zu Ende bearbeitet wird. Man muß daher gegebenanfalls die Variable fehler abfragen und, falls sie gesetzt ist, die Prozedur mit return verlassen. In diesem Zusammenhang ist zu beachten, daß manche Prozeduren intern fmeld() aufrufen. So sollte zum Beispiel nach dem Aufruf folgender Prozeduren

oder ähnlichen immer der Code
 
if (fehler) return;
zu finden sein um gröbere Programmfehler abzufangen.

MAL-Homepage Inhaltsverzeichnis