Prozeduren und Funktionen (Makros)
Eine Prozedur (Funktion) repräsentiert zur Laufzeit wiederverwendbaren Code, der parametrisiert werden kann. Da JASm “nur” globale Variablen kennt, muss die Übergabe von Werten geschickt gehandhabt werden.
Das nachfolgende Beispiel nutzt nun mehrfach den Algorithmus für die Addition (s. o.) ab der Adresse Add. Zur Übergabe der Parameter werden reservierte Speicheradressen verwendet, die hier zur besseren Übersicht mit Add_, also dem “Namen” der Funktion beginnen.
Innerhalb der Funktion müssen die “eigenen” Variablen geordnet wieder initialisiert werden, daher erfolgen einige Rücksetzungen z. B. SUB @Add_tmp @Add_tmp, da andernfalls bei erneutem Aufruf der Funktion diese Zellen bereits mit undefinierten Werten belegt sind. Auch kann nicht ausgeschlossen werden, dass von außerhalb der Funktion diese Zellen manipuliert wurden, da es keinerlei Einschränkungen auf den Speicherbereich gibt.
Für den Aufruf der Funktion bei Add werden im ersten Schritt die erforderlichen Parameter in die Speicherzellen der Funktion übertragen. In diesem speziellen Fall (Addition) nutzen wir die Tatsache, dass die Summe zweier Werte (a+b) der Negation der Summe der negierten Werte -(-a-b) entspricht. Auf diese Weise erspart man sich ein paar Schritte zur Vorzeichenkonvertierung.
Als nächstes muss die Rücksprungadresse hinterlegt werden, damit nach Ausführen der Funktion das Programm an der vorgesehenen Stelle fortgesetzt werden kann. Dies kann nur durch die unmittelbare Manipulation der Rücksprungadresse des JA Befehls in der Funktion erfolgen. Zu Beginn dieses Programms ist die Adresse mit 0 definiert, beim zweiten Aufruf muss die Adresse (Add_ret) wie auch die Speicherzelle tmp auf jeden Fall gezielt auf Null gesetzt werden.
@Start # Initialisierung des Programmzeigers Step: -3 # Schrittweite des Programmzeigers REM Variablen a1: 10 # Wert für a1, hier: 10 b1: 5 # Wert für b1, hier: 5 c1: 0 # Wert für c1, initialisiert mit 0, wird 15 a2: 7 # Wert für a2, hier: 7 b2: 3 # Wert für b2, hier: 3 c2: 0 # Wert für c2, initialisiert mit 0, wird 10 tmp: 0 # Puffer für Negationen ret1: @return1 # Rücksprungadresse für den ersten Aufruf ret2: @return2 # Rücksprungadresse für den zweiten Aufruf Start: REM erste Addition c1=a1+b1 veranlassen, 1. Funktionsaufruf SUB @Add_a @a1 # Wert für a1 an die Funktion übertragen SUB @Add_b @b1 # Wert für b1 an die Funktion übertragen SUB @tmp @ret1 # Rücksprungadresse negieren SUB @Add_ret @tmp # negierte Rücksprungadresse übertragen JA 0 @Add # “Funktionsaufruf” return1: # Ziel für den Rücksprung aus der Funkt. SUB @c1 @Add_res # Ergebnis der Funktion abrufen REM zweite Addition c2=a2+b2 veranlassen, 2. Funktionsaufruf SUB @Add_a @a2 SUB @Add_b @b2 SUB @tmp @tmp # Puffer wieder initialisieren SUB @tmp @ret2 SUB @Add_ret @Add_ret # Speicherzelle für Rücksprung löschen SUB @Add_ret @tmp JA 0 @Add return2: SUB @c2 @Add_res SUB 0 0 # Programm beenden REM Additionsfunktion Add Add_a: 0 # lokale Variable für a Add_b: 0 # lokale Variable für b Add_tmp: 0 # lokaler Puffer für Negation Add_res: 0 # Speicher für Rückgabe des Ergebnisses Add: SUB @Add_res @Add_res # Ergebnisspeicher zurücksetzen SUB @Add_tmp @Add_tmp # Zwischenpuffer zurücksetzen SUB @Add_tmp @Add_a # tmp = -a SUB @Add_tmp @Add_b # tmp = tmp - b = -a - b = -(a + b) SUB @Add_res @Add_tmp # res = -tmp = a + b SUB @Add_a @Add_a # Aufräumen, Speicher initialisieren SUB @Add_b @Add_b # für spätere Aufrufe JA 0 Add_ret:0 # Zurück zur aufrufenden Stelle
Die Ausführung dieses Programms erfordert insgesamt 31 Schritte. Die Ergebnisse befinden sich danach in den Speicherzellen 4 (@c1) und 7 (@c2).
Makro
Unter Verwendung von Makros sieht der Code – ergänzt um eine Ergebnisausgabe – dann wie folgt aus:
@Start # Initialisierung des Programmzeigers Step: -3 # Schrittweite des Programmzeigers REM Variablen a1: 10 # Wert für a1, hier: 10 b1: 5 # Wert für b1, hier: 5 c1: 0 # Wert für c1, initialisiert mit 0, wird 15 a2: 7 # Wert für a2, hier: 7 b2: 3 # Wert für b2, hier: 3 c2: 0 # Wert für c2, initialisiert mit 0, wird 10 INC ADD # An dieser Stelle wird der Code der Addition # eingefügt tmp: 0 # Puffer für Negationen ret1: @return1 # Rücksprungadresse für den ersten Aufruf ret2: @return2 # Rücksprungadresse für den zweiten Aufruf Start: REM erste Addition c1=a1+b1 veranlassen, 1. Funktionsaufruf SUB @ADD_a @a1 # Wert für a1 an die Funktion übertragen SUB @ADD_b @b1 # Wert für b1 an die Funktion übertragen SUB @tmp @ret1 # Rücksprungadresse negieren SUB @ADD_return @ADD_return # Speicherzelle für Rücksprung löschen SUB @ADD_return @tmp # negierte Rücksprungadresse übertragen JA 0 @ADD # “Funktionsaufruf” return1: # Ziel für den Rücksprung aus der Funktion SUB @c1 @ADD_result # Ergebnis der Funktion abrufen SUB -1 @ADD_result # Ergebnis der Berechnung ausgeben REM zweite Addition c2=a2+b2 veranlassen, 2. Funktionsaufruf SUB @ADD_a @a2 SUB @ADD_b @b2 SUB @tmp @tmp # Puffer wieder initialisieren SUB @tmp @ret2 SUB @ADD_return @ADD_return # Speicherzelle für Rücksprung löschen SUB @ADD_return @tmp JA 0 @ADD return2: # Ziel für den Rücksprung aus der Funktion SUB @c2 @ADD_result # Ergebnis der Funktion abrufen SUB -1 @ADD_result # Ergebnis der Berechnung ausgeben INC EXIT # An dieser Stelle wird der Code SUB 0 0 eingefügt
Hierbei werden zwei Makros referenziert: ADD und EXIT.
EXIT ist definiert als SUB 0 0
ADD hingegen ist etwas umfangreicher:
ADD: SUB @ADD_tmp @ADD_tmp # lokalen Speicher initialisieren SUB @ADD_result @ADD_result # lokalen Ergebnisspeicher initialisieren SUB @ADD_tmp @ADD_a # tmp = -a SUB @ADD_a @ADD_a # Eingangsgröße a nach Gebrauch initialisieren SUB @ADD_tmp @ADD_b # tmp -= b SUB @ADD_b @ADD_b # Eingangsgröße b nach Gebrauch initialisieren SUB @ADD_result @ADD_tmp # result = -tmp = a+b JA 0 ADD_return:0 # Rücksprung zur "aufrufenden" Stelle ADD_a: 0 # Eingangsgröße a ADD_b: 0 # Eingangsgröße b ADD_tmp: 0 # lokale Hilfsvariable ADD_result: 0 # Ergebnis der Berechnung a+b
Und weiter?
Die hier gezeigten Beispiele für JASm Code zeigen bereits, dass üblicherweise einfache Aufgaben in JASm abgebildet werden können, allerdings eine nicht unerhebliche Komplexität mit sich bringen. Eine einfache Addition von zwei Werten benötigt 6 Codezeilen – in herkömmlichen Programmiersprachen, selbst Assembler ist dies mit einer einzigen Anweisung zu realisieren.
Bis zu diesem Zeitpunkt war JASm hier nur reine Theorie, wenngleich auch schon eine Umsetzung in PHP existiert. Im nächsten Beitrag wird eine JavaScript Implementierung des Compilers, bzw. Interpreters präsentiert, sodass die JASm Programme auch zum Leben erweckt werden können.