BASIC-Compiler

Benutzerdefinierte Funktionen und Prozeduren

Mit benutzerdefinierten Funktionen und Prozeduren lassen sich Programme wesentlich besser strukturieren als mit den klassischen BASIC-Anweisungen GOSUB und RETURN. Benutzerdefinierte Funktionen liefern einen Wert zurück und werden genauso aufgerufen wie die BASIC-Funktionen. Prozeduren dagegen liefern keinen Wert zurück und werden deshalb wie BASIC-Anweisungen behandelt.

Struktur des BASIC-Programms

Benutzerdefinierte Funktionen und Prozeduren werden nach dem Hauptprogramm implementiert, d.h., die erste FUNCTION- bzw. SUB-Anweisung beendet das Hauptprogramm. Ab hier dürfen außer Kommentare nur noch Implementierungen von benutzerdefinierten Funktionen und Prozeduren folgen.

Mit dem Begriff Hauptprogramm ist der erste Teil des BASIC-Programms gemeint, bei dem die Programmausführung beginnt.

Aufruf

Benutzerdefinierte Funktionen und Prozeduren werden anhand ihres Namens aufgerufen. Dieser Name darf kein reserviertes Schlüsselwort sein. Damit der Compiler bei der Verwendung eines Funktions- oder Prozedurnamens diesen nicht als Variable interpretiert, muss eine benutzerdefinierte Funktion oder Prozedur bei ihrem Aufruf dem BASIC-Compiler bereits bekannt sein. Das ist der Fall, wenn sie weiter oben im BASIC-Programm implementiert wurde. Ist das nicht möglich (z.B. bei Aufruf im Hauptprogramm oder bei Rekursion), muss die Funktion bzw. Prozedur dem Compiler vorher mit der DECARE-Anweisung bekanntgemacht werden.

Lokale Variablen

Eine Besonderheit von benutzerdefinierten Funktionen und Prozeduren ist, dass sie lokale Variablen deklarieren und verwenden können (siehe Anweisung LOCAL). Diese Variablen werden bei jedem Aufruf der Funktion bzw. Prozedur neu angelegt und sind nur innerhalb dieser Funktion bzw. Prozedur sichtbar. Das gilt auch für Rekursionen, d.h., wenn sich eine Funktion oder Prozedur selbst aufruft, hat sie in jeder Aufrufebene separate lokale Variablen. Allerdings muss in dem Fall der Stack-Bereich ausreichend groß gewählt werden, da die lokalen Variablen auf dem Stack angelegt werden.

Innerhalb einer benutzerdefinierten Funktion oder Prozedur müssen die lokalen Variablen zuerst angelegt werden, d.h., alle LOCAL-Anweisungen müssen unmittelbar hinter der FUNCTION- bzw. SUB-Anweisung folgen. Nur Kommentare sind dazwischen noch erlaubt.

Der JKCEMU-BASIC-Compiler unterstützt keine lokalen Feldvariablen, d.h., bei LOCAL können nur einfache Variablen angegeben werden.

Innerhalb einer benutzerdefinierten Funktion oder Prozedur sind sowohl die lokalen als auch die globalen, d.h. die im Hauptprogramm verwendeten, Variablen sichtbar. Hat allerdings eine lokale Variable den gleichen Namen wie eine globale, wird die globale verdeckt und ist somit nicht mehr sichtbar.

Argumente

Benutzerdefinierte Funktionen und Prozeduren können Argumente haben. Diese werden bei der Deklaration und Implementierung hinter dem Funktions- bzw. Prozedurnamen in Form einer in runden Klammern und mit Komma getrennten Liste von Argumentnamen angegeben. Aus den Argumentnamen leitet sich auch der Datentyp ab (Integer oder String, je nachdem, ob der Argumentname auf ein $-Zeichen endet).

Innerhalb einer Funktion bzw. Prozedur sind die Argumente als lokale Variablen implementiert, d.h., ihnen kann auch ein Wert zugewiesen werden. Der einzige Unterschied zwischen diesen "Argumentvariablen" und mit LOCAL deklarierten Variablen besteht darin, dass Argumentvariablen beim Aufruf der Funktion bzw. Prozedur von "außen" initialisiert werden.

Rückgabewert

Benutzerdefinierte Funktionen liefern einen Wert zurück. Der Typ des Rückgabewertes hängt vom Funktionsnamen ab. Endet dieser mit einem $-Zeichen, wird eine Zeichenkette zurückgegeben, anderenfalls ein Integer-Wert. Der gewünschte Rückgabewert ist syntaktisch einer Variable zuzuweisen, die den gleichen Namen hat wie die Funktion. Mehrfache Zuweisungen sind möglich. In dem Fall ist die letzte Zuweisung relevant. Ein Rücklesen des zugewiesenen Rückgabewerts ist aber in der Funktion nicht möglich.

Programmbeispiel

Das Beispiel zeigt die Programmierung einer benutzerdefinierten Funktion mit lokalen Variablen. Als weitere Besonderheit wird bei den DATA- und RESTORE-Anweisungen eine Marke verwendet.

'Eingabe einer Zahl und Ausgabe als roemische Zahl
'Hauptprogramm

DECLARE FUNCTION roemische_zahl$(z)

DO
  INPUT "Zahl: ";Z
  IF Z>0 THEN
    PRINT "Roemische Zahl: ";roemische_zahl$(Z)
  ELSEIF Z=0 THEN
    PRINT "Ende"
    EXIT
  ELSE
    PRINT "Keine negative Zahl!"
  ENDIF
LOOP
END

'Zuordnung Dezimalzahl zu roemischer Zahl
roem_map:
  DATA 1000,"M",900,"CM",500,"D",400,"CD"
  DATA 100,"C",90,"XC",50,"L",40,"XL"
  DATA 10,"X",9,"IX",5,"V",4,"IV",1,"I"

'Implementierung der benutzerdefinierten Funktion
FUNCTION roemische_zahl$(z)
  LOCAL n,t$,rv$
  rv$=""
  RESTORE roem_map
  WHILE z>0
    READ n,t$
    WHILE z>=n
      z=z-n
      rv$=rv$+t$
    WEND
  WEND
  roemische_zahl$=rv$:'Rueckgabewert zuweisen
END FUNCTION