PL/I Reference Manual	2.15		Preprocessor Statements

string.		You can write multiple %REPLACE statements as a single
%REPLACE		statement, with the elements separated by commas.

For example, the statement

%replace true by '1'b;

replaces all occurrences of true by the bit string constant '1'b, so
that the compiler interprets the statement,

do while(true);

do while('l'b);

PL/I requires that all %REPLACE statements occur at the outer block
level before any nested inner blocks.

Note: to facilitate program maintenance and debugging, you should
write all %REPLACE statements directly following the procedure
heading.

End of Section 2

1-1~

2-23
Section 3
Data Types and Attributes

Data items in a PL/I program are either constants or variables. A
constant is a data item whose value cannot change when the program
runs, while the value of a variable can change.

Every data item is associated with a set of properties called
attributes that include such things as the amount of storage
required, the operations that can be applied, and a range of
subscript values. The DECLARE statement explicitly assigns
attributes to data variables, while in some cases, such as
constants, attributes are implicitly assigned by system defaults
(see Section 3.6).

Data variables can represent single data items. A single data item,
either a variable or constant, is called a scalar. Data variables
can also represent multiple data items called aggregates. (Section
5 describes data aggregates.)

PL/I		supports six types of data:

 arithmetic
 string
 label
 entry
 pointer
o file

The following sections describe each of these data types in detail.

3.1		Arithmetic Data

PL/I		supports three types of arithmetic data:

		FIXED BINARY for representing integer values

		FLOAT BINARY for representing numbers that can range from very
small to very large, with a floating binary point

		FIXED DECIMAL for representing decimal numbers that have a
fixed number of total digits and a fixed number of the digits
to the right of the decimal point

Each arithmetic data item has an associated precision value
expressed as an integer constant p enclosed in parentheses. The
precision p specifies the total number of decimal or binary digits
that the item can contain.

3-1
PL/I Reference Manual	3.1	Arithmetic Data

For FIXED DECIMAL numbers, p can optionally be followed by a comma
and an integer constant q called the scale factor. The scale factor
q specifies the number of digits to the right of the decimal point.

If you do not explicitly declare the precision of a variable in a
DECLARE statement, PL/I implicitly supplies it according to default
rules. The default scale factor is 0, meaning no fractional digits.

3.1.1	FIXED BINARY

FIXED BINARY data represents integers. A variable declared as FIXED
BINARY[(p)] is an integer that has p binary digits. The maximum
range of p is

1 <= p <= 15

PL/I internally represents this data type in two's complement form.
Therefore, the range of a FIXED BINARY(15) number is from -32768 to
+32767.

The amount of storage PL/I allocates for a FIXED BINARY number
depends on the precision you declare.

If p <= 7, then PL/I allocates one byte.
If 7 < p <= 15, then PL/I allocates two bytes.

The default precision for FIXED 13INARY is 15. Declaring a variable
as FIXED or BINARY, or FIXED BINARY is equivalent to declaring it as
FIXED BINARY(15).

PL/I treats decimal integers in the source program as FIXED BINARY
data only if they appear in contexts that require FIXED BINARY
values, such as subscripts or arithmetic operations involving other
FIXED BINARY data. Otherwise, constants default to FIXED DECIMAL.
In PL/I, conversion from other types of data usually occurs with
truncation (See Section 4 for the conversion rules). For example,
the following code assigns the value 1 to the variable A.

declare A fixed binary;
A = 1.99;

3.1.2	FLOAT BINARY

FLOAT BINARY data is useful in scientific applications for
representing very large or very small numbers. A variable declared
as FLOAT BINARY(p) has three parts: a sign, s; p binary digits that
are the fraction, or mantissa, and represent significant digits of
the number; and an integer exponent e, that represents the scale
factor. For example, the FLOAT BINARY number 3.56E3 has the
following parts:

3-2
PL/I		Reference Manual		3.1		Arithmetic Data
	sign	mantissa	exponent E

+	3.56	iii~

PL/I supports both single-precision and double-precision FLOAT
BINARY numbers. Table 3-1 shows the allowed precisions and the
approximate range of magnitudes for each type.

Table 3-1. PL/I FLOAT BINARY Numbers
Type			t	Precision p I	Range r
single		1 <= p <= 24	5. 88xlO-'	<= lxl<= 3.4 OX1038 (non-IEEE)
		1.18x 10-3: <=		x <= 3.4 OX1038 (IEEE)
double		25 <= p <= 53	9.46xlO-308 <=	lxl<= 1.8 OX10308 (IEEE)

The default precision for FLOAT BINARY is 24, so declaring a
variable FLOAT is equivalent to declaring it FLOAT BINARY(24).

A FLOAT BINARY constant is a number expressed in scientific notation
as a sequence of decimal digits with an optional decimal point
followed by the letter E, followed by an optionally signed decimal
integer exponent. For example, the code sequence:

A = 2.3E2;
B = -4.67E+5;
C = 1.98E-2;

assigns		the value 230 to A, -467000 to B, and 0.0198 to C.

You can mix constants of different data types in an expression.
PL/I automatically converts to the common data type before
evaluating the expression. For example, if p is declared FLOAT
BINARY, in the assignment statement

p = p + 3.14159;

PL/I converts the FIXED DECIMAL constant 3.14159 to FLOAT BINARY
format before performing the addition. (See Section 4.1.)

3.1.,		_,KED DECINAL

FIXED DECIMAL data is used for calculations where exact decimal
values must be maintained, as for example, in commercial
applications involving dollars and cents. FIXED DECIMAL data with a
zero scale factor can be used to represent integer data.

3-3
PL/I Reference Manual	3.1		Arithmetic Data

