Status

The most current version of this document is available at http://www.flightlab.com/~joe/flightlab/firdef.html. A Postscript version is available at http://www.flightlab.com/~joe/flightlab/firdef.ps.

26 Jun 1998 The programs ffigen (see 3.2. ``FFIGEN'') and xfir (see 3.1. ``XFIR'') are available at ART in the IRIX 5 Flightlab working distribution (~wesley/bin); they are only available on herakles and the other IRIX 5 hosts. The sample Makefile in ~luther/misc/sample.Makefile has been updated with new rules to allow the integration of foreign functions into private versions of Scope.

Calling Foreign Functions from Scope

Joe English
Last updated: Wednesday 08 March 2000, 09:55



1 Overview

A foreign function is a function or procedure written in a language other than Scope. At present, only Fortran language functions are supported by this interface.

To add user-defined external functions to the Scope parser, follow these steps:

  1. Create one or more interface definition file; see 2. ``Interface definition format''. You may also use the xfir utility to extract the interface definition directly from structured comments embedded in Fortran code.
  2. Compile the interface definitions with the mkfir command. This generates a C language source file containing wrapper functions for each function.
  3. Recompile Scope with the new interface library.

Figure...

2 Interface definition format

In the interface definition file, comments are preceded by two slashes (//) and continue to the end of the line.

All keywords are case-insensitive.

It is possible to extract interface definition files from Fortran source code instead of writing them by hand; see 3.1. ``XFIR''.

External declarations specify the calling sequence of the Fortran subroutine and (optionally) the Scope language function interface.

External declarations have the following syntax:

extern extname ( extargs... )
    [ interface ]
    ;

extname is the external procedure name. External names contain only alphanumeric characters and underscores, and must start with a letter. As in Fortran, names are case-insensitive.

extargs is a list of all the procedure arguments, separated by commas. The type, size, and direction of each argument must be specified. The syntax of each argument declaration is:

    type argname [ ( dimensions ) ] direction

type must be INTEGER or REAL. INTEGER corresponds to the Fortran INTEGER type, and REAL corresponds to the Fortran DOUBLE PRECISION type. LOGICAL, CHARACTER, and COMPLEX types are not supported, nor are types with length specifiers (e.g., REAL*4, INTEGER*2).

dimensions is a comma-separated list of the array bounds. If omitted, the parameter is taken to be a scalar.

Each dimension may be specified as an integer constant, a variable name, or an expression built up from variables, constants, and + and * operators. The usual precedence rules for + and * apply.

Variable names used in dimension declarations need not be procedure parameters. If they are, they must be declared as INTEGER, scalar, and IN.

dimensions ::= dimension [ , dimension ... ]
dimension ::=
   argname
   | integer
   | dimension + dimension
   | dimension * dimension
   | ( dimension )

direction is one of the following:

IN
parameter is an input.
OUT
parameter is an output (return value).
IN OUT
parameter is both an input and an output.
SCRATCH
parameter is used as a ``work area'' or ``scratch space''. Scope automatically allocates and frees space for SCRATCH parameters.

The INTERFACE section, if present, specifies the Scope language calling sequence:

interface ::=
    INTERFACE [ outputs ] = name ( inputs )

If the function is a component method implementation, the INTERFACE section takes the following form instead:

interface ::=
    INTERFACE class-name :: method-name

The INTERFACE section may be omitted if the external function should not be callable directly from Scope.

Multiple INTERFACE specifications are allowed. (This is useful when several different components have identical method implementations.)

For example,

extern "fortran" crsprd(real x(3) in, real y(3) in, real z(3) out)
interface z = cross(x,y)
;

It is necessary to fully declare all dimensions of array parameters. The Fortran idiom of declaring only the leading dimension(s) and using 1 or * for the last dimension will not work, since the wrapper function checks the actual array bounds for all arguments in order to keep track of memory allocation.

NOTE --In Scope, the ``leading dimension'' of an array is always the same as its actual size.

NOTE --For Scope, arrays are limited to two dimensions.

3 Compilation process



3.1 XFIR



The xfir command extracts interface definitions directly from Fortran source code. The resulting interface definition file is then processed by ffigen.

Usage:

xfir [ options... ] filename.f... > outfile.fir

3.1.1 Directives

Special comments in the Fortran source code are used to supply the extra information needed. Any line beginning with C. (capital letter `C' followed by a period) is interpreted as an xfir directive. Most directives are used to specify the modes of the parameters (input, output, or in/out). The rest of the information needed -- the name, type, and dimensions of each argument and their order in the calling sequence -- is extracted directly from the source code.

Available directives are:

C.INPUT
Indicates that subsequent variable declarations are inputs. This directive should appear after the SUBROUTINE declaration and before any executable statements. There may be multiple C.INPUT lines in the declaration section.
C.OUTPUT
Indicates that subsequent variable declarations are outputs.
C.INOUT
Indicates that subsequent variable declarations are both inputs and outputs.
C.SCRATCH
Indicates that subsequent variable declarations are ``scratch'' or ``workspace'' variables. Space will be automatically allocated for them when the function is called. Note: scratch variables are implemented for function interfaces only, not for component method interfaces.
C.WORK
Synonym for C.SCRATCH.
C.LOCAL
Signals the beginning of local variable declarations.
C.INTERFACE interface...
Specifies the Scope language interface. The interface must appear on the same line.

3.1.2 Other formatting conventions

xfir supports !-style inline comments, and continuation lines are handled properly. All Fortran code is folded to upper-case before processing.

Do not include any text beyond column 72 in input files; the Fortran compiler ignores it but mkfir does not. Hard tab characters will also confuse mkfir.

Only one parameter may be declared per line. That is, declarations the following are not allowed:

C.INPUT
       DOUBLE PRECISION X(3), Y(3)	! Illegal!

3.2 FFIGEN

The ffigen program generate wrapper functions and/or .CDF files from interface definition files,

Usage:

ffigen -o filename.c filename.fir
ffigen -c filename.cdf filename.fir

3.3 Rebuilding Scope

... TBD

3.4 Using dynamically loaded libraries

... not yet implemented

4 A longer example


C  Example foreign function.
C
C
      SUBROUTINE MVMA(A,M,N, ALPHA, BETA, X, Y)
C
C.INTERFACE: y = mvma(a, alpha, beta, x, y)
C
C MVMA performs a weighted matrix-vector multiply and add,
C
C     Y <- alpha*A*X + beta*Y
C
C.INPUT
       INTEGER M                        ! rows of A, length of y
       INTEGER N                        ! cols of A, length of x
       DOUBLE PRECISION ALPHA           ! weighting factor for A*X
       DOUBLE PRECISION BETA            ! weighting factor for Y
       DOUBLE PRECISION A(M,N)          ! input matrix 
       DOUBLE PRECISION X(N)            ! input vector
C.INOUT
       DOUBLE PRECISION Y(M)            ! On output, y=y_old*beta+alpha*A*x
C.LOCAL
       INTEGER I,J
C
C Begin subroutine:
C
       DO I=1,N
         Y(I) = BETA * Y(I)
         DO J=1,N
           Y(I) = Y(I) + ALPHA * A(I,J) * X(J)
         END DO
       END DO
       RETURN
       END

Running this through xfir produces the following:

// Generated Wed 08 Mar 2000, 09:54 PST
// MVMA
// xmp2.f, line 7
extern "fortran" MVMA(
    real A(M,N) in,
    integer M in,
    integer N in,
    real ALPHA in,
    real BETA in,
    real X(N) in,
    real Y(M) in out)
interface y = mvma(a, alpha, beta, x, y)
;

5 Limitations

For the Scope interface, only DOUBLE PRECISION and INTEGER variables are supported. DOUBLE PRECISION variables may have no more than two dimensions.

INTEGER parameters must be scalar inputs. It is not necessary (or permitted) to specify an integer parameter in the Scope language calling sequence; they may only appear as the array bound in a subsequent variable declaration.

Variadic functions (those taking a variable number of inputs) are not supported. If a function is called with fewer outputs than it returns, later arguments are simply ignored. It is not possible for a function to perform a different computation based on the number of output arguments.

Functions may not return variable-length arrays. That is, the size of all output parameters must be determined by the sizes of the input parameters. This means that functions like FIND cannot be defined with this interface.

The Fortran COMPLEX and CHARACTER data types are not supported. DOUBLE PRECISION and INTEGER are the only valid data types.

If complex arguments are passed to the generated functions, the imaginary part is silently ignored.

1-dimensional arguments must be passed in as column vectors (N by 1, not 1 by N).

FFIGEN diagnostics are not very good at the moment. Unknown types and modes are typically reported as syntax errors, and other errors are often reported as assertion failures followed by a coredump.