DocumentationEndless PL/I for OpenVMSReference Manual  ·  ESS-PFVRM-001

Chapter 7

Procedures

A procedure is the basic executable program unit in PL/I. It consists of a sequence of statements, headed by a PROCEDURE statement and terminated by an END statement, that define an executable set of program instructions. There are three kinds of procedures:

  • A MAIN procedure is the procedure where program execution begins.

  • A subroutine procedure is invoked with a CALL statement and returns values to the invoking procedure by means of a parameter list.

  • A function procedure is invoked by a function reference and returns a scalar value to the invoking procedure. It can also return values through a parameter list.

Subroutines and function procedures can be passed data from the invoking procedure by means of an argument list.

This chapter discusses the following topics:

  • The PROCEDURE statement which defines the beginning of a procedure block

  • Built-in and user-written functions

  • The ENTRY statement and how to specify entry points

  • The CALL statement which transfers control to an entry point

  • Parameters and argument passing

  • Calling external and internal procedures

  • Terminating procedures

  • Passing Arguments to non-PL/I procedures

7.1. PROCEDURE Statement

The PROCEDURE statement defines the beginning of a procedure block and specifies the parameters, if any, of the procedure. If the procedure is invoked as a function, the PROCEDURE statement also specifies the data type attributes of the value that the function returns to its point of invocation. The PROCEDURE statement can denote the beginning of either an internal or an external subroutine or function.

The format of the PROCEDURE statement is as follows:

entry-name: { PROCEDURE } [ (parameter,...) ]
            { PROC      }
          [ OPTIONS (option,...)       ]
          [ RECURSIVE    ]
          [ NONRECURSIVE ]
          [ RETURNS (returns-descriptor) ];
entry-name

A 1- to 31-character identifier denoting the entry label of the procedure. The label cannot be subscripted. The PROCEDURE statement declares the entry name as an entry constant. The scope of the name is INTERNAL if the procedure is contained in any other block, and EXTERNAL if the procedure is not contained in any other block.

parameter,...

One or more parameters (separated by commas) that the procedure expects when it is activated. Each parameter specifies the name of a variable declared in the procedure headed by this PROCEDURE statement. The parameters must correspond, one-to-one, with arguments specified for the procedure when it is invoked with a CALL statement or in a function reference.

OPTIONS (option,...)

An option that specifies one or more options, separated by commas:

  • IDENT(string) An option specifying a character-string constant giving the module ident for the listing and the object files. Only the first 31 characters of the string are recognized.

    Each module should contain only one procedure with the IDENT option. Should there be more than one, the last specified indent will be the one used.

  • MAIN An option specifying that the named procedure is the initial procedure in a program. The identifier of the procedure is the primary entry point for the program. The MAIN option is not allowed on internal procedures, and only one procedure in a program can have the MAIN option.

    A program must have one procedure with OPTIONS(MAIN) in order for condition handling to work properly.

  • UNDERFLOW An option that requests that the run-time system signal underflow conditions when they occur. By default, the run-time system does not signal these conditions.

RECURSIVE or NONRECURSIVE

An option that indicates (for program documentation) that the procedure will or will not be invoked recursively. In standard PL/I, the RECURSIVE option must be specified for a procedure to be invoked recursively. However, any procedure can be invoked recursively, and the RECURSIVE and NONRECURSIVE options are ignored by the compiler.

RETURNS (returns-descriptor)

An option specifying that the procedure is invoked by a function reference, as well as specifying the attributes of the function value returned. One of the possible attributes is TYPE. The syntax of the TYPE attribute is:

