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:
The general rules listed below for specifying parameters are followed by specific rules that pertain only to certain data types.
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.
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.
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:
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.
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:
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.
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.
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.
A written argument that is a variable reference is passed by reference only if the argument and the corresponding parameter have identical data types:
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:
Example 7-2 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, 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 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
RETURN [ (return-value) ];
return-valueThe 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:
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:
The following sections describe the requirements for each of these
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:
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).