MAL-Homepage Inhaltsverzeichnis



MAL Dokumentation: Einführung




Inhalt:

1. START DES INTERPRETERS
2. HELPFUNKTION
3. SYNTAX
3.1. Allgemeines
3.2. Der Stack
3.3. Das Vokabular
3.4. Variablen
3.5. Doppelpunktdefinitionen
3.6. Parameterübergabe
3.7. Datentypen
3.8. Der Dateneditor
3.9. Namen
3.10. Strukturanweisungen
3.11. Codestrings
4. DEBUGGING
4.1. Laufzeitfehler
4.2. Haltepunkte
4.3. Trace
4.4. Unterdrücken von Laufzeitfehlern
5. ARBEITSPRINZIP DES INTERPRETERS


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.

Jene Befehle, Prozeduren oder Variablen, die in der Help-Datenbank unter dem Feld ´source´ einen Dateinamen mit Suffix ´.C´ oder einen Pfadnamen, der mit ´startup_folder´ endet, eingetragen haben, sind direkt durch Eingabe des Namens aufrufbar. Für die anderen ist der Aufruf etwas komplizierter und ist im Detail erst im Kapitel
Programmentwicklung beschrieben.

Die Help-Datenbank wird durch Eingabe von

public \ admin \ update_help

aktualisiert.

Durch Eingabe des Kommandos

public \ admin \ update_html

kann eine (zuvor eingerichtete) Directory mit HTML-Files gefüllt werden. Als Einstieg für den Browser empfehlen sich die Dateien 'index.htm' (alphabetisch sortiert) oder 'topics.htm' (nach Kapiteln geordnet).

MAL-Homepage Inhaltsverzeichnis


3. SYNTAX

3.1. Allgemeines

MAL-Code ist eine Folge von Parametern, die durch ein oder mehrere Blank oder Zeilenwechsel voneinander getrennt sind. Darüber hinaus verlangt der Interpreter keinerlei Formatierung des Quellcodes, es empfiehlt sich jedoch gewisse Konventionen (siehe später) einzuhalten, um die Lesbarkeit des Codes zu gewährleisten.

Es werden drei Arten von Eingabeparametern unterschieden:

  1. Zahlen sind Zeichenfolgen die mit ´+´, ´- ´ oder einer Zahl beginnen. MAL unterscheidet nicht zwischen Real- und Integerzahlen, sondern rechnet ausschließlich mit Realzahlen.
  2. Strings sind Zeichenfolgen, die mit " (Doppelapostroph) beginnen. Sie dürfen maximal 255 Zeichen lang sein und dürfen nicht über das Zeilenende gehen.
  3. Worte sind alle sonstigen Zeichenfolgen. Nachdem in MAL kein syntaktischer Unterschied zwischen Befehlen, Unterprogrammen oder Variablen besteht, wird für alle diese Konstrukte der Begriff ´Wort´ verwendet.
Zahlen und Strings werden auf den Stapelspeicher, den Stack gelegt. Worte werden in einer Liste, dem Vokabular, gesucht und bewirken, abhängig von der Art des Eintrages im Vokabular die Ausführung eines Befehls, Unterprogrammes oder das Laden einer Variablen auf den Stack.

Eine Besonderheit der Sprache MAL ist, daß die Namen für Worte, also Unterprogramme, Befehle oder Variablen, beliebige Zeichen (auch alle abdruckbaren Sonderzeichen) enthalten dürfen. Somit können zum Beispiel folgende Worte definiert werden:

addieren
erhöhe_um+3.75
++7
=? !nicht_ändern!


Zwischen Worten und Zahlen wird aufgrund der ersten zwei Zeichen unterschieden: Eine Zahl ist eine Zeichenfolge, die entweder mit einer Ziffer, ´+´ oder ´-´ anfängt, gefolgt von einer Ziffer oder ´.´ (Zeichen für Komma). Alle anderen Zeichenfolgen sind Worte.

