2.6 UnterprogrammeEinem Programm eine übersichtliche Struktur zu geben ist eine wesentliche Voraussetzung, um verzwickte und schwer zu findende Fehler zu vermeiden.Unterprogramme (Sub-Routinen) sind in sich geschlossene Programmabschnitte, quasi Programme innerhalb eines Programms. Die Vorteile bei der Verwendung von Unterprogrammen sind:
R-BASIC unterstützt folgende Arten von Unterprogrammen:
|
NameDerSub [ < ParameterListe> ] |
|
<variable> = NameDerFunction ( [ <Paramterliste> ] ) |
^2.6.1 Konzept: Lokale VariablenEin Unterprogramm hat vollen Zugriff auf alle global definierten Variablen, Konstanten, Strukturen usw. und kann mit diesen arbeiten. Globale Variablen werden üblicherweise im DIM & DATA Fenster vereinbart. Wenn aber alle Unterprogramme ausschließlich mit globalen Variablen arbeiten, wird das schnell unübersichtlich und es kann zu einer unerwünschten gegenseitigen Beeinflussung der Programmteile führen. Deswegen kann man Variablen "lokal", das heißt nur für dieses eine Unterprogramm definieren. Dazu schreibt man die entsprechende DIM-Anweisung innerhalb des Unterprogramms. Diese Variablen sind dem Compiler nur innerhalb des Unterprogramms bekannt und können auch nur innerhalb dieses Unterprogramms benutzt werden.Stößt der Compiler innerhalb eines Unterprogramms auf eine Variable (z.B. A$), sucht er zuerst, ob diese lokal definiert ist. Ist das der Fall, wird die lokale Variable verwendet. Nur wenn sie nicht lokal definiert ist, wird die entsprechende global definierte Variable verwendet. Diese Technik nennt man Kapselung. Das hat drei sehr praktische Folgen:
Analog wird bei Labels und Konstanten (Anweisung CONST) verfahren. Nur Struktur-Definitionen (STRUCT-Anweisung) sind immer global.
2.6.2 Konzept: ParameterIn vielen Fällen muss man Werte an ein Unterprogramm übergeben, mit denen es dann arbeitet. Zum Beispiel benötigt ein Unterprogramm, das einen Namen in einer Liste suchen soll, den Namen, nach dem es suchen soll. Man könnte diesen Namen in eine globale Variablen schreiben und ihn so an das Unterprogramm übergeben. Das ist besonders für Anfänger leicht zu handhaben, letztlich jedoch ein schlechter und fehleranfälliger Programmierstil.Die bessere Lösung für dieses Problem ist, den Namen direkt an das Unterprogramm zu übergeben. Werte, die man einem Unterprogramm direkt übergeben kann, werden als "Parameter" bezeichnet. Ein einfaches Beispiel. Wir vereinbaren eine SUB, die einen Namen mehrfach ausgeben soll: |
SUB Namensschleife ( name$ as String, x as real)
DIM N
For N = 1 to X
Print name$
NEXT N
End SUB
|
| Name$ und X sind die Parameter. N ist eine lokale Variable. Die For-Schleife gibt den Namen so oft aus, wie X vorgibt. Diese Sub können wir nun beliebig oft aufrufen. |
DIM N, T$ T$ = "Willi" N = 7 Namensschleife "Paul", 5 ' 5x Paul Namensschleife T$, N+3 ' 10x Willi. N ist immer noch 7 |
|
N und T$ seien globale Variablen. Wie oben beschrieben unterscheidet der Compiler zwischen dem globalen N und dem lokalen N in der SUB Namensschleife. Wie Sie sehen ist es völlig egal ob Sie als Parameter einen festen Wert, eine Variable oder eine Berechnung übergeben. R-BASIC wertet den Ausdruck zur Laufzeit aus und kopiert den Wert dann in die Parameter des Unterprogramms (in unserem Fall name$ und X). Intern behandelt R-BASIC die Parameter wie lokale Variablen. Der einzige Unterschied ist, dass sie beim Aufruf des Unterprogramms mit den übergebenen Werten belegt werden. Alle anderen lokalen Variablen werden beim Aufruf des Unterprogramms gelöscht (d.h. mit Nullen belegt). Das hat wieder zwei sehr praktische Folgen:
|
SUB Namensschleife (name$ as String, x as real)
DIM N
name$ = "Der Name ist " + name$
For N = 1 to X
Print name$
NEXT N
End SUB
|
| und übergeben ihr dann die globale Variable T$ |
Namensschleife T$, N+3 |
so wird die globale Variabel T$ dadurch NICHT geändert.
^2.6.3 SUB, END SUBDie Anweisung SUB (für Subroutine = Unterprogramm) vereinbart ein Unterprogramm. Es können Parameter an das Unterprogramm übergeben werden und innerhalb des Unterprogramms können lokale Variablen, Konstanten und Labels definiert werden, die nur innerhalb des Unterprogramms gültig (dem Compiler bekannt) sind.Mit SUB vereinbarte Unterprogramme müssen mit END SUB (Ende der Subroutine, Leerzeichen nicht vergessen) abgeschlossen werden. Ein vorzeitiges Verlassen des Unterprogramms mit RETURN ist möglich. Vereinbarung:
<Parameterliste> Liste Parametern, Aufruf: Name <Parameter> Der Aufruf erfolgt über die Angabe des Namen des Unterprogramms, gefolgt von der Parameterliste. Eine Klammer um die Parameterliste ist zulässig, aber nicht erforderlich. Die einzelnen Parameter sind durch Komma zu trennen. Existiert keine Parameterliste, wird nur der Name angegeben. Beispiel 1: |
SUB Demo () Print "Ich bin ein Sub-Programm" END SUB |
| Aufruf: |
Print "Im Hauptprogramm" Demo Print "Zurück im Hauptprogramm" |
| Ausgabe: |
Im Hauptprogramm Ich bin ein Sub-Programm Zurück im Hauptprogramm |
|
Beispiel 2: |
SUB PrintTableLine (x as real) ' x ist der Parameter DIM y, z as real ' y und z sind lokale Variablen y = x * x + 2 * x - 12 z = 12 * sin(x) Print x, y, z END SUB |
| Aufruf: |
For N = 1 To 14 PrintTableLine (N) Next N |
| Ausgabe: |
1 -9 10.098 2 -4 10.912 3 3 1.6934 4 12 -9.0816 usw. |
|
Beispiel 3: |
SUB CheckValue (a, b as real) ' a, b: Parameter If a = b Then Return ' Rückkehr wenn gleich Print "Warnung! Werte sind nicht gleich!" END SUB |
| Aufruf: |
CheckValue X, 17' Warnt, wenn X nicht 17 ist |
^2.6.4 RETURNDie Anweisung RETURN beendet ein Unterprogramm und kehrt zu der Routine zurück, die das Unterprogramm aufgerufen hat. RETURN in einem Actionhandler beendet die Abarbeitung des Actionhandlers und R-BASIC kehrt in den Wartezustand zurück. RETURN kann an beliebiger Stelle im Programm stehen. Insbesondere ist es erlaubt RETURN innerhalb von Schleifen und Verzweigungen zu verwenden.
^2.6.5 FUNCTION - END FUNCTIONDie Anweisung FUNCTION (für Funktion = Formel, die einen Wert berechnet) vereinbart ein Unterprogramm, das einen Wert zurück liefert. Es können Parameter an die Function übergeben werden und innerhalb der Function können lokale Variablen, Konstanten und Labels definiert werden, die nur innerhalb des Unterprogramms gültig (dem Compiler bekannt) sind.Die Vereinbarung einer FUNCTION endet mit der Anweisung END FUNCTION (Ende der Funktion, Leerzeichen nicht vergessen). Um eine Function zu verlassen, muss die Anweisung |
RETURN <Rückgabewert> |
ausgeführt werden. Üblicher Weise steht diese Anweisung direkt vor der END FUNCTION Anweisung. Sie kann aber auch an beliebiger Stelle innerhalb der Function stehen. Der Rückgabewert muss dabei den in der Vereinbarung der Function angegebenen Typ haben.
Beispiel 1: Diese einfach Funktion berechnet die Anzahl der Pixel auf dem Bildschirm. MaxX und MaxY sind globale Variablen, die die maximale x- und y-Koordinate enthalten. Da die Koordinaten bei Null beginnen müssen wir jeweils 1 addieren. |
FUNCTION PixelsOnScreen () AS Real Return (MaxX+1) * (MaxY+1) END FUNCTION |
| Aufruf: |
DIM anz as Real anz = PixelsOnScreen() |
| oder |
Print PixelsOnScreen() |
|
Beispiel 2: Diese Funktion berechnet den Funktionswert einer linearen Funktion. |
FUNCTION LinFunc (x as real) AS Real ' x: Parameter DIM y as real ' y: lokale Variable y = 2 * x + 1 Return y END FUNCTION |
| Aufruf: |
For N = -2 To 2 Print N, LinFunc(N) Next N |
| Ausgabe: |
-2 -3 -1 -1 0 1 1 3 2 5 |
|
Beispiel 3: Komplexes Beispiel: Diese Funktion manipuliert eine String. |
FUNCTION StringFunc( A$ as String, b as Real) AS String
IF b = 0 THEN Return "" ' Leeren String
IF b > 0 THEN
ReturnLeft$(A$, b) ' die linken Buchstaben
ELSE
b = - b ' Aus Minus mach Plus
Return Right$(A$, b) ' die rechten Buchstaben
END IF
END FUNCTION
|
|
Aufruf: Beachten Sie, dass der Compiler den Parameter A$ von der im folgenden Beispiel vereinbarten Variablen A$ unterscheidet. |
DIM A$, B$
A$ = StringFunc("Hallo Welt", 3)
B$ = StringFunc("Hallo Welt", -3)
Print A$ + B$
|
| Ausgabe: |
Halelt |
|
Funktionen können nur einen einzigen Wert zurückgeben. Wenn Sie mehr als einen Wert zurückgeben wollen, sollten Anfänger auf globale Variablen zurückgreifen. Fortgeschrittene Programmierer sollten eine Struktur definieren, die alle gewünschten Werte enthält und diese zurückgeben. Beispiel: |
STRUCT Worker name$ As String(20) job$ AS String(20) tel AS DWORD END Struct Function InitWorker() as Worker DIM w as Worker w.name$ = "Pink Panther" w.job$ = "Spaßbolzen" w.tel = 47320800 Return w End Function |
^2.6.6 ActionhandlerACTION-Handler sind Unterprogramme, die von einem Objekt direkt aufgerufen werden. Ein R-BASIC Programm besteht eigentlich aus einer Sammlung von Actionhandlern, die zu gegebener Zeit aktiviert werden. Sie können selbst wieder andere Unterprogramme (Sub, Function) aufrufen.Innerhalb eines Actionhandlers können wie bei jedem anderen Unterprogramm lokale Variablen, Konstanten und Labels definiert werden, die nur innerhalb des Handlers gültig (dem Compiler bekannt) sind. Actionhandler müssen mit END ACTION (Ende der Aktion, Leerzeichen nicht vergessen) abgeschlossen werden. Ein vorzeitiges Verlassen des Handlers mit RETURN ist möglich. R-BASIC geht dann wieder in den Wartezustand über. Der Typ des Handlers beschreibt, von welchen Objekten der Handler aufgerufen werden kann. Alle Actionhandler haben den Parameter "sender" (enthält das Objekt, dass den Handler aktiviert hat) sowie weitere, vom Typ des Handlers abhängige Parameter. Bei der Vereinbarung eines Handlers werden die Parameter NICHT explizit angegeben. Tipp: Verwenden Sie den Menüpunkt "Extras"-"Code Bausteine"-"Action-Handler". Damit erhalten Sie neben dem Handler-Rumpf einen Kommentarblock mit allen Parametern des Handlers.
Beispiel |
ButtonAction DemoAction MsgBox "Button gedrückt" END ACTION |
Weitere Informationen zu Actionhandlern finden Sie im Objekt-Handbuch, Kapitel 1.5 (Vereinbarung von Action-Handlern) sowie bei der Beschreibung der einzelnen Objekte.
^2.6.7 Vorab-Vereinbarung mit DECLSie können Unterprogramme (SUB, FUNCTION) erst dann verwenden, wenn diese zuvor dem R-BASIC-Compiler mit Namen und Parametern bekannt sind.Damit Sie die Unterprogramme nicht in der Reihenfolge ihrer Verwendung im Quelltext anordnen müssen gibt es die DECL-Anweisung. Die DECL-Anweisung (Declare = mache bekannt) informiert den Compiler über Namen und Parameterliste von Unterprogrammen, die erst weiter hinten im Quelltext vereinbart werden. Damit kann man
Abarbeitung von UnterprogrammenDie folgenden technischen Details beschrieben, wie der Interpreter intern den Aufruf von Subs und Functions organisiert. Die Kenntnis dieser Details ist für die Verwendung von Unterprogrammen nicht unbedingt erforderlich.
AbwärtskompatibilitätGOSUBR-BASIC unterstützt auch die in vielen BASIC-Interpretern verwendete Kombination GOSUB-RETURN Das kann die Übertragung fremder BASIC-Programme vereinfachen.Die Anweisung GOSUB (Gehe zu Sub-Routine) setzt den Programmablauf an der angegebenen Stelle fort und kehrt nach Beendigung des Unterprogramms (Anweisung RETURN) wieder zurück. Diese einfache Form der Unterprogrammtechnik hat nicht die Vorteile einer SUB oder FUNCTION (Parameterübergabe, lokale Variablen und Labels) und sollte daher in eigenen Programmen nicht verwendet werden.
^ |