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.