Kommentar wird mit der Zeichenfolge ´( ´ (Klammer auf, gefolgt von einem Blank) eingeleitet und dem Zeichen ´)´ (Klammer zu) beendet.

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.:

  1. Die Definition einer Variablen.
  2. Die Definition eines Unterprogrammes (Doppelpunktdefinition).
  3. Die Erweiterung des C++ Sourcecodes des Interpreters.
Das Vokabular kann durch Aufruf des Wortes
vlist jederzeit abgelistet werden.

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:

Unter Zuhilfenahme dieser Worte kann ´quadrieren´ noch etwas kürzer definiert werden:

: quadrieren dup * . ;

In gleicher Weise, wie lokale Variablen in Doppelpunktdefinitionen definiert werden, können auch lokale Doppelpunktdefinitionen definiert werden (auch beliebig geschachtelt).

Beispiel:

: hypothenuse >> b >> a
  : sqr dup * ;
a sqr b sqr + sqrt . ;

3 4 hypothenuse
5



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 * ;


: hypothenuse sqr swap sqr + sqrt . ;
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.

Beispiele:

: hypothenuse >> b >> a
a sqr b sqr + sqrt . ;


: tangens >> winkel winkel sin winkel cos / ;
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´).

Lokale Doppelpunktdefinitionen sollten eingerückt werden (üblicherweise um zwei Zeichen gegenüber der Mutterdefinition).

2. Globale Variable

Die Verwendung von globalen Variablen empfiehlt sich dann, wenn ein Parameter in vielen unterschiedlichen Worten benötigt wird. Nachteil dieser Variante ist, daß man als Anwender von derart programmierten Worten nicht unmittelbar (sondern erst zur Laufzeit) erkennt, welche Eingangsdaten erforderlich sind.

Beispiele:
63 >> Seitenlänge


: drucken . . Seitenlänge . . ;



: hypothenuse a dup * b dup * + sqrt . ;

3 >> a 4 >> b hypothenuse 5
Aufgrund der seriellen Abarbeitung vom Code bei der Interpretation, kann die obige Definition von ´hypothenuse´ auch folgendermaßen aufgerufen werden:
: 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.12
Strings 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).

Beispiele:
"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.

Beispiele:

