Figure 3-13 shows the internal representation of variable entry data.
Figure 3-13 Variable Entry Data Representation
A PL/I file, or file constant, is represented by a file control block. A file control block is an internal data structure maintained by PL/I.
No conversions are defined between file data and other data types. You can assign a file variable only the value of a file constant or the value of another file variable. The only operations that are valid for file data are comparisons for equality (=) and inequality (^=).
This section discusses the following:
You declare file constants by using the FILE attribute without the VARIABLE attribute. All file constants are external by default. To define an internal file constant, you must specify the INTERNAL attribute. For example:
DECLARE INFILE FILE;
This declaration declares a file constant named INFILE whose attributes include EXTERNAL by default.
DECLARE INFILE FILE INTERNAL;
This declaration specifies that the file constant named INFILE is internal to the block in which it is declared.
If you declare a file constant as EXTERNAL, you must use identical
attributes, including ENVIRONMENT attributes, in all blocks that
declare the constant. Otherwise, PL/I uses the last set of attributes
encountered during compilation and ignores the others.
3.9.2 File Values
Whenever a reference to a file constant is interpreted, the result is a file value. A file value is a pointer to the file control block for the file with which the constant is associated.
PL/I supports the passing of external files, but not internal
files, as file value parameters. To pass an internal file, use a file
3.9.3 File Variables
File variables are variables (including parameters) that take file values. If the VARIABLE attribute is specified with the FILE attribute in a DECLARE statement, the declared identifier is a file variable. You can assign to a file variable either another file variable or a file constant.
A file variable is represented internally as a longword that contains a pointer to a file control block. The value of the file variable, when evaluated, is the address of the file control block for the file with which the variable is currently associated.
The scope of a file variable name can be either internal or external. If neither the EXTERNAL nor the INTERNAL attribute is specified with the file variable, the default is external.
If you declare a file variable implicitly or explicitly as EXTERNAL, you must use identical attributes, including ENVIRONMENT attributes, in all blocks that declare the variable. Otherwise, PL/I uses the last set of attributes encountered during compilation and ignores the others.
You can use the file variable to represent different files during the execution of the PL/I program. For example:
DECLARE F FILE VARIABLE, (A,B) FILE; E = A; CALL READFILE(E);
The file constant A is assigned to the file variable E. The CALL statement results in the invocation of the entry point READFILE with file A as its parameter.
You can also declare arrays of file variables. The following example shows an array of external file variables:
DECLARE FILELIST(10) FILE VARIABLE, MYFILE FILE VARIABLE; MYFILE = FILELIST(3);
This assignment statement references the third element of the array
FILELIST. When the statement is executed, this array element must
contain a valid file value.
3.10 Area Data
An area is a region of storage in which based variables can be allocated and freed. You define an area by declaring a variable with the AREA attribute. An area variable can belong to any storage class. Areas provide the following programming capabilities:
All areas must be declared with the AREA attribute before they can be referenced in a BASED attribute or an ALLOCATE statement with the IN option. For example:
DECLARE MYAREA AREA; DECLARE PTR OFFSET(MYAREA); DECLARE MYDATA FIXED BIN(31) BASED(PTR);
The variable MYAREA is given the AREA attribute. Then it is used as the target in another declaration, which defines a pointer offset based on MYAREA. To allocate storage for MYDATA in area MYAREA, use the IN option of the ALLOCATE statement as follows:
ALLOCATE MYDATA IN(MYAREA) SET (PTR);
When these statements are executed, the ALLOCATE statement allocates storage for a variable MYDATA in the area MYAREA and sets PTR to the offset in the area of the allocated storage.
This section discusses the following:
Expressions containing area variables are restricted to the relational operators equal (=) and not equal (^=) and to comparison to the empty () built-in function (BIF).
For example, to test whether an area is empty, that is, to determine whether it currently has storage allocated in it, you can write the following statement:
IF MYAREA = EMPTY() THEN DO;
The EMPTY() built-in function always returns an empty area value.
You can use area variables in simple assignment statements that assign one area variable to another. For example:
AREA_1 = AREA_2; AREA_2 = EMPTY();
An area can be the source or target of data transmission in READ and
WRITE record I/O statements. If the area is written by itself (not as a
member of a structure), only the current allocated portion is
transmitted unless the SCALARVARYING option of the ENVIRONMENT
attribute was specified when the file was opened.
3.10.3 Internal Representation of Area Data
An area occupies the number of bytes, specified in the extent, of
storage. Since this storage includes overhead used by PL/I for
bookkeeping, slightly less than the full amount (specified in the
extent) is available for program allocations.
3.11 Condition Data
PL/I provides a CONDITION attribute for declaring programmer-defined conditions. These conditions may only be signaled by the SIGNAL statement.
Condition data occupies a longword (32 bits) of storage.
No conversions are defined between condition data and other data types. The only operations that are valid for condition data are comparisons for equality (=) and inequality (^=).
Unlike some other noncomputational data type (such as ENTRY and FILE), the CONDITION data type may only be used as a constant. You cannot declare condition variables. For example, the following results in a compile-time error:
DECLARE (C1, C2, C3) CONDITION; DECLARE C CONDITION VARIABLE;
The compiler will reject the declaration of C in the previous example.
An aggregate is a data structure, either an array or structure composed of items as follows:
Arrays provide an orderly way to manipulate related variables of the
same data type. An array variable is defined in terms of the number of
elements that the array contains and the organization of those
elements. These attributes of an array are called its dimensions.
4.1.1 Array Declarations
To declare an array, specify its dimensions in a DECLARE statement using one of the following syntaxes:
DECLARE identifier [DIMENSION] (bound-pair,...) [attribute ...];
DECLARE (identifier [DIMENSION] (bound-pair,...)) [attribute ...];
To declare two or more array variables that have the same dimensions, bounds, and attributes, use the following syntax:
DECLARE (identifier, ...) [DIMENSION] (bound-pair,...) [attribute ...];
identifierA valid PL/I identifier to be used as the name of the array.
bound-pairA specification of the number of elements in each dimension of the array. A bound pair can consist of one of the following:
- Two expressions separated by a colon giving the lower and upper bounds for that dimension
- A single expression giving the upper bound only (the lower bound is then 1 by default)
- An asterisk (*), used in the declaration of array parameters, indicating that the parameter can be matched to array arguments with varying numbers of elements in that dimension
Bound pairs in series must be separated by commas, and the list of bound pairs must be enclosed in parentheses. The list of bound pairs must immediately follow the identifier or the optional keyword DIMENSION or the list of declarations. The following rules apply to specifying the dimensions of an array and the bounds of a dimension:
- An array can have up to eight dimensions.
- The values you can specify for bounds are restricted as follows:
- If the array has the STATIC attribute, you must specify all bounds as restricted integer expressions. A restricted integer expression is one that yields only integral results and has only integral operands, which can be evaluated at translation time. Such an expression can use only the addition (+), subtraction (-), and multiplication (*) operators.
- If the array has the AUTOMATIC, BASED, CONTROLLED, or DEFINED attribute, you can specify the bounds as optionally signed integer constants or as expressions that yield integer values at run time. If the array has AUTOMATIC or DEFINED, the expressions must not contain any variables or functions that are declared in the same block, except for parameters.
- The value of the lower bound you specify must be less than the value of the upper bound.
Table 4-1 shows several forms of bound pairs as used in declarations. Note that all the examples in Table 4-1 would be identical in effect if the optional keyword DIMENSION were added.
attributeOne or more data type attributes of the elements of the array. All attributes you specify apply to each of the elements in the array.
Elements of an array can have any data type. If the array has the FILE or ENTRY attribute, it must also have the VARIABLE attribute.
A single value specifies:
DECLARE VERBS (6) CHARACTER (12) ;
A single range of values specifies:
DECLARE TEMPERATURES (-60:120) ;
A list of values specifies:
DECLARE TABLE (10,10) FIXED BINARY ;
A list of ranges specifies:
DECLARE WINDOWS (1:10,-2:32) FIXED;
Asterisk extents specify:
ADDIT: PROCEDURE (ARR) ;
The declaration of an array specifies its dimensions, the bounds of each dimension, and the attributes of the elements.
One bound pair is specified for each dimension of the array to define the number of elements in that dimension. The total number of elements in the array, called its extent, is the product of the number of elements in all the dimensions of the array. If omitted, the lower bound is 1 by default.
You can use an asterisk (*) as the bound pair when you declare arrays as parameters of a procedure; the asterisk indicates that the parameter can accept array arguments with any number of elements. (If one dimension is specified with an asterisk, all must be specified with asterisks.) For example:
DECLARE SALARIES (100) FIXED DECIMAL (7,2);
The following statement declares a two-dimensional array of 64 integers:
DECLARE GAME_BOARD (8,8) FIXED BINARY (7);
The following statement declares a one-dimensional array of 12 character strings, each having a length of 2:
DECLARE PM_HOURS(13:24) CHARACTER(2);
The elements of the previous array is numbered 13 through 24 instead of 1 through 12.
You can replace the identifier in a statement with a list of declarations, which declares several arrays with the same attributes. For example:
DECLARE (SALARIES,PAYMENTS)(100) FIXED DECIMAL(7,2);
This statement declares SALARIES and another array, PAYMENTS, with the
same dimensions and other attributes.
4.1.2 References to Individual Elements
You refer to an individual element in the array with subscripts. Because an array's attributes are common to all of its elements, a subscripted reference has the same properties as a reference to a scalar variable with those attributes.
You must enclose subscripts in parentheses in a reference to an array element. For example, in a one-dimensional array named ARRAY declared with the bounds (1:10), the elements are numbered 1 through 10 and are referred to as ARRAY(1), ARRAY(2), ARRAY(3), and so on. The lower and upper bounds that you declare for a dimension determine the range of subscripts you can specify for that dimension.
The lower and upper bounds that you declare for a dimension determine the range of subscripts that you can specify for that dimension. The number of elements in any dimension of any array is:
(upper bound) - (lower bound) + 1
For multidimensional arrays, the subscript values represent an element's position with respect to each dimension in the array. Figure 4-1 shows subscripts for elements of one-, two-, and three-dimensional arrays. In subscripted references for multidimensional arrays, the number of subscripts must match the number of dimensions of the array and must be separated by commas.
Figure 4-1 Specifying Elements of an Array
You can specify the subscript of an array element using any variables or expressions having integer values, that is, values that can be expressed as fixed binary or fixed decimal with a zero scale factor. For example:
DECLARE DAYS_IN_MONTH(12) FIXED BINARY; DECLARE (COUNT, TOTAL) FIXED BINARY; TOTAL = 0; DO COUNT = 1 TO 12; TOTAL = TOTAL + DAYS_IN_MONTH(COUNT); END;
Here, the variable COUNT is used as a control variable in a DO loop. As
the value of COUNT is incremented from 1 to 12, the value of the
corresponding element of the array DAYS_IN_MONTH is added to the value
of the variable TOTAL.
4.1.3 Initializing Arrays
Specify the INITIAL attribute for an array to initialize its values in the declaration. For example:
DECLARE MONTHS (12) CHARACTER (9) VARYING INITIAL ('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December');
Each element of the array MONTHS is assigned a value according to the order of the character-string constants in the initial list: MONTH(1) is assigned the value 'January'; MONTH(2) is assigned the value 'February'; and so on.
If the array being initialized is multidimensional, the initial values are assigned in row-major order.
To assign identical initial values to some or all elements of an array, you can use an iteration factor with the INITIAL attribute. For example:
DECLARE TEST_AVGS (30,4) FIXED DECIMAL (5,2) STATIC INITIAL ((120) 50);
This statement declares the array TEST_AVGS with 120 elements, each of which is given an initial value of 50.
You can also use the asterisk (*) iteration factor to initialize all the elements of an array to the same value. For example:
DECLARE TEST_AVGS (30,4) FIXED DECIMAL (5,2) STATIC INITIAL ((*) 50);
This statement also declares the array TEST_AVGS with 120 elements, each of which is given an initial value of 50.
Although Kednos PL/I for OpenVMS VAX and Kednos PL/I for OpenVMS Alpha both support the initialization of automatic arrays with the INITIAL attribute, for the following reasons this is not always the most efficient way (in terms of program compilation and execution) to initialize array elements:
If the array is not modified by your program, you can increase program efficiency by declaring the array with the STATIC and READONLY attributes and using the INITIAL attribute to initialize its elements. In this case, the compiler checks that you have initialized all the elements and that they are valid.
When more than one successive element of an array is to be assigned the same value with the INITIAL attribute, you can specify an iteration factor. An iteration factor indicates the number of times that a specified value is to be used in the assignment of values to elements of an array. You can specify an iteration factor in one of the following formats:
iteration-factorAn unsigned decimal constant indicating the number of times the specified value is to be used in the assignment of an array element. The iteration factor can be zero.
arithmetic-constantAny arithmetic constant whose data type is valid for conversion to the data type of the array.
scalar-referenceA reference to any scalar variable or to the NULL built-in function.
scalar-expressionAny arithmetic or string expression or string constant. The expression or constant must be enclosed in parentheses.
*Symbol used to indicate that the corresponding array element is not to be assigned an initial value.
You can use any of these forms for arrays that have the AUTOMATIC attribute. For arrays with the STATIC attribute, you can use only constants and the NULL built-in function.
For example, the following declaration of the array SCORES initializes all elements of the array to 1:
DECLARE SCORES (100) FIXED STATIC INITIAL ((100)1);
The next declaration initializes the first 50 elements to 1 and the last 50 elements to -1:
DECLARE SCORES (100) FIXED STATIC INITIAL ((50)1,(50)-1);
The following declaration initializes the first 49 elements to 1; the next 2 elements are not initialized; and the next 49 elements are initialized to -1:
DECLARE SCORES (100) FIXED STATIC INITIAL ((49)1,(2)*,(49)-1);
The declaration in the next example initializes all 10 elements of an array of character strings to the 26-character value in apostrophes. The string constant is enclosed in parentheses; this is required to differentiate between iteration factors and replication factors.
DECLARE ALPHABETS (10) CHARACTER(26) STATIC INITIAL((10)('ABCDEFGHIJKLMNOPQRSTUVWXYZ'));