Use the REFER option to create self-defining based structures. In a based structure, the value of one member is used to determine the size of the storage space allocated for another member of the same structure. You can use the REFER option in a DECLARE statement to specify array bounds, the length of a string, or the size of an area. The format of the REFER option is as follows:
refer-element REFER (refer-object-reference)
refer-elementAn expression that represents the value assigned to the refer object when the structure is allocated. The refer element must satisfy the following conditions:
- It must be an expression that produces a FIXED BINARY(31) value or a value that can be converted to FIXED BINARY (31).
- It cannot reference storage in the structure containing the refer element.
refer-object-referenceA reference to a scalar variable. The refer object reference must satisfy the following conditions:
- It cannot be a subscripted variable reference.
- It cannot be locator qualified.
- It must reference a refer object that is a previous member of the structure containing the REFER option.
The refer object is a scalar variable contained by the structure. The refer object must satisfy the following conditions:
An example of a structure declaration containing the REFER option is as follows:
DECLARE 1 STRUCTURE S BASED(P), 2 I FIXED BINARY(31), 2 A CHARACTER(20 REFER(I));
For the compiler to allocate storage for a based structure, the structure must have a known size. In the example, the initial length for A is taken from the refer element, 20. However, the REFER option permits the size of the structure to change at run time as the value of the refer object (I) changes. After allocation, the length of A is determined by I.
You can have multiple REFER options within a structure.
The following example and figures show storage mapping with the REFER option.
DECLARE 1 S BASED (POINTER), 2 I FIXED BINARY(15), 2 J FIXED BINARY(15), 2 A CHARACTER ((X*2+2) REFER(I)), 2 B(2) CHARACTER (Y REFER(J)); X = 5; Y = 10; ALLOCATE S; S.A = 'ABCDEFGHIJKL'; S.B(1) = '0123456789'; S.B(2) = 'NOW IS THE'; . . . END;
When this structure is allocated, the refer elements (X*2+2) and Y are evaluated and used to determine the length of the associated string. The evaluated refer element value (X*2+2) is assigned to the refer object I and Y is assigned to J. Thereafter, the sizes of strings A and B are determined by the value of the refer objects I and J.
Storage for the previous structure is shown in Figure 4-2.
Figure 4-2 Storage of Structure with REFER Option
If the refer object I is assigned the value 6 and the refer object J is assigned the value 4, the resulting storage is remapped as shown in Figure 4-3.
Figure 4-3 Remapped Storage of Structure with REFER Option
PL/I does not restrict the use of the REFER option within structure declarations: therefore, exercise caution in its use.
If you change a value that causes the size of one or more structure members to decrease, then some storage at the end of the allocated storage will become inaccessible for future reference.
If the scalar variable (the refer object) does not satisfy the following criteria, the results are undefined:
The following rules apply to structures containing the REFER option:
To refer to a structure in a program, you use the major structure name, minor structure names, and individual member names. Member names need not be unique even within the same structure. To refer to the name of a member or minor structure, you must ensure only that the reference uniquely identifies it. You can qualify the variable name by preceding it with the name or names of higher-level (lower-numbered) variables in the structure; names in this format, called a qualified reference, must be separated by periods (.).
The following sample structure definition shows the rules for identifying names of variables within structures:
DECLARE 1 STATE, 2 NAME CHARACTER (20), 2 POPULATION FIXED (10), 2 CAPITAL, 3 NAME CHARACTER (30), 3 POPULATION FIXED (10,0), 2 SYMBOLS, 3 FLOWER CHARACTER (20), 3 BIRD CHARACTER (20);
The rules for selecting and specifying variable names for structures are as follows:
If a name is ambiguous, the compiler cannot resolve the reference and issues a message. In the example, the names POPULATION and NAME are ambiguous.
You can specify the name of a major or minor structure in an assignment
statement only if the source expression and the target variable are
identical in size and structure, and all corresponding members have the
same data types.
4.3 Arrays of Structures
An array of structures is an array whose elements are structures. Each structure has identical logical levels, minor structure names, and member names and attributes. For example, a structure STATE can be declared an array:
DECLARE 1 STATE (50), 2 NAME CHARACTER (20) VARYING, 2 POPULATION FIXED (31), 2 CAPITAL, 3 NAME CHARACTER (30) VARYING, 3 POPULATION FIXED (31), 2 SYMBOLS, 3 FLOWER CHARACTER (20), 3 BIRD CHARACTER (20);
A member of a structure that is an array inherits the dimensions of the structure. For example, the member CAPITAL.NAME of the structure STATE inherits the dimension 50. You must use a subscript whenever you refer to the variable CAPITAL.NAME, as in the following example:
PUT LIST (CAPITAL.NAME(I)) ;
A subscript for a member of a structure that is an array element can appear following any name within a qualified reference. For example, all of these references are equivalent:
STATE(10).CAPITAL.NAME STATE.CAPITAL(10).NAME STATE.CAPITAL.NAME(10)
A structure that is defined with a dimension can have members that are arrays. For example:
DECLARE 1 STATE (50), 2 AVERAGE_TEMPS(12) FIXED DECIMAL (5,2), . . .
In this example, the elements of the array STATE are structures. At the second level of the hierarchy of each structure, AVERAGE_TEMPS is an array of 12 elements. Because AVERAGE_TEMPS inherits the dimension of STATE, any of AVERAGE_TEMPS's elements must be referred to by two subscripts:
These subscripts can appear following any name in the qualified reference. For example:
These references are equivalent.
Note the following rules for specifying subscripts for members of structures containing arrays:
A connected array is one whose elements occupy consecutive locations in storage. For example:
DECLARE NEWSPAPERS (10) CHARACTER (30);
In storage, the 10 elements of the array NEWSPAPERS occupy 10 consecutive 30-byte units. Thus, NEWSPAPERS is a connected array.
A connected array is valid as the target of an assignment statement, as long as the source expression is a similarly dimensioned array or a single scalar value. The top diagram in Figure 4-4 shows the storage of a connected array.
In an unconnected array, the elements do not occupy consecutive storage locations. The bottom diagram in Figure 4-4 shows the storage of an unconnected array. An unconnected array is not valid in an assignment statement or as the source or target of a record I/O statement. A structure with the dimension attribute always results in unconnected arrays. When a structure is dimensioned, each member of the structure inherits the dimensions of the structure and becomes, in effect, an array. For example:
DECLARE 1 STATE (50), 2 NAME CHARACTER (20) VARYING, 2 POPULATION FIXED (31);
In this example, the members NAME and POPULATION of the major structure STATE inherit the dimension 50 from the major structure. When PL/I allocates storage for a structure or a dimensioned structure, each member is allocated consecutive storage locations; thus, the elements of the arrays NAME and POPULATION are not connected.
Figure 4-4 Connected and Unconnected Arrays
Structures can be unaligned or naturally aligned. When a structure is unaligned, each of its members (except for unaligned bit string members) is aligned on a byte boundary. Unaligned bit-string members are bit aligned. In an array of unaligned structures (which contain members other than unaligned bit strings), each structure is aligned on a byte boundary. In an array of unaligned structures that contain only unaligned bit strings, the array elements are bit aligned.
When a structure is naturally aligned, each of its members is aligned as described in Table 4-2. In an array of naturally aligned structures, each structure is aligned on the boundary that is the maximum alignment of its members.
The alignment you select is determined by the compile-time /NOALIGN or /ALIGN switch. The /NOALIGN switch (the default) produces unaligned structures. The /ALIGN switch produces aligned structures as described in Table 4-2.
|FIXED BINARY(p)||p <= 7||byte|
|FIXED BINARY(p)||7 < p <= 15||word|
|FIXED BINARY(p)||p > 15||longword|
|FLOAT BINARY(p)||p <= 24||longword|
|FLOAT BINARY(p)||24 < p <= 53||quadword|
|FLOAT BINARY(p)||p > 53||octaword|
|FLOAT DECIMAL(p)||p <= 7||longword|
|FLOAT DECIMAL(p)||7 < p <= 15||quadword|
|FLOAT DECIMAL(p)||p > 15||octaword|
|CHAR ALIGNED BYTE||byte|
|STRUCTURE||maximum of members|
The storage class to which a variable belongs determines whether PL/I allocates its storage at compile time or dynamically at run time. This chapter describes the following classes of variables:
Section 5.7 describes the mechanisms for dynamically allocating storage. Section 5.9 describes how variables can share physical storage locations.
Both Kednos PL/I for OpenVMS VAX and Kednos PL/I for OpenVMS Alpha compilers place an upper limit of 536,870,911 ( 229-1 ) bytes as the maximum size of any data object. The OpenVMS operating system may impose stricter limits depending on the storage-class parameters of the operating system and the parameters associated with your user name. For detailed information on limits, consult the system manager of your operating system.
The default storage-class attribute for PL/I variables is AUTOMATIC. PL/I does not allocate storage for an automatic variable until the block that declares it is activated. When the block is deactivated the storage is released. For example:
CALC: BEGIN; DECLARE TEMP FIXED BINARY (31); . . . END;
Each time the block labeled CALC is activated, storage is allocated for the variable TEMP. When the END statement is executed, the block is deactivated, and all storage for TEMP and all other automatic variables is released. The value of TEMP becomes undefined.
The storage requirements of an automatic variable are evaluated each time the block is activated. Thus, you can specify the length of an automatic character-string variable as follows:
DECLARE STRING_LENGTH FIXED; . . . COPY: BEGIN; DECLARE TEXT CHARACTER(STRING_LENGTH);
When this begin block is activated, the length of TEXT is evaluated.
The variable is allocated storage depending on the value of
STRING_LENGTH, which must have a valid value.
5.2 Static Variables
A static variable is allocated storage when the program is activated, and it exists for the duration of the program. A variable has the static attribute if you declare it with any of the attributes STATIC, EXTERNAL, GLOBALDEF, or GLOBALREF. In declaring static arrays and strings, you must use restricted expressions. (Note that the EXTERNAL scope attribute implies static storage for variables.)
If a block that declares a static variable is entered more than once during the execution of the program, the value of the static variable remains valid. For example:
UNIQUE_ID: PROCEDURE RETURNS (FIXED BINARY(31)); DECLARE ID STATIC INTERNAL FIXED INITIAL (0); ID = ID + 1; /* Increment ID */ RETURN (ID); END;
The function UNIQUE_ID declares the variable ID with the STATIC attribute and specifies an initial value of 0 for it. The variable is initialized to this value when the program is activated. The storage for the variable is preserved, and the function returns a different integer value each time it is referenced.
A variable with the STATIC attribute can also have external scope; that
is, its definition and value can be accessed by
any other procedure that declares it with the STATIC and EXTERNAL
5.3 Internal Variables
An internal variable is known only within the block in which it is
defined and within all contained blocks. By default, PL/I gives all
variables the INTERNAL attribute with the exception of data with the
FILE and CONDITION attributes.
5.4 External Variables
An external variable provides a way for external procedures to share common data. All declarations that refer to an external variable must also declare it with the EXTERNAL attribute (or with an attribute that implies EXTERNAL) and with identical data type attributes. You can abbreviate the EXTERNAL keyword to EXT. The following example and Figure 5-1 shows how procedures can use external variables:
APPLIC: PROCEDURE OPTIONS (MAIN); DECLARE FLAGS BIT (64) ALIGNED EXTERNAL; . . . CALL READY; READY: PROCEDURE; DECLARE FLAGS BIT (64) ALIGNED EXTERNAL;
Figure 5-1 External Variables
The OpenVMS Linker allows more control over the definition and allocation of external variables than does PL/I. With the GLOBALDEF attribute, you can define the allocation and initialization of an external variable in a single module. Other PL/I modules can then declare the variable with the GLOBALREF attribute and with no INITIAL attribute.
Further control is provided by the VALUE attribute, which can be used in conjunction with GLOBALDEF and GLOBALREF. A variable declared in this way is a constant whose value is used immediately in instructions generated by the compiler.
The EXTERNAL attribute is implied by the FILE, GLOBALDEF, GLOBALREF, and CONDITION attributes, and also by declarations of entry constants (that is, declarations that contain the ENTRY attribute but not the VARIABLE attribute). For variables, the EXTERNAL attribute implies the STATIC attribute.
The following rules apply to the use of external names: