The XFUN statement (EXTERNAL_FUNCTION)
The XFUN statement below
declares WAZU to be a function with a COMPLEX result whose first argument is COMPLEX, and whose second argument is REAL. Knowing this, the compiler can perform any necessary type conversions wherever this function is called.
In FALCON, as in FORTRAN, it is not necessary to include declarations of the subprograms called by a program in that program; if something appears in an expression with parentheses behind it that isn't an array, it must be a function call, and the loader is left to find the function. But this limits function and subroutine calls to the constructs that were available in FORTRAN, and requires that each argument be of the correct type. Thus, the XFUN, XSUB, and XOPR statements allow one to provide information about externally-compiled functions, subroutines, and operators to the compiler, so that all the features and all the convenience of subprograms compiled in association with the program can be available.
Note also that, in general, a main program and subroutines supplied to the compiler in a single input file are still treated as separately compiled, so these statements are generally needed whenever advanced subprogram capabilities are used.
The argument types may be separated by commas, colons, or semicolons as the arguments to which they correspond are to be separated. Where arguments are omitted in a function (or subroutine) call, the latter arguments at any level are usually assumed to be omitted. This can be overriden by enclosing the earlier arguments with argument brackets (square brackets, [ and ], or their substitutes ?( and ?)`), with the opening bracket preceded by a period, indicating that they should be considered the first to be omitted.
Where the period does not precede the opening bracket of a pair of argument brackets, they are taken as having their usual function of changing the meaning of any separators found within them (and not within additional parentheses). With the period, this function is not performed, and separators retain their original meanings.
For example, the XFUN statement
will, in ZOTL(A), cause A to be converted to COMPLEX, and in ZOTL(A,B) cause A to be converted to INTEGER, and B to COMPLEX, since the left-first rule applies within square brackets prefixed by a period unless again overriden with another set of brackets prefixed by a period.
Note that this needs to be specified in an XFUN statement only if the arguments differ in type, but it always needs to be specified within the function itself in its FUNCTION statement.
The type NONE (or MEMORY) can be used to specify that no type conversions are to be performed, and the function left to make the best of its arguments in whatever form they appear in memory. This is the type used for each argument of any function not declared in an XFUN statement. (In EASY mode, MUTABLE is used instead, and such problems do not arise.)
Enclosing an argument entry in square brackets preceded by a percent sign, and including a separator within the square brackets, indicates that the type specification is to be repeated indefinitely as needed. Thus, a function with 10 arguments, all REAL, and all separated by commas, can be declared by
although this does not specify the number of arguments, so that an attempt to call it with 11 arguments would not result in an error, at least at compile time.
The innermost parentheses surrounding types within the argument list are required for compatibility with statements which include argument names, since the syntax REAL:X within a header would conflict with the use of the colon (:) as an argument separator.
In addition to NONE, there are several other types that refer not to the type of an argument, but to how it is passed to a function or subroutine. Two of these are TEXT and EQUATE.
If the TEXT attribute is given to an argument, this means that it is a CHARACTER (or STRING, etc.) type argument. What is unusual is how its value is specified in the calling routine; the item entered for that parameter is accepted directly as a text string instead of being evaluated as an expression. Thus,
called by LMN(MERRY,25) is equivalent to LMN('MERRY',25) if LMN had not included a TEXT specification for the first argument. (In both cases, 'MERRY' will be truncated to 'MERR' before being assigned to W if the first argument of LMN is declared CHARACTER*4 in the FUNCTION statement within LMN itself. On the other hand, LMN(XY,23) would cause the caller to pad 'XY' with blanks; a declared external subprogram has all type conversions essential to correct interpretation of arguments performed by the caller, but mere truncation, if physically performed at all, takes place within the called routine as a result of assignments involving arguments.)
A TEXT type argument may not contain commas or other separators; however, if an argument has two types as the result of being duplicated in an ALIAS statement, the argument is then parsed according to its non-text type, and whatever is within the space it occupies is passed as text; thus, commas within array subscripts would be processed correctly.
The EQUATE attribute changes how arguments to a function are indicated. Again, entries in the function call are not treated as expressions; in this case, they are treated as the argument name, followed by an equals sign, and then an expression giving the argument value.
A declaration using this attribute might look like this:
XFUN(REAL) PYTO((EQUATE ((REAL)X,(INTEGER)J:'COUNT'),);N)
and could be called by PYTO(X=2.5,COUNT=7;35).
Also, the MATHEMATICAL attribute can be assigned to individual arguments of a function, indicating that they are not subject to change. (A whole function is declared MATHEMATICAL with the statement of that name.)
Note that the area indicated by an EQUATE attribute must be followed by a higher separator than that used for equate items (or by the end of the argument list), but it may be preceded with any separator.
A call to a function using EQUATE thus does not fully illustrate its true calling sequence, since it conceals the full list of possible arguments, and their order. Another attribute creates function calls which look like those generated with EQUATE; and that is the LIST_EQUATE attribute. This attribute causes a sequence of equates appearing in the argument list to be converted to a value of type LIST, to be passed as a single argument.
LIST_EQUATE attributes look like this:
showing that the first and only argument is to be a list of elements of type MUTABLE, they are to have names of up to 6 characters, and the separator between list elements will be a colon.
The syntax is closer to that of the TEXT attribute than that of the EQUATE attribute, since here the names used are not specified as they are entirely arbitrary.
VLIST_EQUATE attributes are declared with the same syntax as LIST_EQUATE attributes, and create an argument of type VLIST instead of LIST.
The VLIST_GEN attribute generates a VLIST referring to all variables and user-defined functions in the expression that is an argument. This is useful if an expression is duplicated by the ALIAS statement, and the two copies are declared TEXT and VLIST_GEN; then, the VLIST generated by the second copy can be used to evaluate the expression after modification using _EXEV.
An externally compiled subprogram is one compiled entirely separately from the program which calls it, in the sense that neither the caller nor the subprogram has any information about the other at the time of compilation. Such routines may, however, be part of the same source stream, allowing the compiler to create a single object module containing all required routines as output.
Since externally compiled subprograms exist in order to allow actual separate compilation, the operating system must provide some way of using object code from more than one file. This might be as simple as specifying file1+file2 as the file to run in a command, or it might involve running a linkage editor program. Converting an object file containing many subroutines into a library from which only those needed can be selected is also a useful process; all these actions depend on the operating system in use at one's installation.