<< Inhaltsverzeichnis Suchen >>

FUNCTION

Anweisung

Syntax:

Syntax Funktions-Deklaration:

 

FUNCTION FN<VARNAME> ( [<VARIABLE> [,<VARIABLE>]...] )
              ... beliebige Anweisungen außer QUIT, MACRO, GOTO #,
                  FIELD, DIM, SHARED, REPEAT, NEXTFIELD, ENDPROG,

              RETURN <AUSDRUCK>
ENDFUNC

 

Syntax Funktions-Aufruf:

 

FN<VARNAME> ( [<AUSDRUCK> [,<AUSDRUCK>]...] )

Bedeutung:

Funktionen können an jeder beliebigen Stelle im Macro deklariert werden, aber nicht innerhalb von Blöcken IF ... THEN, WHILE ... DO, ON ERROR ... END, usw.).

Um diese Funktionen von externen C- oder Assemblerfunktionen unterscheiden zu können, muß der Funktionsname mit FN... beginnen. Als Folge davon dürfen keine Hilfsvariablen mehr verwendet werden, die mit FN... beginnen. Denn dies führt zu Syntaxfehlern bei der Compilierung.

Der Typ der Funktion (String, numerisch, integer) wird durch die Schreibweise definiert: Endet der Funktionsname mit '$', so definiert dies eine String-Funktion. '%' bedeutet integer, Buchstabe und Ziffer bedeuten numerisch (double). Es können beliebig viele Parameter angegeben werden. Der Typ der einzelnen Parameter ergibt sich wieder aus deren Schreibweise. Es sind auch Funktionen ohne Parameter zulässig.

Beispiel:

FUNCTION FN_DATUM_TIME$()
     RETURN DATEG$+" "+TIME$
ENDFUNC

 

Jede Funktions-Deklaration muß mit ENDFUNC abgeschlossen werden.

In der Funktions-Deklaration können alle Anweisungen und Funktionen verwendet werden mit Ausnahme von: QUIT, MACRO, GOTO #..., FIELD, DIM, SHARED, ENDPROG,  REPEAT, NEXTFIELD.

 

Funktionen liefern als Ergebnis immer einen Wert und können deshalb nicht auf der linken Seite einer Zuweisung vorkommen.

 

Mit der Anweisung RETURN <AUSDRUCK> wird der Ergebniswert festgelegt und die Funktion beendet.

<AUSDRUCK> muß vom selben Typ wie die Funktion sein. Lediglich numerisch und integer können gegenseitig vertauscht werden.

Die letzte Anweisung in der Funktions-Deklaration vor ENDFUNC muß die Anweisung RETURN <AUSDRUCK> sein.

Beispiel:

FUNCTION FNMAX%(I%,J)
     IF I%<J
     THEN RETURN  J
     ELSE RETURN   I%
     ENDIF
ENDFUNC

 

Dies ist nicht zulässig und führt zu einem Fehler. Der Macro-Compiler erkennt nicht, daß sowohl der THEN- als auch der ELSE-Zweig mit RETURN verlassen werden. Zulässig ist das vorhergehende Beispiel oder das Einfügen einer weiteren RETURN-Anweisung, die zwar nie ausgeführt wird, aber eine logisch konsistente Deklaration liefert:

 

