MAL-Homepage
Inhaltsverzeichnis
MAL Dokumentation: Einführung
1. START DES INTERPRETERS
Der MAL-Interpreter ist ein Programm mit dem Namen ´mal´.
Nach korrektem Start meldet er sich mit der Eingabeaufforderung
Ok
MAL-Code kann per Tastatur direkt interaktiv eingegeben werden,
oder von Datei oder MAL internen Datensätzen gelesen werden.
Bei der Eingabe von der Tastatur aus, wird jeweils eine Zeile interpretiert,
wenn sie mit Enter abgeschlossen wird. Nach erfolgreicher Abarbeitung
der Zeile meldet sich der Interpreter wieder mit der Eingabaufforderung ´Ok´.
Tritt bei der Interpretation ein Fehler auf, so wird sie mit einer
Fehlermeldung abgebrochen, kann aber ab der Fehlerstelle
wieder fortgesetzt werden.
Beendet wird der Interpreter durch die Eingabe von
bye
Hat man zum Beispiel eine Datei 'test.mal' mit MAL-Code
editiert, so kann man den MAL-Interpreter auch folgendermaßen
starten
mal test.mal
Die Datei 'test.mal' wird dann automatisch interpretiert. Auch
die Angabe mehrerer Dateinamen ist möglich.
Will man direkt MAL-Code in der Command-Line übergeben, so muss
dieser unter Einfachapostroph eingeschlossen werden.
Beispiel:
mal '10 ramp draw screen bye'
MAL-Homepage Inhaltsverzeichnis
2. HELPFUNKTION
Durch Eingabe von ?? wird die Help-Datenbank eröffnet.
Will man einen Überblick über alle im System existierenden Worte
(=Befehle), so überspringt man das Eingabefeld name mit Enter.
In der Datenbank kann mit den Cursorsteuertasten zeilenweise,
oder mit Ctrl-N (nächste) und Ctrl-R (retour) seitenweise geblättert werden.
Mit der Esc-Taste wird die Help-Datenbank verlassen.
Die angeführten Menüpunkte können durch
Eingabe des Anfangsbuchstabens aufgerufen werden.
MAL-Homepage Inhaltsverzeichnis
MAL-Homepage Inhaltsverzeichnis
3.2. Der Stack
Der Stack ist ein Stapelspeicher (first in - last out buffer), der verschiedene
Datentypen speichern kann, und dient für den Datenaustausch zwischen
den MAL-Worten. Er läßt sich am besten mit einem Bücherstapel
vergleichen, auf den Daten obenauf gelegt werden können oder von
oben weggenommen werden können. Der oberste Stackeintrag wird
manchmal auch als Top of Stack, oder kurz tos,
bezeichnet.
Zahlen oder Strings werden bei der Eingabe direkt am Stack abgelegt.
Jedes MAL-Wort benötigt, abhängig von seiner Definition, eine
bestimmte Anzahl und bestimmte Typen von Stackeinträgen als
Eingangs- und Ausgangsdaten. Die benötigten Eingangsdaten werden
jeweils vom Stack gelöscht, die Ausgangsdaten werden auf den
Stack obenauf gelegt.
Aus dieser, für alle Worte einheitlichen Arbeitsweise, ergibt sich
auch ein für alle Worte einheitliches Syntaxdiagramm. Es werden
die Eingangsdaten symbolisch aufgelistet, dann folgt das Zeichen
´->´ als Platzhalter für das Wort selbst, und anschließend folgt
die symbolische Auflistung der Ausgangsdaten.
Beispiele:
Das Wort + (Addition)
benötigt zwei Operanden und hat die Summe als Ausgangswert.
Syntaxdiagramm:
op1 op2 -> summe
´op1´ ... Erster Operand
´op2´ ... Zweiter Operand
´summe´ ... Ergebnis der Addition von ´op1´ und ´op2´.
Das Wort . (Punkt)
listet den obersten Stackeintrag (Top-of-Stack) am Bildschirm ab.
Syntax:
tos ->
´tos´ ... beliebiger Stackeintrag.
Einfaches Additionsprogramm:
3 4 + .
7
Manche Worte (wie zum Beispiel das Wort
if) benötigen nachfolgende
Parameter (meist den Namen anderer Worte). Solche Parameter werden
im Syntaxdiagramm überstrichen oder unterstrichen, um Verwechslungen
mit den Ausgabedaten zu vermeiden.
Syntax von if:
flag -> wort
´flag´ ... Realzahl, wenn ´flag´#0 wird das Wort ´wort´ ausgeführt.
Aufruf von ´if´:
5 2 1 if + .
7
5 2 0 if + .
2
In den Help-Pages ist es nicht möglich tiefgestellte Zeichen
zu verwenden, daher werden für die allgemeine Bezeichnung von
Indizes Großbuchstaben verwendet.
Also zum Beispiel für xi wird xI geschrieben.
MAL-Homepage Inhaltsverzeichnis
3.3. Das Vokabular
Das Vokabular ist eine Liste, in der alle für die Interpretation
verfügbaren Worte untergebracht sind. Tritt im Sourcecode ein
Parameter auf, der kein String und keine Zahl ist, so wird das
Vokabular durchsucht (vom jüngsten bis zum ältesten Eintrag).
Der gefundene Eintrag bewirkt dann entweder die Ausführung eines
Befehls oder eines Unterprogramms, oder das Holen eines
Variablenwertes auf den Stack. Wird das Wort (der Parameter
aus dem Sourcecode) nicht im Vokabular gefunden, so wird
die Interpretation mit der Fehlermeldung ´?´ abgebrochen.
MAL ist eine erweiterbare Sprache. Der Anwender hat drei
Möglichkeiten, selbst Vokabularseinträge zu definieren.:
MAL-Homepage Inhaltsverzeichnis
3.4. Variablen
Variablen werden mit dem Wort >> eingerichtet.
Syntax von >>:
tos -> variablenname
Es wird ein neues Wort mit dem Namen ´variablenname´ erzeugt und
mit dem Wert des Stackeintrags ´tos´ gefüllt. Ein späterer Aufruf des
Wortes ´variablenname´ bewirkt, daß der Wert von ´tos´ wieder am Stack gelegt wird.
Beispiel:
3 >> x
x .
3
x x + .
6
Will man einer bereits bestehenden Variablen einen neuen
Wert zuweisen, so kann dies mit dem Wort -> geschehen.
Es hat die gleiche Syntax wie >>.
MAL-Homepage Inhaltsverzeichnis
3.5. Doppelpunktdefinitionen
Unterprogramme werden in MAL mit einer Doppelpunktdefinition definiert.
Eine Doppelpunktdefinition erzeugt ein neues Wort (einen neuen Eintrag im
Vokabular) und hat folgende Syntax:
-> name par1 par2 ..... ;
wobei das Symbol -> stellvertretend für das Wort ´:´ steht. Der erste
Parameter nach dem Doppelpunkt gibt den Namen des neu definierten Wortes an.
Die nachfolgenden Parameter (´par1´, ´par2´ usw.) stellen den MAL-Code dar,
der beim Aufruf des neu definierten Wortes ausgeführt werden soll. Als
Abschluß der Definition dient das Zeichen ´;´ (muß durch Blank oder
Zeilenwechsel vom letzten Parameter getrennt sein).
Beispiel:
(Definition)
: quadrieren >> a
a a * . ;
(Aufruf)
2 quadrieren
4
Als erster Parameter nach dem Doppelpunkt erscheint ´quadrieren´. Das heißt,
es wird ein neues Wort mit dem Namen ´quadrieren´ eingerichtet. Beim Aufruf von
´quadrieren´ wird der Code >> a a a * .
zur Ausführung gebracht. Dabei wird
zuerst eine Variable ´a´ eingerichtet, in die der Wert des obersten Stackeintrages
(im Beispiel ´2´) gespeichert wird. Anschließend wird die Variable zweimal am
Stack geholt, mit sich selbst multipliziert und mit ´.´ ausgegeben.
Eine wesentliche Eigenschaft bei der Ausführung von Doppelpunktdefinitionen ist,
daß lokale Definitionen (wie in obigem Beispiel die Variable ´a´) am Ende der
Ausführung, also bei Erreichen des Strichpunkts, wieder aus dem Vokabular
gelöscht werden. Somit ist nach dem Aufruf von ´quadrieren´ keine Variable ´a´
mehr im Vokabular zu finden, was einfach mit ´vlist´ nachgeprüft werden kann.
Definiert man aber zum Beispiel ein Wort ´quadrieren-vlist´ etwa folgendermaßen:
: quadrieren-vlist >> a
a a * . vlist ;
so taucht die Variable ´a´ im Vokabular auf.
Es folgt eine Auflistung von Worten, die in den nachfolgenden
Beispielen verwendet werden:
MAL-Homepage Inhaltsverzeichnis
3.6. Parameterübergabe
Die Übergabe von Werteparameter an eine
Doppelpunktdefinition (eine Prozedur) kann auf verschiedene Arten erfolgen:
1. Datenübergabe am Stack
Bei kleinen Prozeduren können die Eingabedaten direkt vom
Stack verarbeitet werden. Dadurch sind sehr kurze Definitionen möglich.
Beispiele:
: sqr dup * ;Bei größeren Doppelpunktdefinitionen wird diese Methode aber unübersichtlich. Es empfiehlt sich dann, die am Stack übergebenen Parameter in lokale Variable zu speichern. Man beachte, daß die Parameter in umgekehrter Reihenfolge wie sie am Stack gelegt wurden vom Stack geholt werden.
: hypothenuse sqr swap sqr + sqrt . ;
: hypothenuse >> b >> a a sqr b sqr + sqrt . ;Wie eingangs erwähnt, verlangt der Interpreter keine Formatierung des Codes. Um die Lesbarkeit zu gewähren, empfiehlt sich aber, die Definition der Eingangsvariablen direkt in der ersten Zeile der Doppelpunktdefinition anzuführen. Die Ausgangsparameter bedürfen bei einer überlegten Benennung der Prozedur meist keine weitere Erläuterung (wie z.B. bei ´tangens´).
: tangens >> winkel winkel sin winkel cos / ;
63 >> SeitenlängeAufgrund der seriellen Abarbeitung vom Code bei der Interpretation, kann die obige Definition von ´hypothenuse´ auch folgendermaßen aufgerufen werden:
: drucken . . Seitenlänge . . ;
: hypothenuse a dup * b dup * + sqrt . ;
3 >> a 4 >> b hypothenuse 5
: versorgung_von_hypothenuse 3 >> a 4 >> b hypothenuse ;Beim Aufruf des Wortes ´versorgung_von_hypothenuse´ wird zuerst das Vokabular um die Variable ´a´ und ´b´ erweitert. Dann folgt die Ausführung von ´hypothenuse´, das nun auf die Variablen zugreifen kann. Nach Beendigung von ´versorgung_von_hypothenuse´ werden die Einträge ´a´ und ´b´ wieder aus dem Vokabular entfernt, sind also global nicht sichtbar.
MAL-Homepage Inhaltsverzeichnis
3.7. Datentypen
MAL ermöglicht die Behandlung von verschiedensten Datentypen
auf einheitliche Weise. Um den Einstieg möglichst einfach zu gestalten,
werden hier nur die wesentlichsten drei Datentypen erklärt. Mit
den Datentypen Zahl, String und
Verbund
kann der Hauptanteil der in der Bewegungsanalyse üblichen Probleme
gelöst werden. Darüber hinaus existieren noch die Datentypen
Doppelpunktdefinitionen, Verbundanfangskennungen, Codestrings,
Zeiger auf Pooleinträge, Polygone für Graphikausgabe, komprimierte
Felder von Realzahlen, EMED-Fußabdruckbilder, Images,
Kreise für Graphikausgabe und Bitlisten.
Am Stack und in Variablen können alle Datentypen gespeichert
werden. Die meisten Worte (Befehle und Doppelpunktdefinitionen)
können auch mit verschiedenen Datentypen versorgt werden und
passen ihre Ergebnisdaten entsprechend an. Im Detail muß aber
immer das Syntaxdiagramm bzw. der Helptext des entsprechenden
Wortes gelesen werden, um die Möglichkeiten und Reaktionen zu erfahren.
Jeder Datensatz in MAL besitzt eine Datentypkennung, die bei
Umspeicherungen mitgenommen wird, also immer erhalten bleibt,
soferne der Datentyp nicht explizit durch eine Konvertierungsroutine
umgestellt wird. Aufgrund dieser Kennung können die Worte auch
erkennen, wie sie auf die übergebenen Daten reagieren müssen.
Zahlen sind stets Gleitkommazahlen (Realzahlen).
Sie können in ihrer Funktion auch als Integerzahlen (zum Beispiel
Schleifenzähler) oder logische Größen (0 .. false, #0 .. true) Verwendung finden.
Beispiele:
3.1415962 1.0e-3 -17 -0.12Strings sind Zeichenfolgen von maximal 255 Zeichen. Sie sind mit " (Doppelapostroph) vorne und hinten zu begrenzen. Sonderzeichen können als Hexadezimaläquivalent eingegeben werden. Als Kennung gilt in diesem Fall ein vorangestelltes $-Zeichen (Achtung: Strings mit derart definierten Zeichen können bei der Portierung auf andere Maschinen ihre Bedeutung ändern).
"hallo" "Das ist ein String mit Peep $07"Verbunde werden erzeugt, indem mehrere Stackeinträge mit den Zeichen [ und ] eingeschlossen werden. Es können beliebige Stackeinträge zu Verbunden zusammengefaßt werden. Das ermöglicht auch das Schachteln von Verbunden (für mehrdimensionale Felder) oder das Mischen verschiedener Datentypen in einem Verbund.
[ 1 2 3 4 5 ]gemischter Verbund:
[ "Huber" "Franz" 27.5 ]3x3 Einheitsmatrix:
[ [ 1 0 0 ] [ 0 1 0 ] [ 0 0 1 ] ]Für die Handhabung von Verbunden existieren einige sehr nützliche Worte, die in gleicher Weise für fast alle Datentypen mit mehreren Komponenten verwendet werden können:
[ 4 2 6 1 ] 1 + .zu schreiben.
[ x1 x2 x3 ... -> verbundDas erklärt auch, warum zwischen den Verbundklammern Befehle stehen dürfen (wie z. B. in dem oben angeführten Beispiel mit dem Wort ´each´).
´[´ ... Verbundanfangskennung. ´xI´ ... beliebiger Stackeintrag. ´verbund´ ... Verbund mit den Komponenten ´x1´, ´x2´ usw.
8 5 [Das Wort ´]´ verbindet also ´5´ und ´8´ zu einem Verbund. Das Wort ´paar_erzeugen´ könnte etwa folgendermaßen verwendet werden:
MAL-Homepage Inhaltsverzeichnis
3.8. Der Dateneditor
Mit dem Wort d? können Stackdaten analysiert und
editiert werden.
Es hat folgende Syntax:
x -> xwobei 'x' ein beliebiger Stackeintrag sein kann.
MAL-Homepage Inhaltsverzeichnis
3.9. Namen
Stackeinträge können mit Namen versehen werden.
Wird ein Stackeintrag mit einem Namen versehen, so bleibt
ihm dieser so lange erhalten, bis er explizit gelöscht wird.
Besonders hilfreich sind Namen beim Suchen (Indizieren) von
Datensätzen in einem Verbund.
Zum Setzen eines Namens dient das Wort
>name.
Syntax:
tos name -> tos
´tos´ ... Beliebiger Stackeintrag der mit dem Namen versehen werden soll. ´name´ ... String mit dem gewünschten Namen.
tos -> nameBefinden sich Stackeinträge mit Namen in einem Verbund, so können sie mit dem Wort \ (Backslash) indiziert werden.
[ x1 x2 ... ] -> name xIBeispiel:
MAL-Homepage Inhaltsverzeichnis
3.10. Strukturanweisungen
Die Strukturanweisungen sind in MAL immer so gestaltet, daß sie
andere Worte aufrufen. Das bedeutet, daß zum Beispiel für eine
Schleife ein Wort mit einem Schleifenkörper definiert werden muß,
das dann von der Schleifenanweisung (z.B dem Wort
each) wiederholt aufgerufen wird.
Einige häufig benötigte Strukturanweisungen sind:
MAL-Homepage Inhaltsverzeichnis
3.11. Codestrings
Codestrings sind Strings, die exekutierbaren MAL-Code enthalten.
Sie können mit dem Wort make
explizit ausgeführt werden. Sie werden aber auch automatisch
ausgeführt, wenn sie aus einer Variablen auf den Stack geladen,
oder aus einem Verbund indiziert werden.
Jeder String kann mit dem Wort >code
in einen Codestring, und umgekehrt kann jeder Codestring mit
code> in einen normalen
String umgewandelt werden.
Beispiele:
"5 + ." >code >> addiere5
3 addiere5
8
[
"5 + ." >code
"5 - ." >code
] >> plusminus
3 plusminus 1 ,
8
3 plusminus 2 ,
-2
Der wichtigste Anwendungsfall von Codestrings ist die Versorgung
einer Prozedur (Doppelpunktdefinition) mit verschiedenen Funkionen.
Beispiel:
: funktionswerte_berechnen >> funktion
[ 0 1 2 3 4 ] funktion . ;
"dup *" >code funktionswerte_berechnen
[ 0 1 4 9 16 <- 5
]
"3 +" >code funktionswerte_berechnen
[ 3 4 5 6 7 <- 5
]
Will man die automatische Ausführung von Codestrings beim Holen von
Variablen unterdrücken, so muß man das Wort
cool zuhilfe nehmen.
Syntax:
-> variablenname variablenwert
Beispiel:
"5 + ." >code >> addieren
cool addieren .
addieren=code:5 + .
Das Wort cool
kann auch verwendet werden, um die Daten einer
Doppelpunktdefinition auf den Stack zu laden. Das ist zum
Beispiel dann von Interesse, wenn man die Doppelpunktdefinition
editieren will.
Beispiel:
: testwort
"Das ist eine Doppelpunktdefinition" . cr ;
cool testwort (Doppelpunktdefinition am Stack holen)
med (Editor aufrufen)
-> testwort (geänderten Datensatz ins Vokabular)
MAL-Homepage Inhaltsverzeichnis
4. DEBUGGING 4.1. Laufzeitfehler
Tritt bei der Interpretation einer Doppelpunktdefinition ein Fehler auf, so
meldet sich der Interpreter nach Ausgabe der Fehlermeldung mit dem
Prompt debugging>. Dieser Zustand unterscheidet sich von
dem normalen Bedienmodus (Prompt ´ok´) nur dadurch, daß der
Interpreterzustand noch der der Fehlerstelle ist. Das heißt, es
existieren noch die lokalen Variablen und Doppelpunktdefinitionen im
Vokabular und der Stack hat noch den Zustand, den er beim Auftreten
des Fehlers hatte.
Wort ?:
Wenn das Prompt debugging> angezeigt wird kann man mit dem
Wort ? ein Editorfenster öffnen,
in dem die Fehlerstelle markiert ist. Man kann den fehlerhaften
Code sofort editieren.
Wort calls:
Das Wort calls
ist ähnlich wie '?', nur wird eine Liste jener Doppelpunktdefinitionen,
die bis zum Auftreten des Fehlers aufgerufen wurden, ausgegeben.
Auf diese Weise kann der Weg bis zum Auftreten des Fehlers zurück
verfolgt werden (=Aufruf-Callstack).
Beispiel:
: fehlerhafte_prozedur 17 + mist - ;
: rufe_prozedur >> wert
wert fehlerhafte_prozedur . cr ;
: hauptprogramm
[ 1 3 7 ] each rufe_prozedur ;
Ruft man nun das Wort hauptprogramm
auf, so erscheint zunächst
die Fehlermeldung
mist << ?
und das Prompt debugging>.
Ruft man nun das Wort ? auf, so erscheint folgendes
Editor-Fenster:
In den meisten Fällen kann der Code gleich korrigiert werden.
Beim Aufruf des Wortes calls erscheint folgendes Fenster:
Im Debugging-Modus kann der Interpreter ebenso wie unter
dem Prompt ok bedient werden.
Man kann also Variablen aubfragen,
Doppelpunktdefinitionen ausführen oder auch neue definieren u.s.w..
Mit Einführung der Objektorientierten Programmierung in MAL
kann es in manchen Fällen schwierig sein festzustellen, welcher
Code (und vor allem welche Klasse) sich hinter dem Namen eines
bestimmten Wortes verbirgt.
Mit dem Wort i?
kann für ein bestimmtes Wort (der Name muss
im Anschluss an i?
eingegeben werden) festgestellt werden,
welche Versionen existieren und welche dieser Versionen
bei Aufruf des Wortes verwendet wird (dieses wird durch das
Zeichen '*' gekennzeichnet).
Durch Eingabe von ok kann der Debugging-Modus wieder
verlassen werden. Der Stack wird dabei nicht verändert, jedoch das
Vokabular entsprechend gekürzt.
MAL-Homepage Inhaltsverzeichnis
4.2. Haltepunkte
Mit dem Wort breakpoint kann an beliebiger
Stelle ein Haltepunkt eingebaut werden. Der Interpreter meldet sich
beim Erreichen des Wortes ´breakpoint´ mit dem Prompt
breakpoint>.
Der Zustand ist dabei mit dem bei ´debugging>´ ident, jedoch wird
bei der Eingabe von ´ok´ die Interpretation fortgesetzt. Will man
abbrechen, so gibt man einfach ein unbekanntes Wort ein, also
produziert künstlich einen Laufzeitfehler.
Im Breakpoint-Modus und im Debugging-Modus können alle
Möglichkeiten des Interpreters genutzt werden. So kann man z.B.
auch Doppelpunktdefinitionen schreiben, das Vokabular mit ´vlist´
ablisten usw.. Man sollte nur beachten, daß lokale Definitionen wieder
verloren gehen, wenn die aktuelle Doppelpunktdefinition verlassen wird.
MAL-Homepage Inhaltsverzeichnis
4.3. Trace
Mit den Worten trace und
notrace kann der
Trace-Modus ein- bzw. ausgeschaltet werden. Im Tracemodus
wird der ganze interpretierte Code abgelistet. Normalerweise
benötigt man diese Hilfe nur, wenn der Interpreter mit einem
Laufzeitfehler (Interpreterfehler) abstürzt, um die Fehlerstelle
ermitteln zu können.
MAL-Homepage Inhaltsverzeichnis
4.4. Unterdrücken von Laufzeitfehlern
Für die Programmierung von Anwenderlösungen ist oft
der Programmabbruch oder die Ausgabe von Fehlermeldungen
störend. Der MAL-Interpreter bietet die Möglichkeit, für
bestimmte Programmteile Fehlermeldungen zu unterdrücken.
Will man den Abbruch der Interpretation nach Auftreten eines
Laufzeitfehlers vermeiden, so kann man das Wort
nobreak verwenden.
Man muß zu diesem Zweck jenen Programmteil, in dem der Fehler
auftreten kann und darf als ein Wort definieren, das keine Versorgungs-
und Ergebnisdaten am Stack übernimmt. Dieses Wort kann dann durch
Voranstellen des Wortes nobreak
aufgerufen werden.
Beispiel:
: fehlerhaft 3 7 mist + . ; : nicht_abbrechen nobreak fehlerhaft "hallo" . ;Wird nicht_abbrechen aufgerufen, so tritt bei der Interpretation von fehlerhaft an der Stelle mist ein Laufzeitfehler auf. Dort wird eine Fehlermeldung ausgegeben und in den Debugging-Modus gewechselt. Nach der Eingabe von ´ok´ wird die Interpretation aber nicht abgebrochen, sondern mit der Ausgabe des Textes "hallo" fortgesetzt. Die fehlerhafte Doppelpunktdefinition wird allerdings nicht zu Ende interpretiert. Der Stackpointer wird von nobreak dabei wieder auf den alten Wert zurückgestellt.
: on_error >> wort >> meldung "Fehler " . meldung . " bei Ausfuehrung von " . wort . " aufgetreten" . cr ;
MAL-Homepage Inhaltsverzeichnis
5. ARBEITSPRINZIP DES INTERPRETERS
Manche programmiertechnische Fragen lassen sich leichter beantworten,
wenn man sich das Arbeitsprinzip des MAL-Interpreters vor Augen hält:
MAL-Homepage Inhaltsverzeichnis