Introduction to the AWB Macro Environment
- Macro editor
- Übersichtlichkeit
- Debugging
- Die lambda-Funktion
- Rückgabewerte
- Zahlen als Mengen
- Achtung bei mehr als zwei Parametern
Makro-Editor(zurück zum Überblick)
Der Makro-Editor (vgl. New-Window und Abbildung \ref{makedit}) bietet die nötigen Mittel, um Makros zu erstellen, zu testen und auszuführen.
Der Makro-Editor
Im oberen Textfeld steht der Programmcode des Makros, das erstellt werden soll. Windows-Tastenkombinationen wie Ctrl+C und Ctrl+V funktionieren; ihre Funktionen sind aber nicht über AWB-Buttons verfügbar.
Im linken unteren Feld werden bei der Ausführung des Makros die programmierten Ausgaben angezeigt.
Das rechte untere Feld dient der Fehlerausgabe und, per Häkchen einzuschalten, den Informationen des Parsers.
Die Buttons ganz oben des Makro-Editors ermöglichen es dem User,
- den geschriebenen Code zu parsen,
- das Makro auszuführen,
- das Makro in eine *.omf-Datei abzuspeichern,
- den Code eines bereits abgespeicherten Makros zum Code im Makro-Editor hinzuzufügen,
- dem Makro einen beliebigen Namen zu geben,
- die Anzeige-Einstellungen der drei Textfelder im Makro-Editor anzupassen (Schriftart und -grösse, Farbe,...),
- die Makro-Ausführung zu unterbrechen.
(zurück zum Überblick)
Übersichtlichkeit(zurück zum Überblick)
Wenn ein Makro auch nach längerer Zeit noch verstanden werden soll, ist es von Vorteil, den Code übersichtlich zu gestalten. Dies wird zum Beispiel erreicht, indem Einrückungen benutzt werden, sobald man sich im Code innerhalb einer Schleife befindet. Kurze, auskommentierte Hinweise können die Übersichtlichkeit eines Makros auch sehr stark verbessern. Kommentare stehen zwischen zwei "%" und werden vom Parser nicht beachtet. Auch die Benennung der Variablen hilft dem Makro-Leser, das Programm zu verstehen. Folgende zwei Makros machen beide dasselbe, obwohl nicht beide im selben Mass "leserlich" sind.
% Erstes Beispiel: Definieren der rekursiven Funktion fac. %
fac := lambda(n)
if <=(n,0) then % Abbruchbedingung. 1 zurückgeben. %
1;
else % Gib n*fac(n-1) zurück. %
*(n,fac(-(n,1)));
endif;
endlambda;
% Berechne 6! und gib es aus. %
writeln(fac(6));
% Zweites Beispiel: %
richtig := lambda(falsch) if
leq(falsch,-(1,1)) then richtig:=1; else
*(falsch,richtig(-(falsch,1))); endif;
endlambda;writeln(richtig(6));
(zurück zum Überblick)
Debuggen(zurück zum Überblick)
Leider kennt jeder, der schon programmiert hat, die Situationen, in denen alles falsch zu laufen scheint. Es ist oft erstaunlich zu sehen, was überhaupt alles schiefgehen kann... Folgende Checkliste kann helfen, zumindest einige mögliche Fehler zu verhindern.
- Nach jedem Makrobefehl muss ein Semikolon ";" stehen.
- Auch wenn in einer if-Schlaufe die else-Bedingung nicht gebraucht wird, muss
elseaufgeführt werden. Dabei ist oftelse noop; endif;hilfreich. - Bei der Variablenbenennung ist besonders darauf zu achten, nicht zweimal denselben Namen zu verwenden.
- Gerade bei ordnungstheoretischen Berechnungen kann der Befehl
prepare(...);Wunder wirken... - Wenn ein längerer Code-Abschnitt auskommentiert wird (zum Beispiel, um etwas zu testen), ist darauf zu achten, dass nicht Kommentare ineinander verschachtelt werden:
%...% [hier ist aktiv!] %...% - Zum Testen hilft manchmal schon ein
writeln(...)an einer geschickt gewählten Stelle. - Der Befehl
break("Break-Name")zeigt die Werte aller bisher im Makro definierten Variablen an. - Makros werden von oben nach unten interpretiert. Einer Variablen, auf die Bezug genommen wird, muss also vorher ein Wert zugewiesen worden sein (ausser bei gebundenen Variablen wie zum Beispiel
for x in L ...oderlambda(x,y) ...). - Die Syntax der Makrosprache ist case-sensitive. Zum Beispiel werden
sundSnicht als dieselbe Variable behandelt. - Achtung: mittels Makros können Elemente gelöscht werden, auch wenn Unterfenster der Struktur existieren. Dies kann zu Referenzen ins "Nichts" führen (Nullpointer).
(zurück zum Überblick)
Die lambda-Funktion(zurück zum Überblick)
Innerhalb eines Makros können neue Funktionen definiert werden, welche nicht in Form von Makro-Befehlen verfügbar sind - dazu eignen sich die lambda-Funktionen. Eine lambda-Funktion sieht zum Beispiel wie folgt aus:
addieren := lambda(a,b)
+(a,b);
endlambda;
Die Funktion, die dabei definiert wird (noch keine Ausführung!), soll addieren heissen. In der Klammer nach lambda ist ersichtlich, wie viele Parameter die zu definierende Funktion haben soll und wie diese bei der Definition der lambda-Funktion
heissen sollen. Anschliessend kann mit den übergebenen Parametern gespielt werden. Der letzte Wert, der in der Definition der lambda-Funktion steht, gilt als Rückgabewert der Funktion. Würde also zum Beispiel direkt vor endlambda; noch 1; stehen, würde die lambda-Funktion bei allen übergebenen Parametern immer den Wert 1 zurückgeben.
In obigem Beispiel wird die Summe von a und b zurückgegeben. Eine nachfolgende Zeile writeln(addieren(3,5)); hätte dann die Ausgabe 8 zur Folge.
(zurück zum Überblick)
Rückgabewerte(zurück zum Überblick)
Jedes Makro und damit auch jede lambda-Funktion und jeder Makrobefehl haben einen Rückgabewert.
(zurück zum Überblick)
Zahlen als Mengen(zurück zum Überblick)
Zahlen sind grundsätzlich natürliche Zahlen oder reelle Zahlen. Ergibt es die Situation im Makro, so können Zahlen auch als Mengen behandelt werden. Die Menge für die natürliche Zahl n wäre {0,1,...,n-1}.
So gibt zum Beispiel die Zeile writeln(item(3,2)); die Ausgabe 2.
(zurück zum Überblick)
Achtung bei mehr als 2 Parametern(zurück zum Überblick)
Sobald den Befehlen min, max, inf und sup mehr als zwei Parameter übergeben werden, ist es wichtig, die AWB-interne Berechnungsart zu kennen. Alle vier Funktionen werden von links nach rechts ausgewertet.
Das heisst zum Beispiel: max(x1,x2,x3,x4) = max(max(max(x1,x2),x3),x4) (Beachte dabei den Unterschied zwischen der zweistelligen mathematischen Funktion max und dem mehrstelligen Makrobefehl max).
Soll für eine Menge das Minimum, Maximum, Infimum oder Supremum berechnet werden, so werden besser die entsprechenden Befehle minofset, maxofset, infofset und supofset gewählt. Diese Befehle berechnen dann tatsächlich den Extremwert der gesamten Menge (ungeachtet der Reihenfolge der Elemente).
Ein Anwendungsbeispiel:
Sei L der in der Abbildung \ref{VerbandL} gezeigte Verband.
Verband L
Dann erhalten wir vom Makro
L := structurebyname("L");
prepare(L);
X3 := elementbyname(L,"X3");
X4 := elementbyname(L,"X4");
X5 := elementbyname(L,"X5");
write("max(X3,X4,X5) = ");writeln(max(X3,X4,X5));
write("maxofset({X3,X4,X5}) = ");writeln(maxofset({X3,X4,X5}));
writeln("");
write("max(X3,X5,X4) = ");writeln(max(X3,X5,X4));
die Ausgabe
max(X3,X4,X5) = nil
maxofset({X3,X4,X5}) = X5
max(X3,X5,X4) = X5
max(X3,X4,X5) ist nicht definiert, weil X3 und X4 unvergleichbar sind. Der Befehl maxofset({X3,X4,X5}) beachtet die Reihenfolge der Elemente nicht - hier geht es um eine gesamte Menge (deshalb auch die geschweiften Klammern).
max(X3,X5,X4) hingegen ist definiert, weil max(X3,X5) = max(X5,X4)=X5 gilt und damit max(X3,X5,X4) = max(max(X3,X5),X4)=X5.
Die Berechnungkonventionen dieser Bemerkung gelten auch für die entsprechenden Befehle im Ausdruckseditor!
(zurück zum Überblick)