Chapter 3
Data Types
All programs process data items. Data items can be constants or variables. A constant data item has a value that does not change during program execution; a variable data item can represent different values.
A data item has an associated type that you can specify as an attribute or collection of attributes in a declaration. Unlike other languages that often have a distinction between data types and data attributes, a PL/I data type is entirely defined by the data attributes given to a data item identifier. The data type that you select determines the operations that you can perform on data items and how they are stored.
The rest of this chapter describes data types in more detail.
3.1. Summary of Data Types
PL/I supports the following computational data types:
Arithmetic data types define values that can be used in arithmetic computation. They are:
Fixed point (binary and decimal integers and fractions)
Floating point (binary and decimal)
Pictured (fixed point data stored in character form)
Character-string data consists of a sequence of ASCII characters.
Bit-string data consists of sequences of binary digits.
PL/I also supports the following noncomputational data types and attributes:
Pointers and offsets represent the location in memory of data, and are used to access data and areas in system-allocated buffers.
Label constants and variables provide a flexible means of control within a program.
Entry constants and variables are used to invoke procedures through specified entry points.
File constants and variables provide access to files.
Areas are regions of storage in which based variables can be allocated and freed. Offsets represent the location of a based variable in an area.
Programmer-defined conditions represent exceptional conditions for use with the ON statement (Section 8.10.1, “ON Statement”) and SIGNAL statement (Section 8.10.2, “SIGNAL Statement”).
You can place each of these data types in aggregate structures or arrays to form new data types. See Chapter 4, Aggregates for more information.
3.1.1. Declarations
All names referenced in a PL/I program must be declared explicitly, with the exception of entry-point names, statement labels, built-in functions, and the default file constants SYSIN and SYSPRINT. You declare a name and its data type attributes in a DECLARE statement. For example:
DECLARE AVERAGE FIXED DECIMAL; DECLARE NAME CHARACTER (20);
The keywords DECIMAL, FIXED, and CHARACTER describe characteristics, or attributes, of the variables AVERAGE and NAME.
3.1.2. Default Attributes
It is not always necessary to define all the characteristics, or attributes, of a variable; the PL/I compiler makes assumptions about attributes that are not explicitly defined. For example:
DECLARE NUMBER FIXED;
The default FIXED attribute implies the attributes BINARY(31,0). Thus, the variable NUMBER has the attributes FIXED BINARY(31,0).
Table 3.1, “Implied Attributes for Computational Data” shows the default attributes implied by each computational data attribute.
| Specified | Implied |
|---|---|
| FIXED | BINARY(31,0) |
| BINARY | FIXED(31,0) |
| FIXED BINARY | (31,0) |
| FLOAT | BINARY(24) |
| FLOAT BINARY | (24) |
| DECIMAL | FIXED(10,0) |
| FIXED DECIMAL | (10,0) |
| FIXED DECIMAL(p) | (p,0) |
| FLOAT DECIMAL | (7) |
| BIT [ALIGNED] | (1) |
| CHARACTER [VARYING] | (1) |
| PICTURE 'picture' |
3.1.2.1. Attributes of Constants
Constants have attributes implied by the characters used to specify them. The following list describes the expression of constants and their attributes:
A series of characters enclosed in apostrophes is assumed to be a string constant:
If the letter B, which can be lowercase, is appended after the closing apostrophe, the constant is a bit-string constant, for example, '00010101'B. If the integer 2, 3, or 4 is appended to the letter B, the constant is a bit-string constant with the base 4, 8, or 16, respectively. Each digit occupies 2, 3, or 4 bits. For example, '17777'B3 is an octal constant that is represented internally as a string of 15 bits.
If the constant does not have the letter B appended, it is a character-string constant even when it contains only the characters 0 and 1. (However, a character string of 0s and 1s can be converted by a simple assignment to a bit string.)
If the constant is an integer, it has the attributes FIXED DECIMAL(n,0), where n is the number of digits in the integer. For example, the constant 1777 is a constant of type FIXED DECIMAL(4,0).
Constants with an appended or embedded decimal point, but with no following exponent, are of type FIXED DECIMAL(p,q), where p is the total number of digits and q is the number of digits to the right of the decimal point.
Consider this example where a fixed-point decimal constant has the following appended characters:
E [ + ]
digit... [ - ]It is of type FLOAT DECIMAL(p), where p is the total number of digits in the fixed-point constant (that is, the total number to the left of the letter E).
Note that PL/I has no constants with the attributes FIXED BINARY, FLOAT BINARY, or PICTURE. However, this presents no problems in programming because you can assign constants of any computational type to variables of any computational type and they are converted automatically to the target type.
You usually give values to binary variables by assigning decimal constants to them. For example:
I = 1;This converts the decimal integer 1 and assigns the converted value to a fixed-point binary variable I. Consider the following example:
F = 1.333E-12;This converts the floating-point decimal constant 1.333E-12 and assigns the converted value to a floating-point binary variable F.
Picture variables are usually given values by assigning fixed-point decimal constants. For example:
PAY_PIC = 123.44;This assigns the fixed-point decimal value 123.44 to a picture variable PAY_PIC. The value of PAY_PIC is a pictured value, which is stored internally as a character string containing the characters 1, 2, 3, 4, and 4, along with any special formatting symbols defined for PAY_PIC.
3.1.2.2. Arithmetic Operands
The implied data types of constants are important primarily because of PL/I's rules for converting operands in an arithmetic operation. (Bit-string and character-string operations must have bit- and character-string operands, respectively.) All operations, including arithmetic operations, must be performed in a single data type, and automatic conversions are performed on arithmetic operands to make this possible. For example:
DECLARE X FLOAT DECIMAL (49); X = X + 1.3;
In this example, the fixed-point decimal constant 1.3 is converted to floating-point decimal before the addition is performed. The rules for operand conversion are discussed in detail in Section 6.4.2, “Derived Data Types for Arithmetic Operations”.
For information about arithmetic operators, operands, and data conversions, see Chapter 6, Expressions and Data Type Conversions.
3.1.3. Compatible Data Types
In PL/I, the notion of compatible data types is used in the rules for passing arguments by reference and for based, controlled, defined, or external variables. For two nonstructure variables to have compatible data types, the following attributes must agree. That is, if one variable has the attribute, the other variable must also have it after the application of default rules.
| ALIGNED | DIMENSION | OFFSET |
| AREA | ENTRY | picture |
| array bounds | FILE | PICTURE |
| BINARY | FIXED | POINTER |
| BIT | FLOAT | precision |
| CHARACTER | LABEL | PRECISION |
| DECIMAL | length | VARYING |
Two pictured variables must have identical pictures after the expansion of iteration factors.
In addition, the following values must be equal:
Precisions and scale factors for arithmetic data
String lengths and area sizes
Number of dimensions for arrays and bounds in each dimension
Two structure variables have compatible data types if they have the same number of immediate members, and if corresponding members have compatible data types.
In general, you can specify string lengths, area sizes, and array bounds with expressions or with asterisks. The values used to determine whether two variables have compatible data types are obtained as follows:
For static variables, the values must be constants.
For automatic and defined variables, the expressions are evaluated when the block containing such a variable's declaration is activated. The resulting values are used for all references to the variable within that block activation.
For parameters, the declaration specifies any extents either with constants or with asterisks. In the case of asterisks, the extent in a particular procedure invocation is determined by the extent of the argument passed to the parameter. The extent remains the same throughout the procedure invocation.
For based or controlled variables, extent expressions are evaluated each time the variable is referenced.
Consider the following example:
/* Example of extent determination */ DATAT: PROCEDURE (PTR1); DECLARE N FIXED, S CHARACTER(N) BASED(PTR1); DECLARE PTR1 POINTER; N = 10; CALL P(S); P: PROCEDURE(A); DECLARE A CHARACTER(*), B CHARACTER(N); N = 20; PUT LIST(LENGTH(A),LENGTH(B),LENGTH(S)); END P; END DATAT;
The PUT statement writes out:
10 10 20
The assignment to N inside the procedure P affects the extent of S, but not the extents of A or B, which were frozen when P was invoked.
3.2. Arithmetic Data
Arithmetic data types are used for variables on which arithmetic calculations are to be performed. The arithmetic data types supported by PL/I are as follows:
Fixed point-for binary and decimal data with a fixed number of fractional digits
Floating point-for calculations on very large or very small numbers with the decimal point (number of fractional digits) allowed to float
Pictured-for fixed point decimal data that is stored internally in character form with special formatting characters
When you declare an arithmetic variable, you do not always have to define all its characteristics, or attributes.
Table 3.1, “Implied Attributes for Computational Data” shows the implied attributes for computational data.
3.2.1. Precision and Scale of Arithmetic Data Types
The PRECISION attribute applies to decimal and binary data as follows:
The precision of a fixed-point data item is the total number of decimal or binary digits used to represent a value.
The precision of a floating-point data item is the number of decimal or binary digits in the mantissa of the floating-point representation.
The scale of fixed-point data is the number of digits to the right of the decimal or binary point. Floating-point variables do not have a scale factor. In this manual, the letter p is used to indicate precision, and the letter q is used to indicate the scale factor.
You can specify both precision and scale in a declaration. For example:
DECLARE x FIXED DECIMAL(10,3) INITIAL(1.234);
This example indicates that the value of x has 10 decimal digits and that 3 of those are fractional. When a value is assigned to the variable, its internal representation does not include the decimal point; the previous value for x is stored as 1234, and the decimal point is inserted when the number is output. The scale factor has the effect of multiplying the internal representation of the decimal number by a factor of 10-q (where q is the absolute value of the specified scale).
The ranges of values you can specify for the precision for each arithmetic data type, and the defaults applied if you do not specify a precision, are summarized as follows:
|
Data Type Attributes |
Precision |
Scale Factor | Default Precision |
|---|---|---|---|
| BINARY FIXED | 1 <= p <= 31 | p >= q >= -31 | 31 |
| BINARY FLOAT (OpenVMS VAX systems) | 1 <= p <= 113 | - | 24 |
| BINARY FLOAT (OpenVMS Alpha systems) | 1 <= p <= 53 | - | 24 |
| BINARY FLOAT (OpenVMS I64 systems) | 1 <= p <= 53 | - | 24 |
| BINARY FLOAT (OpenVMS x86-64 systems) | 1 <= p <= 53 | - | 24 |
| DECIMAL FIXED | 1 <= p <= 31 | p >= q >= 0 | 10 |
| DECIMAL FLOAT (OpenVMS VAX systems) | 1 <= p <= 34 | - | 7 |
| DECIMAL FLOAT (OpenVMS Alpha systems) | 1 <= p <= 15 | - | 7 |
| DECIMAL FLOAT (OpenVMS I64 systems) | 1 <= p <= 15 | - | 7 |
| DECIMAL FLOAT (OpenVMS x86-64 systems) | 1 <= p <= 15 | - | 7 |
If no scale factor is specified for fixed-point data, the default is 0.
For fixed-point binary data, the scale factor must be within the range -31 through 31 and less than or equal to the specified precision. Positive scale factors for fixed binary numbers function according to the same principles as those for fixed decimal. That is, a positive scale factor is similar to multiplying the internal representation binary number by a factor of 2-q.
A negative scale factor indicates that the number of fractional bits are shifted in the opposite direction. In effect, this is similar to multiplying the binary number by a factor of 2q, where q is the absolute value of the specified scale. For example:
DECLARE (A,B) FIXED BINARY(31,-3), (C,D) FIXED BINARY(31,3); A = 128; /* output = 128 */ B = 7; /* output = 0 */ C = 128; /* output = 128.0 */ D = 7; /* output = 7.0 */ PUT SKIP LIST (A,B,C,D); END;
Internally, binary numbers undergo an implicit conversion and are represented as powers of 2. For instance, in the previous example variable A is first divided by 23 because it is declared with a scale factor of -3. The stored number is 16. On output, the number 16 is multiplied by 23 and the number is again 128. However, when variable B is first divided by 23, the result is 0, which is the value of the stored number. Therefore, on output, 0 is multiplied by 23 and the output is 0.
Integer variables declared in the previous example with a positive scale factor are output as they were input, but they are followed on the right with a decimal point and a 0.
Even though arithmetic operands can be of different arithmetic types, all operations must be performed on objects of the same type. Consequently, the compiler can convert operands to a derived type, as previously shown. Therefore, when you declare a fixed binary number with a scale factor and assign it a decimal value, the results may not be as you expect because the binary scale factor left-shifts the specified number of bits to the right of the decimal point. During conversion to a decimal representation, the difference between the resulting binary number and its decimal representation is not the equivalent of dividing or multiplying the decimal number by 10. Instead, the binary number is first converted to its internal representation and then this representation is converted to its decimal representation.
When excess fractional digits are truncated, no condition is signaled. If there is any resulting loss of precision, it may be difficult to detect because truncated fractional digits do not signal a condition.
For example:
A: PROCEDURE OPTIONS (MAIN); DECLARE A FIXED BIN (31,3), B DECIMAL (10,5), C DECIMAL (10,5); A = .3; B = 34.8; C = MULTIPLY(A,B,10,5); PUT SKIP LIST (A,B,C); END;
Before the multiplication is performed, the variables are converted to fixed binary so that the operands share a common data type. However, after conversion, variable A is output as 0.2 rather than 0.3. The output from the previous example is:
0.2 34.80000 8.6875
If variable A was declared with the attributes FIXED DECIMAL (10,5), the output will be:
0.30000 34.80000 10.44000
3.2.2. Fixed-Point Binary Data
The attributes FIXED and BINARY are used to declare integer variables and fractional variables in which the number of fractional digits is fixed (that is, nonfloating-point numbers). The BINARY attribute is implied by FIXED.
For example, a fixed-point binary variable can be declared as:
DECLARE X FIXED BINARY(31,0);
The variable X is given the attributes FIXED, BINARY, and (31,0) in this declaration. The precision is 31. The scale factor is 0, so the number is an integer.
There is no representation in PL/I for a fixed-point binary constant. Instead, integer constants are represented as fixed decimal. However, fixed decimal integer constants (and variables) are converted to fixed binary when combined with fixed binary variables in expressions. For example:
I = I+3;In this example, if I is a fixed binary variable, the integer 3 is represented as fixed decimal; however, PL/I converts it to fixed binary when evaluating the expression.
Fixed binary variables have a maximum precision of 31, and therefore fixed binary integers can have values only in the range -2,147,483,648 through 2,147,483,647. An attempt to calculate a binary integer outside this range, in a context that requires an integer value, signals the FIXEDOVERFLOW condition.
The attributes FIXED BINARY are used to declare binary data in PL/I. The BINARY attribute is implied by FIXED. The format of a declaration of a single, fixed-point, binary variable is:
DECLAREidentifierFIXED [BINARY] [(precision[,scale-factor])];
There is no form for a fixed-point binary constant, although constants of other computational types are convertible to fixed-point binary. A fixed-point binary variable usually receives given values by being assigned to an expression of another computational type or another fixed-point binary variable.
3.2.2.1. Internal Representation of Fixed-Point Binary Data
Figure 3.1, “Internal Representation of Fixed-Point Binary Data” shows the internal representation of fixed-point binary data. Storage for fixed-point binary variables is always allocated in a byte, word, or longword. For any fixed-point binary value:
If p is in the range 1 through 7, a byte is allocated.
If p is in the range 8 through 15, a word is allocated.
If p is in the range 16 through 31, a longword is allocated.
The binary digits of the stored value go from right to left in order of increasing significance; for example, bit 6 of a FIXED BINARY (7) value is the most significant bit, and bit 0 is the least significant.
In all cases, the high-order bit (7, 15, or 31) represents the sign.
3.2.3. Fixed-Point Decimal Data
Fixed-point decimal data is used in calculations where exact decimal values must be maintained, for example, in financial applications. You can also use fixed-point decimal data with a scale factor of 0 whenever integer data is required.
The following sections describe fixed-point constants and variables and their use in expressions.
This discussion is divided into the following parts:
Constants
Variables
Use in expressions
Internal representation
3.2.3.1. Fixed-Point Decimal Constants
A fixed-point decimal constant can have between 1 and 31 of the decimal digits 0 through 9 with an optional decimal point or sign, or both. If there is no decimal point, PL/I assumes it to be immediately to the right of the rightmost digit. Some examples of fixed-point decimal constants are:
12 4.56 12345.54 -2 01.
The precision of a fixed-point decimal value is the total number of digits in the value. The scale factor is the number of digits to the right of the decimal point, if any. The scale factor cannot be greater than the precision.
3.2.3.2. Fixed-Point Decimal Variables
The attributes FIXED and DECIMAL are used to declare fixed-point decimal variables. The FIXED attribute is implied by DECIMAL.
If you do not specify the precision and the scale factor, the default values are 10 and 0, respectively.
The format of a declaration of a single fixed-point decimal variable is:
DECLAREidentifier[FIXED] DECIMAL [(p[,q])];
Some examples of fixed-point decimal declarations are:
DECLARE PERCENTAGE FIXED DECIMAL (5,2); DECLARE TONNAGE FIXED DECIMAL (9);
3.2.3.3. Use in Expressions
You cannot use fixed-point decimal data with a nonzero scale factor in calculations with binary integer variables. If you must use the two types of data together, use the DECIMAL built-in function to convert the binary value to a scaled decimal value before attempting an arithmetic operation. For example:
DECLARE I FIXED BINARY, SUM FIXED DECIMAL (10,2); SUM = SUM + DECIMAL (I);
3.2.3.4. Internal Representation of Fixed-Point Decimal Data
Fixed-point decimal data is stored in packed decimal format. Each digit is stored in a half-byte, as shown in Figure 3.2, “Fixed-Point Decimal Data Representation”. Bits 0 through 3 of the last half-byte contain a value indicating the sign. Normally, the hexadecimal value C indicates a positive value and the hexadecimal value D indicates a negative value.
3.2.4. Floating-Point Data
The floating-point data types provide a way to express very large and very small numbers such as in scientific calculations. All floating-point calculations are performed on values in one of the binary floating-point formats. In general, the precision of the result is determined by the maximum precision of any operands in the operation. The numerical result of an operation is rounded to the result precision.
The following sections describe floating-point constants and variables and their use in expressions.
This discussion of floating-point data is divided into the following parts:
Constants
Variables
Use in expressions
Floating-point data formats
Internal representation of floating-point data
3.2.4.1. Floating-Point Constants
A floating-point constant can have one or more of the decimal digits 0 through 9 (with an optional decimal point), followed by the letter E and from one to five decimal digits representing a power of 10. The floating-point value and the integer exponent can both be signed. The first portion of the value, to the left of the letter E, is called the mantissa. The value to the right of the letter E is called the exponent.
Some examples of floating-point constants are:
2E10 -3E8 32E-8 .45632E16
The decimal precision of each of these values is the number of digits in the mantissa.
If you write a constant without the E and the exponent, it is considered to be fixed-point decimal. However, you can use such constants anywhere in expressions involving floating-point data.
All floating-point constants are decimal.
3.2.4.2. Floating-Point Variables
The keyword FLOAT identifies a floating-point variable in a declaration.
A floating-point value can be either binary or decimal. Because the internal representation of floating-point variables is binary, it is recommended that you use FLOAT BINARY (which is the default) to declare variables, unless you need the properties of FLOAT DECIMAL. (The difference between FLOAT BINARY and FLOAT DECIMAL appears only when a conversion to another type, such as character, for doing I/O is necessary.) You should declare all floating-point variables using the same base.
To declare a single floating-point binary variable, specify a DECLARE statement as follows:
DECLAREidentifierFLOAT [BINARY] [(p)];
You can optionally specify the precision for a floating-point variable in the declaration. For example:
DECLARE X FLOAT BINARY(53);
The keyword FLOAT identifies a floating-point variable.
To declare a decimal floating-point variable, use the following format:
DECLAREidentifierFLOAT DECIMAL [(p)];
For example:
DECLARE X FLOAT DECIMAL (30);
3.2.4.3. Using Floating-Point Data in Expressions
You can use both integer and scaled decimal constants in floating-point expressions. An arithmetic constant is always converted to the appropriate internal representation for use in a floating-point operation. The target type for the conversion depends on the context. For example:
DECLARE X FLOAT BINARY (53); X = X + 1.3;
Here, the constant 1.3 is converted to floating point when the expression is evaluated.
Such a conversion is normally done during compilation, but in some cases the constant is maintained in decimal until run time.
3.2.4.4. Floating-Point Data Formats
Table 3.2, “Supported Floating-Point Formats” summarizes the floating-point formats supported by the different implementations of PL/I.
| Implementation | Supported Formats |
|---|---|
| OpenVMS VAX systems | F, D, G, and H |
| OpenVMS Alpha systems | F, S, D, G, and T |
| OpenVMS I64 systems | F, S, D, G, and T |
| OpenVMS x86-64 systems | F, S, D, G, and T |
The S and T formats conform to the IEEE standards of floating-point formats.
Table 3.3, “Ranges of Floating-Point Formats” summarizes the approximate ranges of the floating-point formats.
| Format | Range |
|---|---|
| F or S | 0.29 * 10-38 to 1.7 * 1038 |
| D | Same as F but with a more precise mantissa (see Table 3.4, “Ranges of Precision for Floating-Point Types”) |
| G or T | 0.56 * 10-308 to 0.9 * 10308 |
| H | 0.84 * 10-4932 to 0.59 * 104932 |
Table 3.4, “Ranges of Precision for Floating-Point Types” summarizes the ranges of precision (sign bits, exponent bits, and fractional bits of accuracy) for each type. Section 3.2.4.5, “OpenVMS VAX Internal Representation of Floating-Point Data” and Section 3.2.4.6, “OpenVMS Alpha Internal Representation of Floating-Point Data” describe the internal representation of floating-point data.
| Floating-Point Type[a] | Sign Bits | Exponent Bits | Fractional Bits |
|---|---|---|---|
| F or S (single precision) | 1 | 8 | 24 |
| D (double precision) | 1 | 8 | 53 |
| G or T (double precision) | 1 | 11 | 53 |
| H (quadruple precision) | 1 | 15 | 113 |
[a] You can perform G- and H-floating computations with software emulation on some older processors. In addition, floating-point hardware is optional on most MicroVAX systems. See the appropriate processor manual for more information. | |||
The PL/I compiler selects the appropriate floating-point type based on the precision you specify and on a compile-time qualifier on the PLI command. The types are selected as shown in Table 3.5, “Floating-Point Types Used by PL/I”, where p indicates precision.
| Precision (DECIMAL) | Precision (BINARY) | OpenVMS VAX | OpenVMS Alpha | OpenVMS I64 | OpenVMS x86-64 |
|---|---|---|---|---|---|
| 1 <= p <= 7 | 1 <= p <= 24 | F | F or S[a] | F or S[a] | F or S[a] |
| 8 <= p <= 15 | 25 <= p <= 53 | D or G[b] | D, G or T[c] | D, G or T[d] | D, G or T[d] |
| 16 <= p <= 34 | 54 <= p <= 113 | H | Warning[e] | Warning[e] | Warning[e] |
[a] If no qualifier is supplied, the default type is S [b] If no qualifier is supplied, the default type is D. If the /G_FLOAT qualifier is supplied, type G is used. [c] If no qualifier is supplied, the default type is D. If /FLOAT=G_FLOAT, type G is used. If /FLOAT=IEEE_FLOAT, type T is used. [d] If no qualifier is supplied, the default type is T [e] A precision of 53 is used for precisions greater than 53 | |||||
3.2.4.5. OpenVMS VAX Internal Representation of Floating-Point Data
In all VAX floating-point formats, the value 0 is indicated when the sign bit and all exponent bits are set to 0. In effect, this allows for the representation of a value with a 24-bit fraction and an 8-bit exponent in single precision, even though only 23 bits in the format are allocated for the fraction.
The double-precision and G-floating formats as used by PL/I have the same fractional precision; G-floating format allows an extra three bits for the exponent. The double-precision format has 56 bits available for the fraction, but only 53 bits are used by PL/I. If you specify a floating-point binary precision in the range 54 to 56, the numbers with this range of precision are represented by the H-floating format.
This small reduction in the precision of double-precision numbers is necessary to keep the compiler from selecting H-floating format on machines that lack the necessary hardware. The intent is to preserve the size of a structure containing double-precision data regardless of whether the G_FLOAT qualifier is used.
Figure 3.3, “VAX Internal Representation of Floating-Point Data” shows the internal structure of floating-point data for VAX systems. For a more detailed description of VAX floating-point formats, see the VAX Architecture Reference Manual.
3.2.4.6. OpenVMS Alpha Internal Representation of Floating-Point Data
This section describes the S and T floating-point formats supported by OpenVMS Alpha systems. OpenVMS Alpha also supports the F, D, and G floating-point formats described in Section 3.2.4.5, “OpenVMS VAX Internal Representation of Floating-Point Data”.
IEEE S_floating Format
The following PL/I types are represented using S_floating data, which occupies four contiguous bytes:
FLOAT BINARY (P) P ≤ 24 FLOAT DECIMAL (P) P ≤ 7
Bits are labeled from the right, 0 through 31, as shown in Figure 3.4, “IEEE S_floating Data Representation”.
The form of S_floating data is sign magnitude, with bit 31 the sign bit (0 for positive numbers, 1 for negative numbers), bits 30:23 an exponent, and bits 22:0 a normalized 24-bit fraction including the redundant most significant fraction bit not represented. The value of data is in the range 1.17549435E-38 (normalized) to 3.40282347E38. The precision is approximately one part in 2**23; that is, typically seven decimal digits.
When loaded into a 64-bit register, the S_floating value resides in bits 29-63.
IEEE T_floating Format
The following PL/I types are represented using T_floating data, which occupies eight contiguous bytes:
FLOAT BINARY (P) 24 < P ≤ 53 FLOAT DECIMAL (P) 7 < P ≤ 15
Bits are labeled from the right, 0 through 63, as shown in Figure 3.5, “IEEE T_floating Data Representation”.
The form of T_floating data is sign magnitude, with bit 63 the sign bit (0 for positive numbers, 1 for negative numbers), bits 62:52 an exponent, and bits 51:0 a normalized 53-bit fraction including the redundant most significant fraction bit not represented. The value of data is in the approximate range 2.225073859E-380 (normalized) to 1.797693135E308. The precision is approximately one part in 2**52; that is, typically fifteen decimal digits.
3.2.5. Pictured Data
Use pictured data when you want to manipulate a quantity arithmetically and accept or display its value using a special format.
A picture specification (or picture) describes both the numeric attributes of a pictured variable and its input/output (I/O) format. A simple picture might look like this in a DECLARE statement:
DECLARE CREDIT PICTURE '$99999V.99DB';
This statement declares the variable CREDIT as a pictured variable. The characters within the apostrophes describe its format.
The formatting possible with pictured data is useful in many applications, but pictured data is much less efficient than fixed-point decimal data for strictly computational use.
This section discusses the following topics:
The picture characters that make up a specification in the PICTURE attribute and in the P format item. It also describes picture syntax.
The process by which a value is assigned to a pictured variable or written out with the P format item.
The process by which a pictured value is assigned to other variables or acquired with the P format item.
Editing by picture.
The internal representation of pictured variables.
The formatting possible with pictured data is useful in many applications, but pictured data is less efficient than fixed-point decimal data in computations. Therefore, do not use pictured data unless you need the formatting.
3.2.5.1. Picture Characters
Table 3.6, “Picture Characters” summarizes the PL/I picture characters, their meaning, and whether they effect numeric interpretation and internal representation. The paragraphs following the table describe the picture characters and syntax. All picture characters are shown here in uppercase, but their lowercase equivalents can be used.
| Character | Meaning | Numeric Interpretation | Internal Representation |
|---|---|---|---|
| V | Position of assumed decimal point | yes | no |
| 9 | Decimal digit, including leading zeros | yes | yes |
| Z | Decimal digit with leading-zero suppression | yes | yes |
| * | Decimal digit with asterisk for leading zero | yes | yes |
| Y | Decimal digit with space for any zero | yes | yes |
| (n) | Iteration factor for subsequent character | yes | yes |
| T | Position of digit and encoded plus sign or minus sign | yes | yes |
| I | Position of digit and encoded plus sign if number >= 0 | yes | yes |
| R | Position of digit and encoded minus sign if number < 0 | yes | yes |
| $ | Position(s) of (drifting) dollar sign | yes | yes |
| + | Position(s) of (drifting) plus sign if number >= 0 | yes | yes |
| - | Position(s) of (drifting) minus sign if number < 0 | yes | yes |
| S | Position(s) of (drifting) plus sign or minus sign | yes | yes |
| , | Position at which comma is inserted | no | yes |
| . | Position at which decimal point is inserted | no | yes |
| / | Position at which slash is inserted | no | yes |
| B | Position at which space is inserted | no | yes |
| CR | Positions at which 'CR' is inserted if number < 0 | no | yes |
| DB | Positions at which 'DB' is inserted if number < 0 | no | yes |
Decimal Place Character (V)
The V character shows the position of the assumed decimal point, or the scale factor for the fixed-point decimal value. The V character has no effect on the internal representation of the pictured value and does not cause a decimal point to appear in the internal representation or in the output (use the period insertion character for this purpose). The following rules apply to the V character:
Only one V character can appear in a picture.
If a picture does not contain the V character, the V is assumed to be at the right end of the picture. That is, the pictured value has a scale factor of 0.
When a fixed-point value is assigned to a pictured variable, the integral portion of the assigned value is described by the picture characters to the left of the V; the fractional portion of the assigned value is described by the picture characters to the right of the V. Values with too many or too few digits are handled as follows:
If the assigned value has fewer integral digits than are indicated by the picture characters to the left, then the integral value of the pictured variable is extended on the left with zeros. If the assigned value has too many integral digits, the value of the pictured variable is undefined and the FIXEDOVERFLOW condition is signaled.
If the assigned value has fewer fractional digits than are indicated in the picture, then the fractional value of the pictured variable is extended on the right with zeros. If the assigned value has too many fractional digits, then the excess fractional digits are truncated on the right; no condition is signaled. Thus, if the V character is the last character in the picture or is omitted, assigned fixed-point values are truncated to integers.
The following example shows the effect of the V character:
DECLARE PRICE PICTURE '$$9V.99', BAD_PRICE PICTURE '$$9.99'; PRICE = .98; /* Output as $0.98 */ BAD_PRICE = .98; /* Output as $0.00 */ PRICE = 98; /* Output as $98.00 */ BAD_PRICE = 98; /* Output as $0.98 */
In this example, note that the variable PRICE, which contains the V character, represents the value properly. The variable BAD_PRICE, which contains only the period insertion character, has an assumed V character at the end of the picture, which causes the variable to misrepresent the value.
Digit Characters (9, Z, *, Y)
The characters 9, Z, and Y, and the asterisk character (*) mark the positions occupied by decimal digits. The number of these characters present in a picture specifies the number of digits, or precision, of the fixed-point decimal value of the pictured variable. The following rules apply to these characters:
The position occupied by 9 always contains a decimal digit, whether or not the digit is significant in the numeric interpretation of the pictured value. Leading zeros at positions occupied by a 9 are output.
The position occupied by Z contains a decimal digit only if the digit is significant in the integral portion of the numeric interpretation; if the digit is a leading 0, it is replaced by a space. Several additional rules apply to the Z character:
The Z character must not appear in the same picture with the asterisk character (*). It must not appear to the right of the characters 9, T, I, or R nor to the right of a drifting string.
If the Z character appears to the right of the V character, then all digits to the right of the V must be indicated by Z characters. Fractional zeros are then suppressed only if all fractional digits are 0 and all of the integral digits are suppressed; in that case, the internal representation contains only spaces in the digit positions.
The position occupied by the asterisk character (*) functions identically with the Z character, except that leading zeros are replaced by asterisks instead of spaces.
The position occupied by the Y character contains a decimal digit only if the digit is not 0. All zeros in the indicated positions, whether significant or not, are replaced by spaces.
Iteration Factor (n)
You can precede any picture character that can appear more than once in a picture by an iteration factor, which must be a positive integer constant enclosed in parentheses. For example:
'(4)9'This picture is the same as the following one:
'9999'Encoded-Sign Characters (T, I, R)
You can use the characters T, I, and R, which are encoded-sign characters, wherever 9 is valid. Each represents a digit that has the sign of the pictured value encoded in the same position. You can use only one encoded-sign character in a picture.
An encoded-sign character cannot be used in a picture that contains one of the following characters: S, +, -, CR, or DB (described in the following text).
The meanings of the characters are:
The T character indicates that the position contains an encoded minus sign if the numeric value is less than 0 and an encoded plus sign if the numeric value is greater than or equal to 0.
The I character indicates an encoded plus sign if the numeric value is greater than or equal to 0. Otherwise, the position contains an ordinary digit.
The R character indicates an encoded minus sign if the numeric value is less than 0. Otherwise, the position contains an ordinary digit.
Table 3.7, “ASCII Representation of Encoded-Sign Characters” lists the encoded-sign characters and their ASCII equivalents.
| Digit | ASCII Character | Digit | ASCII Character |
|---|---|---|---|
| +0 | { | -0 | } |
| +1 | A | -1 | J |
| +2 | B | -2 | K |
| +3 | C | -3 | L |
| +4 | D | -4 | M |
| +5 | E | -5 | N |
| +6 | F | -6 | O |
| +7 | G | -7 | P |
| +8 | H | -8 | Q |
| +9 | I | -9 | R |
Drifting Characters ($, +, -, S)
The dollar sign ($), plus sign (+), minus sign (-), and S character are drifting characters. You can use the drifting characters to indicate digits, and they also indicate a symbol to be inserted when, for example, a pictured value is written out by PUT LIST. The meanings of the characters are:
The dollar sign ($) causes a dollar sign to be inserted.
The plus sign (+) causes a plus sign to be inserted if the numeric value is greater than or equal to 0.
The minus sign (-) causes a minus sign to be inserted if the numeric value is less than 0.
The S character causes a plus sign to be inserted if the numeric value is greater than or equal to 0, and a minus sign if the value is less than 0.
If one of these characters is used alone in the picture, it marks the position at which a special symbol or space is always inserted, and it has no effect on the value's numeric interpretation. In this case, the character must appear either before or after all characters that specify digit positions.
However, if a series of n of these characters appears, then the rightmost n-1 of the characters in the series also specify digit positions. If the digit is a leading 0, the leading 0 is suppressed, and the leftmost character drifts to the right; the character appears either in the position of the last drifting character in the series or immediately to the left of the first significant digit, whichever comes first.
Used this way, the n-1 drifting characters also define part of the numeric precision of the pictured variable, because they describe at least some of the positions occupied by decimal digits. For an example of this behavior by a drifting character (the dollar sign), refer to the V decimal place character description.
The following additional rules apply to drifting characters:
A drifting string is a series of more than one of the same type of drifting character. Only one drifting string can appear in the picture; any other drifting characters can be used only singly and therefore designate insertion characters, not digits.
The Z and asterisk (*) cannot appear to the right of a drifting string.
A digit position cannot be specified (for instance, with a 9) to the left of a drifting string.
A drifting string can contain the V character and one of the insertion characters, which are defined as follows:
If the drifting string contains an insertion character, it is inserted in the internal representation only if a significant digit appears to its left. In the position of the insertion character, a space appears if the leftmost significant digit is more than one position to the right; the drifting symbol appears if the next position to the right contains the leftmost significant digit.
If the drifting string contains a V character, all digit positions to the right of the V (the fractional digits) must also be part of the drifting string. In this case, insignificant fractional digits are suppressed only when all integral and fractional digits are zeros: they are replaced by spaces in the internal representation. If any digit is not 0, all fractional digits appear as actual digits.
Any insertion characters immediately to the right of a drifting string are considered part of it.
Insertion Characters (, . / B)
The insertion characters indicate that characters are inserted between digits in the pictured value. The insertion characters are the comma (,), period (.), slash (/), and the space (B). The B character indicates that a space is always inserted at the indicated position.
The drifting characters ($, +, -, S) also function as insertion characters when used singly (that is, not as part of a drifting string).
The period (.) does not imply a decimal place character V (see the example in the description of the V character, described earlier).
The following rules describe insertion by the comma, period, and slash insertion characters.
In general, the insertion character itself is inserted in the internal representation of the pictured value. In particular, this is true if the insertion character is the first character in the picture, or if all the picture characters to its left are characters that do not specify decimal digits.
If 0 suppression occurs, the insertion character is inserted only in these cases:
If a significant digit appears immediately to its left
If the V character appears immediately to its left, and the fractional part of the numeric value contains significant digits
If the position preceding the insertion character is occupied by an asterisk or drifting string and the preceding position is taken by a leading 0, then the preceding character also indicates the character to be inserted in the position of the insertion character. If, however, the preceding position is taken by a leading 0 and does not have an asterisk or drifting string, then the insertion character's position is a space in the internal representation of the pictured value.
To guarantee that the decimal point is in the same position in both the numeric and character interpretations, the V and period characters must be adjacent. However, if the period precedes the V, then it is suppressed if there are no significant integral digits, even though all the fractional digits are significant. This property can make fractions appear to be integers when the internal (character) value is displayed. Consequently, the period should immediately follow the V character; it will then be in the correct location and will appear whenever any fractional digit is significant. The following example shows the correct and incorrect placement of the period:
DECLARE NUM PICTURE 'ZZZV.ZZ', BAD_NUM PICTURE 'ZZZ.VZZ'; NUM=0.02; /* Output as .02 */ BAD_NUM=0.02; /* Output as 02 */
You can use other insertion characters, such as the comma, to separate the integral and fractional portions of a number. Do not use the comma with GET LIST input, because in that context it separates different data items in the input stream.
Credit (CR) and Debit (DB) Characters
These picture characters are always specified as the character pairs CR and DB. If either pair is included, it appears if the numeric value is less than zero. In each case, the associated positions contain two spaces if the numeric value is greater than or equal to 0.
The characters are inserted with the same case as used in the picture. If the lowercase form cr is used in the picture, lowercase letters are inserted in the pictured value; if the combination Cr is used, then Cr is inserted.
The credit and debit characters cannot be combined in one picture, nor can they be used in the same picture as any other character that specifies the sign of the value (S, plus sign (+), and minus sign (-) characters). In addition, they must appear to the right of all picture characters specifying digits.
Picture Syntax
After all its iterations are expanded and all its insertion characters are removed, a picture must satisfy the following syntax rules (the notation character, or ellipsis (...), indicates a series of the same character, with no embedded characters).
Picture:
'[left-part]center-part[right-part]'
Left-part:
{ $ }
{ + }
{ - }
{ S }Right-part:
{ $ }
{ + }
{ - }
{ S }
{ CR }
{ DB }Center-part:
{ 9...[V[9...]] }
{ V9... }
{ Z...[9...[V[9...]]] }
{ Z...[V[9...]] }
{ [Z...]VZ... }
{ *...[9...[V[9...]]] }
{ *...[V[9...]] }
{ [*...]V*... }
{ ++...[9...[V[9...]]] }
{ ++...[V[9...]] }
{ - -...[9...[V[9...]]] }
{ - -...[V[9...]] }
{ SS...[9...[V[9...]]] }
{ SS...[V[9...]] }
{ $$...[9...[V[9...]]] }
{ $$...[V[9...]] }
{ +[+...]V+... }
{ -[-...]V-... }
{ S[S...]VS... }
{ $[$...]V$... }Note
The character Y, T, I, or R can appear wherever 9 is valid with the following restrictions. Only one character T, I, or R can appear in a picture. A picture cannot contain T, I, or R if it also contains S, +, -, CR, or DB.
Examples
Valid Pictures
'S99V.99'
The picture specifies a signed fixed-point number with a precision of 4 (p=4) and a scale factor of 2 (q=2). The sign of the number is always included in its representation, in the first position. A period is inserted at the position of the assumed decimal point.
'****99'The picture specifies a 6-digit integer, with the first four leading zeros replaced by asterisks.
'****V.**'The picture specifies a fixed-point number with p=6, q=2. The first four leading zeros are replaced by asterisks in the integral portion. Both fractional digits always appear unless all six digits are 0. A period is inserted at the position of the assumed decimal point.
'ZZ99V.99'The picture specifies a fixed-point number with p=6, q=2. The first two digits in the integral portion are replaced with spaces if they are zeros. Two digits always appear on either side of the decimal point.
'(4)SV.99'The picture specifies a fixed-point number with p=5, q=2. (The iteration factor 4 specifies a string of four S characters, one of which specifies a sign and three of which specify digits.) A plus (+) or minus (-) symbol is inserted to the immediate left of the first significant integral digit, or to the left of the decimal point if no integral digit is significant. Any insignificant integral digits are replaced with spaces or with the sign symbol.
'ZZZ,ZZZV.99'The picture specifies a fixed-point number with p=8, q=2. If the integral portion has four or more significant digits, a comma is inserted between the third and fourth digit; otherwise, both the leading zeros and the comma are suppressed. The decimal point always appears followed by two fractional digits.
'ZZZ.ZZZV,99'The picture specifies a fixed-point number with p=8, q=2. If the integral portion has four or more significant digits, a period is inserted between the third and fourth; otherwise, both the leading zeros and the period are suppressed. The decimal point (indicated by a comma) always appears followed by two fractional digits.
'ZZZ/ZZZ/ZZZ'The picture specifies a fixed-point number with p=9, q=0. A slash is inserted between the 3-digit groups unless the digit preceding the slash is a suppressed 0.
Invalid Pictures
'999ZZZZV.99'
The picture is invalid because a 9 occurs to the left of Z.
'$$$-99v.99'The picture is invalid because it contains two drifting strings ('$$$' and '- -').
'(4)-V.ZZZ'The picture is invalid because fractional digits in this case must be pictured either with a drifting minus sign or with 9s.
3.2.5.2. Assigning Values to Pictured Variables
Assignment of a computational value to a pictured variable is performed in the following two steps:
The value is converted to fixed decimal, with precision and scale as specified by the picture.
The resulting fixed decimal value is edited into the pictured variable.
If PL/I cannot perform one of these steps in a meaningful fashion, an error occurs. The following examples show two programming errors that are common in assignments to pictured variables.
CREDIT = '$12443.00';This example signals the CONVERSION condition, because the character string contains a dollar sign and cannot be converted to fixed-point decimal. The value assigned to CREDIT should be either '12443.00' or 12443.00, both of which result in the same value assigned to CREDIT.
If a negative value is assigned to a pictured variable, the picture must include one of the sign picture characters (such as DB). For example:
CREDIT = -12443.00;If the picture of CREDIT did not contain the DB characters, this assignment would signal the FIXEDOVERFLOW condition, because the sign would be lost. In some circumstances (for example, with the READ statement), it is possible to assign a value to a pictured variable that is not valid with respect to the variable's picture specification. In such cases, you can use the VALID built-in function to validate the contents of the variable.
3.2.5.3. Extracting Values from Pictured Data
When you use a pictured value in an arithmetic context (such as an assignment to an arithmetic variable), the picture is used to extract the fixed-point decimal number from the character string that internally represents the pictured value. Extraction also occurs when you input a pictured value with the GET EDIT statement and the P format item. If the contents of the pictured variable or input item do not conform to the picture, an error occurs.
For example:
DECLARE CREDIT PICTURE '$99999V.99DB';
In the picture for CREDIT, the 9 character specifies the position of a decimal digit; because the picture contains seven of these, the fixed-point decimal precision of CREDIT is 7. The V character separates the integral and fractional digits; because there are two 9 characters to the right of the V, the scale factor of CREDIT is 2. Because the V character specifies only a numeric property, a period picture character (.) is included after the V to ensure that the output value has a decimal point in the correct place.
The period and dollar sign are always inserted in the internal representation and the output value regardless of CREDIT's numeric value.
The picture character DB appears only when the value of CREDIT is less than 0; otherwise, two spaces appear in the indicated positions. The DB character also indicates that CREDIT's value is numerically negative, so that if CREDIT is later assigned to an arithmetic variable the variable will be given a negative value.
3.2.5.4. Editing by Picture
Any computational value or expression can be assigned to a pictured variable, as long as it meets these two qualifications:
The value either is a fixed-point decimal value or can be converted to a fixed-point decimal value.
The fixed-point decimal value can be represented with the precision and scale factor of the picture specified for the target pictured variable.
When a value is assigned to a pictured variable, the value is edited to construct a character string that meets the picture specification. Editing also occurs when a value is output with the PUT EDIT statement and the P format item. Editing was performed in the previous examples in which fixed-point decimal values were assigned to the pictured variable CREDIT.
Because a picture specifies a fixed-point decimal value, the FIXEDOVERFLOW condition is signaled in the same circumstances as for assignment of an expression to a FIXED DECIMAL variable.
3.2.5.5. The Internal Representation of Pictured Variables
A pictured variable has the attributes of a fixed-point decimal variable, but values assigned to it are stored internally as character strings. Such a character string contains digits describing the variable's numeric value as well as special symbols. An individual picture character and its position in the picture indicate the interpretation of an associated position in the pictured value.
The picture characters fall into three categories:
Characters that do not affect internal representation. The decimal place character (V) is the only one in this category.
Characters that affect both the numeric interpretation and internal representation of the value. These characters indicate how the digits of the numeric value should be placed in the string and where to place a sign as follows:
The digit characters (9, Z, *, Y)
The encoded-sign characters (T, I, R)
The drifting characters ($, +, -, S)
Characters that affect only the internal representation of the value. These characters appear in the internal characters string as follows:
The insertion characters (comma, period, slash, space)
The credit (CR) and debit (DB) characters
Section 3.2.5.1, “Picture Characters” describes each picture character in more detail. The assignment CREDIT =
12443.00; stores data internally, as shown in Figure 3.6, “Internal Representation of a Pictured Variable”, as a character string where delta
(△) represents a space.
The assignment CREDIT = -12443.00; stores data internally as shown in Figure 3.7, “Internal Representation of a Pictured Variable”.
In situations that call for a character representation of a pictured data item (such as output with PUT LIST), this internal representation is used, including the nonnumeric characters. On output, the values assigned to CREDIT would look like this:
$12443.00 /* a positive value (credit) */ $12443.00DB /* a negative value (debit) */
3.3. Character-String Data
A character string is a sequence of zero or more characters. The value of a character-string variable can consist of any DEC Multinational Character to a maximum length of 32,767 characters. The first 128 characters of the DEC Multinational Character Set are the ASCII characters. See Appendix B, Digital Multinational Character Set for the entire character set.
Every character-string variable has a length attribute that specifies either the length of all values of the variable (fixed-length strings) or the maximum length of a value of the variable (varying-length strings).
This discussion of character-string data is divided into the following parts:
Constants
Variables
Fixed-length character strings and their internal representation
Varying-length character strings and their internal representation
Alignment of character strings
3.3.1. Character-String Constants
A character-string constant can consist of any characters in the DEC Multinational Character Set (see Appendix B, Digital Multinational Character Set). When you use character-string constants in a program, you must enclose the strings in apostrophes, as shown in the following examples:
'Total is:' 'Enter your name and age' 'Error - value is out of range'
To specify a string containing a literal apostrophe, use two apostrophes within the string. For example:
'Life isn''t fair'When a character string that has embedded apostrophes is specified as previously shown, the final result contains only a single apostrophe.
Note that the quotation mark (") is not a legal delimiter for PL/I character constants.
3.3.1.1. Replication of String Constants
You can use a replication factor to replicate character-string and bit-string constants in any context of the program. A replication factor is an unsigned integer constant that specifies the number of times a simple string constant is replicated to produce a resulting string constant. For example:
(4)'season '
In this example, the string is repeated four times. The character constant resulting from this specification is equivalent to:
'season season season season 'You can use a replication factor in combination with the iteration factor in INITIAL. For example, the following two statements are equivalent:
INITIAL ((10)('ABCABC')) INITIAL ((10)((2)'ABC'))
The first example uses an iteration factor exclusively, but the second example combines an iteration factor of 10 with a replication factor of 2. Note that an extra set of parentheses is required to separate the iteration factor from the replication factor and the character string.
3.3.2. Character-String Variables
The CHARACTER keyword identifies a variable as a character-string variable in a declaration. The format for specifying a character-string variable is:
DECLAREvariable-name[ CHARACTER [(n)] ]; [ VARYING CHARACTER [(n)] ] [ CHARACTER [(n)] VARYING ]
The CHARACTER keyword identifies a character-string variable in a declaration.
The addition of the VARYING attribute indicates a varying-length character-string variable.
An optional number in parentheses specifies the length of the variable, that is, the number of bytes needed to contain its value (maximum is 32,767). This length attribute specifies either the length of all values of the variable (fixed-length strings) or the maximum length of a value of the variable (varying-length strings). If the length is not specified, PL/I uses the default length of one character, or byte. The rules for specifying the length are:
For a static variable declaration, the length must be an integer constant.
In the declaration of a parameter or returns descriptor, you can specify the length as an integer constant or as an asterisk (*). The resulting string is fixed length unless VARYING is also specified.
For an automatic, based, or defined variable, you can specify the length as an integer constant or as an expression. In the case of automatic or defined variables, the expression must not contain any variables or functions that are declared in the same block, except for parameters.
The maximum length in any declaration is 32,767.
If specified, n must immediately follow the keyword CHARACTER and must be enclosed in parentheses.
3.3.2.1. Fixed-Length Character-String Variables
A fixed-length character string is one that does not have the VARYING attribute. For a particular allocation of a fixed-length character-string variable, all its values have the same length. When a program assigns a value to a fixed-length character-string variable, however, the value does not need to have the same length defined for the variable. Depending on the size of the value, PL/I adjusts the assignment length according to the following rules:
If the value is smaller than the length of the character string, PL/I pads the character string with spaces on the right. For example:
DECLARE STRING CHARACTER (10); STRING = 'ABCDEF';
The final value of the variable STRING is 'ABCDEF ', that is, the characters ABCDEF followed by four space characters.
If the value is larger than the length of the variable, PL/I truncates the character string on the right. For example:
DECLARE STRING CHARACTER (4); STRING = 'ABCDEF';
Here, the final value of STRING is 'ABCD', that is, the first four characters of the value 'ABCDEF'.
3.3.2.2. Internal Representation of Fixed-Length Character Data
PL/I stores fixed-length character string data in a contiguous sequence of bytes with the leftmost character occupying the lowest memory address.
3.3.2.3. Varying-Length Character-String Variables
When you define a character-string variable, you can also specify the VARYING attribute. In a varying character-string variable, the length is not fixed. The length specified in the declaration of the variable defines the maximum length of any value that can be assigned to the variable. Each time a value is assigned, the current length changes. For example:
DECLARE NAME CHARACTER (20) VARYING; NAME = 'COOPER'; NAME = 'RANDOM FACTOR';
The declaration of the variable NAME indicates that the maximum length of any character-string value it can have is 20. The current length becomes 6 when NAME is assigned the value 'COOPER'; the length becomes 13 when NAME is assigned the value 'RANDOM FACTOR'; and so on.
When a varying character string is assigned a value with a length greater than the maximum defined, the value is truncated on the right.
The initial length of an automatic varying-length character-string variable is undefined unless the variable is initialized.
You can use the LENGTH built-in function to determine the current length of any string, and the MAXLENGTH built-in function to determine the maximum length.
3.3.3. Alignment of Character Strings
The PL/I language makes a distinction between aligned and unaligned (fixed-length) character-string variables. (No such distinction is made for varying character strings or for character-string constants.) A character-string variable is aligned if it is declared with the ALIGNED attribute.
This distinction affects only argument passing. If a procedure declares a parameter as ALIGNED CHARACTER, and if the corresponding argument is an unaligned character-string variable or vice versa, the actual argument will be a dummy variable. For example:
DECLARE GETSTRING ENTRY (CHARACTER (*) ALIGNED); DECLARE STRING CHARACTER (8); CALL GETSTRING (STRING);
PL/I constructs a dummy variable here to pass the unaligned string variable STRING to the called procedure GETSTRING, rather than passing the actual argument by reference.
All character strings on the VAX and Alpha hardware are aligned on byte boundaries. You should not use the ALIGNED attribute to declare character-string variables.
3.4. Bit-String Data
A bit string consists of a sequence of binary digits, or bits. It can be used as a Boolean value, which has one of two states: true (if any bit is non-zero) or false (if all bits are 0).
Like a fixed-length character string, a bit string has a fixed length defined in the declaration or specified by the number of bits in a bit-string constant. The maximum length of any bit string is 32,767 bits. However, bit-string variables cannot be declared with the VARYING attribute.
The rest of this section discusses bit-string constants and variables, alignment of bit-string data, and the use of bit strings to represent integers.
This discussion of bit-string data is divided into the following parts:
Constants
Variables
Alignment
Internal representation
Bit strings and integers
3.4.1. Bit-String Constants
To specify a bit-string constant, enclose the string in apostrophes and follow the closing apostrophe with the letter B. For example:
'0101'B '10101010'B '1'B
The length of a bit-string constant is always the number of binary digits specified; the B does not count in the length of the string. You can specify a bit-string constant with a maximum of 1000 characters between the apostrophes.
You can also specify a bit-string constant using the following syntax:
'character-string'Bn
nIs the number of bits to be represented by each digit in the string. n can have the value 1 through 4, and if not specified defaults to 1.
This format allows you to specify bit-string constants with bases other than 2. You can use base 4, 8, and 16, where n equals 2, 3, and 4 respectively. For example:
'EF8'B4 '117'B3 '223'B2
These constants specify the hexadecimal value EF8, the octal value 117, and the base 4 value 223. All such constants are stored internally as bit strings, not as integer representations of the value.
The valid characters for each type of bit-string constant are as follows:
For B or B1, only the characters 0 and 1 are valid
For B2, only the characters 0, 1, 2, and 3 are valid
For B3, only the characters 0, 1, 2, 3, 4, 5, 6, and 7 are valid
For B4, the characters 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, and F are valid (the letters A through F can be either upper- or lowercase)
Using the B format items, you can also acquire or output (with the GET EDIT and PUT EDIT statements) bit-string data in binary, base 4, octal, or hexadecimal format. See Section 9.2.4.2, “B Format Items” for more information on the B format item.
3.4.1.1. Replication Factor for Bit-String Constants
A replication factor is an unsigned integer constant that specifies the number of times a simple bit-string constant is replicated. A replication factor permits repetition of bit strings in any context where a simple string constant is permissible, including format items and assignment, string, and arithmetic operations. The format of a replication factor is as follows:
(r)'string'BnrAn unsigned integer that represents the number of times that the string is to be replicated.
stringA simple bit string constant to be replicated. The bit string is enclosed in apostrophes.
An example of replication is:
DECLARE (A) BIT (800); A = (400) '2'B2; PUT SKIP LIST ((A)); END;
In this example, A will be replicated to its maximum specified length of 800 characters.
The resulting character constant looks like this:
'10101010101010101010101010101010 ⋮ 10101010101010101010101010'B
You can use the replication factor in combination with the iteration factor in INITIAL. For example, the following two statements are equivalent:
INITIAL ((10)('ABCABC'B4)) INITIAL ((10)((2)'ABC'B4))
The first statement uses an iteration factor exclusively; the second statement combines an iteration factor of 10 with a replication factor of 2. An extra set of parentheses is required to separate the iteration factor from the replication factor and the bit string.
3.4.2. Bit-String Variables
Use the BIT attribute to declare a bit-string variable. The format is:
DECLAREvariable-nameBIT [(length)];
You can optionally specify the length of the variable in parentheses. The length can be from 0 to 32,767; the default length is one bit. The rules for specifying the length are as follows:
If BIT is specified for a static variable declaration or in a returns descriptor, the length must be an integer constant.
If BIT is specified in the declaration of a parameter or in a parameter descriptor, you can specify the length as an integer constant or as an asterisk (*).
If BIT is specified for an automatic, based, or defined variable, you can specify the length as an integer constant or as an expression. In the case of automatic or defined variables, the expression must not contain any variables or functions that are declared in the same block, except for parameters.
A program can assign to a bit-string variable a value larger or smaller than the variable's defined length. In such cases, PL/I does the following:
If the assigned string is shorter than the defined length, PL/I pads the bit-string value with zeros in the direction of least significance. The less significant bits are on the right as the string is represented by PUT LIST.
If the assigned string is longer, PL/I truncates the least significant bits from the bit-string value.
You can convert bit-string variables to other data types; however, there are some precautions you must observe if you do so. Section 6.4, “Data Type Conversion of Operands and Expressions” describes how to convert bit-string variables.
3.4.3. Alignment of Bit-String Data
PL/I distinguishes between aligned and unaligned bit-string variables. (Bit-string constants are always unaligned.) A bit-string variable is aligned only if it is declared with the ALIGNED attribute, as shown in the following example:
DECLARE FLAGS BIT (8) ALIGNED;
If the default packed alignment is in effect, PL/I allocates storage for an aligned bit-string variable on a byte boundary and reserves an integral number of bytes to contain the variable. If natural alignment is in effect, PL/I allocates storage for an aligned bit-string variable on a longword boundary and reserves an integral number of longwords to contain the variable. See the PL/I for OpenVMS Systems User Manual for more information on the /ALIGN and /DATA command line qualifiers, which affect what type of alignment is in effect.
Unaligned bit-string variables always occupy only as many bits as are needed to contain them. They need not be on byte boundaries. You can optionally specify the UNALIGNED attribute in a declaration; UNALIGNED is the default for bit strings.
In general, operations involving unaligned bit-string variables are less efficient than those involving aligned bit-string variables. Unaligned bit-string variables are also invalid as the targets of the FROM and INTO options of record I/O statements, and as the argument of the ADDR built-in function. Moreover, most non-PL/I programs that accept bit-string arguments require the strings to be aligned.
In most cases, you should declare bit-string variables with the ALIGNED attribute. Use unaligned bit-string variables when bit strings must be packed as tightly as possible, for example, in arrays and in structures. See Section 2.2.1, “ALIGNED Attribute” for a description of the ALIGNED attribute.
3.4.4. Internal Representation of Bit Data
In this discussion, the term most significant bit means the leftmost bit in an external representation of a string, as, for example, when the string is output by the PUT LIST statement. The least significant bit is the rightmost bit in the external representation.
The notion of significance has no meaning for bit strings unless they are used to store integers. PL/I permits the use of bit strings for this purpose, and has defined rules for conversions between bit strings and other data types.
Note
The use of PL/I bit-string data to store integers is not recommended, for two reasons:
In assignments involving two bit strings of different lengths, the source string is padded or truncated as required to make a string of the length of the target.
As shown in the following discussions, the significance of bits results in bit strings being stored in the reverse order from actual numeric data. Consequently, conversion of bit strings to arithmetic data is expensive in terms of execution speed, except in the special case of a 1-bit string.
You should use the UNSPEC built-in function and UNSPEC pseudovariable when you must store integers in a compact form. Otherwise, use the data types FIXED BINARY and FIXED DECIMAL for integer arithmetic.
Note
Sophisticated applications that depend on the internal representation of bit strings and other types of data may not be directly transportable from other PL/I implementations to Endless PL/I.
In Endless PL/I, bit strings are stored in memory with the leftmost bit (as represented by PUT LIST) in the lowest memory location, and bits following the leftmost in successively higher memory locations. This representation of a bit string is reversed by PUT with respect to a conventional picture of memory locations, in which the lowest location appears on the right and higher locations on the left. If you are accustomed to using PL/I on computers other than OpenVMS systems and if you do not change your data to correct for this difference, the result is likely to be in error.
If you wish to use bit strings to represent integers and you would like to associate the leftmost bit (as it might be represented in a PUT LIST statement) with the Most significant bit, use the BINARY builtin function, an example of which appears in Section 11.4.43, “INT”.
- Unaligned Bit Strings
An unaligned bit string is stored beginning at an arbitrary bit location in storage; this location is the location of the most significant bit. The subsequent, less significant, bits are stored in progressively higher locations in memory, as shown in Figure 3.8, “Unaligned Bit String Storage”.
Figure 3.8. Unaligned Bit String StorageThe following programming sequence shows how a value for an unaligned bit-string variable is stored:
DECLARE ABIT BIT (10); ABIT = '1011'B;
After the assignment, the variable appears in storage as shown in Figure 3.9, “Sample Unaligned Bit String Storage”.
Figure 3.9. Sample Unaligned Bit String Storage- Aligned Bit Strings
PL/I allocates storage for an aligned bit-string variable on a byte boundary and allocates an integral number of bytes. The number of bytes to be allocated is calculated as:
ceil(n/8)
Here, n is the length specified for the bit string.
Beginning at bit 0 (the lowest memory location) of the lowest allocated byte, the bit string is stored like unaligned bit-string data; that is, the beginning bit is used to hold the most significant bit in the string. Less significant bits are stored in progressively higher memory locations. Unused bits are set to 0 each time the bit-string variable is assigned a value.
The representation is shown in Figure 3.10, “Aligned Bit String Storage”.
Figure 3.10. Aligned Bit String StorageThe following programming sequence shows how values are stored for aligned bit strings:
DECLARE ABIT BIT (10) ALIGNED; ABIT = '10011'B;
In this example, the variable ABIT is aligned. When it is assigned the value 10011, the value is stored as shown in Figure 3.11, “Sample Aligned Bit String Storage”.
Figure 3.11. Sample Aligned Bit String Storage
3.4.5. Bit Strings and Integers
PL/I defines conversions between bit-string data and other data types, and the PL/I compiler carries out these conversions. However, the conversions defined by PL/I are not always straightforward or intuitive; the padding and truncation that take place during assignment of bit strings of different lengths result in implicit multiplication or division of the bit string's integer value. For example:
DECLARE BITSTR BIT (10); BITSTR = 1; PUT LIST (BITSTR);
The output is:
'0001000000'BThe result may seem incorrect, but it conforms to PL/I's rules for conversion to bit strings. In this case, the fixed-decimal constant 1 is converted to a FIXED BINARY(4) value, which is in turn converted to an intermediate bit string of length 4:
'0001'BNext, this intermediate bit string is assigned to the variable BITSTR. Because BITSTR is of length 10, the intermediate bit string is padded on the right with zeros, producing the result as output by PUT LIST. If you now attempt to interpret the value of BITSTR as an integer (for example, by using BITSTR as the argument of the BINARY built-in function), the result would be 64, not 1.
Extra execution time is required to reverse the order of bits when the integer's value is computed. Using arithmetic variables to represent integers is more efficient.
Because of the unexpected results and longer execution time, avoid using bit strings to represent integers or other data types.
3.5. Pointer Data
A pointer is a variable whose value represents the address in memory of another variable or data item.
Pointers are used to qualify references to based variables, that is, variables for which storage is explicitly allocated at run time by the ALLOCATE statement. For example:
DECLARE LIST_POINTER POINTER; DECLARE 1 LIST_STRUCTURE BASED, 2 FORWARD_PTR POINTER, 2 MEMBER_NAME CHAR(20) VAR; ALLOCATE LIST_STRUCTURE SET (LIST_POINTER); LIST_POINTER -> LIST_STRUCTURE.MEMBER_NAME = 'newname';
When these statements are executed, the ALLOCATE statement allocates storage for a variable LIST_STRUCTURE and sets the pointer LIST_POINTER to the address in memory of the allocated storage. This dynamically created variable is called an allocation of the variable LIST_STRUCTURE.
In the assignment statement, the locator qualifier (->) and the identifier LIST_POINTER distinguish this allocation of LIST_STRUCTURE from allocations created by other ALLOCATE statements, if any. Pointers may also be used directly in declarations of based variables. For example:
DECLARE X POINTER, BUFFER CHARACTER(80) BASED (X);
The variable X is given the POINTER attribute. Then it is used as the target pointer in another declaration, which defines a buffer to be based on X.
This section discusses the following:
Pointer variables in expressions
Internal representation of pointer data
3.5.1. Pointer Variables in Expressions
Expressions containing pointer variables are restricted to the relational operators equal (=) and not equal (^=).
For example, to test whether a pointer is currently pointing to valid storage, you can write the following statement:
IF LIST_POINTER ^= NULL() THEN DO;
The NULL built-in function always returns a null pointer value.
You can use pointer variables in simple assignment statements that assign a pointer value to a pointer variable. For example:
LIST_POINTER_1 = LIST_POINTER_2;
LIST_END = NULL();You can also use a pointer variable as the source or target in an assignment statement involving an offset variable or offset value.
3.6. Offset Data
You declare an offset variable with the OFFSET attribute, optionally followed by an area variable reference. The value of the offset variable will be interpreted as an offset within the specified area, unless the POINTER function is used to explicitly specify another area. You must omit the area reference if the OFFSET attribute is specified within a returns descriptor, parameter declaration, or parameter descriptor. For example:
DECLARE MAP_SPACE AREA (40960), MAP_START OFFSET (MAP_SPACE), MAP_LIST(100) CHARACTER(80) BASED (MAP_START);
These declarations define an area named MAP_SPACE; an offset variable, MAP_START, that will contain offset values within that area; and a based variable whose storage is located by the value of MAP_START.
Offset variables are given values by assignment from existing offset values or from conversion of pointer values. The OFFSET built-in function (described in Section 11.4.59, “OFFSET”) converts a pointer value to an offset value. PL/I also automatically converts a pointer value to an offset value, or an offset value to a pointer value, in an assignment statement. The following assignments are valid:
pointer-variable= pointer-value;offset-variable = offset-value;
pointer-variable= offset-variable;offset-variable = pointer-value;
In assignment 2, any area references are ignored in the assignment; therefore, the offset value and variable can refer to different areas. In assignments 3 and 4, the offset variable must have been declared with an area reference.
Expressions containing offset variables are restricted to the relational operators = and ^=, for testing the equality or inequality of two values.
3.7. Label Data
A label identifies a statement so that it can be referred to elsewhere in the program, for example, as the target of a GOTO statement. A label precedes a statement and consists of any valid identifier terminated by a colon. Some examples are:
TARGET: A = A + B; READ_LOOP: READ FILE (TEXT) INTO (TEMP);
These statements contain the implicit declarations of the names TARGET and READ_LOOP as label constants.
No statement can have more than one label. A statement can, however, be preceded by any number of labeled null statements. For example:
A: ; B: DO I = 1 TO 5;
Other statements in the program can refer to the DO statement in this example by specifying either label A or label B.
A name occurring as a statement label is implicitly declared as a label constant. It has the attributes LABEL and constant. You cannot explicitly declare label constants.
This section discusses the following:
Label array constants
Label values
Label variables
Internal representation or variable label data
3.7.1. Label Array Constants
Any label constant except the label of a PROCEDURE or FORMAT statement can have a single subscript. Subscripts must be specified with integer constants; a subscript must appear in parentheses following the label name. An example for VAX and Alpha is:
PART(1): ⋮ PART(2): ⋮ PART(*):
When labels are written this way, the unscripted label name represents the implicit declaration of a label array constant. In this example, the array is named PART and is treated as if it were declared within the block containing the subscripted labels. In VAX, a default label can be created by using the asterisk (*) in place of a label constant. If a default label is used, it must be the last label in the list. If the variable subscript is out of range and the default label is present, the default label will be executed.
Elements of the array can be referenced in GOTO statements that specify a subscript. For example:
GOTO PART(I);I is a variable whose value represents the subscript of the element of PART that is the label to be given control.
Within a single block, you cannot use the same subscript value in two different subscripted references with the same name. For example:
PART(1):This label array constant can be used only once in a block. However, the subscript values are not constrained to be in any particular order or to be consecutive. For example, you can use the array constants PART(1) and PART(3) without using PART(2).
If a name is used as a label array constant in two or more different blocks, each declaration of the name is treated as an internal declaration. For example:
LIST(2): RETURN; BEGIN; GOTO LIST (ELEMENT); LIST(1):; LIST(3): END;
In this example, the value of ELEMENT cannot cause control to pass to the RETURN statement labeled LIST(2) in the containing block. The subscripted LIST labels in the begin block restrict the scope of the name to that block.
3.7.2. Label Values
Whenever a reference to a label constant is interpreted, the result is a label value. A label value has two components:
The first component designates the statement identified by the label constant.
The second component designates an activation of the block in which the label was declared (that is, to which the labeled statement belongs). If the label belongs to the current block, this block activation is the current block activation. If the label belongs to a containing block, the activation is found on the chain of parent block activations ending with the current block.
The GOTO statement with a label reference transfers control to the designated statement in the designated block activation. If the target block activation is different from the block activation in which the GOTO statement is executed, then the GOTO is nonlocal. For example:
DECLARE LV LABEL; /* LABEL variable */ . . . LV = L; /* assigns a bound label value to LV */ BEGIN; . . . GOTO LV; /* nonlocal GOTO */ END; L: RETURN;
Operations on label values are restricted to the operators = and ^= for testing the equality or inequality of two values. Two values are equal if they refer to the same statement in the same block activation.
Any reference to a label value after its block activation ceases to exist is an error with unpredictable results.
3.7.3. Label Variables
When an identifier is explicitly declared with the LABEL attribute, it acquires the VARIABLE attribute by default. You can use such a variable to denote different label values during the execution of the program. For example:
DECLARE PROCESS LABEL; . . . IF CODE THEN PROCESS = BILLING; ELSE PROCESS = CHARGE; . . . GOTO PROCESS;
When the GOTO statement evaluates the reference to the label PROCESS, the result is the current value of the variable. The GOTO statement transfers control to either of the labels BILLING or CHARGE, depending on the current value of the Boolean variable CODE.
You can also give values to label variables by passing label values as arguments or by returning a label value as the value of a function (although the latter method can lead to programming errors that are difficult to diagnose). For example:
CALL COMPUTER(ERROR_EXIT, YVAL, XVAL);
.
.
.
ERROR_EXIT:In this example, the actual argument that is passed for ERROR_EXIT is a dummy argument whose value consists of the following:
The location in memory of the statement labeled ERROR_EXIT
A pointer to the stack frame for the block in which the CALL statement is executed
Restrictions
Any statement in a PL/I program can be labeled except the following:
A DECLARE statement
A statement beginning an ON-unit or THEN, ELSE, WHEN, or OTHERWISE clauses
Labels on PROCEDURE, ENTRY, and FORMAT statements are not considered statement labels and cannot be used as the targets of GOTO statements.
An identifier occurring as a label in a block cannot be declared in that block (except as a structure member), and cannot occur in a parameter list of that block.
3.7.4. Internal Representation of Variable Label Data
Figure 3.12, “Variable Label Data Representation” shows the internal representation of variable label data.
3.8. Entry Data
Entry constants and variables are used to invoke procedures through specified entry points. An entry value specifies an entry point and a block activation of a procedure.
This section discusses the following:
Entry constants
Entry values
Entry variables
Internal representation of variable entry data
3.8.1. Entry Constants
You declare entry constants by using labels on PROCEDURE or ENTRY statements.
You declare internal entry constants by using labels on PROCEDURE or ENTRY statements whose procedure blocks are nested in another block. You can use an internal entry constant anywhere within its scope to invoke its procedure block.
You declare external entry constants either by using labels on PROCEDURE or ENTRY statements that belong to external procedures, or by explicitly declaring the constant names with the ENTRY attribute. You can use an external entry constant to invoke its procedure block from any program location that is within its scope. Its scope is either the scope of its declaration (as a label) or the scope of a DECLARE statement for the constant.
In DECLARE statements, you declare external entry constants with the ENTRY attribute. The declaration must agree with the actual entry point. That is, the declaration of the external entry constant must contain parameter descriptors for any parameters specified at the entry point, and, if the entry constant is to be used in a function reference, the declaration must have a returns descriptor describing the returned value.
3.8.2. Entry Values
Whenever a reference to an entry constant is interpreted, the result is an entry value. An entry value is the entry point of a procedure, and it serves to activate the block in which the entry point is declared (that is, the block in which the entry point's name appears as the label of a PROCEDURE or ENTRY statement). This block activation is the current block activation if the entry point belongs to the current block. If the entry point belongs to a containing block, the activation is on the chain of parent activations that ends at the current block activation.
No conversions are defined between entry data and other data types. You can assign an entry variable only the value of an entry constant or the value of another entry variable. The only operations that are valid for entry data are comparisons for equality (=) and inequality (^=). Two entry values are equal if they refer to the same entry point in the same block activation.
PL/I supports the passing of external procedures, but not internal procedures, as entry value parameters. To pass an internal procedure, use an entry parameter.
3.8.3. Entry Variables
Entry variables are variables (including parameters) that take entry values. If the VARIABLE attribute is specified with the ENTRY attribute in a DECLARE statement, the declared identifier is an entry variable. You can assign to an entry variable either another entry variable or an entry constant.
When an entry variable is used to invoke a procedure, its declaration must agree with the definition of the entry point. If the value you assign to an entry variable specifies an entry point with parameters, the parameters must be described with parameter descriptors in the declaration of the variable. If the assigned value specifies an entry point that is invoked as a function, then the declaration of the entry variable must have a RETURNS attribute that describes the data type of the returned value.
The scope of an entry variable name can be either internal or external. If neither the EXTERNAL nor the INTERNAL attribute is specified with the entry variable, the default is INTERNAL.
You can use the entry variable to represent different entry points during the execution of the PL/I program. For example:
DECLARE E ENTRY VARIABLE, (A,B) ENTRY; E = A; CALL E;
The entry constant A is assigned to the entry variable E. The CALL statement results in the invocation of the external entry point A.
You can also declare arrays of entry variables. The following example shows an array of external functions:
DECLARE EXTRACT(10) ENTRY (FIXED,FIXED) VARIABLE RETURNS (FLOAT), GETVAL FLOAT; GETVAL = EXTRACT(3)(1,3);
This assignment statement references the third element of the array EXTRACT. When the statement is executed, this array element must contain a valid entry value.
Note
Exercise caution using static entry variables. The value of a static entry variable is valid only as long as the block in which that value was declared is active.
3.8.4. Internal Representation of Variable Entry Data
Figure 3.13, “Variable Entry Data Representation” shows the internal representation of variable entry data.
3.9. File Data
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:
File constants
Files values
File variables
3.9.1. File Constants
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 parameter.
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:
Based variables can be allocated within a specific area, and the entire area can be assigned or transmitted in a single operation. The variables can be referred to by offset values within the area; the offset values remain valid throughout assignment or transmission.
You can control the allocation of storage for related variables by placing them in the same area, which improves the locality of reference. Also, you can use one operation to recover the storage for all allocations within an area by freeing or initializing the area itself.
You can use a structure containing an area to represent a disk file that is mapped into a process's virtual address space.
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:
Area variables in expressions
Reading and writing areas
Internal representation of area data
3.10.1. Area Variables in Expressions
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();3.10.2. Reading and Writing Areas
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.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.