Zahlenverbund:
[ 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: Die Zählung der Indizes in MAL beginnt immer mit 1.

Beispiele:

[ 1 5 3 7 ] 2 , .
5

[ 1 5 3 7 ] 3 cut . .

[ 7 ]
[ 1 5 3 ]

"Apfel" "baum" & .
Apfelbaum

[ 3 2 7 ] 4 append .

[ 3 2 7 4 ]

[ 2 4 5 ] 2 remove .

[ 2 5 ]

: plus1 1 + ;

[ [ 4 2 6 1 ] each plus1 ] .

[ 5 3 7 2 ]


Das Wort each ist eine Schleife und ruft das nachgestellte Wort (im Beispiel ´plus1´) jeweils mit einer Komponente des übergebenen Verbunds (im Beispiel ´[ 4 2 6 1 ]´) auf. Das bedeutet, ´plus1´ wird viermal aufgerufen. Beim ersten mal wird ihm ´4´ am Stack übergeben, beim zweiten mal ´2´ usw.. Die außen angeführten Klammern fassen die einzelnen Stackeinträge wieder zu einem Verbund zusammen.

Die Problemstellung dieses Beispiels kann allerdings in MAL wesentlich einfacher gelöst werden, weil alle Operatoren (also, ´+´, ´-´, ´*´ usw.) und auch alle Funktionen (also ´sin´, ´cos´ usw.) auch für Verbunde von Zahlen (sogenannte Realverbunde) verwendet werden können. Es genügt also:
[ 4 2 6 1 ] 1 + .
zu schreiben.

Es können auch zwei Verbunde miteinander addiert werden:

[ 2 3 4 ] [ 2 4 5 ] + .

[ 4 7 9 ]

Sind die Verbunde ungleich lang, so hat das Ergebnis die
Länge des kürzeren Feldes:

[ 1 2 3 4 ] [ 2 3 5 ] + .

[ 3 5 8 ]

Auch für die Handhabung von Verbunden ist das Wissen über die Arbeitsweise des MAL-Interpreters hilfreich. Die Worte ´ [´ und ´]´ haben eine unterschiedliche Arbeitsweise:

´[´ erzeugt einen Stackeintrag mit einem eigenen Datentyp (Verbundanfang). Dieser bleibt als Anfangskennung am Stack, die nachfolgenden Daten werden darüber gestapelt. Das Wort ´]´ durchsucht den Stack von oben nach unten, bis es einen Eintrag ´[´ entdeckt. Dann faßt es alle gefundenen Einträge zu einem einzigen neuen zusammen. Das Syntaxdiagramm für ´]´ ist also:
[ x1 x2 x3 ... -> verbund


´[´ ... Verbundanfangskennung. ´xI´ ... beliebiger Stackeintrag. ´verbund´ ... Verbund mit den Komponenten ´x1´, ´x2´ usw.
Das erklärt auch, warum zwischen den Verbundklammern Befehle stehen dürfen (wie z. B. in dem oben angeführten Beispiel mit dem Wort ´each´).

Daher ist auch folgendes möglich:

: paar_erzeugen [ swap dup 3 + ] ;
5 paar_erzeugen .

[ 5 8 ]
Der Aufruf von ´swap´ bewirkt, daß die Zahl ´5´ über der Verbundanfangskennung am Stack zu liegen kommt. Dann wird sie dupliziert und 3 addiert. Der Stack sieht dann folgendermaßen aus:
8
5
[
Das Wort ´]´ verbindet also ´5´ und ´8´ zu einem Verbund. Das Wort ´paar_erzeugen´ könnte etwa folgendermaßen verwendet werden:

: paar_erzeugen [ swap dup 3 + ] ;
[ [ 1 2 3 ] each paar_erzeugen ] .

[
[ 1 4 ]
[ 2 5 ]
[ 3 6 ] ]
Auch hier werden alle zwischen den äußeren Klammern erzeugten Komponenten zu einem Verbund zusammengefaßt.





MAL-Homepage Inhaltsverzeichnis


3.8. Der Dateneditor

Mit dem Wort
d? können Stackdaten analysiert und editiert werden.

Es hat folgende Syntax:

                 x    ->  x
wobei 'x' ein beliebiger Stackeintrag sein kann.

Das Wort d? startet eine Bedienoberfläche, deren Struktur von der Datenstruktur von x abhängt. Die meisten Datentypen können auch editiert werden. Der Dateneditor ist vor allem für die Analyse verschachtelter Verbunde von großem Nutzen.

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.


Mit dem Word name> kann der Name eines Stackeintrages gelesen werden.

Syntax:
tos -> name 
Befinden sich Stackeinträge mit Namen in einem Verbund, so können sie mit dem Wort \ (Backslash) indiziert werden.

Syntax:
[ x1 x2 ... ] -> name xI
Beispiel:

[
"Franz" "vorname" >name
"Huber" "familienname" >name
24 "alter" >name
85.3 "gewicht" >name
] >> person


person \ vorname .
vorname=Franz


person \ gewicht .
gewicht=85.3


Es ist nicht erforderlich, daß alle Komponenten des Verbunds einen Namen besitzen. Die Suche im Verbund erfolgt immer von hinten nach vorne und endet mit dem ersten gefundenen Eintrag.

Man kann auch mit dem Wort >voc den ganzen Verbund in das Vokabular laden. Dann wird für jede Komponente mit einem Namen ein Wort eingerichtet.

Beispiel:

person >voc


vorname .
vorname=Franz


alter .
alter=24




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:

Eine vollständige Liste der Strukturanweisungen findet man unter Topic structure.

ifelse funktioniert ebenso wie das bereits erläuterte Wort if, nur daß es noch ein zweites nachfolgendes Wort verlangt, das ausgeführt wird, wenn ´flag´=0 ist. Es gibt keine Case- oder Switch-Anweisung in MAL. Diese kann mit Hilfe von Codestrings (siehe später) realisiert werden.

Das Schleifenwort do ruft das nachfolgende Wort ´anzahl´ mal in einer Schleife auf, wobei bei jedem Aufruf der Schleifenzähler am Stack übergeben wird.

Beispiel:

: schleifenkörper >> i
"i=" . i . cr ;


3 do schleifenkörper
i=1
i=2
i=3

Das Wort stepdo läßt darüber hinaus beliebige Schrittweiten und Grenzen zu.

Beispiel:

2.5 1.5 0.5 stepdo schleifenkörper
i=1.5
i=2
i=2.5

Hinweis: Als ungeübter MAL-Benutzer neigt man leicht dazu, unnötige Schleifen zu progammieren. Die meisten Worte können direkt Felder bearbeiten, was die Programme schneller und übersichtlicher macht.

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.

Eine weitere Möglichkeit den Abbruch bei Laufzeitfehlern zu unterdrücken bietet das Wort try. Man kann es mit einer Liste von Worten versorgen, die der Reihe nach durchprobiert werde, bis die erste ohne Fehler ausgeführt werden kann. Ist keine fehlerfrei durchführbar, so wird abgebrochen.

Der Wechsel in den Debugging-Modus nach dem Auftreten eines Laufzeitfehlers kann ausgeschaltet werden, indem man einer Variable debug_mode mit dem Wert 0 einrichtet.

Die Ausgabe von Fehlermeldungen und kann unterbunden werden, indem eine Variable mit dem Namen error_message mit dem Wert 0 eingerichtet wird. Dadurch wird implizit auch der Wechsel in den Debugging-Modus unterdrückt.

Es besteht auch die Möglichkeit, die Ausgabe von Laufzeitfehlern umzuleiten, indem man eine Doppelpunkt-Definition mit dem Namen on_error einrichtet. Diese wird dann im Fehlerfall aufgerufen. Anschließend erfolgt dann die Ausgabe der Fehlermeldung auf die Konsole (soferne nicht '0 >> error_message' eingerichtet ist) und dann der Wechsel in den Debug-Mode (soferne nicht '0 >> debug_mode' eingestellt ist).

Das Wort on_error muss zwei Stackeinträge erwarten, nämlich den Fehlermeldungstext und den Namen des Wortes, bei dem der Fehler erkannt wurde.

Beispiel:
: 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:

Der Sourcecode wird vom Interpreter schrittweise der Reihenfolge nach abgearbeitet.

Schritt1: der Parameter ´2´ wird als Zahl erkannt und landet am Stack.

Schritt2: ´6´ landet am Stack.

Schritt3: Der Parameter ´+´ wird als Wort erkannt und im Vokabular gesucht. Die enstprechende C++ Prozedur wird ausgeführt, nimmt die obersten beiden Einträge vom Stack, addiert sie und legt das Ergebis ´8´ am Stack.

Schritt4: Der Parameter ´.´ wird im Vokabular gesucht. Die Prozedur gibt den Top of Stack aus.

Schritt5: Die Prozedur für ´cr´ gibt einen Zeilenwechsel aus.

Bei der Suche nach einem Wort im Vokabular wird stets vom jüngsten zum ältesten Eintrag hin gesucht und der erste gefundene verwendet. Das bewirkt, daß bei Mehrfachdefinitionen immer der jüngste Eintrag gültig ist

Durch die Doppelpunktdefinition von ´sqr´ wird das Vokabular um einen Eintrag erweitert (Schritt1). Im dazugehörigen Datensatz wird der unter ´sqr´ definierte MAL-Code gespeichert.

Nachdem die Zahl ´3´ am Stack gelegt wurde (Schritt 2), wird im Vokabular das Wort ´sqr´ gesucht (Schritt 3) und der dazugehörige Code ausgeführt.

MAL-Homepage Inhaltsverzeichnis