FUNCTION FNMAX%(I%,J)
     IF I%<J
     THEN RETURN  J
     ELSE RETURN  I%
     ENDIF
     RETURN  0     /* Diese Anweisung wird nie ausgeführt, ist aber
                             /* aus syntaktischen Gründen hier notwendig.
ENDFUNC

 

Alle in einer Funktions-Deklaration verwendeten nicht-dimensionierten Hilfsvariablen sind lokal bezüglich der Funktions-Deklaration. D.h. außerhalb der Funktions-Deklaration existieren diese Variablen nicht. Diese Variablen werden auf dem Stack angelegt und bei jedem Aufruf der Funktion neu initialisiert.

 

 

Achtung: Auch lokale Variablen gleichen Namens, die im selben Macro wie die Funktions-Deklaration definiert wurden, unterscheiden sich von den Hilfsvariablen der Funktion.

 

 

Beispiel:

LOCAL I%
I% = 1
FUNCTION FNI%(J%)
     RETURN I% * J%        /*  Liefert als Ergebnis immer Null,
                                           /* da I%  nicht identisch ist mit der
                                           /* lokalen Variablen I% und I% beim
                                           /* Aufruf der Funktion mit 0
                                           /* initialisiert wird.
ENDFUNC

 

Dimensionierte Hilfsvariablen sind immer global bezüglich des Programms. Es gibt keine lokalen DIM-Variablen!

 

Sprungmarken sind in Funktions-Deklarationen zulässig, Sprünge aus der Funktions-Deklaration heraus aber nicht.

 

Beispiel:

N1: I% = 0
...
FUNCTION FNX(A,B)
              IF A < B
              THEN GOTO N1
              ENDIF
              ...
N1:        /* Dies ist zulässig. Der Sprung ist eindeutig definiert, auch
              /* wenn außerhalb der Funktions-Deklaration die Sprung-
              /* marke N1 noch einmal vorkommt.
              RETURN A
              ...
              GOTO N2            /* Nicht zulässig, da der Sprung aus der
                                            /* Deklaration heraus führt.
              ...
              RETURN 0
ENDFUNC
...
N2: ...

 

Funktions-Aufruf:

 

Funktionen können an jeder beliebigen Stelle in beliebiger Schachtelungstiefe aufgerufen werden. Als Parameter können beliebige Ausdrücke übergeben werden. Der Typ des Ausdrucks muß jeweils mit dem Typ des Parameters in der Funktions-Deklaration übereinstimmen. String-Parameter werden ‘by reference’ an die Funktion übergeben, numerische und integer Parameter ‘by value’. Dies hat zur Folge, daß bei einer Wertzuweisung an einen Stringparameter innerhalb der Funktions-Deklaration der Wert der aufgerufenen Variablen verändert wird. Numerische und integer Variable können dagegen durch Funktionsaufrufe nicht verändert werden.

 

 

Achtung: Werden alphanumerische Indexdatei-Variablen an eine Funktion als Parameter übergeben, so darf die Funktion die Länge dieser Variablen nicht verändern. Indexdatei-Variable haben im EBUS-Programm stets eine feste Länge. Wird die Länge in einer Funktion geändert, so kann dies nicht wie bei den anderen Befehlen und Funktionen vom EBUS-GENERATOR-C erkannt werden. Die Folge sind unvorhersehbare Programmfehler.

Beispiel:

FUNCTION FNTEST(A%,B,C$)
     A% = 1
     B = 2.3            /* Diese beiden Anweisungen haben keine Wirkung. Sie
                             /* ändern nur den auf dem Stack übergebenen Wert.
     C$ = "Hallo"
     RETURN 1
ENDFUNC

I% = 99
B = 0
C$ = "   XX"
X% = FNTEST(I%,B,C$)
/* C$ hat jetzt den Wert "Hallo".
/* I% ist immer noch 99 und B immer noch 0.

 

Für numerische Parameter können beim Funktionsaufruf auch integer-Werte­ und bei integer-Parametern numerische Werte übergeben werden. Der Macro-Compiler konvertiert die Parameter automatisch in das bei der Deklaration festgelegte Format. Da der Macro-Compiler des EBUS-GENERATOR-C ein 1-Pass-Compiler ist, können bei numerischen Parametern Probleme auftreten, wenn bei der Compilierung ein Aufruf der Funktion vor deren Deklaration compiliert wird. In diesem Fall versucht der Macro-Compiler, anhand der übergebenen Parameter den Typ der Parameter festzulegen. Bei numerischen Parameter kann dies zu nicht erwarteten Fehlermeldungen führen.

Beispiel:

Die Compilierung des Aufrufs der Funktion FNMAX(1,2) erfolgt vor der Compilierung der Funktions-Deklaration. Der Macro-Compiler geht davon aus, daß beide Parameter vom Typ integer sind. Lautet nun die später compilierte Funktions-Deklaration

 

FUNCTION FNMAX(A,B)
...
ENDFUNC

 

so führt dies zu einer Fehlermeldung, da die Parameter A und B numerisch (double) und nicht integer sind. Würde die Compilierung der Funktions-Deklaration vor der Compilierung des Aufrufs erfolgen, so wüßte der Macro-Compiler, daß die Parameter numerisch (double) und nicht integer sind, und würde bei der Generierung die Parameter 1 und 2 automatisch nach double konvertieren. Dies ist notwendig, da sonst der C-Compiler Typendeklarationsfehler meldet.

 

Um dieses Problem zu vermeiden gibt es 2 Möglichkeiten:

 

1.

Man wartet ab, ob der Macro-Compiler einen Fehler meldet. Falls nicht, so ist alles in Ordnung. Wird ein Fehler gemeldet, so könnte man den obigen Funktionsaufruf ändern in FNMAX(1.0,2.0). Der Macro-Compiler erkennt 1.0 und 2.0 als numerische (double) Parameter. Ein weiterer Aufruf der Form FNMAX(I%,J%) müßte dann aber umständlich geändert werden:

I = I%
J = J%
...FNMAX(I,J)

Alle derartigen Aufrufe zu ändern ist dann aber nicht sinvoll, wenn ein Parameter das Ergebnis einer anderen Funktion ist und die Funktionsaufrufe stark verschachtelt sind. Es müßten dann die verschachtelten Aufrufe in jeweils einzelne Anweisungen zerlegt werden, was mühsam und nicht sehr effizient ist. Deshalb empfiehlt sich die 2. Möglichkeit:

 

2.

Man sorgt dafür, daß die Deklaration vor dem Aufruf compiliert wird. Dazu muß man wissen, welche Macros wann compiliert werden. Dies ist nicht immer eindeutig vorhersebar. Deshalb genügt es zu wissen, daß die Init-Macros vor und nach Index-Open stets als erstes compiliert werden. Die sicherste Methode ist es also, alle Funktionen in den Init-Macros zu deklarieren.

 

Im Hauptprogramm deklarierte Funktionen gelten auch für alle Unterprogramme, sind also global für das gesamte Programm. Im Unterprogramm deklarierte Funktionen gelten nur für das einzelne Unterprogramm.

 

Um mehrfache Deklarationen und damit mehrfache Generierung der Funktionen zu vermeiden, empfiehlt es sich, stets alle in Unterprogrammen benötigten Funktionen im Hauptprogramm zu deklarieren.

Beispiel:

FUNCTION FNCAT$(H1$,H2$)
     RETURN H1$+H2$
ENDFUNC

 

FUNCTION FNMAX%(I%,J)
     IF I%<J THEN RETURN J ENDIF
     RETURN I%
ENDFUNC