A variable declared as FIXED DECIMAL[(p[,qj)j is a decimal number
with a sign, a total of p decimal digits, with q digits to the right
of the decimal point. The maximum number of digits p for FIXED
DECIMAL is 15, and the scale factor q must be nonnegative and less
than or equal to the precision. The range of a FIXED DECIMAL number
x is

- 10**(p-q) < jxj < 10**(p-q)

where:

1 <= P <= 15		and	0 <= q <= p

All decimal constants, with or without a decimal point, default to
FIXED DECIMAL. The only exception is when the constant is used in a
FIXED BINARY context. The default precision for a FIXED DECIMAL
variable is 7. The default scale factor for a FIXED DECIMAL
variable is 0. For a FIXED DECIMAL constant, the form implicitly
determines its default precision and scale factor. For example,

3.25 defaults to FIXED DECIMAL(3,2)
302 defaults to FIXED DECIMAL(3,O)

Internally, PL/I represents decimal numbers in ten's complement
packed BCD format. The number of bytes occupied by a FIXED DECIMAL
number depends on its declared precision. If the precision is p,
the number of bytes reserved is the integer part of

(p+2)/2

resulting in a minimum of one byte and a maximum of eight bytes.

PL/I truncates any value whose scale factor is greater than that of
the FIXED DECIMAL variable to which it is assigned. Also, PL/I
signals a FIXEDOVERFLOW condition if a value assigned to the
variable has more significant digits to the left of the decimal
point than the declared precision of the variable allows.

3.2		String Data

PL/I		supports two types of string data:

 character string
 bit string

A character string is any sequence of ASCII characters, including
the empty sequence, which is the null string. A bit string is a
sequence of bits. The length of a string is the number of
characters or bits in the string. The following sections describe
each type of string data.

3-4
PL/I Reference Manual	3.2		String Data

3.2.1 Character-string Data

A variable declared as CHARACTER(n) is a character string of length
n, where n is a value between 1 and 254. For example, the
statement,

declare A character(10);

defines the variable A as a character string ten characters long.
If a character string assigned to A is shorter than A, PL/I pads the
string with blanks on the right to the length of A. If a longer
string is assigned to A, PL/I truncates the string on the right.

Character-string constants are a sequence of characters enclosed in
apostrophes. If an apostrophe is part of the string, it is written
as two consecutive apostrophes. Thus, the string constant whose
value is

	What's Happening?
	is written as:

'What''s Happening?'

The null or empty character string has a length of zero and is
defined by using two consecutive apostrophes.

Character-string variables can also have the VARYING attribute
indicating that the variable can represent varying length strings to
a maximum length of n. For example, the statement,

declare A character(10) varying;

defines A to represent any character-string value whose length can
vary from 0 to 10.

PL/I allows control characters in string constants. The circumflex
character (-) in a string constant indicates a control character.
PL/I masks the high-order three bits of the character to zero, thus
converting the string -M, or m, to a carriage return character.
Similarly, it converts the string -I to the horizontal tab
character. PL/I translates a double circumflex (^^) within the
string to a single ^ character.

Note: you should avoid using the control character feature if
compatibility is a requirement, because the circumflex escape
convention is not available in other implementations.

3.2.2 Bit-string Data

Bit strings represent logical data items. A bit string containing
all zero-bits is false; a bit string containing any one-bits is
true.

3-5
PL/I Reference Manual	3.2	String Data

A variable declared as BIT(n) is a bit-string data item containing n
bits, where n is a value between 1 and 16. For example, the
statement,

declare A bit(3);

defines a bit string of length 3. If a bit string assigned to A is
shorter than A, PL/I pads the string with zero-bits on the right to
the length of A. If a longer string is assigned to A, PL/I
truncates the string on the right.

Note:	bit-string variables cannot have the VARYING attribute.

You can write bit-string constants in any of four different formats.
Each format corresponds to a base which is the number of bits used
to represent each digit in the constant. A bit-string constant is a
sequence of digits and letters enclosed in apostrophes followed by
the letter B, and optionally followed by a digit indicating the
base. The default base is 2, indicated by B or Bl. Table 3-2
shows the various formats.

Table 3-2. Bit-String Constant Formats

- Format	=Base	Digits and/or Characters in Representation
	B	2	O'l
	Bi	2	O'l
	B2	4	0,1,2,3
	B3	8	0,1,2,3,4,5,6,7
	B4	16	0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F

Note: the characters and/or digits used in the sequence must be
valid for the base specified by the format.

The following examples illustrate the equivalence of the optional
formats to the base 2 format:

1101'Bl		is	equivalent	to	'101'B
11011B2		is	equivalent	to	'010001'B
'101'B3		is	equivalent	to	'001000001'B
'101'B4		is	equivalent	to	'000100000001'B
'9A'B4	is		equivalent	to	110011010'B
'77'B3	is		equivalent	to	'111111'B

3.3 Control Data Items

Control data items determine the flow of control when a program
runs. PL/I support two types of control data:

 LABEL data
 ENTRY data

3-6
PL/I Reference Manual	3.3 Control Data Items

3.3.1 LABEL Data

LABEL data consists of label constants and label variables. A label
constant is a label identifier that prefixes an executable
statement. A label variable is a variable defined in a DECLARE
statement with the LABEL attribute. The form is

DECLARE name LABEL;

and PL/I supplies the VARIABLE attribute by default. A label
variable can take on the value of different label constants when the
program runs.

You cannot explicitly declare a label constant in a DECLARE
statement. However, any name used as statement label constitutes an
implicit declaration of the name as a label constant. PL/I does not
allow labels on the following statements:

 the DECLARE statement

 the statement that begins an ON-unit (see Section 9.1)

 the statement that begins an ELSE or THEN clause (see Section
8.3)

Assignments of label constants or other label variables can be made
to a label variable using the same rules as assignments of other
types of variables.

The only operators that you can use with LABEL data are the equal
(=) and not equal (^= or -=) comparison operators.

Both label constants and label variables are subject to the same
scope rules as declared names. A LABEL data item is known only
within the block in which it is declared explicitly by a DECLARE
statement, or implicitly by its use as a label constant. The
occurrence of the same label name within any other block, including
a contained block, defines a new declaration local to that block.

You can subscript label constants using a single, optionally signed,
integer constant. All occurrences of subscripted labels with the
same identifier in a single block constitute an implicit declaration
of a constant-label array for that block. Any such implicitly
defined constant-label array is defined only for those subscripts
that occur in its corresponding block. You can explicitly define
label variables to be singly subscripted arrays in a DECLARE
statement.

3-7
PL/I Reference Manual	3.3 Control Data Items

The following code sequence illustrates a constant-label array:

case-num (1)

case-num(2):

cas;-num(3):

PL/I treats case - num as if it was declared as an array in the block
containing the subscripted labels. Therefore, you can reference any
element in the array using a GOTO statement (see Section 8.5) such
as:

goto case_num(i);

where i is an integer. The value of the variable i represents which
label is to receive control.

Note: PL/I does not treat the labels on FORMAT (see Section 11.3.5)
or PROCEDURE statements as valid labels, but rather as FORMAT
constants and ENTRY constants, respectively. They cannot be the
targets of GOTO statements.

The following code sequence illustrates label variables:

declare do-it label;

if	(answer = 'yes') then
	do - it = geometric_mean;
else
	do-it = arithmetic-mean;

goto do-it;

In this example, the GOTO statement transfers control to either of
the labels geometric - mean or arithmetic-mean depending the current
value of the label variable do it, which is based on the result of
the test in the IF statement.

3-8
PL/I Reference Manual	3.3		Control Data Items

3.3.2 ENTRY Data

In PL/I all ENTRY data items are either entry constants or entry
variables. Entry constants correspond to either internal
procedures, or to separately compiled external procedures. Entry
variables are data items that can take on entry-constant values when
the program runs.

The calling program must use an ENTRY declaration to define the
characteristics of the parameters and returned values for all
externally compiled procedures.

Note: you must ensure that the ENTRY declaration matches the
externally defined procedure, so that the linkage editor can
properly combine the program segments.

Variables that take on entry constant values are also defined with
an ENTRY declaration. If required by the application, entry
variables can be subscripted, but entry constants cannot. As with
LABEL data, the only operators used with ENTRY data are the equal
and not equal comparison operators.

The declaration of an external entry constant has the form:

DECLARE entry-name		[EXTERNAL]
	[ENTRY[(parameter-list)]
[RETURNS(return-att)];

The declaration of an entry variable has the form:

DECLARE entry-name		[(bound-pair-l,...,bound-pair-n)I
	[ENTRY[(parameter-list)] VARIABLE
[RETURNS(return-att)];

where the attributes can be in any order, but must specify either
ENTRY or RETURNS.

The identifiers are given in the following manner:

e		entry-name gives the name of the ENTRY variable or constant.
e		bound-pair-l,...,bound-pair-n gives the optional bound-pair
	list.
* parameter-list gives the list of parameter attributes.
e return-att gives return-value attribute.

The EXTERNAL attribute indicates that entry-name is a separately
compiled procedure. The VARIABLE attribute indicates that entry
name is an entry variable that must be assigned an entry constant
value when the program runs. The RETURNS attribute implies that
entry-name is a function rather than a subroutine.

3-9
PL/I Reference Manual	3.3 Control Data Items

You can omit the list of parameter attributes if the procedure does
not require any parameters. In this case, you can also omit the
ENTRY attribute if you specify the RETURNS attribute. If you
specify a bound-pair list, you must use the VARIABLE attribute. If
you do not specify either EXTERNAL or VARIABLE, PL/I supplies
EXTERNAL as the default.

If a particular parameter has the dimension attribute, it must
appear as the first attribute. If the parameter is a structure, the
structuring information that the level numbers provide must precede
the attribute definition. (See Section 5.5.)

The following are some examples of ENTRY declarations:

declare X entry;
declare Y entry variable;
declare P (0:10) entry(fixed,float) variable;
declare Q entry(l, 2 fixed, 2 float,(5:10) decimal);
declare R returns(character(10));
The following code sequence illustrates entry data items:

declare
(X,Y) float binary,
A entry variable,
F(3) entry(float) returns(float) variable,
ZZ entry(float) returns(float);
Pl:
procedure;
X=5;
end Pl;
P2:
procedure;
X=25;
end P2;
Y=9;
if Y = 5 then
A = Pl;
else
A = P2;
call A;
F(2) = ZZ;
Y = F(2)(X);
put list(Y);

3-10
PL/I Reference Manual	3.4		POINTER Data

3.4		POINTER Data

POINTER data items address specific locations in memory. The value
of a POINTER data item is the address of a variable in the program.
A POINTER variable declaration has the form:

DECLARE X POINTER;

PL/I does not perform conversion between POINTER and other data
types, so an assignment statement can only assign pointer variables
to other pointer variables. Also, pointer variables cannot be
output to a STREAM file (see Section 11) . As with LABEL and ENTRY
data, the only operators defined for POINTER data are the equal and
not equal comparison operators. Two pointers are equal if they
represent identical storage locations.

You can use POINTER data with based variables to dynamically manage
storage. Section 7.2 describes based variables.

3.5		FILE Data

FILE data items consist of file constants and file variables that
access external data. A file constant declaration has the general
form:

DECLARE file-id FILE;

A file variable declaration has the form:

DECLARE file-id FILE VARIABLE;

where file -_ id is a PL/I identifier assigned to represent the file.
If file - id is not a parameter, PL/I automatically treats the
identifier as EXTERNAL, so that it accesses the same data set in all
modules that declare it EXTERNAL.

If you do not open the file explicitly with an OPEN statement
including the TITLE option, PL/I accesses the disk file named
file-id.DAT on the default drive.

Section 10 presents FILE data in more detail. The PL/I Language
Programmer's Guide contains examples of FILE data use.

3.6		The DECLARE Statement

In PL/I, you must use the DECLARE statement to define all variable
names in a program that are not the names of built-in functions or
pseudo-variables (Section 6.8). File constants and variables must
also be defined in a DECLARE statement. Control constants, such as
statement labels and procedure names, are declared implicitly by
their use in a program.

3-11
PL/I Reference Manual	3.6	The DECLARE Statement

The DECLARE statement associates each variable name with the proper
attributes for the declared data type. The simple form of the
DECLARE statement for scalar variables is
DECLARE name [attribute-list];

where name is the variable identifier, and attribute-list is one or
more characteristics of the variable name. Multiple attributes can
appear in any order but must be separated by spaces.
The following examples illustrate DECLARE statements:

declare x fixed binary;
declare pi float binary(53);
declare overtime_pay fixed decimal(5,2) initial(OOO.00);
declare EOF bit(l) initial('l'b);
declare list-head pointer static initial(null);

3.7 Multiple Declarations

For convenience and simplicity, PL/I allows multiple declarations in
a single statement. Usually, you can write any sequence of DECLARE
statements of the form,

DECLARE definition-1;
DECLARE definition-2;

DECLARE definition-n;

in the equivalent form:
DECLARE definition-1, definition-2, ... definition-n;

where each definition item is separated by commas and zero or more
spaces, and the DECLARE statement is terminated by a semicolon.

If several item definitions share the same attributes, you can
factor them to the right. That is, you can write a sequence of
definitions of the form,
item-1 attr-A, item-2 attr-A, ... item-n attr-A
in an equivalent factored form:
(item-1, item-2, ... item-n) attr-A
For example,
declare (first-name,last-name) character(20) varying;

3-12
PL/I Reference Manual	3.7		multiple Declarations

Repeated applications of this rule are also allowed. For example,
the statement:

	declare ((A,B) fixed binary, C float binary) static external;
	is equivalent to the statement:

declare		A fixed binary static external,
B fixed binary static external,
C float binary static external;

3.8		Default Attributes

An attribute list cannot contain conflicting attributes, such as two
data types, or two storage class attributes. If you do not specify
a complete set of attributes in a DECLARE statement, then the
compiler supplies the attributes according to the following default
rules:

		If no attribute is specified, FIXED BINARY(15) is assumed.

		If DECIMAL or BINARY is specified without FIXED or FLOAT, then
FIXED is assumed.

		If FIXED or FLOAT is specified without BINARY or DECIMAL, then
BINARY is assumed.

		If no precision for FIXED BINARY is specified, FIXED BINARY(15)
is assumed.

		If no precision and scale factor for FIXED DECIMAL is
specified, FIXED DECIMAL(7,O) is assumed.

		If no precision for FLOAT BINARY is specified, then FLOAT
BINARY(24) is assumed.

		If no length is specified for BIT, then BIT(l) is assumed.

		If no length is specified for CHARACTER, then CHARACTER(l) is
assumed.

End of Section 3

3-13
Section 4
Data Conversion

Data conversion is the process that changes the representation of a
given value from one type to another. In PL/I, all conversion
involves a source, a target, and a result. The source is the data
item being converted; the target is the type to which the source
item is being converted, and the result is the actual converted
value with the data type of the target.

PL/I performs conversions in the following general categories:

arithmetic to arithmetic (type and precision)
arithmetic to string
string to arithmetic
format specified in EDIT-directed 1/0 (see Section 13)

PL/I does not perform conversion of ENTRY, FILE, LABEL, or POINTER
values.

Part of the versatility and power of PL/I lies in your freedom to
declare data in a wide variety of types. With this freedom comes a
responsibility to understand how the language converts data from one
type to another, either explicitly or implicitly.

The following list shows some of the contexts in which PL/I performs
default data conversion.

		In an assignment statement, PL/I converts the expression to the
type of the variable to which it is assigned.

variable = expression;

		In a RETURN statement, PL/I converts the specified value to the
type specified in the RETURNS attribute of the PROCEDURE
statement.

proc-name:
PROCEDURE		RETURNS(return-att);

	RETURN (return-exp);
	END [proc-namel;
PL/I Reference Manual	4	Data Conversion

		In any arithmetic expression, if the operands are not the same
type, PL/I converts them to a common type before performing the
operation. For example, if A is FLOAT BINARY and B is FIXED
BINARY, in any of the following operations

A + B
A B
A B
A B
A B

the common type is FLOAT BINARY, and PL/I converts B in each
case.

		During 1/0 processing, PL/I converts to and from character
string data when using the PUT or GET statements respectively.
For example, if I is a FIXED BINARY value, in the statement

PUT LISTM;

PL/I converts I to CHARACTER. In the statement:

GET LISTM;

PL/I converts characters in the input stream from CHARACTER to
FIXED BINARY.

		PL/I converts values specified in some statements to integer
values. For example, in the iterative DO-group

DO control-variable = start-exp TO end-exp BY incr-exp;

END;

PL/I converts the start-exp, the end-exp, and the incr-exp to
integers (FIXED BINARY) value before executing the DO statement.

		PL/I has built-in functions (BIFS) that perform specific
conversions.

4.1	Arithmetic Conversions

PL/I performs arithmetic conversions in several contexts. The first
context is when an assignment statement assigns an arithmetic
expression to an arithmetic variable. PL/I converts the expression
to the precision and scale factor of the target variable.

Another context is when an arithmetic-valued function returns an
arithmetic expression with a RETURN statement. PL/I converts the
expression to the target data type, with the precision and scale

4-2
PL/I Reference Manual	4.1		Arithmetic Conversions

factor specified in the RETURNS attribute of the function's
declaration.

When any arithmetic infix operator, other than exponentiation, has
operands with different data types, PL/I performs a three-step
process.

Step One

PL/I determines the common type of the two operands.

		Case A. If one operand is FIXED BINARY and the other is FLOAT
BINARY, the common type is FLOAT BINARY.

		Case B. If one operand is FIXED BINARY and the other operand
is FIXED DECIMAL, the common type is FIXED BINARY.

		Case C. If one operand is FLOAT BINARY and the other operand
is FIXED DECIMAL, the common type is FLOAT BINARY.

Table 4-1 summarizes the common type in expressions involving
mixed operands.

Table 4-1. Common Operand Types in Mixed Operand Expresssions

Operand 2

	FIXED BINARY		FLOAT BINARY	FIXED DECIMAL
Operand I

FIXED BINARY		FIXED BINARY	FLOAT BINARY	FIXED BINARY

FLOAT BINARY		FLOAT BINARY	FLOAT BINARY	FLOAT BINARY

FIXED DECIMAL		FIXED BINARY	FLOAT BINARY	FIXED DECIMAL

Step Two

PL/I converts one of the operands to the common type.

e		Case A. If the common type is FLOAT BINARY then

-		PL/I converts a FIXED BINARY(p) operand to FLOAT BINARY(p)

-		PL/I converts a FIXED DECIMAL(p,q) operand to FLOAT
BINARY (pl ) , where p' = MIN (CEIL (p/3. 322) 53) . MIN and CEIL
are PL/I BIFs (Section 15).
PL/I Reference Manual	4.1	Arithmetic Conversions

Case B. If the common type is FIXED BINARY then

- PL/I converts a FIXED DECIMAL(p,O) operand to FIXED
BINARY(p'), where p' = MIN(CEIL(p/3.322),15)

Note: PL/I cannot convert a FIXED DECIMAL (p,q) operand to FIXED
BINARY if q ^= 0.

Step Three

After converting to a common type, PL/I derives the precision (and
scale factor) of the result. The result type depends on the common
type.

	Case A. If the common type is FIXED BINARY, the result is
FIXED BINARY. If p, is the precision of the first operand, and
P2 is the precision of the second operand, PL/I derives the
precision of the result pl depending on the operation.

For addition or subtraction,

p I = (MIN (15, MAX (p, , p, ) +1)

For multiplication,

p' = (MIN(15,p, +p2+1))

For division, you must use the DIVIDE BIF with a scale factor
of zero to produce an integer FIXED BINARY result, because PL/I
Subset G does not support a FIXED BINARY data type with a non
zero scale factor.

	Case B. If the common type is FLOAT BINARY, the result is
FLOAT BINARY. The precision of the result is MAX (p, FP2) r where
p, and P2 are the precisions of the two operands.

	Case C. If the common type is FIXED DECIMAL, the result is
FIXED DECIMAL. If the first operand has precision and scale
factor(p,,q,), and the second operand has precision and scale
factor (P2 q2) I PL/I derives the precision and scale factor of
the result (p',q') depending on the operation.

For addition or subtraction,

pl = MIN(l5,MAX(p,-q,,p,-q2) + MAX(q,,q 2)+l)

q' = MAX(q,,q 2)

For multiplication,

p' = MIN(15'PI+P2+1)

q' = (ql+q 2)

4-4
PL/I Reference Manual	4.1		Arithmetic Conversions

For division,

P' = 15

q' = 15-(p,+q,-q,)

Note: use caution when dividing FIXED DECIMAL values. The
precision and scale factor of the operands must be such that
the divide operation does not produce a negative scale factor.
You can use the DIVIDE BIF to control the precision of the
quotient.

If the infix operator is that of exponentiation, expressed as
X**Y, there are two cases.

		Case A. Y is a decimal integer constant. If X is FIXED BINARY
with precision p and ((p+l)*Y-1) <= 15, then the result is
FIXED BINARY with precision

P, = ((P+1)*Y-l)

If X is FIXED DECIMAL with precision and scale factor (p,q) and
((p+l)*Y-1) <= 15, then the result is FIXED DECIMAL with
precision and scale factor (p',q'):

P, = (P+1)*Y-l

q' = q*Y

		Case B. If either operand is FLOAT BINARY, PL/I converts the
other operand to FLOAT BINARY and the result is FLOAT BINARY
with precision p' = MAX(p, IP 2 ) where p, and p 2 are the
precisions of the operands.

In any arithmetic operation involving conversion, PL/I truncates the
result if the declared precision of the target is insufficient to
hold the value. Truncation occurs on the right for FLOAT BINARY
data items, and fractional digits are lost in FIXED DECIMAL
computations. In FIXED BINARY computations, unpredictable results
occur if the absolute value of any intermediate value exceeds 32767.

Thedefault precision for floating-point values is FLOAT BINARY(24).
However, if you declare a literal constant with more than 7
significant decimal digits, PL/I automatically stores it as double
precision. In expressions involving FLOAT BINARY operands of
different precisions, PL/I performs conversion to the greater
precision. For example, if A is FLOAT BINARY(24) and B is FLOAT
BINARY(53), in the expression:

A = A + B;

4-5
PL/I Reference Manual	4.1	Arithmetic Conversions

PL/I first converts A to double precision, performs the addition,
and then converts the result back to single precision.

Note: use caution when performing assignments involving mixed
precision expressions. The largest positive number representable as
a single-precision value is 3.40 * 1038 . whereas the largest
positive number representable as a double-precision value is 1.80 *
lo308 . Therefore, if 3.40 * 1038 < N <= 1.80 * 10308 , and you
assign N to a single-precision variable, the run-time system signals
the arithmetic error condition

OVERFLOW(2)

Conversely, the smallest positive number representable as a single
precision value is 5.88 * 10-39 , whereas the smallest positive
number representable as a double-precision value is 9.46 * 10 -30 8
If 5.88 * 10-39 < N <= 9.46 * 10-308 , and you assign N to a
single-precision variable, the run-time system signals the
arithmetic error condition:

UNDERFLOW(2)

4.2	Arithmetic Conversion Functions

PL/I provides a number of BIFs to control conversion from one
arithmetic data type to another. They are

 BINARY
 DECIMAL
 DIVIDE
 FIXED
e FLOAT

The following sections describe these functions.

4.2.1	The BINARY BIF

The BINARY BIF has the form:

BINARY(X[,p]) I BIN(X[,p])

where X is the arithmetic variable or string expression to be
converted to a BINARY arithmetic data type, and p is the target
precision.

When converting arithmetic variables, if X is FIXED BINARY or FIXED
DECIMAL, the result is FIXED BINARY. If X is FLOAT BINARY, the
result is FLOAT BINARY.

4-6
PL/I Reference Manual	4.2		Arithmetic Conversion Functions

If you do not specify p, then the result is as follows:

X FLOAT BINARY(p) returns FLOAT BINARY(p)
X FIXED BINARY(p) returns FIXED BINARY(p)
X FIXED DECIMAL(p,q) returns FIXED BINARY(MIN(CEIL((p-q)*3.322)+1,15))

4.2.2		The DECIMAL BIF

The DECIMAL BIF has the form:

DECIMAL(X[,p[,q]]) I DEC(X[,p[,q]])

where X is the arithmetic variable or expression to be converted to
a FIXED DECIMAL arithmetic data type, and p and q are the precision
and scale factor of the result. A non-zero scale factor is valid
only if X is FIXED DECIMAL. If you do not specify p and q, then the
result is as follows:

X FIXED BINARY(p)		returns	FIXED DECIMAL(CEIL(p/3.322)+1,0)
X FLOAT BINARY(p)		returns	FIXED DECIMAL(MIN(CEIL(p/3.322),15),O)
X FIXED DECIMAL(p,q)		returns	FIXED DECIMAL(p,q)

4.2.3		The DIVIDE BIF

The DIVIDE BIF controls the precision and scale factor of results
for divide operations. The DIVIDE BIF has the form:

DIVIDE(X,Y,p[,q])

where X and Y are arithmetic expressions, and X is to be divided by
Y. p is a FIXED BINARY expression indicating the desired precision,
and q is a FIXED BINARY expression indicating the desired scale
factor. if you do not specify q, the default is 0. A nonzero scale
factor is valid only if X and Y are FIXED DECIMAL.

PL/I requires the DIVIDE function for FIXED BINARY division. In the
full language FIXED BINARY division can generate a nonzero scale
factor, but PL/I Subset G does not support non-zero scale factors
for FIXED BINARY values.

4.2.4		The FIXED BIF

The FIXED BIF has the form:

FIXED(X[,p[,qll)

where X is the arithmetic variable or expression to be converted to
a FIXED arithmetic data type, and p and q specify the target
precision and scale factor.

4-7
PL/I Reference Manual	4.2	Arithmetic Conversion Functions

If X is FIXED DECIMAL, the result is FIXED DECIMAL. Otherwise, the
result is FIXED BINARY. If X is FIXED BINARY, you must specify q
0. A nonzero scale factor is valid only if X is FIXED DECIMAL.

If you do not specify p or q, then the result depends on the
precision and scale factor of X as follows:

X FIXED BINARY(p)	returns	FIXED BINARY(p)
X FLOAT BINARY(p)	returns	FIXED BINARY(MIN(15,p)
X FIXED DECIKAL(p,q)	returns	FIXED DECIMAL(p,q)

4.2.5	The FLOAT BIF

The FLOAT BIF has the form:

FLOAT(X[,p])

where X is the arithmetic variable or expression to be converted to
a FLOAT arithmetic data type, and p is the target precision. If you
do not specify p, then the result is as follows:

X FIXED BINARY(p) returns FLOAT BINARY(p)
X FLOAT BINARY(p) returns FLOAT BINARY(p)
X FIXED DECIMAL(p,q) returns FLOAT BINARY(MIN(CEIL((p-q)*3.322),53))

4.3	String Conversions

PL/I performs conversion between arithmetic and nonarithmetic string
data items when they are combined in expressions. Table 4-2 shows
the built-in functions used for converting between arithmetic and
nonarithmetic data types.

Table 4-2. PL/I Bus for Conversion
Between Arithmetic and Nonarithmetic Data Types
Conversion	I	PL/I BIF

Arithmetic to Bit	BIT(S[,Ll)
Arithmetic to Character	CHARACTER(S[,Ll)
Bit to Arithmetic	BINARY(X[,Pl)
Bit to Character	CHARACTER(S[,L])
Character to Arithmetic	BINARY(X[,Pl)
	FLOAT(X[,p])
	DECIMAL(X[,p[,qll)
Character to Bit	BIT(S[,Ll)

The following sections describe these PL/I BIFs and the various
conversion rules for string operands.

4-8
PL/I Reference Manual	4.3		String Conversions

4.3.1 Arithmetic to Bit-string Conversion

The BIT BIF has the form:

BIT(S[,Ll)

where S is an arithmetic or string expression, and L is a positive,
FIXED BINARY expression.

PL/I first converts ABS(S) to FIXED BINARY according to the
arithmetic conversion rules. It then converts the FIXED BINARY
intermediate value to a bit string of length L.

If the target length is longer than L, PL/I pads the intermediate
result on the right with zero-bits. If the target length is less
than L, it truncates the right excess bits of the intermediate
result.

4.3.2 Arithmetic to Character Conversion

The CHARACTER BIF has the form:

CHARACTER I CHAR(S[,Ll)

where S is an arithmetic or string expression, and L is a positive,
FIXED BINARY expression.

PL/I		first converts the various arithmetic data types to
intermediate character strings as follows:

 FIXED BINARY(p)

PL/I converts the source to FIXED DECIMAL(p'), where p'
CEIL (p/3.322) +1, and then converts the FIXED DECIMAL (p' ) result
to a character string of length p'+3 with the format described
above.

For example, converting a FIXED BINARY(15) data item with value
-32 results in the character string VVVVVV-32.

 FLOAT BINARY(p)

PL/I converts the fractional part to a FIXED DECIMAL (p' where
pl = CEIL(p/3.322). The resulting character string is of
length p'+6 for single precision, or p'+7 for double precision
in scientific notation format. That is, the first character is
a minus sign if the source value is negative, otherwise the
position contains a space.

The next position contains the most significant digit of the
value, followed by a decimal point, and the remaining p-l
fractional digits. The exponent indicator E follows, with an

4-9
PL/I Reference Manual	4.3	String Conversions

exponent sign and an exponent value. Single precision
exponents have two digits, and double precision exponents have
three digits.

For example, converting a FLOAT BINARY(24) data item with value
250.1E1 results in the character string V2.5010000E+03.

 DECIMAL(p,q), q = 0

The resulting character string is length p+3. The characters
are composed of the digits of the source, without leading
zeros, preceded by a minus sign if the source value is
negative, and padded on the left with blanks to produce a
character string of length p+3.

For example, converting a FIXED DECIMAL (3) data item with value
330 results in the character string ~#330, where X denotes a
blank position. Converting the value zero produces five blanks
and a single zero digit result.

 DECIMAL(p,q), q > 0

The resulting character string is also of length p+3, with the
same string format as above, except that the decimal point and
the fractional digits are included.

For example, converting a FIXED DECIMAL(5,2) data item with
value -13.25 results in the character string VO-13.25. PL/I
omits leading zeros except for the one immediately preceding
the decimal point.

After performing the intermediate conversions, PL/I pads the
string on the right with blanks if the target length is greater
than the length of the intermediate result. Conversely, if the
target length is shorter than the intermediate result, PL/I
truncates the string on the right to produce the shorter
length.

4.3.3	Bit-string to Arithmetic Conversion

The BINARY BIF is described in Section 4.2.1. When used to convert
a bit string of length n (0 <= n <= 15) to an arithmetic data type,
PL/I first converts the string to its FIXED BINARY(15) equivalent.
PL/I then converts the FIXED BINARY intermediate value to the target
value according to the rules discussed in Section 4.1.

For example, '11011B converted to FIXED BINARY(15) yields the value
13.

4-10
PL/I Reference Manual	4.3		String Conversions

4.3.4		Bit to Character-string Conversion

The CHARACTER BIF is described in Section 4.3.2. when used to
convert a bit string of length n (0 <= n - 15) to a character
string of length n, PL/I converts a zero-bit to a 0 character and a
one-bit to a 1 character. If the target length is longer than the
source, PL/I pads the target on the right with blanks. If the
target length is shorter than the source length, PL/I truncates the
excess characters on the right.

4.3.5		Character to Arithmetic Conversion

The conversion functions apply as follows:

		FIXED(Xt,p[,q]] ) or DECIMAL(X[,p[,q]]) returns a FIXED DECIMAL
value. If you do not specify p, the default is 15.

		BINARY(X[,p)) returns a FIXED BINARY value. If you do not
specify p, the default is 15. The result is only the integer
part of X.

		FLOAT(X[,p]) returns a FLOAT BINARY value. If you do not
specify p, the default is 53. If X is null or contains all
blanks, the converted value is zero. If the target is not
declared with sufficient precision to hold the converted value,
the run-time system signals OVERFLOW(2) or UNDERFLOW(2).

When performing character to arithmetic conversion, the character
string must contain a valid arithmetic constant value. PL/I signals
the ERROR(l) condition if the character string is not a valid
arithmetic representation.

The following examples illustrate various conversions from character
to arithmetic data types:

Table 4-3. Character to Arithmetic Conversion

Result
Character		Target
'009871	FIXED BINARY(15)	987
19.871	FIXED DECIMAL(6,2)	0009.87
'-9.87E2'	FLOAT BINARY(24)	-9.87E2
'-9.87E2'	FIXED DECIMAL(9,2)	0000987.00
1-9.87E2'	FIXED DECIMAL(5.0)	00987
'-987.3721	FIXED DECIMAL(4,2)	ERROR
12X36	FIXED BINARY(15)	ERROR
	FIXED BINARY(15)	0
	FIXED BINARY(15)	0

4-11
ZT -17

v UoTqOqS go pua

	-sqTq-ojaz go buijqs e si
	qTnsai aqq uaqq 'SNuvTq TTP SUTP4UOD JO JbUTJ4s TTnu aqq si aoinos
	a TT4 -4 1 -qqbTj aqq uo saqpc)unj,4 4T uaLI,4 lql6u8T aoinos aqq upqq
	J94joqs ST qq6uaT 4abJP4 944 JI *sqTq-ojaz q4Tm qqbTj aqq uo sped
	I/ad u9q4 'q46uaT aoinos aq4 ueqq J9:je8J6 ST Lj46U9-[ 196Jel a44 JI

-UOTqpquasajdaj qTq PTTeA P qOU ST BUTJJS J94OeJPqO aqj
JT UOTjTPUOO (T)HOUUS aLl'4 sTPUf:)TS I/Ild -s5jue q pappaqwe Auv qou qnq
T
JSNUPTq 6UTTTeJ4 JO BuTP991 ule-4uOO OSTP upO :iI -T PUP 0 SJ9-40eJPtlO
aLl-4 A-[uo uiequoo -4snw 6UTJ-4S ja-4oeieqo aoinos 9LI-4 'UO-[S.79AUOO BU7 ' I J-4S
-qTq ol iaqoejeqo f:)uiwj*ogjad uaqm		-qTq-euo e oq JaqOvJe4O T Ljoea
pup lqTq-ojaz e ol Ja4OPJPqO 0 q3ga SqJ9AUOD I/qd '6UTJ4S J940PIERO
e 4J9AUOO 04 pasn uaqt4			-T-E-V u0140aS ul paqTjosap ST ais jis aqi

UOTSJOAU03 i5UTJjS-4Tff 04 jaqaPjeqO 9-E-t

SUOTSlaAUOD 6UTa4S			E-V	lenuew aouaiaja-d i/qd
Section 5
Data Aggregates

An aggregate is a grouping of multiple data items. In PL/I, there
are two kinds of aggregates: arrays and structures.

		An array is an ordered collection of data items called elements
which all have the same attributes. The elements of an array
can be scalar data items or structures. PL/I allows you to
reference an entire array by name, or to reference an
individual element of an array by using integer subscripts that
denote the relative position of the element in the array.

		A structure is a collection of data items called members which
can have different data types. The members of a structure can
be arrays. PL/I allows you to reference an entire structure by
name, or to reference an individual member of a structure with
a qualified reference that gives both the name of the structure
and the name of the member.

A variable that represents a data aggregate is called either an
array variable or a structure variable.

5.1 Array Declarations

You define an array variable by specifying its attributes in terms
of the number of elements in the array and the organization of the
elements. These attributes are called the dimensions of the array.
The general form of an array variable declaration is

DECLARE name(bound-pair .... ) [attribute-list);

where name is any valid PL/I identifier. Each bound-pair specifies
the number of elements in each dimension of the array and has the
format:

[L-IU

where L is the lower-bound of the array, and U is the upper-bound.
The values L and U can be any integer values such that L is less
than or equal to U.

The attribute-list is the set of data attributes that apply to all
the elements in the array. The ordering of attributes is
unimportant, but the bound-pair list must precede the attribute
list.

5-1
PL/I Reference Manual	5.1 Array Declarations

The number of elements in each dimension is the extent, and is given
by

(upper bound) - (lower bound) + 1

The total number of elements in an array is the product of the
extents of each dimension.

For example, the following statements are equivalent:

declare A(3,4) character(2);
declare A(1:3,1:4) character(2);

Both statements define an array whose dimension is two, and whose
elements are character strings of length two. The extent of the
first dimension is 3, and the extent of the second dimension is 4.
Thus, you can visualize A as an array with three rows and four
columns whose elements are character strings of length two.

1	2	3 	4

1	XX	XX	XX 	XX

2	XX	XX	XX 	XX

3	XX I XX I XX I XX

Figure 5-1. Two-dimensional Array

The statement

declare B(-2:5,-5:5,5:10) fixed binary;

defines the array B to be a three-dimensional array whose subscripts
range from -2 to 5, -5 to 5, and 5 to 10, respectively. The
corresponding extents are eight, eleven, and six, respectively.
Thus, B contains 528 data items of FIXED BINARY data type.
PL/I Reference Manual	5.1 Array Declarations

The following rules apply when specifying dimensions in an array:

		In PL/I, there is no formal limit to the number of dimensions
an array can have. However, the practical limit is limited by
the total amount of available data storage, and the overall
complexity of any expression that you use to reference an
individual element within the array.

		All bounds must be integer constants.

		The lower bound must be less than or equal to the upper bound.

		At run-time, an out-of-bound array reference produces
unpredictable results.

5.2 Array References

In PL/I , any reference to an individual array element must be
subscripted. The list of subscripts must be enclosed in
parentheses. In multidimensional arrays, the number of subscripts
must match the number of dimensions.

A subscripted reference to an array element can be any variable or
expression that PL/I converts to an integer value. For example,

declare scores(20) fixed binary;
declare (counter, total) fixed binary;
total = 0;
do		counter = 1 to 20;
	total = total + scores(counter);
end;

Figure 5-2 illustrates the concept of subscripted array references.

DECLARE ARRAY-A(4) FIXED; /* 4 COLUMNS

	#	4
	ARRAYA(1) 	ARRAY-A(3)

Figure 5-2. Array Element References

5-3
PL/I Reference Manual	5.2	Array References

DECLARE ARRAY-B(3,4) FIXED;/* 3 ROWS, 4 COLUMNS V

2	3	4

ARRAY-B(1,4)

1
2
3 	m 		-

ARRAY-B(3,3)

DECLARE ARRAY-C(2,3,4) FIXED; /* 2 PLANES, 3 ROWS, 4 COLUMNS
2	3	4
2 Z:
A
C, 42., I ~ WO

-ARRAY-C(1,1,3)

2	ARRAY-C(2,3,4)

3

Figure 5-2. (continued)

5-4
PL/I Reference Manual	5.3		Initializing Array Elements

5.3		Initializing Array Elements

You can use the INITIAL attribute with an array declaration to
specify values for the elements before execution. For example, the
statement

declare		colors(4) character(10) varying
	static initial ('RED','BLUE','GREEN','YELLOW')

assigns a value to each of the elements of the array as shown in
Figure 5-3.

1	2	3	4
RED	BLUE			I	GREEN I 	YELLO

Figure 5-3. Array Initialization

If you assign each element of an array the same value, the INITIAL
attribute can specify an iteration factor in the form:

	INITIAL(value[,value] ...
	where value has the form:

[(iteration-factor)] constant-expression

The iteration factor is an unsigned decimal constant indicating the
number of times to use the specified constant. The constant
expression can be any reference to an arithmetic or string constant
or to the NULL built-in function, and must be compatible with the
data being initialized.

For example, the statement:

	declare		test-scores(100) fixed binary
		static initial((100)0);
initializes all the elements of the array test-scores to 0.
The statement:

	declare		grid(15) pointer;
		static initial((15)null);
initializes the array grid with null pointer values.

5-5
PL/I Reference manual	5.3	Initializing Array Elements

The statement:

declare	numbers(10) character(10)
	static initial((10)101234567891);

initializes all ten elements of numbers with the character string
constant '01234567891 (see Appendix A).
The statement:

declare	numbers(10) character(10)
	static initial((5)10123456789',(5)1()V);

initializes five elements of numbers with the constant 10123456789,
and five elements with the constant '01.

PL/I stores the elements of an array internally in row-major order.
That is, the far right subscript varies the most rapidly. If you
declare the array with the INITIAL attribute, or reference the
entire array in a GET or PUT statement, PL/I accesses the elements
in the same order.
For example, using the array declaration:

	declare test-scores(2,2,2)	fixed static
		initial (l,2,3,4,5,6,7,8);
PL/I assigns values to the elements in the following order:

test scores(1,1,1) = 1
test scores(1,1,2) = 2
test scores(1,2,1) = 3
test scores(1,2,2) = 4
test scores(2,1,1) = 5
test scores(2,1,2) = 6
test scores(2,2,1) = 7
test-scores(2,2,2) = 8

PL/I uses the same order to output the elements in a PUT statement,
such as:

do i = 1 to 2;
do j = 1 to 2;
do k = 1 to 2;
E end; put list(test-scores(i,j,k));
	end;
	end;

5-6
PL/I Reference Manual	5.4		Arrays in Assignment Statements

5.4 Arrays in Assignment Statements

Only in certain restricted cases does PL/I allow an array variable
to be the target of an assignment statement. Any statement of the
form:

array-variable A = array_variable B;

is valid if the arrays are identical in dimension and data type, and
the storage for both arrays is connected. In this case, each
element in array-variable-A is assigned the corresponding element in
array-variable-B. For example,

declare A(20) fixed binary;
declare B(20) fixed binary;
A = B;

Individual elements of an array can also be targets of assignment
statements. For example, in the following code sequence the
elements of one array are assigned values computed using the
elements in another array.

declare		array_A(10) float binary;
declare		array_B(10)fixed binary static
	initial (0,l,2,3,4,5,6f7,8,9);
declare		i fixed binary;
do i = i to 10;
	array_A(i) = sqrt(array_B(i));
	end;

Array variables cannot be operands for arithmetic operators such as
+ and		For example, any statement of the form:

	C		A + B;
is invalid if A, B, and C are array variables.

PL/I does not allow any statement of the forms:

 array-variable = constant;
	 array-variable = expression;
	For example, the following code sequence is illegal in PL/I:

declare A(10) fixed binary;
declare n fixed binary static initial(2);
A = n;
PL/I Reference Manual	5.4 Arrays in Assignment Statements

However, you can obtain the same effect with the sequence:

declare A(10) fixed binary;
declare n fixed binary static initial(2);
declare i fixed binary;
do i = i to 10;
	A(i) = n;
	end;

5.5 Structures

A structure is an aggregate that can contain items of different data
types. You can use structures to represent data that more closely
reflect real-life objects.

The data items contained in the structure are called its members.
Structures can contain scalar data items, arrays of scalar items, or
other structures called substructures. Structures are ordered
hierarchically. The main structure is called the major structure
and any substructure is called a minor structure.

A structure declaration defines the organization of levels and the
names of the members on each level in the structure. Every
structure declaration must contain the following:

		a name for the major structure,

		the names and data attributes of its members,

		and a level number for each name to define its level in the
hierarchical order.

A structure variable declaration has the form:

DECLARE [level] name [attribute-list] ...
[,[level] name [attribute-list]];

Level numbers precede the names and must be separated from them by
one or more spaces. The level number of a major structure is always
one. The definitions of each member, including its level number,
name, and attributes, must be separated by commas. The level
numbers of the members of a minor structure must be greater than the
level number of the minor structure. However, because level numbers
precede their member names, they are factored to the left. A
sequence of the form:

level-k item-1, level-k item-2, ... level-k item-n

is equivalent to the sequence:

level-k (item-1, item-2, ... item-n)

5-8
PL/I Reference Manual	5.5 		Structures

For example, the statement:

declare 1 A based,
2		(B fixed binary,
	C character(2));
	is equivalent to:

declare 1 A based,
2		B fixed binary,
2		C character(2);

Note: Level 1 structure names cannot have data type attributes, but
can have a dimension attribute. Level 1 structure names can also
have the BASED, AUTOMATIC, EXTERNAL, PARAMETER, or STATIC
attributes.
The following statement is an example of a structure declaration:

declare 1 bill,
2		name,
	3 last name character(20),
	3 firs-E name character(20),
	3 middle initial character(l),
2		address,
	3 street character(20),
	3 city character(10),
	3 state character(3),
	3 zip character(5),
2		charges,
	3 shop fixed decimal(10,2),
	3 snack bar fixed decimal(10,2),
	3 misc fixed decimal(10,2),
	3 dues fixed decimal(10,2);

Figure 5-4 shows the hierarchy of levels corresponding to this
declaration.

1-1-1

5-9
PL/I Reference Manual		5.5		Structures
	BILL	NAME		LAST NAME
		FIRSTNAME
		MIDDLE INITIAL
	ADDRESS	STREET
		CITY
		STATE
		Z I P
	CHARGES	SHOP
		SNACKBAR
		MISC
		DUES

Figure 5-4. Hierarchy of Structure Levels

Both level numbers and names can be factored. Ambiguities can arise
when referencing the members of structures because the name of a
structure member can occur as the name of the member of another
structure, or as the name of a data item in a substructure of the
same structure. These ambiguities arise only with member names in a
common scope of definition.

To resolve such ambiguities, use qualified names to reference
members of structures. In a qualified name, the member name is
preceded by a list of structure names in ascending order of level
number, each followed by a period and zero or more blanks. The only
structure names required are those that determine a unique reference
to the member name.

For example, in the structure:

declare 1 A,
	2 B,
		3 C fixed,
		3 D fixed,
	2 BB,
		3 C fixed,
3 D fixed;

a reference to item C, or D, or A.C, or A.D is ambiguous. The
qualified names B.C, or B.D, or BB.C, or BB.D uniquely identify the
structure elements. The fully qualified names are

A.B.C
A.B.D
A.BB.C
A.BB.D

5-10
PL/I Reference Manual	5.5 		Structures

Figure 5-5 shows the hierarchy of levels.

A	B 	C FIXED
'----D FIXED

	--~C FIXED
BB 	-D FIXED

Figure 5-5. Hierarchy of Structure Levels

5.6 Mixed Aggregates

A mixed aggregate is either an array whose elements include
structures, or a structure whose members include arrays. You can
define an array whose elements are a single type of structure by
giving the major structure name a dimension attribute in the
structure declaration. You can also give minor structures a
dimension attribute. When you declare a structure with a dimension
attribute, each member of the structure inherits the dimension and
becomes an array.

For example, the statement:

declare 1 student list(100),
	2 student name,
		3 last name character(10),
		3 firs-E name character(10),
		3 middle initial character(l),
	2 social-security_number character(9),
	2 country character(10),
2 grades(5) character(2);

defines an array of structures whose major structure name is
student - list. Figure 5-6 shows an array of these structures with
their efements.

5-11
PL/I Reference Manual		5.6	Mixed Aggregates
STUDENT-LIST (100)	STUDENT~_NAME			LAST NAME
				FIRST-NAME
	SOCIAL-SECURIT	_~_~MIDDLEJNITIAL

COUNTRY

GRADES(5)

Figure 5-6. An Array of Structures

Each structure element of the array has the subarray grades as a
member. To reference an entry in the array, you must use a
qualified name together with subscripts for the structure names that
have a dimension attribute, and the member name if it has a
dimension attribute. The subscripts do not have to appear with
their corresponding name, but must occur in parentheses separated by
commas and in correct order.

For example, any of the following forms is a fully qualified,
unambiguous reference to the third grade entry for the sixty-first
entry of the array student-list:

student list(61).grade(3)
student list.grade(61,3)
student-list(61,3).grade

5.7 Mixed Aggregate Referencing

You can reference an entire mixed aggregate by name. A reference to
data items inside a mixed aggregate can be partially subscripted,
and/or partially qualified. Any such reference to a mixed aggregate
must identify connected storage (see Appendix A) . Connected storage
means the data elements occupy consecutive storage locations.

5-12
PL/I Reference Manual	5.7 Mixed Aggregate Referencing

For example, consider how PL/I stores the data elements for the
declaration:

DECLARE 1 COLOR(100),
2 HUE CHARACTER (10) VARYING,
2 INTENSITY FIXED BINARY;

HUE(1)
INTENSITY(l)

HUE(2)
INTENSITY(2)

-(3)
t4SMY
COLOR(3)		INTIE	COLOR.HUE

COLOR.HUE(100)			HUIE1100)
		INTEN$11TY1100),
	Figure 5-7a. An Array of Structures

5-13
PL/I Reference Manual	5.7 Mixed Aggregate Referencing

Now, the similar declaration,

declare 1		color,
	2 hue(100) character(10) varying,
	2 intensity(100) fixed binary;
	stores the data elements as shown in Figure 5-7b.

COLOR.HUE ~

INTENSITY(2)

INTENSITY(3)

INTENSITY(100)

Figure 5-7b. A Structure of Arrays

In Figure 5-7a, color is dimensioned and each of its members, hue
and intensity, inherits the declared dimension. Therefore, each
appears as an array, but the elements do not occupy consecutive
storage locations.

In Figure 5-7b, color has two members, both of which are
dimensioned. The elements of each array occupy consecutive storage
locations.
PL/I Reference Manual	5.7 Mixed Aggregate Referencing

Referring to Figure 5-7a, the storage for color(3), or
color.hue(100) is connected storage, but the storage for color.hue
is unconnected. However, in Figure 5-7b, the storage for color.hue
is connected.

Each type of declaration has its advantages and disadvantages. The
specific application and method of access in a program determine the
type of declaration and the storage that results.

End of Section 5

5-15
	Section 6
Assignments and Expressions

6.1		The Assignment Statement

The assignment statement sets a variable equal to the value of an
expression or constant. The assignment statement has the general
form:

variable = expression;

where variable is a scalar element, an array, a structure name, or a
pseudo-variable (Section 6.8) . The assignment statement contains no
distinctive keyword.

PL/I does not allommultiple assignments in a single statement. For
example,

	A, B, C = 5;
	is invalid.
	PL/I does allow statements such as:

A = (B = C);

In this context, PL/I treats the equal (=) sign inside the
parentheses as a relational operator (see Section 6.5). Thus, if
the variable B has the same value as the variable C, the relation is
true and PL/I assigns the bit-string value 111b to the variable A

6.2		Expressions

An expression is any valid combination of operands and operators
that PL/I computes at run-time to produce a value.

Various syntactic rules govern the arrangement of references,
operators, and varentheses in an expression. A reference can be a
constant, a variable, or a function. An operator defines the
computation to perform, using the operands to which it is applied.
Parentheses enclose various portions of the expression.

The following sections present the proper formulation of operands,
operators, and parentheses.

6-1
PL/I Reference Manual	6.2 	Expressions

6.2.1	Prefix Expressions

A prefix expression consists of a unary prefix operator followed by
an expression called the operand. PL/I first evaluates the operand
and then applies the unary operator to the result.

The following are two examples of prefix expressions:

-A	/* logical Not of A */
-SQRT(B)	/* minus square root of B

6.2.2	Infix Expressions

An infix expression consists of two expressions called operands
separated by an infix operator. PL/I first evaluates the operands,
that can be expressions, and then applies the operator to the
result.

The following are two examples of infix expressions:

A+B	/* sum of A and B)
C**2	/* C squared) */

6.3	Precedence of Operators

In any unparenthesized expression or subexpression, PL/I applies
operators according to a set of precedence rules. Table 6-1 shows
the fixed order of precedence from highest to lowest with operators
of equal precedence listed on the same line.

Table 6-1. PL/I Operator Precedence

Operator	Symbol	Priority

Exponentiation				1
Logical Not		or		1
Prefix Operators				1
Multiplication, Division				2
Addition, Subtraction				3
Concatenation			or	4
Relational Operators
	<=, >=		5
Logical And	&			6
Logical Or	11	!, or	7

When evaluating an unparenthesized expression, PL/I inserts a
balanced parentheses pair around the highest precedence operators
and their corresponding operands first. It continues descending to
lower precedence operators and their operands until the entire
expression is properly parenthesized.

6-2
PL/I Reference Manual	6.3		Precedence of Operators

When equal precedence operators occur at the same level, PL/I
evaluates prefix operators and exponentiation from right to left,
with the remaining operators evaluated from left to right.

For example, the compiler treats the unparenthesized expression:

2 + z * X ** Y		2		5 	Q

as the expression:

(2 + ((Z * (X		(Y	2))) / 5)) 	Q
I		L-	1 	1

6.4		Concatenation

The infix operator 11 concatenates either bit strings or character
strings. Both operands must be of the same type, and the result is
the same type as the operands. The length of the resulting string
is always the sum of the lengths of the operands.

For character- s tr ing concatenation, if either operand has the
VARYING attribute, then the result has the VARYING attribute. For
example, the code sequence:

declare
	A character(3),
	B character(6) varying,
	C character(20);
A		= 'ABC';
B		= 'ABCDEF';
C = A 11 B;

assigns the character string ABCABCDEF of length 9 to the variable
C.

6.5		Relational Operators

In PL/I, relational operators are infix operators that compare the
relationship between two operands in an algebraic sense.
Computational values can be compared according to general algebraic
rules, but noncomputational values can only be compared for equality
or inequality.

Character string, bit string, and arithmetic data items can be
compared using any relational operator. ENTRY, FILE, LABEL, and
POINTER data can only be compared using the equal and not equal
operators.

6-3
PL/I Reference Manual	6.5	Relational operators

ENTRY values are equal only if they identify the same entry point in
the same block activation.

LABEL values are equal only if they identify the same statement in
the same block activation. A LABEL value that identifies a label on
a null statement is not equal to a LABEL value on any other
statement.

POINTER values are equal only if they identify the same storage
location, or they are both null values.

FILE values are equal only if they identify the same File Parameter
Block (see Section 10.4).

If the operands differ in data type, PL/I first converts them to a
common type before making the comparison, and then produces a bit
string of length one with the value '1'B, true, if the operands are
equal, and 'O'B, false, if the operands are not equal (see Section
4).

PL/I compares character strings by extending the shorter operand on
the right with blanks until it is the same length as the longer
operand. It makes the comparison character-by-character from left
to right using the ASCII collating sequence (see Appendix C). In
this sequence, the value of any upper-case letter is less than any
lower-case letter, and the value of any numeric character is less
than any alphabetic character.

For example, given the two strings JACK and JACKSON, PL/I first pads
the shorter string with blanks and then compares the strings
starting on the left as shown, V denotes a blank:
J A IC IK Ite IV Ib( I
4A 41 43 4B 20 20 20
- I I I I I I
i A C K S 0 N

4A 41 43 4B 53 4F 4E

Because S, 53h, is greater than a blank, 20h, JACKSON is greater
than JACK.

PL/I compares bit strings by extending the shorter string on the
right with zero-bits. Comparison is then made bit by bit from left
to right with zero considered less than one. For example
'00010000'B is less than '00010001'B.

6-4
PL/I Reference Manual	6.6		Bit-string operators

6.6 Bit-string Operators

Table 6-2 shows the PL/I bit-string operators.

Table 6-2. PL/I Bit-string Operators

Operator 	Symbol

Complement		(logical Not)	or -
Inclusive Or		(logical Or)	or ! or
And	(logical And) 	&

PL/I performs bit-string operations on a bit-by-bit basis. The
unary Not operator reverses each bit value in the bit-string
operand, changing a zero-bit to a one-bit, and a one-bit to a zero
bit. For example, given the bit string A = '01110010'B, then ^A
'10001101'B.

The Or and And operators require two bit-string operands. If the
operands are of unequal length, PL/I extends the shorter one on the
right with zero-bits until it is equal in length to the other
operand. The resulting string length equals the longer of the two
operands.

The Or and And operators follow the rules of Boolean algebra:
x			I	y	xly	x	y	I 	X&Y
0		0	0	0	0	0
0		1	1	0	1 	0
1		0	1	1	0	0

Additional Boolean functions are easily constructed using the BOOL
built-in function (see Section 13.3).

6.7 Exponentiation

PL/I computes exponentiation as a series of multiplications if the
exponent is a nonnegative integer constant. Otherwise, it evaluates
the operation using the built-in LOG and EXP transcendental
functions. When evaluating an exponential expression, PL/I treats
the following as special cases:

6-5
PL/I Reference Manual	6.7 	Exponentiation

	If X=O and Y>O, then X**Y = 0.

	If X=O and Y<O, then the run-time system signals the ERROR(3)
condition.

	If X^=O and Y=O, then X**Y = 1.

	If X<O and Y is not an integer, then the run-time system
signals the ERROR(3) condition.

6.8	Pseudo-variables

SUBSTR and UNSPEC are the names of two PL/I built-in functions
(BIFs) that you can use as source operands in expressions. However,
you can also use SUBSTR and UNSPEC as the target operands on the
left side of assignment statements. In this case SUBSTR and UNSPEC
are cal~led pseudo-var i able s because they appear to act like simple
program variables.

6.8.1 Character SUBSTR

The SUBSTR built-in function allows you to access a substring of a
string. It takes one of the following two forms:

SUBSTR(char-variable,i)
SUBSTR(char-variable,i,j)

where char-variable is an optionally subscripted reference to
CHARACTER variable or CHARACTER VARYING variable, and i and j are
FIXED BINARY expressions.

SUBSTR with two arguments extracts the substring starting at
position i and continuing to the end of the string. (Position 1 is
the first character of the string, position 2 the second, and so
on.) The result is undefined if i exceeds the string length.

SUBSTR with three arguments extracts the substring starting at
position i and continuing for j characters. The result is undefined
if either i or i+j exceeds the string length, where the length is
the declared fixed size for CHARACTER variables, and the current
length for CHARACTER VARYING variables.

For example, if the variable word contains the character string
'Josephine', then the following assignments result in the strings
indicated.

x = SUBSTR(word,l); /* x = 'Josephine'
y = SUBSTR(word,5); /* y = 'phine'
z = SUBSTR(word,1,4); /* z = 'Jose'

6-6
PL/I Reference Manual	6.8 		Pseudo-variables

The SUBSTR pseudo-variable is similar to the SUBSTR built-in
function, except that it appears on the left of an assignment, and
it must appear alone. That is, SUBSTR cannot be embedded in a
string expression when it serves as the target of a string
assignment. SUBSTR appears in this context as one of the following
forms:

SUBSTR(char-variable,i)		= char-exp;
SUBSTR(char-variable,i,j)		= char-exp;

The SUBSTR pseudo-variable with two arguments assigns the character
expression given by char-exp to the substring in the char-variable,
starting at position i, and extending through the length of the
char-variable.

The SUBSTR pseudo-variable with three arguments assigns the
character expression given by char-exp to the substring in the char
variable, starting at position i and continuing for j characters.
The values of i and i+j must be within the current or fixed string
length, otherwise undefined results might occur.

The same char-variable can appear on both the left and right side of
an assignment statement without partial substring overwrite during
the assignment.

For example, if the variable word contains the character string
'Collegiate', then following the statement,

substr(word,7) = substr(word,10,1);

the variable contains the string 'CollegeIOW.

6.8.2 Bit SUBSTR

In PL/I, bit substring operations are similar to the character
SUBSTR shown in Section 6.8.1, with some restrictions. First, PL/I
limits bit strings to the precision range 1 through 16,
corresponding to single- and double-byte values. To account for the
intermediate precision values during compilation, the length of a
bit substring operation must be constant.

Thus, the forms for bit substring are

SUBSTR(bit-variable,k)
SUBSTR(bit-variable,i,k)

where the bit-variable is an optionally subscripted BIT variable
reference; k is an integer constant in the range 1 to 16, and i is a
FIXED BINARY expression.

6-7
PL/I Referencd Manual	6.8 	Pseudo-variables

The effect of using SUBSTR with bit strings is identical to the
character operation described, except PL/I selects a bit string of
length k when SUBSTR appears in an expression, and assigns it when
SUBSTR appears on the left as a target of a bit-string store
operation.

The following section gives an example of bit SUBSTR.

6.8.3	UNSPEC

The UNSPEC BIF returns a bit-string value of the internal
representation of the argument. The UNSPEC BIF has the form:

variable = UNSPEC(argument);

where the argument is an optionally subscripted reference to a data
item that occupies a single- or double-byte memory location.

Note:	PL/I does not allow an expression as the argument to UNSPEC.

When UNSPEC appears as a pseudo-variable on the left of an
assignment statement, PL/I converts the assigned value to a bit
string and directly stores it into the single- or double-byte
location of the variable. Thus, UNSPEC allows you to access single
and double-byte variables as if they are 8-bit and 16-bit string
data items.

The UNSPEC pseudo-variable is often used as an escape mechanism when
the usual features of the language do not appear to allow access to
the underlying facilities. Do not use UNSPEC instead of a more
appropriate high-level language facility, because UNSPEC is
implemen tat ion-dependen t. In fact, whenever it seems necessary to
use UNSPEC, examine the problem in a more general way to see if its
use can be avoided.

The following example shows two memory locations being accessed.
The UNSPEC operation loads two absolute addresses into two pointer
variables. Two based variables, in turn, overlay these two memory
locations so they can be accessed as 16- and 8-bit quantities. The
bit SUBSTR pseudo-variable is then applied to move a substring from
one location to the other.

6-8
PL/I Reference Manual	6.8 		Pseudo-variables

declare
(P, Q) pointer,
A bit(16) based(P),
B bit(8) basecl(Q),
I fixed;

I = 4;
unspec(P) = 'FF80'b4;
unspec(Q) = 'FFFO'b4;

lubstr(B,4,2) = substr(A,I,2);

End of Section 6

6-9
	Section 7
Storage Management

7.1		Storage Classes

Every variable in a PL/I program is associated with a storage class.
The storage class determines how and when PL/I allocates storage for
a variable, and whether the variable has its own storage or shares
storage with another variable.

PL/I		supports four different storage classes:

*		AUTOMATIC (the PL/I default)
*		BASED
	PARAMETER
	STATIC

For the AUTOMATIC and STATIC storage classes, the compiler allocates
storage before execution by generating code that automatically
associates the variable name with a given storage location at run
time. For the BASED and PARAMETER storage classes, the compiler
maintains the variable name and attributes, but does not allocate
any storage for it. The run-time system allocates and frees BASED
and PARAMETER storage when the program runs.

To improve performance, PL/I treats AUTOMATIC storage the same as
STATIC storage, except in procedures marked as RECURSIVE.

Storage class attributes are properties of elements, arrays, and
major structure variables. Entry names, filenames, or members of
data aggregates cannot have these attributes.

7.1.1		The AUTOMATIC Storage Class

The compiler allocates storage for a variable belonging to the
AUTOMATIC storage class before execution of the main procedure. The
storage remains allocated until the program ends. Variables
belonging to the AUTOMATIC storage class can have their data values
initialized with the INITIAL attribute (see Section 7.1.4).

Usually, the AUTOMATIC storage class forces data storage allocation
upon entry to the PROCEDURE or BEGIN block in which the variable
appears. In PL/I, AUTOMATIC storage is statically allocated to
improve performance.

The only exception is in the case of recursion, where the AUTOMATIC
variables must use the dynamic storage mechanism to prevent data
overwrite on recursive calls.

7-1
PL/I Reference Manual	7.1	Storage Classes

7.1.2 The BASED Storage Class

A based variable is a variable that describes storage that must be
accessed with a pointer (see Section 3.4) . The pointer is the
location where the storage for the based variable begins, and the
based variable itself determines how PL/I interprets the contents of
the storage beginning at that location. Thus the based variable
together with a pointer is equivalent to a nonbased variable.

You can visualize a based variable as a template that overlays the
storage specified by its base. Thus a based variable and pointer
can refer to storage allocated for the based variable itself, or to
storage allocated for other variables.

The BASED variable declaration has the form:

DECLARE name BASED [(pointer-reference)];

where the pointer reference is an unsubscripted POINTER variable, or
a function call, with zero arguments, that returns a POINTER value.

A pointer-qualified reference can be either implicit or explicit.
When you declare a variable as BASED without a pointer reference,
each reference to the variable in the program must include an
explicit pointer qualifier of the form:

pointer-exp -> variable

where pointer-exp is a pointer-valued expression.

When you declare a variable as BASED with a pointer reference, you
can reference it without a pointer qualifier. The run-time system
reevaluates the pointer reference at each occurrence of the
unqualified variable using the pointer expression given in the
variable declaration.

The following example illustrates the difference between explicit
and implicit, pointer-qualified reference.

Main:
procedure options(main);
declare
list A(100) fixed binary based,
list B(100) fixed binary based(list-B_ptr),
(lis -A-ptr,list-B_ptr) pointer;

list - A - ptr	list-A(47) = 0;	/*	explicit reference
list-B(47)	0;	/* implicit reference

end main;

7-2
PL/I Reference Manual	7.1		Storage Classes

You can declare the same pointer name in a different environment,
and use it to make an implicit pointer-qualified reference.
However, PL/I takes the pointer variable name or pointer-valued
function name given in the pointer reference from the scope of the
original BASED declaration. The following example illustrates this
concept.

A:
procedure options(main);
declare
(i,j) fixed binary,
p pointer,
x fixed binary based(p);
p = addr(i);
x = 2; /* implicit reference; x refers to i
B:
procedure;
declare
p pointer; /* local to B
p = addr(j);
x = 12; /* implicit reference; x still refers to i
p -> x = 3; /* explicit reference; x now refers to j
end B;

end A;

The following statements are examples of BASED variable
declarations:

declare A character(8) based;
declare B pointer based(Q);
declare C fixed based(P);
declare D bit(8) based(FO);

7.1.3 The PARAMETER Storage Class

If a variable appears in a parameter list, the compiler assigns it
the PARAMETER storage class. Storage for parameters is allocated by
the calling procedure when it passes the parameters to the called
procedure.

See Appendix A for restrictions on the use of the PARAMETER storage
class.

7-3
PL/I Reference Manual	7.1		Storage Classes

7.1.4		The STATIC Storage Class

The compiler allocates storage for a variable belonging to the
STATIC storage class before execution of the main procedure. The
storage remains allocated until the program ends. Variables
belonging to the STATIC storage class can have their data values
initialized with the INITIAL attribute.

The INITIAL attribute directs the compiler to assign initial
constant values to STATIC data items upon storage allocation. The
general form of the INITIAL attribute is

INITIAL (valuef,value] ...

where value has the form:

[(iteration-factor)] constant-expression

The optional iteration-factor is an integer that specifies the
number of times the constant is repeated. The constant-expression
must be a literal constant value that is compatible with the data
type being initialized. It consists of either an optionally signed
arithmetic constant, a string constant, or a NULL pointer value.

You can initialize array data items with a single statement. The
statement must begin with the first element of the array, and
continue in row-major order until the end of the set of initialized
constants. The number of constants should not exceed the size of the
initialized array. Structure members must be individually
initialized.

The assignment of constants follows the rules for assignment
statements. For example, if you assign a character string to a
variable that is longer than the string, PL/I pads the string with
blanks on the right.

Note: only STATIC variables can have the INITIAL attribute to be
compatible with the ANSI Subset G PL/I standard.

The following code sequence illustrates the STATIC storage class and
the INITIAL attribute:

declare A fixed binary static initial(O);
declare B(8) character(2) initial((8)'AB') static;
declare
I fcb static,
	2		fcb drive	fixed(7)	initial(O),
	2		fcb name	character(8) initial('EMP'),
	2		fcb type	character(3) initial('DAT'),
	2		fcb ext	bit(8)	initial('OOIB4),
	2		fcb-fill(19) bit(B);

7-4
PL/I Reference Manual	7.1		Storage Classes

The following statements are examples of BASED variable
declarations:

declare A character(8) based;
declare B pointer based(Q);
declare C fixed based(P);
declare D bit(8) based(Fo);

7.2		The ALLOCATE Statement

The ALLOCATE statement explicitly allocates storage for a variable
with the BASED attribute. The ALLOCATE statement has the form:

ALLOCATE based-variable SET(pointer-variable);

The ALLOCATE statement directs the run-time system to obtain a
segment of storage from the dynamic storage area that is large
enough to hold the value of the based-variable. If a segment of the
requested size is not available, the run-time system signals
ERROR(7).

The based-variable must be an unsubscripted variable reference,
where the variable is declared with the BASED attribute in the scope
of the ALLOCATE statement. The run-time system stores the
allocation address into the pointer- variable named in the SET
clause.

Storage allocated in this manner rei,.ains allocated until a
corresponding FREE statement is executed, using the allocation
address held by the pointer-variable as an operand.

7.3		Multiple Allocations

The ALLOCATE statement allocates storage each time it is executed in
the program. A program can allocate storage for a single based
variable more than once, and as long as each allocation has a unique
pointer, the program can reference all of them. For example,
PL/I Reference Manual	7.3 Multiple Allocations

declare names(5) character(10) based;
declare (P,Q) pointer;
allocate names set(P);
P -> names(l) = 'John';

allocate names set(Q);
Q -> names(3) = 'Smith';

In this example, there is no compile-time storage allocation for the
array variable names. The compiler automatically allocates storage
for the pointers P and Q at compile time. At run-time, the ALLOCATE
statements obtain two different allocations for names that can then
be referenced with the appropriate pointer. Figure 7-1 illustrates
this concept.

	STORAGE
STATEMENT 	ALLOCATED

DECLARE NAMES (5) CHARACTER (10) EASED; NO STORAGE

DECLARE (P,Q) POINTER;

ALLOCATE NAMES SET ( P)
P -> names(l) = 'John , i

ALLOCATE NAMES SET (Q)
Q -> names(3) = 'Smith

Figure 7-1. Multiple Allocations of a BASED Variable

7-6
PL/I Reference Manual	7.3 Multiple Allocations

Note: when multiple allocations of a based variable all have the
same pointer, the pointer only references the most recent
allocation, and not any preceding ones.

7.4 The FRIKE Statement

Storage for a BASED variable remains allocated until released with
the FREE statement. The FREE statement has the form:

FREE [pointer-variable ->] based-variable;

where the pointer variable addresses an allocation of storage that
must have been previously obtained from the dynamic storage area
using the ALLOCATE statement. Unpredictable results can occur if a
program attempts to free unallocated storage.

If the pointer variable is not given in the FREE statement, then the
based variable must be declared with the pointer reference option.
In this case, the run-time system returns the storage addressed by
the pointer reference to the dynamic storage area.

The run-time subroutines that maintain the dynamic storage area
automatically coalesce contiguous storage segments as they are
released using the FREE statement.

Note: when the FREE statement releases a storage allocation, both
the pointer and the contents of the storage area become undefined.
Unpredictable results can occur if the program makes any subsequent
reference to the freed storage.

The following code sequence illustrates the FREE statement:

declare
	(P, Q, R) pointer,
	A character(10) based,
B fixed based(R);

allocate A set(P);
allocate B set(R);
allocate A set(Q);

free P A;
free Q A;
free B;

7-7
PL/I Reference Manual	7.5	The NULL BIF

7.5	The NULL BIF

The NULL BIF returns a pointer value that is a unique, nonvalid
storage address. This address is useful in marking various pointer
values as empty, and is especially useful in the construction of a
linked list.

A linked list is a data structure composed of elements that not only
contain a data area but also contain a pointer to the next element
in the list. In such a list, the last element has no following
element, and its pointer has an invalid (null) value. Figure 7-2
shows a linked list.

POINTER	ITEM	ITEM	ITEM	ITEM
TO LIST	1	2	N-1	N
	POINTER	POINTER	POINTER	NULL
	to	to	to	POINTER
		ITEM 3	~IT I M 'N"
ITEM 2 	_I

Figure 7-2. Linked List

The NULL built-in function has the form:

NULL[()]

Pointer values do not necessarily begin with a null value when
program execution begins. However, pointer values can be given a
null value by using the value returned by NULL in the variable
declaration INITIAL option.

NULL is an invalid pointer qualifier for a based variable. For
example, the following code sequence is invalid in PL/I:

declare A pointer;
declare list(10) fixed binary based(A);

* = null();
* -list(10) = 32767;	/*	this is invalid!!

Section 10 in the PL/I Language Programming Guide contains sample
programs that illustrate the use of BASED variables and the NULL
function.

7-8
PL/I Reference manual	7.6		The ADDR BIF

7.6		The ADDR BIF

The ADDR BIF returns a pointer to the memory address occupied by the
variable name given as the argument. The ADDR BIF has the form:

ADDR(variable name)

Note: the variable name must have an assigned memory address, and
cannot be a temporary result created through the application of
functions and operators, nor can it be a constant or a named
constant such as a FILE, ENTRY, or LABEL constant.

7.7		Storage Sharing

Use of BASED variables in conjunction with the ADDR BIF allows
storage sharing in PL/1. With storage sharing, the based variable
is not explicitly given storage with the ALLOCATE statement.
Rather, the based variable acts as a template that overlays the
storage for an existing variable.

To share storage, you must use the ADDR BIF to set the pointer base
for the based variable to the address of the existing variable.
Subsequent access to the based variable then accesses the overlayed
variable. The only requirement is that the length of the based
variable, in bits, be less than or equal to the length of the
existing variable, in bits.

The following program illustrates storage sharing. Here, the value
of a character string is overlayed by a bit-string vector. The
output from the program is the character-string value, written in
hexadecimal bit-string form.

declare
i fixed binary,
ptr pointer,
word character(8),
bit vector(8) bit(8) based(ptr);
ptr = addr(word);
get list(word);
do i = 1 to 8;
put edit(bit-vector(i)) (x(2),b4(2));
end;

If you enter the word Digital at the console, the storage location
allocated for the variable word appears as shown:
_F
D	g	t			I	a 	sp

7-9
PL/I Reference Manual	7.7	Storage Sharing

The based variable bit vector is simply a template that overlays the
storage for word as ~Eown:

where x denotes a single bit. Thus on output, the program reads the
bit string starting at the location of word and converts it to a
hexadecimal representation of the individual characters stored in
word.

Note: there is an important consideration involved in this type of
storage sharing. The preceding example depends on knowledge of the
internal data representation used by PL/I; namely, eight bits
represent a character. Thus, the program is implementation
dependent. This runs counter to the Subset G philosophy of writing
transportable programs. PL/I allows such storage sharing using
based variables, but the resulting code might not be transportable
to a different implementation.

7.8 Programing Considerations

Based variables and pointers are powerful tools because they give
you direct access to memory. However, use them with caution.
Remember that storage obtained with the ALLOCATE statement remains
allocated until it is freed or the program ends. Any based
variables and pointers that refer to the allocated storage remain
active only as long as the block in which they are declared remains
active. When control passes out of the block, the storage becomes
inaccessible.

Note: PL/I cannot tell if the size of a based variable does not
correspond to the size of the storage to which it refers. If a
program assigns a value to a pointer-qualified reference whose size
does not match the allocated storage, then the contents of adjacent
storage locations can be destroyed.

The following errors are common when using based variables and
pointers:

	assigning a pointer the NULL value somewhere in the program and
subsequently using it elsewhere in a pointer-qualified
reference.

	using a pointer to reference a based variable whose storage has
been freed.

	using a pointer whose value has been lost because of the
deactivation of the block in which it was declared.

End of Section 7

7-10
Section 8
Sequence Control

PL/I program statements usually execute sequentially. You can use
sequence control statements to alter this normal flow with
conditional and unconditional branching and controlled looping, as
discussed below. Procedure invocations including function calls
also alter the normal execution sequence, and are thus considered
sequence control statements (see Section 2.5).

8.1 The Simple DO Statement

A DO-group is a sequence of statements that begins with a DO
statement and ends with an END statement. The statements must be
executable. A DO-group cannot define variables whose environment is
limited to the body of the DO-group. A DO-group can occur in one of
two forms: the simple, noniterative DO-group, and the controlled,
iterative DO-group.

The simple DO statement has the form shown in Figure B-1 where
Statement-1 through Statement-n constitute the body of the DO-group.

DO;

END;

Figure 8-1. Forms of the DO Statement

8-1
PL/I Reference Manual	8.1	The Simple DO Statement

The following code sequence illustrates the simple DO-group:

do;
	x = 3.14/2;
	y = sin(x);
	z	+ y;
end;

8.2 The Controlled DO Statement

The controlled DO statement has one of two general forms:

Do WHILE(condition);
DO control-variable = do-specification;

where the control-variable is a scalar variable; the condition is a
Boolean expression, and the do-specification is one of the
following:

start-exp [TO end-exp] [BY incr-exp] [WHILE(condition)]
start-exp [BY incr-exp] [TO end-exp] [WHILE(condition)]
start-exp [REPEAT repeat-exp] [WHILE(condition)]

In these general forms, start-exp is an expression specifying the
initial value of the control -variable; end-exp is an expression
representing the terminal value of the control-va r i able; incr-exp is
an expression added to the control-variable after each execution of
the loop, and the repeat-exp is the expression that is assigned to
the control -variable after each iteration. Condition is an
expression yielding a bit-string value that is considered true if
any of the bits in the string are one-bits.

If the TO end-exp form is included but the BY incr-exp is omitted,
then PL/I assumes the incr-exp to be one. The two forms using TO
and BY execute in exactly the same manner, and differ only in the
order of these two elements in the program text.

PL/I evaluates the WHILE expression each time before executing the
DO-group. If the condition is false, the loop execution terminates,
and control passes to the statement following the balanced END
statement.

With the exception of the REPEAT expression and the WHILE
expression, PL/I evaluates expressions in the do-specification
before executing the loop, so that changes made to the start, end,
or incremental values do not affect the number of times a loop
executes.

8-2
PL/T Reference Manual	8.2		The Controlled DO Statement

In the case of the REPEAT option however, PL/I recomputes the
repeat-exp after each iteration. It then assigns this recomputea
expression to the control-variable and evaluates the WHILE test, if
there is one.

PL/I defines the actions of iterative groups by a sequence of
equivalent IF and GOTO statements. Expressions el, e2, e3, and e4
are appropriate start-exp, end-exp, incr-exp, repeat-exp, and
condition values, while i represents a valid control-variable.

8.2.1		The DO WHILE Statement

DO WHILE(el);

END;

is equivalent to the sequence of statements:

DO WHILE(E),

END,

Figure		8-2. The DO WHILE Statement

8.2.2		The DO REPEAT Statement

DO i		el REPEAT(e2);

END;

is equivalent to the sequence of statements shown in Figure 8-3.

8-3
PL/I Reference Manual	8.2		The Controlled DO Statement

DO I + El REPEAT(E2)~

END;
L*
Figure		8-3. The DO REPEAT Statement

Note: in this case, the loop proceeds indefinitely until terminated
by an embedded GOTO or STOP statement.

8.2.3 The DO REPEAT WHILE Statement
DO i = el REPEAT(e2) WHILE(e3);

	END;
	is equivalent to the sequence of statements shown in Figure 8-4.

DO I El REPEAT(E2) WHILE(U);

I-E2

END;

	F
E3

T

Figure 8-4. The Do REPEAT WHILE Statement

8-4
PL/I Reference Manual	8.2		The Controlled DO Statement

Thus, the simple iterative DO-group:

DO i = el TO e2;

END;

is equivalent to the sequence of statements:

DO i = el TO e2 BY e3;

END;

where e3 =1, that can be expressed as the equivalent sequence:

i = el;
LAST = e2;
	INCR = e3;
	LOOP:
IF endtest THEN
GO TO ENDLOOP;

i		i + INCR;
	GOTO LOOP;
	ENDLOOP:;

where the IF statement containing the endtest compares the control
variable with the value of LAST. The comparison is based on the
sign of the incrementing value INCR. If INCR is negative, the END
test is

IF		i < LAST THEN
	GOTO ENDLOOP;

Otherwise, the END-test becomes

IF		i > LAST THEN
	GOTO ENDLOOP;

8-5
PL/I Reference Manual	8.2		The Controlled DO Statement

8.2.4		The DO BY WHILE Statement

DO	el TO e2 BY e3 WHILE(e4);

END;

is equivalent to the sequence of statements shown in Figure 8-5.

	F
E4
DO I E I TO E2 BY E3 WH I LE(E4),

T
F

T

END,
I-El

tF
El-E2
	T

,E3

Figure 8-5. The DO BY WHILE Statement

In these equivalent sequences, the value of LAST and INCR take on
the characteristics of the expressions e2 and e3. Arithmetic
conversions and comparisons take place at each step according to
PL/I rules.

8.3 The IF Statement

The IF statement allows conditional execution of a statement or
statement group, based upon the true or false value of a Boolean
expression. The optional ELSE clause provides an alternative
statement or group of statements to execute when the Boolean
expression produces a false value.

8-6
PL/I Reference Manual	8.3		The IF Statement

The IF statement has the general form:

IF expression THEN action-1 [ELSE action-2]

where the expression is a scalar expression that yields a bit-string
value. Action-1 and action-2 can be either simple statements, or
compound statements contained within a DO-group or BEGIN block. If
either action-1 or action-2 is a simple statement, it cannot be a
DECLARE, END, ENTRY, FORMAT, or PROCEDURE statement. The statements
in action-1, and action-2 if included, must terminate with a
semicolon; therefore, the semicolon is not included in the preceding
general statement form shown.

PL/I evaluates the expression to produce a bit string. If any bit
in the string is equal to one, then PL/I performs action-1.
Otherwise, control passes to action-2, if included, or to the next
statement in sequence following the IF statement.

IF statements can be nested, in which case PL/I pairs each ELSE with
the innermost unmatched IF THEN pair. You can use null statements
to force the desired IF ELSE pairing. For example, in the following
code sequence containing nested IF statements, the null statement
following the second ELSE corresponds to the second IF THEN test.

if A = Y then
['f
Z = X then
if W > B then
C = 0;
Eelse C = 1;
else;
-else A = Y2;

8.4 The STOP Statement

The STOP statement unconditionally stops the program, closes all
open files, and returns control to the operating system. You can
use the STOP statement anywhere you want to stop the program.

The STOP statement has the form:

STOP;

8.5 The GOTO Statement

The GOTO statement unconditionally transfers control to a specific
labeled statement. The GOTO statement has either of the forms:

GOTO label constant label variable;
GO TO label constant label variable;

where the label constant is a literal label that appears as the
prefix of some labeled statement, and label variable is a simple or

8-7
PL/I Reference Manual	8.5	The GOTO Statement

subscripted label variable that is assigned the value of a label
constant.

The evaluated label constant must label a statement in the scope of
the GOTO statement, and cannot be within an embedded iterative DO
group of any sort. The following example illustrates this kind of
invalid transfer.

A: proc options(main);

goto no-no;

-do i=l to 10;

	no-no:;	/* invalid transfer!!
end;

end A;

Transferring control with a GOTO statement is valid only when the
target label is known in the block containing the GOTO statement.
Thus, transfer of control using GOTO statements and labels is
limited to the currently active block or a containing block.

The following are examples of GOTO statements:

goto labl;
goto where;
go to L(J);

8.6 The Nonlocal GOTO Statement

In a nonlocal GOTO statement, the evaluated target label constant
occurs outside the innermost block containing the GOTO statement.

Usually, you should avoid the nonlocal GOTO because it makes the
program harder to debug and maintain.

There are situations when the nonlocal GOTO is appropriate. With
nonrecoverable error conditions, it is often useful to branch
directly to a global error recovery label where program execution
recommences. In such a case, PL/I automatically reverts all
embedded ON-units and discards procedure return information.

8-8
PL/I Reference Manual	8.6 The Nonlocal GOTO Statement

The following code sequence shows an instance of a nonlocal GOTO
from within a procedure definition:

p: procedure;

on		endfile(sysin)
	begin;
	goto eof;
	end;
	i = 1;
	do while ('l I b)
	get file(sysin) list(a(i));
i		+
	end;
end p;

call p;
eof;

End of Section 8

111-N,

8-9
Section 9
Condition Processing

PL/I supports run-time interception of conditions that would usually
end the program. The ON, REVERT, and SIGNAL statements provide this
facility.

A condition is any occurrence that interrupts the program's normal
flow of execution. A condition can be signaled by the run-time
system or by the program itself, at which point control passes to a
preestablished logical unit for that condition.

Certain conditions are nonrecoverable. This means that the
specified logical unit cannot return control to the point where the
condition was signaled, but instead must execute a GOTO to a
nonlocal label. Other conditions are recoverable, so that the unit
can perform some local action and then return control to the point
of the signal.

PL/I recognizes the following general categories of conditions:

e a general error condition (ERROR)

* arithmetic error conditions such as

- FIXEDOVERFLOW
- OVERFLOW
- UNDERFLOW
- ZERODIVIDE

* and 1/0 conditions such as

- ENDFILE
- ENDPAGE
- KEY
- UNDEFINEDFILE

9.1 The ON Statement

The ON statement defines the action to take when the specified
condition is signaled.

The ON statement has the general form:

ON condition-name ON-unit;

where the condition-name can be one of the preceding listed
conditions.

9-1
PL/I Reference Manual	9.1	The ON Statement

An ON-unit is enabled when it is ready to intercept a condition. An
ON-unit is active when it is processing a signaled condition. An
ON-unit can be a PL/I statement, or several PL/I statements
contained in a BEGIN block. PL/I processes the ON-unit when the
particular condition named in the ON statement is signaled.

Exit from an ON-unit cannot be through a RETURN statement, although
this restriction does not preclude a procedure definition within a
BEGIN block.

Once all the statements of the ON-unit are executed, the flow of
control resumes at the point where the condition was signaled,
provided that the condition is recoverable. Alternatively, the ON
unit can execute a nonlocal GOTO and transfer control to some label
outside the ON-unit.

An ON-unit remains active until the program executes a corresponding
REVERT statement, or control leaves the block containing the ON
statement. You can establish more than one ON-condition in the same
block. For example, ERROR(l) and ERROR(2) are different conditions.
However, if you establish more than one ON-unit for the same
condition in the same block, PL/T automatically reverts the previous
ON-unit before establishing the new one.

9-2
PL/I Reference Manual	9.1 The ON Statement

A:

PROCEDURE OPTIONS(MAIN);

ON ENDFILE
ON ENDPAGE
ON ERROR(1)

B:
PROCEDURE;

ON ERROR(1)

REVERT ERROR(1)

-END B;

-END A;

Figure 9-1. ON-unit Activation

In Figure 9-1, PL/I first enables the ON-units for the ENDFILE,
ENDPAGE, and ERROR(l) conditions. At this point, there are three
ON-units enabled. When control flows into procedure B, PL/I enables
the second ON-unit for the ERROR(l) condition and associates it with
the activation of procedure B. There are now four enabled ON-units.

Executing the REVERT statement reverts the current ON-unit for
ERROR(l), the one associated with procedure B. This reestablishes
the ON-unit for ERROR(l) in the encompassing procedure, A, and again
leaves three enabled ON-units. Note that if B returns control to A
without executing the REVERT statement, PL/I automatically reverts
the ON-unit.

9-3
PL/I Reference Manual	9.2	The SIGNAL Statement

9.2	The SIGNAL Statement

The	SIGNAL statement causes a particular condition to occur
programmatically and invokes a corresponding ON-unit, if one is
enabled. If no ON-unit for the condition is enabled, the PL/I
default action occurs. If the condition is nonrecoverable the
default action prints a traceback and terminates the program.
The SIGNAL statement has the form:
	SIGNAL condition-name;

where		the condition-name is one of the conditions listed previously.
For example, the statement:
	signal zerodivide;
invokes the current ZERODIVIDE ON-unit.

9.3	The REVERT Statement

The REVERT statement disables the current ON-unit for a specific
condition and reestablishes the one that preceded it, if it exists.
The REVERT statement has the form:
REVERT condition-name;
where the condition-name is one of the conditions listed previously.
For example, the statement:
revert overflow;
disables the current ON-unit for the OVERFLOW condition.

Note: upon exit from a PROCEDURE block, PL/I automatically reverts
any ON-units enabled within the block.

9.4	The ERROR Condition

The ERROR condition is the broadest category of all PL/I conditions.
It includes through its subcodes, both system-defined and user
defined conditions. There are four groups of ERROR condition
subcodes:

(A)	0	-	63	Reserved for PL/I	(Nonrecoverable)
(B)	64	-	127	User-defined	(Nonrecoverable)
(C)	128	-	191	Reserved for PL/I	(Recoverable)
(D)	192	-	255	User-defined	(Recoverable)
				9-4
PL/I Reference Manual	9.4		The ERROR Condition

Usually, the error codes are implementation-specific. See the PL/I
Language Programmer's Guide for the codes currently assigned in
group A.

The ON statement with the ERROR condition has the forms:

ON ERROR[(integer-expression)] on-body;
SIGNAL ERROR[(integer-expression)];
REVERT ERROR[(integer-expression)];

where integer expression is a specific subcode in the range 0-255.
For example, the statement:
ON ERROR(3) ... ;

intercepts the ERROR condition with the subcode 3.

The forms:

ON ERROR on-body;
ON ERROR(O) on-body;

intercept any error condition, regardless of the subcode.

The following code sequence shows a simple example of the ERROR
condition:

on error(l)
begin;
put skip list('Invalid Input:');
goto retry;
end;
retry:
get list(x);

The GET statement reads variable x from the SYSIN file, and if the
data is invalid, the run-time system signals ERROR(l) . In this
case, control passes to the ON-body, which writes an error message
to the console, and recommences execution at the retry label.

You can use the SIGNAL statement with the ON statement to intercept
either nonrecoverable or recoverable conditions. For example, the
statement:
signal error(64);

signals the ERROR(64) condition, and if there is an ON-unit enabled
for ERROR(64), then the corresponding ON-body receives control.
Otherwise, the program ends with an error message. The statement:
signal error(255);

performs a similar action except that the program does not end if an
ON-unit for the ERROR(255) condition is not enabled.

9-5
PL/I Reference Manual	9.5	Arithmetic Error Conditions

9.5	Arithmetic Error Conditions

PL/I handles several arithmetic error conditions. These conditions
are

 FIXEDOVERFLOW[(i)]
 OVERFLOWHi)]
 UNDERFLOW[W]
 ZERODIVIDE[(i)]

where i is an optional integer expression denoting a specific error
subcode. Similar to the ERROR function, the ON, REVERT, and SIGNAL
statements can specify any of the preceding conditions.

If you do not specify an integer expression, PL/I assumes a value of
zero. An ON statement with subcode of zero intercepts any subcode
from 0-255. PL/I divides the arithmetic condition subcodes into
system-defined and program-defined values, analogous to the ERROR
function.

Note: all arithmetic error conditions are nonrecoverable. When
setting an ON condition for an arithmetic exception, the ON-body
should transfer control to a global label. Otherwise, the program
ends upon return from the ON-unit.

Table 9-1 shows the system codes for arithmetic error conditions.

Table 9-1. Arithmetic Error Condition Codes

Condition	Meaning
FIXEDOVERFLOW(l)	Decimal Operation
OVERFLOW(l)	Floating-point operation
OVERFLOW(2)	Float Precision Conversion
UNDERFLOW(l)	Floating-point operation
ZERODIVIDE(l)	Decimal Divide
ZERODIVIDE(2)	Floating-point Divide
ZERODIVIDE(3)	Integer Divide

9-6
PL/I Reference Manual	9.6		The ONCODE BIF

9.6		The ONCODE BIF

The ONCODE BIF returns a FIXED BINARY(15) value representing the
type of error that signaled the most recent condition. If a signal
is not active, ONCODE returns a zero. After an ON-unit is
activated, ONCODE can determine the exact source of the error. The
following code sequence illustrates the use of ONCODE.

on error
begin;
declare
code fixed;
code = oncodeo;
if code = 1 then
do;
put list('Bad Input:');
goto retry;
end;
put list('Error#',code);
end;
retry:

9.7		Default ON-units

PL/I has default ON-units for each of the condition categories that
usually output an appropriate error message and end the program.
PL/I does not signal the FIXEDOVERFLOW condition for FIXED BINARY
overflow, although it does for FIXED DECIMAL overflow.

9.8		1/0 Conditions

During 1/0 processing, the run-time system can signal several
conditions relating to the access of a particular file. These
conditions are the following:

ENDFILE(file-reference)
UNDEFINEDFILE(file-reference)
KEY(file-reference)
ENDPAGE(file-reference)

where file-reference denotes a file-valued expression. The file
value that results need not denote an open file. Section 10.5
describes each of the 1/0 conditions in detail.

End of Section 9
Section 10
Input and Output Processing

PL/I provides a device- independent input/output system that allows a
program to transmit data between memory and an external device such
as a console, a line printer, or a disk file.

The collection of data elements transmitted to or from an external
device is called the data set. A corresponding internal f ile
constant or variable is called a file.

As with other data items, you must declare all files before you use
them in a program. The general form of a file declaration is

DECLARE file-id FILE [VARIABLE];

where file id is the file identifier. The declaration defines a
f ile cons-Eant if you do not include the VARIABLE attribute.
Including the VARIABLE attribute defines a file variable that can
take on the value of a f ile constant through an assignment
statement. 1/0 operations on file variables are valid only after
you assign a file constant to a file variable.

Note: by default, PL/I assigns the EXTERNAL attribute to a file
constant. Unless you declare a file variable as EXTERNAL, PL/I
treats it as local to the block where you declare it.

10.1 The OPEN Statement

PL/I requires that a file be open before performing any 1/0
operations on the data set. You can open a file explicitly, by
using the OPEN statement, or implicitly by accessing the file with
one of the following 1/0 statements:

 GET EDIT
 PUT EDIT
 GET LIST
 PUT LIST
 READ
 WRITE
 READ Varying
 WRITE Varying

Sections 11 and 12 contain detailed descriptions of the various 1/0
statements.

10-1
PL/I Reference Manual	10.1	The OPEN Statement

The OPEN statement has the form:

OPEN FILE(file-id) [file-attributes];

where file id is the identifier that appears in a FILE declaration
statement, and file-attributes denotes one or more of the following
PL/I keywords:

o STREAM 	RECORD
	o PRINT
	INPUT	OUTPUT I UPDATE
	SEQUENTIAL I DIRECT
		KEYED
		TITLE
		ENVIRONMENT
		PAGESIZE
		LINESIZE

All the attributes are optional and you can specify them in any
order. Multiple attributes on the same line are conflicting
attributes so you can only specify one. The first one listed is the
default attribute. PL/I Subset G requires any implementation
specific information to be isolated in the TITLE and ENVIRONMENT
attributes. See Appendix A.

A STREAM file contains variable length ASCII data. You can
visualize it as a sequence of ASCII character data, organized into
lines and pages. Each line in a STREAM file is determined by a
linemark, that is a line-feed or a carriage return line-feed pair.
Each page is determined by a pagemark, or form-feed. Some text
editors automatically insert a line-feed following each carriage
return, but files that PL/I creates can have line-feeds without
preceding carriage returns. PL/I then senses the end of the line
when it encounters the line-feed.

A RECORD file contains binary data. PL/I accesses the data in
blocks determined by a declared record size, or by the size of the
data item you use to access the file. A RECORD file may also have
the KEYED attribute, and you can use FIXED BINARY keys to directly
access the fixed-length records.

PRINT applies only to STREAM files, and indicates that the data is
for output on a line printer.

For an INPUT file, PL/I assumes that the file already exists when it
executes the OPEN statement. For an OUTPUT file, PL/I creates the
file when it executes the OPEN statement. If the file already
exists, PL/I first deletes the old one, then creates a new file.

You can read from and write to an UPDATE file. PL/I creates an
UPDATE file if it does not exist when executing the OPEN statement.
An UPDATE file must have the RECORD attribute and cannot have the
STREAM attribute.

10-2
PL/I Reference Manual	10.1		The OPEN Statement

SEQUENTIAL files are accessed sequentially from beginning to end.
DIRECT files are accessed randomly using keys. PL/I automatically
gives DIRECT files the RECORD and KEYED attributes. PL/I requires
you to declare all UPDATE files with the DIRECT attribute so that
you can locate the individual records.

A KEYED file is simply a fixed-length record file. The key is the
relative position of the record in the file based upon the fixed
record size. You must use keys to access a KEYED file. PL/I
automatically gives KEYED files the RECORD attribute.

The LINESIZE attribute applies only to STREAM OUTPUT files, and
defines the maximum input or output line length in characters. The
default is LINESIZE(80).

The PAGESIZE attribute applies only to STREAM PRINT files, and
defines the number of lines per page. The default is PAGESIZE (60) .

The TITLE(c) attribute defines the programmatic connection between
an internal filename and an external device or a file in the
operating system's file system. If you do not specify a TITLE
attribute, the external filename defaults to the value of the file
reference, with the filetype DAT. For example,

TITLE('file-id.DAT')

The character string c can specify either an external device name or
a disk filename. Usually, the names of external devices are
implementation specific. The following table shows the names of
external devices used in different implementations.

Table 10-1. External Device Names

Implementation
External Device		CP/Ma	IBM DOS
System 		Console	$CON	CON:
System 		List Device	$LST	LPT1: or PRN:
System 		Reader	$RDR	AUX or COM:l
System 		Punch	$PUN	AUX or COM:l

If the character string c is a disk filename, it must be in the
f orm:

d:filename.typ;password

The drive specification d:, the filetype typ, and the password are
optional. If you specify a password in the TITLE attribute, the
ENVIRONMENT attribute (described later in Section 10.1) defaults to
ENVIRONMENT(Password(Read)).

10-3
PL/I Reference Manual	10.1 The OPEN Statement

Note: not all implementations support password protection. See
Appendix A.

Either the filename, filetype, or both, can be $1 or $2. If you
specify $1 then PL/I takes the first default name from the command
line and fills it into that position of the title. Similarly, $2 is
taken from the second default name and filled into the position
where it occurs.

You must specify the filename, and you cannot use an ambiguous, or
wildcard, reference in the filename, filetype, or the drive
specification. You can open a physical 1/0 device only as a STREAM
file. A reader device must have the INPUT attribute, and a punch or
list device must have the OUTPUT attribute.

The ENVIRONMENT attribute defines fixed- and variable-length record
sizes for RECORD files, internal buffer sizes, the file open mode,
and password protection level.

The ENVIRONMENT attribute has the form:

ENVIRONMENT(option.... )

where option is one or more the following:

		Locked I L
		Readonly I R
	Shared 1 5
	Password[(level)) I P[(level)]
 Fixed(i) 	F(i)
 Buff(b) 	B(b)

You can specify options in the ENVIRONMENT attribute in any order
with the exception that Fixed(i) must precede Buff(b).

The default mode for opening a file is locked mode, and prevents
other users from accessing the file while it is open. Readonly
allows more than one user to open the file for Read/Only access.
Shared, or unlocked, mode means that more than one user can open the
file and access it. In Shared mode, you can apply the LOCK and
UNLOCK built-in functions to individual records in the file. You
can abbreviate each of the open modes with a single character.
Thus, you can specify either Locked or L, Readonly or R, and Shared
or S.

The option Password[ (level) defines the password protection level
of the file. The valid protection levels are the following:

Read	R
Write	W
Delete ~ 	D

10-4
PL/I Reference Manual	10.1 The OPEN Statement

Read means that the password is required to read the file; this is
the default mode. Write means that the file can be read but the
password is required to write to the file. Delete means that the
file can be read or written to, but the password is required to
delete the file. You can abbreviate each of the protection levels
with a single character. Thus, you can specify Read or R, Write or
W, and Delete or D.

The option Buff(b) directs the 1/0 system to buffer b bytes of
storage, where b is a FIXED BINARY expression that PL/I will round
to the next higher multiple of 128 bytes. If the Buff(b) option is
specified and the Fixed(i) option is not specified, the 1/0 system
assumes that the file has variable-length records and therefore
cannot have the KEYED attribute because the record size is not
fixed.

The option Fixed(i) defines a file with fixed-length records
containing i bytes each, where i is a FIXED BINARY expression that
PL/I internally rounds to the next multiple of 128 bytes. If you
use this option, you must also specify the KEYED attribute. When
using this option, the default buffer size is i bytes, rounded to
the next higher multiple of 128 bytes.

The options Fixed (i) Buff (b) defines a file containing fixed-length
records of i bytes, rounded as described previously, with a buffer
size of b bytes, again, rounded. You can specify a fixed-length
record larger than the buffer size. When using these options, you
must also specify the KEYED attribute.

10.2		Establishing File Attributes

When executing the OPEN statement, PL/I establishes the file
attributes before associating the file with an external data set.
If the OPEN statement does not specify a complete set of attributes,
PL/I augments them with implied attributes. Table 10-2 shows the
implied attributes for each specified attribute.

Table 10-2. PL/1 Implied Attributes

Specified Attribute	Implied Attribute(s)
	DIRECT		RECORD KEYED
	KEYED		RECORD
	PRINT		STREAM OUTPUT
	SEQUENTIAL		RECORD
	UPDATE		RECORD

Note: the OPEN statement cannot contain conflicting attributes
either explicitly or by default through the mechanisms that give the
implied attribute.

10-5
PL/I Reference Manual	10.2	Establishing File Attributes

Each type of 1/0 statement implicitly determines a specific set of
f ile attributes. If you use the OPEN statement to explicitly
specify the attributes, the attributes implied by the 1/0 statement
cannot conflict with the attributes supplied in the OPEN statement.
Table 10-3 summarizes the valid attributes for each of the 1/0
statements.

Table 10-3. Valid File Attributes for each 1/0 Statement

1/0 Statement	Valid Attributes

GET FILE(f) LIST	STREAM		INPUT
PUT FILE(f) LIST	STREAM		OUTPUT
GET FILE(f) EDIT	STREAM		INPUT
PUT FILE(f) EDIT	STREAM		OUTPUT
READ FILE(f) INTO(v)	STREAM		INPUT
READ FILE(f) INTO(X)	RECORD		INPUT SEQUENTIAL

READ FILE(f) INTO(x) KEYTO(k)	RECORD INPUT SEQUENTIAL
	KEYED ENVIRONMENT(Fixed(i))

READ FILEM INTOW KEY(k)	RECORD INPUT DIRECT KEYED
	ENVIRONMENT(Fixed(i))
	RECORD UPDATE DIRECT KEYED
	ENVIRONMENT(Fixed(i))
WRITE FILE(f) FROM(v)	STREAM OUTPUT
WRITE FILE(f) FROM(x)	RECORD OUTPUT SEQUENTIAL

WRITE FILE(f) FROM(x) KEYFROM(k)		RECORD OUTPUT DIRECT KEYED
	ENVIRONMENT(Fixed(i))

RECORD UPDATE DIRECT KEYED
ENVIRONMENT(Fixed(i))

10-6
PL/I Reference Manual	10.2		Establishing File Attributes

Table 10-4 summarizes the valid attributes that can be associated
with any file either through an explicit OPEN statement, or
implicitly by an 1/0 access statement.

Table 10-4. PL/I Valid File Attributes
Type		F 	Attribute
STREAM		INPUT	ENVIRONMENT TITLE
STREAM		OUTPUT	ENVIRONMENT TITLE LINESIZE
STREAM		PRINT	ENVIRONMENT TITLE LINESIZE PAGESIZE
RECORD		INPUT	SEQUENTIAL ENVIRONMENT TITLE
RECORD		OUTPUT	SEQUENTIAL ENVIRONMENT TITLE
RECORD		INPUT	SEQUENTIAL KEYED ENVIRONMENT TITLE
RECORD		OUTPUT	SEQUENTIAL KEYED ENVIRONMENT TITLE
RECORD		INPUT	DIRECT KEYED ENVIRONMENT TITLE
RECORD		OUTPUT	DIRECT KEYED ENVIRONMENT TITLE
RECORD		UPDATE	DIRECT KEYED ENVIRONMENT TITLE

Note: once established, the set of attributes applies only to the
current opening of the file. You can close the file and reopen it
with a different set of attributes.

The following are some examples of the OPEN statement. In each
case, there is a source statement with the default and augmented
attributes shown after the statement. Each file is assumed to be
declared as a file constant.

Statement:		open file(fl);

Attributes:		STREAM INPUT ENVIRONMENT(Locked,Buff(128))
	TITLE('fl.DAT') LINESIZE(80)

10-7
PL/I Referenbe Manual	10.2	Establishing File Attributes

Statement:	open file(f2) print env(r);

Attributes:	STREAM OUTPUT PRINT ENVIRONMENT(Readonly,Buff(128)
	TITLE(lf2.DAT') LINESIZE(80) PAGESIZE(60)

Statement:	open file(f3) sequential
		title(Inew.fil;John');
Attributes:	RECORD INPUT SEQUENTIAL
	ENVIRONMENT(Locked,Password(Read),Buff(128))
	TITLE('new.fil;john')
Statement:	open title(la:111c) file(f4)
		direct keyed env(s,f(2000));
Attributes:	RECORD DIRECT INPUT KEYED
	ENVIRONMENT(Shared,Fixed(2048),Buff(2048))
	TITLE('a:'Ilc)
Statement:	open update keyed file(f5)
		env(locked,f(300),b(100));
Attributes:	RECORD DIRECT UPDATE KEYED
	ENVIRONMENT(Locked,Fixed(384),Buff(128))
	TITLE ('f5.DATI)
Statement:	open file(f6) input direct
		title('d:accounts.new;topaz')
		env(shared,p(d),f(100),b(2000));
Attributes:	RECORD DIRECT INPUT KEYED
	ENVIRONMENT(Shared,Password(Delete),Fixed(128),Buff(2048))
	TITLE('d:accounts.new;topazl)

In each of the preceding examples, PL/I allows integer expressions
wherever a constant appears. Thus, the statement:

open file(fl) linesize(k+3) pagesize(n-4) env(b(x+128));

is a valid OPEN statement.

10.3	The CLOSE Statement

The CLOSE statement disassociates the file from the external data
set, clears and frees the internal buffers and permanently records
the output files on the disk. The CLOSE statement has the form:

CLOSE FILE(file-id);

10-8
PL/I Reference Manual	10.3		The CLOSE Statement

where file - id is a file reference. You can subsequently reopen the
file using the OPEN statement previously described. If the file is
not open, PL/I ignores the CLOSE statement.

10.4		The File Parameter Block

PL/I associates every file constant with a File Parameter Block
(FPB) . A FPB is a statically allocated segment of memory containing
information about the file. A file variable has no corresponding
FPB until you assign it a file constant. Each FPB contains the
following information:

		the file title naming the external device or data set
associated with the file

		the column position that the run-time system maintains to
locate the next position to get or put data in a STREAM file

		current line count in STREAM OUTPUT files

		current page count for PRINT files

		current record position

		line size

		page size

*		fixed record size

		internal buffer size

		File Descriptor containing one of the valid sets of file
attributes as previously described

While the file is open, the run-time system maintains an entry in a
data structure called the Open List, which is allocated from the
free storage area. Also, while the file is open, the FPB contains a
pointer to the address of the operating system File Control Block
(FCB).

10-9
PL/I Reference Manual	10.5	1/0 Conditions

10.5	1/0 Conditions

During 1/0 processing, the run-time system can signal several
conditions relating to the access of a particular file. The
conditions are

ENDFILE(file-reference)
UNDEFINEDFILE(file-reference)
KEY(file-reference)
ENDPAGE(file-reference)

where file reference is a file constant or a file variable that does
not yet have to be open.

10.5.1	The ENDFILE Condition

The run-time system signals the ENDFILE condition whenever it reads
an end-of-file character, CTRL-Z, from a STREAM file, or it
encounters the physical end-of-file in a RECORD file being processed
in SEQUENTIAL mode. A read operation on a DIRECT file using a key
beyond the end-of-file also signals the ENDFILE condition. Output
operations that exceed the disk storage capacity signal the
ERROR(14) condition.

10.5.2	The UNDEFINEDFILE Condition

The run-time system signals the UNDEFINEDFILE condition whenever a
program attempts to open a file for INPUT, and the file does not
exist on the specified disk. The run-time system also signals the
UNDEFINEDFILE condition if a program attempts to open a password
protected file without the correct password. The run-time system
also signal this condition if the program attempts to access a
physical 1/0 device as a KEYED or UPDATE file.

10.5.3	The KEY Condition

The run-time system signals the KEY condition when a program uses an
invalid key value during an 1/0 operation.

10-10
PL/I Reference Manual	10.5		1/0 Conditions

10.5.4		The ENDPAGE Condition

The run-time system signals the ENDPAGE condition for PRINT files
when the value of the current line reaches the PAGESIZE for the
specified file. The current line always begins at zero, and the
run-time system increases it by one for each line-feed that is sent
to the file. If the file is initially opened with PAGESIZE (0) , then
the run-time system never signals the ENDPAGE condition. The run
time system resets the current line to one whenever:

 a form-feed is sent to the output file
 a PUT statement with a PAGE option is executed
 the default system action for ENDPAGE is performed

If the run-time system signals the ENDPAGE condition during
execution of a SKIP option, the SKIP processing ends.

If an ON-unit intercepts the ENDPAGE condition, but does not execute
a PUT statement with the PAGE option, then the current line is not
reset to one. That is, until the program executes a PUT statement
with the PAGE option, the run-time system continues to increment the
current line, and does not signal the ENDPAGE condition. The
current line counts up to 32767 and then begins again at 1.

10.5.5		Default 1/0 ON-units

If an ON-unit receives control for the ENDFILE, UNDEFINEDFILE, or
KEY conditions and returns to the point where the signal occurred,
the run-time system terminates the current 1/0 operation, and passes
control to the statement following the 1/0 statement that signaled
the condition.

If there is no ON-unit enabled for the ENDFILE, UNDEFINEDFILE, or
KEY condition, the default system action ends the program and
outputs an appropriate error message.

If there is no ENDPAGE ON-unit enabled, the default system action
performs a PUT PAGE on the output file, and continues processing.

10.6		1/0 Condition BIFs

PL/I has several built-in functions which are useful in 1/0
handling. They are

 ONFILE
* ONKEY
 PAGENO
 LINENO

10-11
PL/I Reference Manual	10.6	1/0 Condition BIFs

10.6.1	The ONFILE Function

The ONFILE function returns a character string value of the internal
filename involved in the last 1/0 operation that signaled a
condition. With a conversion error, the ONFILE function produces
the name of the file that is active at the time. If a signaled
condition does not involve a file, then ONFILE returns a null
string. The following code sequence illustrates the use of ONFILE.

on error(l)
Fbegin;
put list('Bad Data in file:',onfileo);
goto retry;
end;
retry:

10.6.2	The ONKEY Function

The ONKEY function returns the value of the key involved in the 1/0
operation that signaled the KEY condition. ONKEY is valid only in
the ON-body of the activated ON-unit. The following code sequence
illustrates the use of ONKEY.

on	key(newfile)
	put skip list('bad key',onkeyo);

10.6.3	The PAGENO Function

The PAGENO function returns the current page number for the PRINT
file named as the parameter. When the ENDPAGE condition is signaled
as the result of a PUT statement, the line number is one greater
than the page size for the file.

10.6.4	The LINENO Function

The LINENO function returns the current line number for the PRINT
file named as the parameter. When the ENDPAGE condition is signaled
as the result of a PUT statement, the line number is one greater
than the page size for the file.

10.7	Predefined Files SYSIN and SYSPRINT

PL/I contains two predefined file constants called SYSIN and
SYSPRINT. You do not have to declare these file constants unless
you make an explicit file reference to them with an OPEN, GET, PUT,
READ, or WRITE statement.

10-12
PL/I Reference Manual		10.7	Predefined Files SYSIN and SYSPRINT

Otherwise, PL/I opens SYSIN with the default attributes:

STREAM INPUT ENVIRONMENT(Locked,Buff(128)) TITLE('$CON')
LINESIZE(80)
and SYSIN becomes the console keyboard.
Note: TITLE under IBM DOS is 'CON:'.
PL/I opens SYSPRINT with the default attributes:

STREAM PRINT ENVIRONMENT(Locked,Buff(128)) TITLE('$CON')
LINESIZE(80) PAGESIZE(O)
and SYSPRINT becomes the console output display.
Note: TITLE under IBM DOS is 'CON:'.

10.8		1/0 Categories

PL/I supports two general categories of file access:

e STREAM 1/0 (sequential access only)
e RECORD 1/0 (sequential or random access)

10.8.1		STREM 1/0

A STREAM file is a sequence of ASCII characters, possibly containing
linemarks and pagemarks. When transmitting the data in a STREAM
file to and from external devices, PL/I can format the data and
perform conversion to other data types. Section 11 contains
complete descriptions of the STREAM 1/0 statements.

10.8.2		RECORD 1/0

In RECORD 1/0, individual data items are called records, and they
vary in size according to the data declaration. PL/I does not
perform data conversion when transmitting data using the RECORD 1/0
statements (see Section 12), but just transfers the internal
representation of the data item.

Note: different computers use different internal representations
for PL/I data. Do not assume that you can interchange file between
two different computers.

End of Section 10

10-13
Section 11
Stream 1/0

PL/I supports three forms of STREA14 1/0:

LIST-directed;		transfers data items without format
specifications.

EDIT-directed; allows formatted access to character data items
(see Section 11.3).

Line-directed; allows access to variable length character data
in an unedited form. Note that PL/I provides line-directed
STREAM 1/0 using READ and WRITE statements that may or may not
be available in other implementations of PL/I.

The following rules apply to all STREAM 1/0:

The column position, line number, and page number for a file
are initially 1.

Each occurrence of a linemark or pagemark resets the column
position to 1.

If the input or output character is a special character, the
column position advances by one.

On output, if the column position exceeds the line size, the
run-time system writes a linemark, increments the line number
by one, and resets the column position to one.

When the line number exceeds the page size, the run-time system
signals the ENDPAGE condition. If no ENDPAGE ON-unit is
enabled, the run-time system writes a pagemark, increments the
page number, and resets the column position and line number to
one.
PL/I Reference Manual	11 Stream 1/0

The naming conventions in Table 11-1 appear throughout this section
when describing the various STREAM 1/0 statements.

	Table 11-1. Stream 1/0		Naming Conventions
Name	_T 	Meaning
file-id	The file identifier.
nl	A FIXED BINARY expression that defines the
number of linemarks to skip on input, or the
number of linemarks to write preceding the data
item on output.

input-list	A list of variables separated by commas, to
which PL/I transmits the data items from the
input stream. The input-list determines the
number and order of the variables assigned by
the input data in the stream. In PL/I, the
variables must be scalar values. You can
include iterative DO-groups in the input-list
but they require an extra set of parentheses.
The DO header format is the same as the DO
statement except that the REPEAT clause is not
allowed. The general format is (item
1,...,item-n DO iteration). For example, the
following are equivalent:

do	i = 1 to 10;
	put list(A(i));
end;
put list((A(i) do i = 1 to 10));

output-list	A list of output items consisting of constants,
variables, or expressions separated by commas.
The output-list can also include iterative DO
groups.

11.1 LIST-directed 1/0

The following constraints apply to the input stream for list
directed 1/0:

	Data items in the stream can be arithmetic constants,
character-string constants, or bit-string constants.

	Each data item must be followed by a separator, which consists
of a series of blanks, a comma optionally surrounded by blanks,
or an end-of-line character.

11-2
PL/I Reference Manual	11.1		LIST-directed 1/0

		PL/I treats an embedded tab character (CTRL-I) as a blank.

		Character string data that actually contain blanks or commas
must be enclosed in apostrophes. Otherwise, PL/I treats the
blanks or commas as separators.

		A comma as the first, nonblank character in the input line, or
two consecutive commas optionally separated by one or more
blanks indicate a null field in the input stream. The null
field indicates that no data is to be transmitted to the
associated data item in an input-list. Thus, the value of the
target data item remains unchanged.

11.1.1 The GET LIST Statement

The GET LIST statement reads data using list-directed STREAM 1/0.
The GET LIST statement has the form:

GET [FILE(file-id)] [SKIPHnl)11 LIST(input-list);

You can specify the options FILE or SKIP in any order; LIST must
appear last. If you do not specify the FILE option, PL/I assumes
FILE (SYSIN) . In a GET statement with the SKIP option, the run-time
system ignores nl linemarks. If you do not specify n1 with the SKIP
option, then nl defaults to 1, and the run-time system ignores 1
linemark.

After transmission of all data items to the variables named in the
input-list, the column position in the input stream remains at the
character following the last data item read.

You can optionally enclose character strings in the input stream in
apostrophes. If you do so, the run-time system does not transmit
the enclosing apostrophes to the input variable. Likewise, for bit
string constants, the run-time system does not transmit the
enclosing apostrophes and the trailing B to the input variable.

PL/I limits input strings to one line. Thus, string input from the
console only requires the leading apostrophe when the string ends
with a carriage return.

11.1.2 The PUT LIST Statement

The PUT LIST statement writes data using list-directed STREAM 1/0.
The PUT LIST statement has the form:

PUT [FILE(file-id)] [SKIP[(nl)ll [PAGE] LIST(output-list);

You can specify the options FILE, SKIP, or PAGE in any order; LIST
must appear last. If you do not specify the FILE option, PL/I
assumes FILE(SYSPRINT).

11-3
PL/I Reference Manual	11.1	LIST-directed 1/0

If you do not specify nl with the SKIP option, then nl defaults to
1. If nl = 0, the run-time system does not write a linemark but
resets the column position to 1. In either case using the SKIP
option, the run-time system resets the column position to 1.

The PAGE option is valid only for PRINT files. Whenever the run
time system writes a pagemark, both the column position and line
number are reset to 1.

When writing data items to a STREAM file, PL/I converts the items in
the output-list to their char acter-str ing representation. The run
time system uses blanks to separate the data on the output line. If
the data item is longer than the number of characters left on the
output line, the run-time system writes the item at the beginning of
the next line. If the length of the character string representation
of the data item exceeds the line size, the run-time system writes
the data item by itself on a single line that extends past the line
size.

If the output transmission exceeds the page size, PL/I signals the
ENDPAGE condition.

PL/I usually writes character strings enclosed in apostrophes. Each
embedded apostrophe is written as a pair of apostrophes, ' ' .
However, if the file has the PRINT attribute, the additional
apostrophes are omitted. PL/I always writes bit-string data
enclosed within apostrophes followed by the letter B.

11.2	Line-directed 1/0

PL/I supports two forms of the READ and WRITE statement for
processing variable-length ASCII records in a STREAM file. The two
forms, called READ Varying and WRITE Varying, are not usually
available in other implementations. PL/I programs should avoid
using these statements if compatibility is important.

11.2.1 The READ Varying Statement

The READ Varying statement reads variable length STREAM INPUT files.
The READ Varying statement has the form:

READ [FILE(file-id)] INTO(v);

where v is a CHARACTER VARYING string variable. I f you do not
specify the FILE option, PL/I assumes FILE(SYSIN).

READ Varying reads data from the input file until it reaches the
maximum length of v, or it reads a line-feed character. READ
Varying sets the length of v to the number of characters read,
including the line-feed character.

11-4
PL/I Reference Manual	11.2		Line-directed 1/0

Note:		if you do not explicitly OPEN the file, the READ Varying
statement causes an implicit OPEN with the file attributes STREAM
and INPUT.
Given the declaration:

declare
	F file,
	1 buffer,
	2 buffch character(254) varying;
	the statement:
	read file(F) into(buffer);

produces RECORD data transmission because the target is a structure,
not a CHARACTER VARYING variable. However, PL/I interprets the
statement:
read file(F) into(buffch);

as ASCII STREAM INPUT data transmission because the target variable
is CHARACTER VARYING.

The READ Varying statement is differentiated from the READ statement
only by the fact that the target variable has the attributes,
CHARACTER VARYING.

11.2.2		The WRITE Varying Statement

The WRITE Varying statement writes variable length ASCII STREAM
data. The WRITE Varying statement has the form:
WRITE [FILE(file-id)] FROM(v);

where v is a CHARACTER VARYING string variable. If you do not
specify the file option, PL/I assumes file (SYSPRINT).

PL/I adds no additional control characters to the output string. If
the application requires control characters, you must include them
in the string. Recall that PL/I allows embedded control characters
as a part of string constants, denoted by a preceding ^ in the
string.

Note: if you do not explicitly OPEN the file, the WRITE Varying
statement causes an implicit OPEN with the file attributes STREAM
and OUTPUT.

For example, given the previous declaration, PL/I interprets the
statement:
write file(F) from(buffer);
as RECORD data transmission. PL/I interprets
write file(F) from(buffch);

11-5
PL/I Reference Manual	11.2	Line-directed 1/0

as a WRITE Varying statement, operating on an ASCII STREAM OUTPUT
file, because the source variable is CHARACTER VARYING.

The WRITE Varying statement differs from the WRITE statement only by
the fact that the source variable has the attributes, CHARACTER
VARYING.

11.3	EDIT-directed 1/0

The input-list and the output-list for EDIT-directed 1/0 are
analogous to those for LIST-directed 1/0. However, EDIT-directed
1/0 uses a format list to specify how PL/I reads and writes the
data.

11.3.1	The Format List

The format-list is a list of format items, separated by commas.
There are three types of format items:

		Data format items which describe the data items to be read.

		Control format items which specify the placement of the data
items in the stream.

		Remote format items which reference another format-list.

The format-list has the form:

(n] fmt-item ... [,[n] fmt-item]

where n is an integer constant value in the range 1 to 254 giving
the repetition factor of the following fmt-item. If omitted, PL/I
assumes a repetition factor of one. The fmt-item is either a data
format item or a control format item.

An fmt-item can also be a remote format item. In PL/I, however, a
remote format item must be the only format in the list, and cannot
be preceded by a repetition factor.

11.3.2	Data Format Items

Data format items read or write numeric or character fields to or
from an external STREAM data set. PL/I supports the following data
format items:

11-6
PL/I Reference Manual	11.3		EDIT-directed 1/0

The A[(w)] Format

This format reads or writes w characters of character string data.
With GET EDIT, you must include w to be compatible with full PL/I.
However, PL/I allows you to omit w with GET EDIT, and the A format
reads the remainder of the current line up to, but not including the
carriage return line-feed.

Input Value	Format	Input Result
	byte	A(6)	'byte'
	Napoleon	A(10)	'Napoleon'
	string	A	Istring'

With PUT EDIT, if you omit w, then the A format assumes w to be the
length of the output string. If w is greater than the output string
length, then the A format adds blanks on the right. If w is less
than the output string length, the A format truncates the string in
the rightmost positions.

Value	Format	Output Result
abcdef	A(6)		abcdef
abcdef	A(3)		abc
	A(4)		1312(bw

The B[nl[(w)] Format

This format reads or writes bit-string data. With GET EDIT, you
must include w. n gives the number of bits to be used for each
digit. If you omit n, the default is 1, so B is equivalent to Bl
and only 0 and 1 can be in the input stream; otherwise PL/I signals
the ERROR(l) condition. The valid digits for each value of n are
the following:

n	valid digits
1	0,1
2	0,1,2,3,
3	0,1,2,3,4,5,6,7
4	0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F

Input Value	Format	Input Result
	00101	B(5)		1001011B
	22	B2(2)		11010'B
	7C4	B4(3)		'011111000100'B

11-7
PL/I Reference Manual	11.3	EDIT-directed 1/0

With PUT EDIT, the B format first converts the variable to a bit
string type, and then converts it to its character string
representation. If you do not include w, the B format outputs the
resulting character string. If you include w and it is longer than
the character string, then the B format pads the string, with
blanks, on the right. If the resulting character string is longer
than w, the run-time system signals the ERROR(l) condition.

Value	Format	Output Result

100'B	B	00
111B	B(4) 	0001
1011101'B	B3(2)	35

The E(w[,d]) Format

This format reads and writes floating-point data. With GET EDIT,
the E format converts the input characters to FLOAT BINARY values.
w is the field width and d is the number of digits to the right of
the decimal point.

Input Value	Format	Input Result
bb]Zfb(	E(4)	0
2.9E7	E(5,3)	.29E+8
345678	E(6,2)	.345678E+4

With PUT EDIT, the E format converts the data item to FLOAT BINARY
and represents it in scientific notation. w must be at least 7 more
than d, because the output field appears as +n.ddddE+eee, where +
represents sign positionsl n is the leading digit, dddd represents
the fractional part of length d, and E+eee represents the exponent
field.

Value	Format	Output Result
0	E(11,3)	VO.OOOE+000
4.7E-10	E(11,3)	W4.700E-010
-30	E(15)	W-3.OOOOOOE+001

The F(w[,d]) Format

This format reads and writes fixed-point arithmetic data. w is the
width, the number of characters in the field, and d is the number of
characters to the right of the decimal point.

With GET EDIT, the F format reads as many characters as specified by
W. If the character string contains a decimal point, then the
decimal point determines the scale factor. Otherwise, d determines

11-8