[(TYPE (reference)];

RETURNS must be specified for functions. It is invalid for procedures that are invoked by CALL statements.

For valid return descriptors, see the RETURN statement section of Section 7.7, “Terminating Procedures”.

7.2. Functions and Function References

A function is a procedure that returns a value and that receives control when its name is referenced in an expression. There are two types of functions:

  • PL/I built-in functions

  • User-written functions

A user-written function must have the following elements:

  • The RETURNS option on the PROCEDURE statement

  • A value on the RETURN statement; the value must be of a data type that is valid for conversion to the one specified in the RETURNS option

For example:

ADDER: PROCEDURE (X,Y) RETURNS (FLOAT);
DECLARE (X,Y) FLOAT;
        RETURN (X+Y);
        END;

The function ADDER has two parameters, X and Y. They are floating-point binary variables declared within the function. When the function is invoked by a function reference, it must be passed two arguments to correspond to these parameters. It returns a floating-point binary value representing the sum of the arguments. The function ADDER can be referenced as follows:

TOTAL = ADDER(5,6);

The arguments in the reference to ADDER are converted to FLOAT.

If a function has no parameters, you must specify a null argument list; otherwise, the compiler treats the reference as a reference to an entry constant. Specify a null argument list as follows:

GETDATE = TIME_STAMP();

This assignment statement contains a reference to the function TIME_STAMP, which has no parameters.

This rule applies to PL/I built-in functions as well; however, if you declare a PL/I built-in function explicitly with the BUILTIN attribute, you need not specify the empty argument list. For example:

DECLARE P POINTER,
        NULL BUILTIN;
   ⋮
P = NULL;

This example assigns a null pointer value to P. Without the declaration of NULL as a built-in function, the assignment statement would have been as follows:

P = NULL();

7.3. ENTRY Statement

The ENTRY statement defines an alternate entry point to a procedure. Its format is as follows:

entry-name: ENTRY [ (parameter,...) ]
                 [ RECURSIVE    ]
                 [ NONRECURSIVE ]
                 [ RETURNS (returns-descriptor) ];
entry-name

A 1- to 31-character label for the entry point. Specifying the entry name declares the name as an entry constant. The scope of the name is external if the ENTRY statement is contained in an external procedure, and is internal if it is contained in an internal procedure.

parameter,...

One or more parameters that the procedure requires at this entry point. Each parameter specifies the name of a variable declared in the block to which this ENTRY statement belongs. The parameters must correspond, one to one, with arguments specified for the procedure when it is invoked via the ENTRY statement.

RECURSIVE or NONRECURSIVE

An option that indicates (for program documentation) that the procedure will or will not be invoked recursively. In standard PL/I, the RECURSIVE option must be specified for a procedure to be invoked recursively. However, any procedure can be invoked recursively, and the RECURSIVE and NONRECURSIVE options are ignored by the compiler.

RETURNS (returns-descriptor)

For an entry that is invoked as a function reference, an option giving the data type attributes of the function value returned.

One of the possible attributes is TYPE. The syntax of the TYPE attribute is:

[(TYPE (reference)];

For entry points that are invoked by function references, the RETURNS option is required; for procedures that are invoked by CALL statements, the RETURNS option is invalid.

Restrictions

An ENTRY statement is not allowed in a begin block, in an ON-unit, or in a DO group except for a simple DO.

You should avoid unnecessary use of ENTRY statements, because their effect is detrimental to the overall optimization of the program and they make debugging more complicated.

7.3.1. Specifying Entry Points

The entry points of a procedure are the points at which it can be invoked. The PROCEDURE statement specifies one entry point. You can specify additional entry points with ENTRY statements within the procedure block. ENTRY statements are allowed anywhere except as specified in the restrictions described in Section 7.3, “ENTRY Statement”.

The labels used on PROCEDURE and ENTRY statements declare those names as entry constants. The scope of the declarations is internal if the PROCEDURE and ENTRY statements appear in internal procedures, and external if they appear in external procedures.

You declare an entry name in the block containing the procedure to which the entry point belongs. For example:

P: PROCEDURE;
   DECLARE E: ENTRY;

Q: PROCEDURE;
   DECLARE E FIXED BINARY;
END Q;
END P;

The entry names E and Q are declared in procedure P. Within procedure Q, E is declared as a fixed-point binary variable. This does not conflict with the declaration of E as an entry in procedure P.

You can invoke an entry point by using the appropriate entry constant as the reference in a CALL statement or function reference. Invoking an entry point enters a procedure at the specified point and activates the procedure block that contains the entry point.

If the CALL statement or function reference invokes an entry point in an external procedure, the entry constant must be declared with the ENTRY attribute, as in Example 7.3, “Invoking an External Procedure”. The declaration of an external constant must also describe the parameters for that entry point, if any. For example:

DECLARE PITCH ENTRY (CHARACTER(*), FIXED BINARY(15));

The identifier PITCH is declared as an entry constant. When the procedure containing this declaration is linked to other procedures, one of the external procedures must define an entry point named PITCH, either as the label of a PROCEDURE statement or as the label of an ENTRY statement.

The data type attributes in parentheses (known as “parameter descriptors”) are the data types of the parameters that are defined elsewhere for the entry point PITCH. Arguments of these types must be supplied when PITCH is invoked.

If PITCH is to be used as a function, the DECLARE statement must also include a RETURNS attribute to describe the attributes of the returned value, as in the following example:

DECLARE PITCH ENTRY (CHARACTER(*), FIXED BINARY(15))
  RETURNS(FIXED);

Within the scope of this DECLARE statement, the entry constant PITCH must be used in a function reference. The function reference will invoke the external entry point, and a returned fixed-point binary value will become the value of the function reference.

7.3.2. Multiple Entry Points

A procedure can be entered at more than one point. However, only one entry point can be specified by a PROCEDURE statement; additional entry points are declared with ENTRY statements.

The rules governing the declaration of multiple entry points follow:

  • A particular parameter need not be specified in all of a procedure's entry points (including the point defined by the PROCEDURE statement). However, a reference to the parameter is valid only if the procedure was invoked through one of the entries specifying the parameter.

  • In a procedure that has multiple entry points, a RETURN statement must be compatible with the entry point by which the procedure was invoked. If the entry point does not have a RETURNS option, the RETURN statement must not specify a return value. (In addition, it must be invoked as a “subroutine”-that is, with the CALL statement.) If the entry point has a RETURNS option, the RETURN statement must specify a return value that is valid for conversion to the data type specified in the RETURNS option.

  • An ENTRY statement is not executable. If control reaches it sequentially, control immediately continues to the next statement.

The following example shows a procedure with two alternative entry points:

QUEUES: PROCEDURE(ELEMENT,QUEUE_HEAD);
   ⋮
ADD_ELEMENT: ENTRY(ELEMENT);
   ⋮
REMOVE_ELEMENT: ENTRY(ELEMENT);

This procedure can be entered by CALL statements that reference QUEUES, ADD_ELEMENT, or REMOVE_ELEMENT. If invoked at QUEUES, the procedure must be passed two parameters. If invoked at either of the alternative entries ADD_ELEMENT or REMOVE_ELEMENT, the procedure must be passed only one parameter.

When this procedure is entered at either alternative entry point, the entire block beginning at QUEUES is activated, but execution begins with the first executable statement following the entry point.

7.4. CALL Statement

The CALL statement transfers control to an entry point of a procedure and optionally passes arguments to the procedure. The format of the CALL statement is as follows:

CALL entry-name [(argument,...)];
entry-name

The name of an external or internal procedure that does not have the RETURNS attribute. The entry name can also be an entry variable or a reference to a function that returns an entry value.

[(argument,...)]

The argument list to be passed to the called procedure. If specified, the arguments must correspond to the parameters specified in the PROCEDURE or ENTRY statement that identifies the entry name of the called procedure.

You must enclose arguments in parentheses. Multiple arguments must be separated by commas.

You can use the CALL statement to call an internal or external procedure. The following example illustrates a main procedure, CALLER, and a call to an internal procedure, PUT_OUTPUT. PUT_OUTPUT has two parameters, INSTRING and OUTFILE, that correspond to the arguments LINE and DEVICE specified in the CALL statement.

CALLER: PROCEDURE OPTIONS(MAIN);
   ⋮
        CALL PUT_OUTPUT(LINE,DEVICE);
   ⋮
PUT_OUTPUT:PROCEDURE(INSTRING,OUTFILE);
   ⋮
END PUT_OUTPUT;
END CALLER;

7.5. Parameters and Arguments

A PL/I procedure can invoke other procedures, as well as pass values to and receive them from the invoked procedure. Values are passed to an invoked procedure by means of arguments written in the procedure invocation. Values are returned to the invoking procedure by means of parameters and also, in the case of functions, by specifying a value in the function's RETURN statement.

You can specify arguments for a subroutine (invoked by a CALL statement) or for a function (invoked by a function reference). Subroutines and functions return values by different means.

  • A subroutine can return values only through a list of parameters. A subroutine must not specify a return value in its RETURN statement, and the declaration of an external entry point must not include the RETURNS attribute if the entry point is to be invoked as a subroutine. Instead, you can return values by assigning them, within the invoked subroutine, to the variables listed as parameters.

  • A function can return values through its parameter list like a subroutine and, in addition, must return a single value that becomes the value of the function reference in the invoking procedure; this value is specified in the function's RETURN statement. The attributes of this returned value are specified within the invoking procedure, in the function's PROCEDURE or ENTRY statement, or in the declaration of the external entry constant or entry variable used to invoke the function.

Example 7.1, “Parameters and Arguments” illustrates the relationship between arguments (specified in a CALL statement) or function reference and parameters (specified in a PROCEDURE or ENTRY statement).

Example 7.1. Parameters and Arguments
CALLER:PROCEDURE;
  DECLARE COMPUTER EXTERNAL ENTRY  ❶
          (FIXED BINARY (7), CHARACTER (80) VARYING);
  CALL COMPUTER (5,'ABC'); ❷
END CALLER;
COMPUTER:PROCEDURE (X,Y); ❸
   DECLARE X FIXED BINARY (7); ❹
   DECLARE Y CHARACTER (80) VARYING;
END COMPUTER;

❶

The ENTRY attribute in a DECLARE statement provides a parameter descriptor for each parameter of the called procedure. A parameter descriptor is a set of data type attributes.

❷

In a CALL statement or a function reference, arguments appear in parentheses following the name of the procedure. Arguments can be variables, expressions, aggregates, or (as in this example) constants.

The data type of each argument is matched with the corresponding parameter descriptor in the declaration of the entry.

❸

The PROCEDURE statement for the called procedure specifies the parameters of the procedure. These parameters correspond, in the order specified, to the arguments specified in the CALL statement.

❹

Each parameter specified in the PROCEDURE statement must be declared within the procedure.

A parameter is a variable that occurs in the parameter list of a PROCEDURE or ENTRY statement. When the procedure is invoked, each argument variable in the list is associated with a parameter. Within the called procedure, any reference to the parameter is equivalent to a reference to the associated argument variable.

If the invoked procedure is external to the invoking procedure, the attributes of the parameters must be described in parameter descriptors, which are part of the declaration of the external procedure.

An argument variable associated with a parameter is passed in a dummy argument if the argument is specified as a constant. References to that parameter in the invoked procedure do not modify any storage in the invoking procedure. For example:

test: procedure options(main);

    declare a fixed bin(31);

    a = 100;
    call subroutine(a,100);
    put skip list (a,100);

end test;

subroutine: procedure(x,y);
    declare (x,y) fixed bin(31);

    x = 101;
    y = 101;

end subroutine;

The result of this example would be:

    101   100

7.5.1. Rules for Specifying Parameters

The general rules listed below for specifying parameters are followed by specific rules that pertain only to certain data types.

  • You must declare a parameter explicitly in a DECLARE statement (to give it a data type) within the invoked procedure. This declaration must not be part of a structure.

  • You cannot declare a parameter with any of these attributes:

    AUTOMATICEXTERNALREADONLY
    BASEDGLOBALDEFSTATIC
    CONTROLLEDGLOBALREF 
    DEFINEDINITIAL 
  • A maximum of 253 parameters can be specified for an entry point.

  • The parameters of an external entry must be explicitly specified by parameter descriptors in the declaration of the entry constant. The parameters of a procedure that is invoked through an entry variable must be specified by parameter descriptors in the ENTRY attribute of the variable's declaration. You cannot declare an internal entry (and its parameters) in the containing procedure.

  • Each parameter must have a corresponding argument at the time of the procedure's invocation. PL/I matches the data type of the parameter with the data type of the corresponding argument and creates a dummy argument if they do not match or if the parameter is a constant, expression, or is enclosed in parentheses.

Array Parameters

If the name of an array variable is passed as an argument, the corresponding parameter descriptor or parameter declaration must specify the same number of dimensions as the argument variable. You can declare the bounds of a dimension for an array parameter using asterisks (*) or optionally signed integer constants. If the bounds are specified with integer constants, they must match exactly the bounds of the corresponding argument. An asterisk indicates that the bounds of a dimension are not known. (If one dimension contains an asterisk, all the dimensions must contain asterisks.) For example:

DECLARE SUMUP ENTRY ((*) FIXED BINARY);

This declaration indicates that SUMUP's argument is a one-dimensional array of fixed-point binary integers that can have any number of elements. Any one-dimensional array of fixed-point binary integers can be passed to this procedure.

All the data type attributes of the array argument and parameter must match.

Arrays are always passed by reference. They cannot be passed by dummy argument.

Structure Parameters

If the name of a structure variable is passed as an argument, the corresponding parameter descriptor or declaration must be identical, in terms of structure levels, members' sizes, and members' data types. The level numbers do not have to be identical, but the levels must be logically equivalent. You can specify array bounds and string lengths with asterisks or with optionally signed integer constants. The following example shows the parameter descriptor for a structure variable:

DECLARE SEND_REC ENTRY (1,
                          2 FIXED BINARY(31),
                          2 CHARACTER(40) VARYING,
                          2 PICTURE '999V99');

The written argument in the invocation of the external procedure SEND_REC must have the same structure, and its members must have the same data types.

Structures are always passed by reference. They cannot be passed by dummy argument.

Character-String Parameters

If a character-string variable is passed as an argument, the corresponding parameter descriptor or parameter declaration can specify the length using an asterisk (*) or an optionally signed nonnegative integer constant. For example:

COPYSTRING: PROCEDURE (INSTRING,COUNT);
DECLARE INSTRING (CHARACTER(*));

The asterisk in the declaration of this parameter indicates that the string can have any length. The string is fixed length unless VARYING is also included in the declaration.

Entry, File, and Labels Parameters

An entry, file, or label can be passed as an argument. The actual parameter is a variable.

7.5.2. Argument Passing

This section describes how PL/I passes an argument to procedures written in PL/I.

Number of Arguments

The number of arguments in the argument list must equal the number of parameters of the invoked entry point. The compiler checks that the count matches as follows:

  • For an internal procedure, the compiler checks the number of arguments in the argument list against the number of parameters on the PROCEDURE or ENTRY statement for the internal procedure.

  • For an external procedure, the compiler checks that the number of parameter descriptors in the ENTRY declaration list matches the number of arguments in the procedure invocation.

You specify arguments for a subroutine or function by enclosing the arguments in parentheses following the procedure or entry-point name. For example, a procedure call can be written as follows:

CALL COMPUTER (A,B,C);

The variables A, B, and C in this example are arguments to be passed to the procedure COMPUTER. The procedure COMPUTER might have a parameter list like this:

COMPUTER: PROCEDURE (X, Y, Z);
DECLARE (X,Y,Z) FLOAT;

The parameters X, Y, and Z, specified in the PROCEDURE statement for the subroutine COMPUTER, are the parameters of the subroutine. PL/I establishes the equivalence of the arguments A, B, and C to the parameters X, Y, and Z.

Actual Arguments

When a PL/I procedure is invoked, each of its parameters is associated with a variable determined by the corresponding written argument of the procedure call. This variable is the actual argument for this procedure invocation. It can be one of the following:

  • A reference to the written argument

  • A dummy argument

The data type of the actual argument is the same as that of the corresponding parameter. When a written argument is a variable reference, PL/I matches the variable against the corresponding parameter's data type according to the rules given under the heading “Argument Matching,” below. If they match, the actual argument is the variable denoted by the written argument. That is, the parameter denotes the same storage as the written variable reference. If they do not match, the compiler creates a dummy argument and assigns to it the value of the written argument.

Dummy Arguments

A dummy argument is a unique temporary variable allocated by the compiler, which exists only for the duration of the procedure invocation.

When the written argument is a constant or an expression, the actual argument is always a dummy argument. The value of the written argument is assigned to the dummy argument following the rules of data type conversion before the call (this is described later). The data type of the written argument must be valid for assignment to the data type of the dummy argument.

Aggregate Arguments

An array, structure, or area argument must be a variable reference that matches the corresponding parameter. It cannot be a reference to an unconnected array. A dummy argument is never created for an array, structure, or area.

Argument Matching

A written argument that is a variable reference is passed by reference only if the argument and the corresponding parameter have identical data types:

  • For an internal procedure, the attributes of the argument must match those specified in the declaration of the parameter.

  • For an external procedure or a procedure invoked through an ENTRY variable, the attributes specified in the ENTRY attribute parameter descriptor must match those of the arguments.

When the compiler detects that a scalar variable argument does not match the data type of the corresponding parameter, it issues a warning message, creates a dummy argument, and associates the address of the dummy argument with the corresponding parameter. You can suppress the warning message and force the creation of a dummy argument if you enclose the argument in parentheses. For example, if a parameter requires a character varying string and an argument is a character nonvarying variable, you would enclose the variable in parentheses.

For string lengths and array bounds, an asterisk (*) in the parameter matches any expression. An integer constant matches only an integer constant with the same value.

Conversion of Arguments

When the data type of a written argument is suitable for conversion to the data type of the corresponding parameter descriptor, PL/I performs the conversion of the argument to a dummy argument using the rules described in Section 5.4.3.

7.6. Calling External and Internal Procedures

An external procedure is one whose text is not contained in any other block. The source text of an external procedure can be compiled separately from that of a calling procedure. The differences between internal and external procedures are as follows:

  • Before an external procedure can be invoked (except through an entry variable), its name must be declared within the procedure that invokes it. The DECLARE statement for the external entry name must also provide a list of parameter descriptors that give the data types of the parameters that the procedure requires, if any, as well as a RETURNS attribute for a function procedure.

    You cannot explicitly declare internal procedures. The procedure name is implicitly declared by its occurrence in the PROCEDURE or ENTRY statement.

  • External procedures can reference the same variable only if it is declared (implicitly or explicitly) with the EXTERNAL attribute in all of them.

    An internal procedure, on the other hand, can reference internal variables declared in any procedure in which it is contained.

  • Any procedure can call an external procedure.

    An internal procedure can be called only by the procedure that contains it or by other procedures at the same level of nesting within the containing procedure. The only exception is invocation through an entry variable.

Example 7.2, “Invoking an Internal Procedure” illustrates the use of an internal procedure:

Example 7.2. Invoking an Internal Procedure
MAINP: PROCEDURE OPTIONS (MAIN);
   COMPUTE: PROCEDURE;
      ADD_NUMBERS: PROCEDURE;

      END ADD_NUMBERS;
   END COMPUTE;
   PRINT_REPORT: PROCEDURE;
   END PRINT_REPORT;
END MAINP;

In Example 7.2, “Invoking an Internal Procedure”, the procedures COMPUTE and PRINT_REPORT are internal to the procedure MAINP, and the procedure ADD_NUMBERS is internal to the procedure COMPUTE. MAINP can invoke the procedures COMPUTE and PRINT_REPORT, but not ADD_NUMBERS. COMPUTE and PRINT_REPORT can invoke one another. ADD_NUMBERS can call COMPUTE and PRINT_REPORT.

Example 7.3, “Invoking an External Procedure” illustrates the use of an external procedure:

Example 7.3. Invoking an External Procedure
WINDUP: PROCEDURE;
DECLARE PITCH EXTERNAL ENTRY (CHARACTER(15) VARYING,
                              FIXED BINARY(7) );
CALL PITCH (PLAYER_NAME,NUMBER_OF_OUTS);

The procedure WINDUP declares the procedure PITCH with the EXTERNAL and ENTRY attributes. The text of PITCH is in another source program that is separately compiled. When the object module that contains WINDUP is linked, the linker must be able to locate the object module that contains PITCH. You can accomplish this by including both object modules on the linker command line, or by placing PITCH in an object module library and including the library on the linker command line.

When a CALL statement or function reference invokes an entry point in an external procedure, the entry constant must be declared with the ENTRY attribute, as in the example above. Such a declaration must also describe the parameters for that entry point, if any. For example:

DECLARE PITCH ENTRY (CHARACTER(*), FIXED BINARY(15));

The identifier PITCH is declared as an entry constant. When the procedure containing this declaration is linked to other procedures, one of them must define an entry point named PITCH as the label either of a PROCEDURE statement or an ENTRY statement. If the linker cannot locate an external entry point, it issues a warning message.

The parameter descriptors define the data types of the parameters for the entry point PITCH. Arguments of these types must be supplied when PITCH is invoked.

If PITCH is to invoke a function, the DECLARE statement must also include a RETURNS attribute describing the attributes of the returned value, as follows:

DECLARE PITCH ENTRY (CHARACTER(*), FIXED BINARY(15))
    RETURNS(FIXED);

Within the scope of this DECLARE statement, the entry constant PITCH must be used in a function reference. The function reference will invoke the external entry point, and a returned fixed-point binary value will become the value of the function reference.

A PL/I program can invoke an external procedure that is not written in PL/I. A common instance is the use of a system service by a PL/I program to obtain some system function not available directly through PL/I. Or, a PL/I program can invoke an external procedure written in another language that provides an application-specific function. Such instances are possible because of the OpenVMS Procedure Calling and Condition Handling Standard, which includes a set of conventions for passing arguments among procedures.

7.7. Terminating Procedures

The execution of subroutines and functions can be terminated with the following statements:

  • END statement

    If an END statement closes the procedure block of a subroutine before a RETURN or STOP statement is executed, the END statement has the same effect as RETURN. A function cannot be terminated without a RETURN statement. See Section 8.3, “END Statement” for more information about the END statement.

  • Nonlocal GOTO statement

    A GOTO statement that transfers control to a label that is outside the current block terminates a subroutine or a function. The label specified on the GOTO statement must be known within the block that contains the GOTO statement, and the block containing the specified label must be active when the GOTO is executed. See Section 8.6, “GOTO Statement” for more information about the GOTO statement.

  • STOP statement

    A STOP statement ends the entire program execution. It does not pass a return value. See Section 8.8, “STOP Statement” for more information about the STOP statement.

  • RETURN statement

    A RETURN statement provides a normal termination for a subroutine or function. For a function, a RETURN statement must specify a return value. The rest of this section describes the RETURN statement.

RETURN Statement

The RETURN statement terminates execution of the current procedure. The format of the RETURN statement is as follows:

RETURN [ (return-value) ];
return-value

The value to be returned to the invoking procedure. If the current procedure was invoked by a function reference, a return value must be specified. If the current procedure was invoked by a CALL statement, a return value is invalid.

A return value can be any scalar arithmetic, bit-string, or character-string expression; it can also be an entry, pointer, or label expression or other noncomputational expression. The return value must be valid for conversion to the data type specified in the RETURNS option of the function.

The action taken by the RETURN statement depends on the context of the procedure activation, as follows:

  • If the current procedure is the main or only active procedure, the RETURN statement terminates the program.

  • If the current procedure was activated by a CALL statement, the next executable statement in the calling procedure is executed.

  • If the current procedure was activated by a function reference, control returns to continue the evaluation of the statement that contained the function reference.

  • If the RETURN statement is executed in a begin block, control returns from the containing procedure to the calling procedure.

Restrictions

The RETURN statement must not be immediately contained in an ON-unit or in a begin block that is immediately contained in an ON-unit.

7.8. Passing Arguments to Non-PL/I Procedures

There are three ways that a PL/I procedure can pass an argument to a non-PL/I procedure:

  • By immediate value. The actual value of the argument is passed.

  • By reference. The address in storage of the argument is passed.

  • By descriptor. The address in storage of a data structure describing the argument is passed.

The following sections describe the requirements for each of these argument-passing mechanisms.

7.8.1. Passing Arguments by Immediate Value

To pass an argument by immediate value, use the VALUE attribute in a parameter description. The following declaration of the external entry VHF illustrates a declaration for an external routine that receives its parameter by immediate value.

DECLARE VHF ENTRY (FIXED BINARY(31) VALUE);

You can also define PL/I procedures that receive arguments by immediate value. To do this, you must specify the VALUE attribute in the declaration of the parameter. For example, the corresponding definition of the procedure VHF would be as follows:

VHF: PROCEDURE (LENGTH);
.
.
DECLARE LENGTH FIXED BINARY(31) VALUE;
.

Arguments that can be passed by immediate value are limited to the following data types:

  • FIXED BINARY(m), where m <= 31

  • FLOAT BINARY(n), where n <= 24

  • BIT(o) ALIGNED, where o <= 32

  • ENTRY

  • OFFSET

  • POINTER

PL/I supports the passing of external procedures, but not internal procedures, as value parameters. To pass an internal procedure, use an entry parameter.

When you specify the VALUE attribute in a parameter descriptor, you can specify the ANY attribute instead of declaring any data type attributes. For example, the declaration of SYS$SETEF can appear as follows:

DECLARE SYS$SETEF ENTRY (ANY VALUE);

At the time of the procedure's invocation, PL/I converts the written argument as needed to create a longword dummy argument.

You can use the VALUE built-in function to force an argument to be passed by immediate value to a non-PL/I procedure, regardless of the declaration of the formal parameter (see Section 11.4.97, “VALUE”).

7.8.2. Passing Arguments by Reference

By default, PL/I passes all arguments by reference except character strings and arrays with nonconstant extents. The parameter descriptor for an argument to be passed by reference need specify only the data type of the parameter.

On OpenVMS systems for example, the Read Event Flags (SYS$READEF) system service requires that its first argument be passed by immediate value and its second by reference. You could declare this procedure as follows:

DECLARE SYS$READEF ENTRY (FIXED BINARY(31) VALUE,
                          BIT (32) ALIGNED);

When the procedure is invoked, the second argument must be a variable declared as BIT(32) ALIGNED. PL/I passes the argument by reference.

An argument of any data type can be passed by reference. Bit-string variables, however, must have the ALIGNED attribute.

The data types in the parameter descriptors of all output arguments must match the data types of the written arguments. For convenience, you can specify ANY in the parameter descriptor. To describe an argument to be passed by reference, you can specify the ANY attribute without the VALUE attribute. When you specify ANY for an argument to be passed by reference, you cannot specify data type attributes. Note that if you specify the VALUE attribute in conjunction with the ANY attribute, PL/I passes the argument by immediate value.

The ANY attribute is especially useful when you must specify a data structure as an argument. You need not declare the structure within the parameter descriptor, only the ANY attribute.

When an argument is passed by reference, PL/I passes the address of the actual argument. This address can be interpreted as a pointer value; you can explicitly specify a pointer value as an argument for data to be passed by reference; for example:

DECLARE SYS$READEF (ANY VALUE, POINTER VALUE),
        FLAGS BIT(32) ALIGNED;

CALL SYS$READEF (4, ADDR(FLAGS));

At this procedure invocation, PL/I places the pointer value returned by the ADDR built-in function directly in the argument list.

7.8.3. Passing Arguments by Descriptor

A descriptor is a structure that describes the data type, extents, and address of a data item. When passing an argument by descriptor, PL/I creates the descriptor and places its address in the argument list for the called procedure.

PL/I passes arguments by descriptor when a parameter descriptor specifies the following:

  • A character string with an asterisk length or an array with asterisk extents

  • An unaligned bit string or an array or structure consisting entirely of unaligned bit strings

  • A structure containing any strings or arrays with asterisk extents

  • ANY without VALUE, and the corresponding written argument is specified with the DESCRIPTOR built-in function

For example, PL/I passes by descriptor the arguments associated with the following parameter descriptors:

DECLARE UNSTRING ENTRY (CHARACTER(*)),
        TESTBITS ENTRY (BIT(3)),
        MODEST ENTRY (1,
                        2 CHARACTER(*),
                        2,
                          3 BIT(3),
                          3 BIT(3));

When you declare a non-PL/I procedure that requires a character-string descriptor for an argument, specify the parameter descriptor as CHARACTER(*). For example, the Set Process Name (SYS$SETPRN) system service requires the address of a character-string descriptor as an argument. You can declare this service as follows:

DECLARE SYS$SETPRN ENTRY (CHARACTER(*));

When a parameter is declared as CHARACTER(*), its written argument can be one of the following:

  • A character-string constant or expression.

  • A fixed-length character-string variable.

  • A varying character-string variable or a variable declared as CHARACTER(*)VARYING.

For any of those arguments, PL/I constructs a character-string descriptor and passes its address.

To force an argument to be passed by descriptor, use the DESCRIPTOR built-in function. For example:

DECLARE P ENTRY (ANY);
DECLARE (X,Y) FIXED DECIMAL (7,2);

CALL P(DESCRIPTOR (X));
CALL P(Y);

Here, X is passed by descriptor as specified by the DESCRIPTOR built-in function. Y is passed by reference (see Section 11.4.28, “DESCRIPTOR”).