DocumentationEndless PL/I for POSIX SystemsReference Manual  ·  ESS-PFURM-001

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 integers 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 or EBCDIC 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. You can do a limited subset of arithmetic operations on pointers and offsets.

  • 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 (See Section 8.10.1, “ON Statement”) and SIGNAL statement (See 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

To establish an identifier as a name in PL/I, you can declare it either implicitly or explicitly. Implicit declarations occur when you use an identifier as a name without explicitly declaring it. PL/I recognizes the identifier by context, giving it default attributes. Some common examples of implicit declaration are using an identifier as an entry-point name, statement label, or built-in function name, or using the default file constants SYSIN and SYSPRINT.

To explicitly declare an identifier, use 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.

Important

By explicitly declaring identifiers you can give them the specific attributes you require, instead of the default attributes, which may not be appropriate for your needs.

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;

If you are using the Digital variant of Endless PL/I for POSIX Systems, the default FIXED attribute implies the attributes BINARY(31). Thus, the variable NUMBER has the attributes FIXED BINARY(31). If you are using the IBM variant, the default FIXED attribute implies the attributes BINARY(15), and NUMBER has the attributes FIXED BINARY (15).

Table 3.1, “Implied Attributes for Computational Data” shows the default attributes implied by each computational data attribute for the Digital variant (-D dec compiler option) and for the IBM variant (-D ibm compiler option).

Table 3.1. Implied Attributes for Computational Data
SpecifiedDigital VariantIBM Variant
implicit declaration[a]FIXED BINARY(31)

If name begins with the letters I through N:

FIXED BINARY(15)

Otherwise::

FLOAT DECIMAL(6)

FIXEDBINARY(31)BINARY(15)
BINARYFIXED(31)FIXED(15)
FIXED BINARY(31)(15)
FLOATBINARY(24)BINARY(21)
FLOAT BINARY(24)(21)
DECIMALFIXED(10,0)FIXED(5,0)
FIXED DECIMAL(10,0)(5,0)
FIXED DECIMAL(p)(p,0)(p,0)
FLOAT DECIMAL(7)(6)
BIT [ALIGNED](1)(1)
CHARACTER [VARYING](1)(1)

[a] The compiler issues a warning for each variable that you declare implicitly.


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. 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 (6);
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:

ALIGNEDENTRYpicture
AREAFILEPICTURE
array boundsFIXEDPOINTER
BINARYFLOATprecision
BITLABELPRECISION
CHARACTERlengthVARYING
DECIMALOFFSET

DIMENSION

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 integer binary data 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.

Scale factors are supported for fixed-point decimal data. The scale of fixed-point data is the number of digits to the right of the decimal point. Fixed-point binary and floating-point data 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).

Table 3.2, “Default Values for Precision” summarizes the ranges of values you can specify for precision for each arithmetic data type and the defaults applied if you do not specify a precision.

Table 3.2. Default Values for Precision
Data Type AttributesPrecisionScale FactorDefault Precision
BINARY FIXED1 <= p <= 31-31
BINARY FLOAT (Digital Variant)1 <= p <= 113-24
BINARY FLOAT (IBM Variant)1 <= p <= 109-21
DECIMAL FIXED (Digital Variant)1 <= p <= 31p >= q >= 010
DECIMAL FIXED (IBM Variant)1 <= p <= 15p >= q >= 05
DECIMAL FLOAT (Digital Variant)1 <= p <= 34-7
DECIMAL FLOAT (IBM Variant)1 <= p <= 33-6

If no scale factor is specified for fixed-point decimal data, the default is 0.

3.2.2. Fixed-Point Binary Data

You can use the attributes FIXED and BINARY to declare integer variables and fractional variables in which the number of fractional digits is fixed (that is, nonfloating-point numbers). The FIXED attribute implies BINARY.

For example, you can declare a fixed-point binary variable as:

DECLARE X FIXED BINARY(31);

The compiler gives variable X the attributes FIXED, BINARY, and (31) in this declaration. The precision is 31.

PL/I has 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, so 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:

DECLARE identifier FIXED [BINARY] [(precision)];

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.

Figure 3.1. Internal Representation of Fixed-Point Binary Data
Internal Representation of Fixed-Point Binary Data sign 7 6 0 Byte sign 15 14 0 Word sign 31 30 0 Longword

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:

DECLARE identifier [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. (PL/I also supports using the hexadecimal values A, E, and F for positive values and the hexadecimal value B for negative values.)

Figure 3.2. Fixed-Point Decimal Data Representation
Fixed-Point Decimal Data Representation 7 4 3 0 digit 1 digit 2 digit 3 digit 4 … sign

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:

DECLARE identifier FLOAT [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:

DECLARE identifier FLOAT DECIMAL [(p)];

For example:

DECLARE X FLOAT DECIMAL (10);

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

PL/I supports the IEEE standards of floating point formats—the S (single precision) and T (double precision) types. Table 3.3, “Ranges of Floating-Point Formats” summarizes the approximate ranges of the floating-point formats.

Table 3.3. Ranges of Floating-Point Formats
FormatRange
S0.29 * 10 -38 to 1.7 * 10 38
T0.56*10 -308 to 0.9 * 10 308

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, “IEEE S_floating Format” and Section 3.2.4.6, “IEEE T_floating Format” describe the internal representation of floating-point data.

Table 3.4. Ranges of Precision for Floating-Point Types
Floating-Point TypeSign BitsExponent BitsFractional Bits
S (single precision)1824
T (double precision)11153

The PL/I compiler selects the appropriate floating-point type based on the precision you specify. The types are selected as shown in Table 3.5, “Floating-Point Types Used by PL/I”, where p indicates precision.

Table 3.5. Floating-Point Types Used by PL/I
Precision (DECIMAL)Precision (BINARY)Digital UNIX
1 <= p <= 71 <= p <= 24S
8 <= p <= 1525 <= p <= 53T

3.2.4.5. IEEE S_floating Format

The following PL/I types are represented using S_floating data, which occupies four contiguous bytes:

  • FLOAT BINARY (P) where P ≤ 24

  • FLOAT DECIMAL (P) where P ≤ 7

Bits are labeled from the right, 0 through 31, as shown in Figure 3.3, “IEEE S_floating Data Representation”.

Figure 3.3. IEEE S_floating Data Representation
IEEE S_floating Data Representation 31 30 23 22 0 S I G N EXPONENT FRACTION :A

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.

S_floating Value in a 64-Bit Register 63 62 52 51 29 28 0 S I G N EXPONENT FRACTION 0 :A

3.2.4.6. IEEE T_floating Format

The following PL/I types are represented using T_floating data, which occupies eight contiguous bytes:

  • FLOAT BINARY (P) where 24 < P ≤ 53

  • FLOAT DECIMAL (P) where 7 < P ≤ 15

Bits are labeled from the right, 0 through 63, as shown in Figure 3.4, “IEEE T_floating Data Representation”

Figure 3.4. IEEE T_floating Data Representation
IEEE T_floating Data Representation 63 62 52 51 0 S I G N EXPONENT FRACTION :A

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.225073859D-308 (normalized) to 1.797693135D308. The precision is approximately one part in 2**52; that is, typically fifteen decimal digits.

3.2.5. Character Pictured Data

Use character pictured data to define fixed-length character strings and also specify that certain positions in the character string must contain specific types of characters.

A character picture specification must contain one or more A or X picture specification characters, and can also contain one or more 9 picture specification characters. A character picture specification might look like this in a DECLARE statement:

DECLARE EMPLOYEE_NUMBER PICTURE 'AAA999999X';

This statement declares the variable EMPLOYEE_NUMBER as a character pictured variable. The characters within the apostrophes describe its format.

The formatting possible with character pictured data is useful in applications where you have a specific defined format for a character string, such as an employee id or part number, but do not use the numeric portion of the string for calculations.

3.2.5.1. Character Picture Characters

lists the PL/I character picture characters and describes their meaning in a character pictured data item:

XAny character in the DEC Multinational Character set.
AAny alphabetic character, blank, $, #, or @
9Any numeric digit or blank. Note that blanks are allowed, although they are not allowed when you use a '9' in a numeric picture character specification.

3.2.5.2. Examples of Character Picture Variable Definitions

The following examples show valid and invalid pictures given the following declaration for EMPLOYEE_NUMBER:

DECLARE EMPLOYEE_NUMBER PICTURE 'AAA999999X';
Valid pictures
'MFG123456A'
'prs52      x' (prs52 followed by four blanks and an x)
'$ab123456+'
Invalid pictures
'MF9123456A' (9 is invalid given the A format item for that position)
'prsA#3456x' (A and # are invalid given the 9 format item for those positions)

3.2.6. Numeric Pictured Data

Use numeric pictured data when you want to manipulate a quantity arithmetically and accept or display its value using a special format.

A numeric 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.6.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.

Table 3.6. Picture Characters
CharacterMeaningNumeric InterpretationInternal Representation
VPosition of assumed decimal pointyesno
9Decimal digit, including leading zerosyesyes
ZDecimal digit with leading-zero suppressionyesyes
*Decimal digit with asterisk for leading zeroyesyes
YDecimal digit with space for any zeroyesyes
(n)Iteration factor for subsequent characteryesyes
TPosition of digit and encoded plus sign or minus signyesyes
IPosition of digit and encoded plus sign if number >= 0yesyes
RPosition of digit and encoded minus sign if number < 0yesyes
$Position(s) of (drifting) dollar signyesyes
+Position(s) of (drifting) plus sign if number >= 0yesyes
-Position(s) of (drifting) minus sign if number < 0yesyes
SPosition(s) of (drifting) plus sign or minus signyesyes
,Position at which comma is insertednoyes
.Position at which decimal point is insertednoyes
/Position at which slash is insertednoyes
BPosition at which space is insertednoyes
CRPositions at which 'CR' is inserted if number < 0noyes
DBPositions at which 'DB' is inserted if number < 0noyes
F ( [] n )Scaling factor for fixed decimal numbersyesyes
KPositions the exponent fieldyesyes
EPositions the letter E, indicating the start of the exponent fieldyesyes

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.

Table 3.7. ASCII Representation of Encoded-Sign Characters
DigitASCII CharacterDigitASCII Character
+0{-0}
+1A-1J
+2B-2K
+3C-3L
+4D-4M
+5E-5N
+6F-6O
+7G-7P
+8H-8Q
+9I-9R

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 or to 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.

Scaling Factor Character (F([+ or -] n))

The F character specifies the scale factor for a fixed-point decimal value. You can specify it once, at the right end of the picture specification.

Format
F ( [] n )
F

Indicates that the following number is a scaling factor.

(+ or -)

Indicates whether the decimal point should be moved to the right (if positive) or left (if negative).

n

The number of places to move the decimal place. You must specify n such that the number of digits following the V picture character minus the number specified with the F picture character is between -128 and 127.

Exponent Characters (K and E)

Use the K and E characters in numeric pictures to describe picture equivalents for floating-point decimal numbers. These characters delimit the exponent field.

K

Shows the position where the exponent field begins. This character does not appear in the data item.

E

Shows the position where the letter E, followed by the exponent field, appears in the data item.

Only one K or E can appear in a picture.

For example:

DECLARE RESULT PICTURE 'SZ999V.99ES99'

3.2.6.2. 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 (...), indicate 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          }
{ F( [ + ]n ) }
{    [ - ]    }
{ K           }
{ E           }

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.

3.2.6.3. 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 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.6.4. Assigning Values to Pictured Variables

Assignment of a computational value to a pictured variable is performed in the following two steps:

  1. The value is converted to fixed decimal, with precision and scale as specified by the picture.

  2. 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.6.5. 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 (.) 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.6.6. 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.6.7. 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.6.1, “Picture Characters” describes each picture character in more detail. The assignment CREDIT = 12443.00; stores data internally, as shown in Figure 3.5, “Internal Representation of a Pictured Variable”, as a character string where delta () represents a space.

Figure 3.5. Internal Representation of a Pictured Variable
Internal Representation of a Pictured Variable First character $ 1 2 4 4 3 . 0 0 Δ Δ

The assignment CREDIT = -12443.00; stores data internally as shown in Figure 3.6, “Internal Representation of a Pictured Variable”.

Figure 3.6. Internal Representation of a Pictured Variable
Internal Representation of a Pictured Variable First character $ 1 2 4 4 3 . 0 0 D B

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.

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.

When you use character-string constants in a program, you must enclose the strings in apostrophes or quotation marks, as shown in the following examples:

'Total is:'
"Enter your first name: "

To specify a character string containing a literal apostrophe, use two apostrophes within the string. For example:

'Life isn''t fair'

When you specify a character string with embedded apostrophes as shown, the final result contains only a single apostrophe.

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 is:

DECLARE variable-name { CHARACTER [(n)]               } ;
                      { VARYING CHARACTER [(n)]       }
                      { CHARACTER [(n)] VARYING       }
                      { OPTIONS (C)                   }

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 string 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.2.4. Internal Representation of Varying Character Data

A varying-length character string consists of a fixed binary (15) value (stored as a word) specifying the string's current length, followed by a sequence of bytes in sequentially higher memory addresses.

3.3.3. Alignment of Character Strings

The PL/I language makes a distinction between aligned and unaligned varying character strings. (No such distinction is made for fixed length character strings or for character string constants.) A varying character string 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 Digital 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:

  • 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
n

Is 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'Bn
r

An unsigned integer that represents the number of times that the string is to be replicated.

string

A 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));

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:

DECLARE variable-name BIT [(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;

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. 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 more information.

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.

Important

The use of PL/I bit-string data to store integers is not recommended, for two reasons: 1. 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. 2. 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. 3. Internal representation is implementation specific. Do not rely on internal representation in your program, especially if you are writing transportable code.

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 .

In Endless PL/I for POSIX Systems, 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 VAX or Alpha AXP machines and if you do not change your data to correct for this difference, the result is likely to be in error.

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.7, “Unaligned Bit String Storage”.

Figure 3.7. Unaligned Bit String Storage
Unaligned Bit String Storage … … most significant bit least significant bit

The 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.8, “Sample Unaligned Bit String Storage”.

Figure 3.8. Sample Unaligned Bit String Storage
Sample Unaligned Bit String Storage most significant bit … 0 0 0 0 0 0 1 1 0 1 … least significant bit

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.9, “Aligned Bit String Storage”.

Figure 3.9. Aligned Bit String Storage
Aligned Bit String Storage Byte n+1 Byte n least significant bit most significant bit

The 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.10, “Sample Aligned Bit String Storage”.

Figure 3.10. Sample Aligned Bit String Storage
Sample Aligned Bit String Storage Byte Byte … 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 … unused least significant bit most significant bit

3.4.5. Bit Strings and Integers

PL/I defines conversions between bit-string data and other data types, and the 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'B

The 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'B

Next, 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 (^=), and the assignment operator.

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.5.2. Internal Representation of Pointer Data

A pointer occupies a longword (32 bits) of storage and represents a virtual memory address.

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. 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:

  1. pointer-variable = pointer-value;

  2. pointer-variable = pointer-value ± fixed-binary-number;

  3. offset-variable = offset-value;

  4. pointer-variable = offset-variable;

  5. offset-variable = pointer-value;

In assignment 3, any area references are ignored in the assignment; therefore, the offset value and variable can refer to different areas. In assignments 4 and 5, 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 subscript. Subscripts must be specified with integer constants and can be either a simple constant or, using the IBM dialect, an array of up to seven dimensions. A subscript must appear in parentheses following the label name as shown in the following example:

PART(1):
       ⋮
PART(2):
       ⋮
PART(*):
       ⋮

The following example shows labels with two dimensions (valid in the IBM dialect only):

PART(1,1):
       ⋮
PART(1,2):
       ⋮
PART(*,*):
       ⋮

When labels are written this way, the unsubscripted 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. 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.

Make sure all the labels referenced by teh GOTO statement occur after the statement. See Section 8.6, “GOTO Statement” for more information.

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

You can also declare arrays of label variables with up to seven dimensions. For example:

DECLARE LAB_ARRAY(10,20) LABEL;
       ⋮
GOTO LAB_ARRAY(I,J);
       ⋮
LAB_ARRAY(1,1):
       ⋮
LAB_ARRAY(1,2):
       ⋮

Restrictions

Any statement in a PL/I program can be labeled except 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 Label Variables

Figure 3.11, “Variable Label Data Representation” shows the internal representation of variable label data.

Figure 3.11. Variable Label Data Representation
Variable Label Data Representation 31 0 address of label parent frame pointer

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

To declare entry constants, use labels on PROCEDURE or ENTRY statements.

To declare internal entry constants, use 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.

To declare external entry constants, either use labels on PROCEDURE or ENTRY statements that belong to external procedures, or explicitly declare 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.

You can declare external entry constants in DECLARE statements by using 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

Be careful when 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 Entry Variables

Figure 3.12, “Entry Variable Data Representation” shows the internal representation of entry variables.

Figure 3.12. Entry Variable Data Representation
Entry Variable Data Representation 31 0 address of this entry point parent frame pointer

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

To declare file constants, use 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 passing both external files and internal files as file value parameters.

3.9.3. File Variables

File variables are variables (including parameters) that take file values. If you specify the VARIABLE attribute with the FILE attribute in a DECLARE statement, the declared identifier is a file variable. You can assign either another file variable or a file constant to a file variable.

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.

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.10.3. Internal Representation of Area Data

An area occupies the number of bytes, specified in the extent, of storage. Since this storage includes overhead used by PL/I for bookkeeping, slightly less than the full amount (specified in the extent) is available for program allocations. See Section 2.2.3, “AREA Attribute” for information on specifying the extent of an area.

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 (^=).

You can use the CONDITION data type as either a constant or a variables. For example, the following are valid declarations:

DECLARE (C1, C2, C3) CONDITION;
DECLARE C CONDITION VARIABLE;