SUBROUTINE-ENDSUBROUTINE

Define an external subroutine

WSupported on Windows
USupported on Unix
VSupported on OpenVMS
NSupported in Synergy .NET
[access] [subroutine_mod ...] SUBROUTINE name[, option, ...]
    parameter_def
    .
    .
    .
[ENDSUBROUTINE|END]

access

(optional) One of the following access modifiers:

PUBLIC

Access is not restricted. This is the most accessible option.

PROTECTED

Access is limited to the containing class or types derived from the containing class.

PRIVATE

Access is limited to the containing type. This is the least accessible option. (default)

INTERNAL

Access is limited to the current assembly. (Synergy .NET only)

PROTECTED INTERNAL

Access is limited to the current assembly and types derived from the containing class. (Synergy .NET only)

subroutine_mod

(optional) One or more of the following modifiers (Synergy .NET only):

STATIC

Accessed without a reference object. The method can be executed even if the class that contains the method hasn’t been instantiated.

VARARGS

More than the declared number of arguments can be passed to this routine.

name

The name of the external subroutine to define.

option

(optional) One or more of the following modifiers:

LOCAL | LOCALDATA

Keep record contents constant for as long as the routine is activated at one or more levels.

STACK | STACKDATA

Make record contents unique for every activation of the routine.

STATIC | STATICDATA

Keep record contents constant throughout every activation of the subroutine.

REENTRANT

Allow multiple active instances of the subroutine.

RESIDENT

Keep the routine in memory, even when not in use. (Windows, Unix only)

ROUND

Use rounding rules for implied-decimal data types within the subroutine.

TRUNCATE

Use truncation rules for implied-decimal data types within the subroutine. (traditional Synergy only)

VARARGS

More than the declared number of arguments can be passed to this routine.

parameter_def

Subroutine parameter definition. See Defining a parameter.

Discussion

The SUBROUTINE statement identifies the beginning of an external subroutine.

Subroutine names of longer than 30 characters are truncated when the routine is linked (although you can specify up to 255 characters as long as the first 30 characters are unique).

The compiler performs a page feed when the SUBROUTINE statement is encountered.

The LOCAL, STACK, and STATIC modifiers specify the default state of an unqualified RECORD statement. For example, given the following statement:

subroutine fred, STACK

all unqualified RECORD statements in function fred are treated as if they are STACK RECORD statements. LOCAL, STACK, and STATIC are mutually exclusive. If you don’t specify one, the default is LOCAL in traditional Synergy (unless the REENTRANT option is specified) and STACK in Synergy .NET. If ­REENTRANT is specified, unqualified RECORD statements default to STACK data, rather than LOCAL data, for each instance of the function. For example, given the following statement:

subroutine fred, REENTRANT

all of the unqualified RECORD statements in subroutine fred are treated as if they are STACK RECORD statements.

For information about the precedence of storage qualifiers (LOCAL, STACK, STATIC, and REENTRANT) in the SUBROUTINE statement with those specified in the RECORD statement or on the compiler command line (-qlocal, -qstack, and -qstatic), see the Discussion for RECORD-ENDRECORD.

In Synergy .NET, all routine stack data is refreshed on entry, as if REENTRANT were specified.

Note

The REENTRANT modifier causes all local records to be stack records unless otherwise qualified. Fields in stack records do not allow default or explicit initial values.

By default, an external subroutine cannot call itself; if it does, the runtime generates a “Recursive XCALL” error ($ERR_RECEXTCAL). However, specifying the REENTRANT modifier on the SUBROUTINE statement enables you to call an external subroutine recursively. (In other words, the subroutine can call itself.)

Note

Object handles are not allowed in local records in REENTRANT routines.

On Windows and Unix, by default, a subroutine may be removed from memory when it is no longer in the calling chain. If you specify the RESIDENT modifier, the routine stays in memory.

VARARGS is optional for unprototyped subroutines and functions, but if you want to pass more arguments than declared, it is required when using -qnet or strong prototypes (or internal routine prototyping unless -qrelaxed:param is set).

A program by default rounds all expression results. You can change the default to truncate in traditional Synergy by setting system option #11. However, specifying the ROUND or TRUNCATE modifier on a SUBROUTINE statement overrides the default rounding behavior for that routine (including if system option #11 is set). You cannot specify both TRUNCATE and ROUND in the same statement. (Neither TRUNCATE nor system option #11 are supported in Synergy .NET.)

A subroutine can be declared either inside or outside of a namespace or class. A subroutine declared outside of a class is considered to be a global subroutine. In Synergy .NET, when the compiler generates the .exe or .dll file, it puts any global subroutines in a new global class called _CL. If a subroutine is also declared outside of a namespace, it is placed in _NS_assemblyname._CL.

Understanding Routines