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

Chapter 6

Expressions and Data Type Conversions

An expression is a representation of a value or of the computation of a value, and an assignment gives the value contained in an expression to a variable. Together, expressions and assignments form the mechanism for performing computation.

This chapter covers the following topics:

  • The assignment statement

  • Operators and operands, the elements of an expression

  • The manner in which expression evaluation takes place

  • Conversion of operands and expressions

  • Conversion of operand data types during expression evaluation and assignment

6.1. Assignment Statement

The assignment statement gives a value to a specified variable. The format of the assignment statement is:

target, ... = expression;
target

A reference to a variable to be assigned the value of the expression. If there are two or more targets, they are separated by commas. A target can be:

  • A reference to a scalar variable or scalar array element

  • A reference to a pseudovariable (for example, SUBSTR)

  • A reference to a major or minor structure name or any member of a structure

  • A reference to an array variable

expression

Any valid expression.

PL/I evaluates the targets and the expression in any order. Thus, a program should not depend on the evaluation of the targets before the expression.

PL/I performs the following steps for assignment. Note that the only certain things about the order of steps performed are that step 1 precedes step 3 and that step 4 is performed last.

  1. The expression is evaluated, producing a value to be assigned to the target. An expression can consist of many subexpressions and operations, each of which must be evaluated.

  2. Each target is evaluated. If a target contains a pseudovariable, any expressions in the argument list are evaluated.

  3. If the data type of the result does not match the data type of a target variable, the resulting value is converted to the data type of the target, if possible. The compiler issues a WARNING message to alert you to the implicit conversion.

  4. The value of the expression is assigned to the targets.

Some general rules regarding the types of data you can specify in assignment statements are listed in Table 6.1, “Data Types for Assignment Statement”. For the complete rules for data conversion in assignments, see Section 6.4, “Data Type Conversion of Operands and Expressions”.

Table 6.1. Data Types for Assignment Statement
Data TypeRules
AreaOnly the current extent of an area is moved from the source area to a target. If the target area is not large enough to hold the extent, the AREA condition is raised. Note that the assignment is performed in such a way that all offsets in the source area are valid in the target area after the assignment. Areas cannot be assigned as members of structures.
Arithmetic

PL/I converts an arithmetic expression to the type of its target if their types are different. If the target is a character- or bit-string variable, PL/I converts the arithmetic expression to its character- or bit-string equivalent.

A character-string expression can be converted to the data type of an arithmetic target only if the string consists solely of characters that have numeric equivalents.

Arrays

You can specify an array variable as the target of an assignment statement in only the following ways:

  • array-variable = expression;

where expression yields a scalar value. Every element of the array is assigned the resulting value.

  • array-variable-1 = array-variable-2;

where the specified array variables have identical data type attributes and dimensions. Each element in array-variable-1 is assigned the value of the corresponding element in array-variable-2.

The storage occupied by the two arrays must not overlap.

Any array variable specified in an assignment statement must occupy connected storage. All other specifications of an array variable as a target of an assignment statement are invalid.

BitWhen a target of an assignment is a bit-string variable, the resulting expression is truncated or padded with trailing zeros to match the length of the target.
Character

When a target of an assignment is a fixed-length character string, the resulting expression is truncated on the right or padded with trailing spaces to match the length of the target. If a target is a varying-length character string, the resulting expression is truncated on the right if it exceeds the maximum length of the target.

When one character-string variable is assigned to another, the storage occupied by the two variables cannot overlap.

EntryIf the specified expression is an entry constant, an entry variable, or a function reference that returns an entry value, the target variable must be an entry variable.
LabelIf the specified expression is a label constant, a label variable, or a function reference that returns a label value, the target variable must be a label variable.
Pointer and OffsetIf the specified expression is a pointer or offset, or a function reference that returns a pointer or offset, the target variable must be a pointer or offset variable.
Structures

You can specify the name of a major or minor structure as a target of an assignment statement only if the source expression is an identical structure with members in the same hierarchy and with identical sizes and data type attributes. The storage occupied by the two structures must not overlap.

Any structure variable specified in an assignment statement must occupy connected storage.


The following examples show types of assignment statements:

A = 1;
A = B + A;
SUM = A + 3;
STRING = 'word';
A,B = 5;

6.2. Operators and Operands

An operator is a symbol that requests a unique operation. Operands are the expressions on which operations are performed. Built-in functions can also be considered operators, as well as their arguments considered operands.

Operators

A prefix operator precedes a single operand. The prefix operators are the unary plus (+), the unary minus (-), and the logical NOT (^)

  • The plus sign can prefix an arithmetic value or variable. However, it does not change the sign of the operand.

  • A minus sign reverses the sign of an arithmetic operand.

  • The logical NOT (^) prefix operator performs a logical NOT operation on a bit-string operand; the bit value is complemented.

The following examples show expressions containing prefix operators:

A = +55;
B = -88;
BITC = ^BITB;

An infix operator appears between two operands, and indicates the operation to be performed on them. PL/I has infix operators for arithmetic, logical, and relational (comparison) operations, and for string concatenations. Following are some examples of expressions containing infix operators:

RESULT = A / B;
IF NAME = FIRST_NAME || LAST_NAME THEN GOTO NAMEOK;

An expression can contain both prefix and infix operators. For example:

A = -55 * +88;

You can apply prefix and infix operators to expressions by using parentheses for grouping. For a table giving the categories of operators and the operator symbols, see Chapter 1, Program Structure and Content.

Operands

Because all operators must yield scalar values, operands cannot be arrays or structures. The data type that you can use for an operand in a specific operation depends on the operator:

  • Arithmetic operators must have arithmetic operands; if the operands are of different arithmetic types, they are converted before the operation to a single type, called the derived data type. Section 6.4.2, “Derived Data Types for Arithmetic Operations” describes this process.

  • Logical operators must have bit-string operands.

  • Relational operators must have two operands of the same type. (Note, however, that comparisons are allowed between offsets and pointers.)

  • The operators greater than (>), less than (<), not greater than (^>), not less than (^<), greater than or equal to (>=), and less than or equal to (<=) are valid only with computational operands.

  • The concatenation operator must have two bit-string operands or two character-string operands.

6.2.1. Arithmetic Operators

The arithmetic operators perform calculations. Programs that accept numeric input and produce numeric output use arithmetic operators to construct expressions that perform the required calculations. The infix arithmetic operators are listed in Table 6.2, “Infix Arithmetic Operators”.

Table 6.2. Infix Arithmetic Operators
OperatorOperation
+Addition
-Subtraction
*Multiplication
/Division
**Exponentiation

In addition, there are two prefix operators: unary plus (+) and unary minus (-). The unary plus is valid on any arithmetic operand, but it performs no actual operation. The unary minus reverses the sign of any arithmetic operand.

For any arithmetic operator, operands must be arithmetic; that is, they must be constants, variables, or other expressions with the data type attribute BINARY, DECIMAL, or PICTURE. Operands of different arithmetic types are converted to a common type before the operation is performed.

Arithmetic operators have a predefined precedence that governs the order in which operations are performed. All expressions can be enclosed in parentheses to override the rules of precedence. Table 6.4, “Precedence of Operators” lists the precedence of operators.

6.2.2. Logical Operators

The logical operators perform logical operations on one or two operands. The operands of the logical operators must be bit-string expressions, except that the operand of the NOT operator can be a bit-string expression or a single relational operator. All relational expressions result in bit-string values of length 1, and they can therefore be used as operands in logical operations.

Except when the NOT operator is used as the prefix of a relational operator, the result of a logical operation is always a bit string.

Except for AND THEN and OR ELSE, logical operations are performed on their operands bit by bit. If bit-string operands are not the same length, PL/I extends the smaller of the operands on the right (that is, in the direction of the least significance) with zeros to match the length of the larger operand. This length is always the length of the result.

Table 6.3, “Logical Operators” describes the prefix and infix operators.

Table 6.3. Logical Operators
Prefix OperatorOperation
^ (circumflex)Logical NOT. In a logical NOT operation, the value of the operand is complemented; that is, a 1 bit becomes a 0 and a 0 bit becomes a 1. The value of a relational expression is also complemented; that is ^(A <B) is equivalent to (A >= B).
Infix OperatorOperation
& (ampersand)Logical AND. In a logical AND operation, two operands are compared. If corresponding bits are 1, the result is 1; otherwise, the result is 0.
| (vertical bar) or ! (exclamation point)Logical OR. In a logical OR operation, two operands are compared. If either or both of two corresponding bits are 1, the result is 1; otherwise the result is 0. (The | and the ! characters can be used interchangeably.)
&: (ampersand and colon)Logical AND THEN. The operation is like AND except that the second operand is evaluated only if the first operand is true, and except that AND THEN does not do bit-by-bit operations on bit-string operands.
^ (circumflex)Logical EXCLUSIVE OR. Two operands are compared, and the result is 1 if one of the corresponding bits is 1 and the other is 0.
|: (vertical bar and colon) or !: (exclamation point and colon)Logical OR ELSE. The operation is like OR except that the second operand is evaluated only if the first operand is false, and except that OR ELSE does not do a bit-by-bit operation on bit-string operands.

You can define additional operations on bit strings with the BOOL built-in function.

Logical expressions will not be completely evaluated in some cases. If the result of the total expression can be determined from the value of one or more individual operands, the evaluation can be terminated. For example:

A & B & C & D & E

In this expression, evaluation will stop when any operand or the result of any operation is a bit string containing all zeros.

Examples
DECLARE (BITA,BITB,BITC) BIT(4);
BITA = '0001'B;
BITB = '1001'B;
BITC = ^BITA;  /* BITC equals '1110'B */
BITC = BITA | BITB;    /* BITC equals '1001'B */
BITC = BITA & BITB;    /* BITC equals '0001'B */
BITC = ^(BITA & BITB); /* BITC equals '1110'B */
BITC = ^(BITA > BITB); /* BITC equals '1000'B (true) */

In the last assignment statement, the logical NOT expression yields '1'B; when this value is assigned to BITC, a BIT(4) variable, the value is padded with zeros and becomes '1000'B.

6.2.2.1. NOT

The logical NOT operator in PL/I is the circumflex character (^) used as a prefix operator. In a logical NOT operation, the value of a bit is reversed. If a bit is 1, the result is 0; if a bit is 0, the result is 1.

The NOT operator can be used on expressions that yield bit-string values (bit-string, relational, and logical expressions). It can also be used to negate the meanings of the relational operators (<, >, =). For example:

IF A ^> B THEN
       /* equivalent to IF A <= B ... */

The result of a logical NOT operation on a bit-string expression is a bit-string value. For example:

DECLARE (BITA, BITB) BIT (4);
BITA = '0011'B;
BITB = ^BITA;

The resulting value of BITB is 1100.

The NOT operator can test the falsity of an expression in an IF statement. For example:

IF ^(MORE_DATA) THEN ...

6.2.2.2. AND

The ampersand (&) character is the logical AND operator in PL/I. In a logical AND operation, two bit-string operands are compared bit by bit. If two corresponding bits are 1, the corresponding bit in the result is 1; otherwise, the resulting bit is 0.

The result of a logical AND operation is a bit-string value. All relational expressions result in bit strings of length 1; they can therefore be used as operands in an AND operation. If the two operands have different lengths, the shorter operand is converted to the length of the longer operand, and the greater length is the length of the result.

Examples
DECLARE (BITA, BITB, BITC) BIT (4);
BITA = '0011'B;
BITB = '1111'B;
BITC = BITA & BITB;

The resulting value of BITC is '0011'B.

The AND operator can test whether two or more expressions are both true in an IF statement. For example:

IF (LINENO(PRINT_FILE) < 60) &
       (MORE_DATA = 'YES') THEN ...

6.2.2.3. OR

The vertical bar character (|) represents the logical OR operation in PL/I. In a logical OR operation, two bit-string operands are compared bit by bit. If the two operands are of different lengths, the shorter operand is converted to the length of the longer operand, and this is the length of the result. If either of two corresponding bits is 1, the resulting bit is 1; otherwise, the resulting bit is 0.

All relational expressions result in bit strings of length 1, and they can therefore be used as operands in an OR operation.

The result of the OR operation is a bit-string value. For example:

DECLARE (BITA, BITB, BITC) BIT (4);
BITA = '0011'B;
BITB = '1111'B;
BITC = BITA | BITB ;

The resulting value of BITC is '1111'B.

The OR operator can test whether one of the expressions in an IF statement is true. For example:

IF (LINENO(PRINT_FILE) < 60) |
       (MORE_DATA = YES) THEN ...

You can use the exclamation point (!) vertical bar, for compatibility with other PL/I implementations.

6.2.2.4. EXCLUSIVE OR

The EXCLUSIVE OR operator (infix or dyadic ^) causes a bit-by-bit comparison of two bit-string operands. If the two operands are not of equal length, the shorter is padded with 0s until it is the same length as the other, and this length is also the length of the result. If either of two corresponding bits is 1 and the other is 0, the result is 1. If both are 1, or if both are 0, the result is 0.

All relational expressions result in bit strings of length 1, and they can therefore be used as operands in an EXCLUSIVE OR operation.

The result of the EXCLUSIVE OR operation is a bit-string value. For example:

DECLARE (BITA, BITB, BITC) BIT (4);
BITA = '0011'B;
BITB = '1011'B;
BITC = BITA ^ BITB;

The resulting value of BITC is '1000'B.

The EXCLUSIVE OR operator can be used to test whether one and only one of the expressions in an IF statement is true. For example:

IF (A > 0) ^ (B > 0) THEN ...

6.2.2.5. AND THEN

The ampersand-colon token (&:) is the AND THEN operator in PL/I. The AND THEN operator causes the first operand to be evaluated; if it is false, the result returned is '0'B. The second operand will never be evaluated if the first operand is false. If and only if the first operand is true, the second operand is evaluated. If both are true, the result returned is true ('1'B); otherwise, the result is false ('0'B).

The AND THEN operator performs a Boolean truth evaluation, not a bit-by-bit operation, even when the two operands are bit strings. For example, '00001'B &: '10000'B yields '1'B (not '00000'B, which would be the result of an AND operation on these two bit strings). The reason is that each operand is a non-zero bit value, and therefore each evaluates to '1'B.

The AND THEN operator yields the same result as the AND operator (&) when expressions are tested in an IF statement (as in the last example in Section 6.2.2.2, “AND”). The difference is that the AND operator can have its operands evaluated in either order.

The AND THEN operator is useful in compound test expressions in which the second test should occur only if the first test was successful. For example:

IF (P ^= NULL()) &: (P->X ^= 4) THEN ...

This statement causes P->X to be evaluated only if P is not a null pointer. If the AND operator were used instead of AND THEN, this expression could cause an access violation (invalid pointer reference).

6.2.2.6. OR ELSE

The vertical bar and colon characters (|:) together are the OR ELSE operator in PL/I. The OR ELSE operator causes the first operand to be evaluated. If it is true, the result returned is '1'B. If and only if the first operand is false, the second operand is evaluated. If either or both operands are true, the result returned is '1'B; otherwise, the result is '0'B.

The OR ELSE operator performs a Boolean truth evaluation, not a bit-by-bit operation, even when the two operands are bit strings. For example:

'00001'B |: '10000'B

This yields:

'1'B

It does not yield'10001'B, which would be the result of an OR operation on these two bit strings. The reason is that each operand is a nonzero bit value, and therefore each evaluates to '1'B.

The OR ELSE operator yields the same result as the OR operator (|) when expressions are tested in an IF statement (as in the last example in the "OR Operator" entry). The difference is that the OR operator can have its operands evaluated in any order.

The OR ELSE operator is useful in compound test expressions in which the second test should occur only if the first test failed. For example:

IF (A=0) |: (B/A > 1) THEN ...

This results in the second expression (B/A > 1) being evaluated only if the first expression is false. Thus, the OR ELSE operator prevents an attempt to divide by zero.

6.2.3. Relational Operators

The relational, or comparison, operators test the relationship of two operands; the result is always a Boolean value (that is, a bit string of length 1). If the comparison is true, the resulting value is '1'B; if the comparison is false, the resulting value is '0'B. The relational operators are all infix operators. The following table describes all the relational operators:

OperatorOperation
<Less than
^<Not less than
<=Less than or equal to
=Equal to
^=Not equal to
>=Greater than or equal to
>Greater than
^>Not greater than

Note that PL/I recognizes the tilde symbol (~)as synonymous with the circumflex (^).

Relational operators compare any of the following data types: arithmetic (decimal or binary); bit-string; character-string; and entry, pointer, label, or file data. Specific results of operations on each type of data are elaborated below. The following general rules apply:

  • All operands must be scalar.

  • Both operands must be arithmetic, or they must have the same data type.

6.2.3.1. Arithmetic Comparisons

Arithmetic and picture operands are compared algebraically. If the operands have a different base, scale, or precision, PL/I converts them according to the rules for arithmetic operand conversion.

6.2.3.2. Bit-String Comparisons

When two bit strings are compared, they are compared bit by bit from the most significant bit to the least significant bit (as represented by PUT LIST). If the operands have different lengths, PL/I extends the smaller operand with zeros in the direction of the least significance. Null bit strings are equal.

6.2.3.3. Character-String Comparisons

When two character strings are compared, they are compared character by character in a left-to-right order. The comparison is based on the ASCII collating sequence. The ASCII characters are the first 128 characters of the DEC Multinational Character Set.

Note the following characteristics of the collating sequence:

  • Uppercase letters are less than any lowercase letters.

  • Numeric characters are less than any letters.

If the operands do not have the same length, PL/I extends the smaller operand on the right with blanks for the comparison. Either or both of the strings can have the attribute VARYING; PL/I uses the current length of a varying character string when it makes the comparison. Null character strings are equal.

6.2.3.4. Comparing Noncomputational Data

Only the following operators are valid, or meaningful, for comparisons of any of the noncomputational data types except areas (condition, entry, file, label, offset, and pointer):

OperatorOperation
=Equal
^=Not equal

The results of the comparisons provide the information indicated below for each data type.

Condition Data

Two condition values are equal if they identify the same condition values.

Entry Data

Two entry values are equal if they identify the same entry point in the same block activation of a procedure.

File Data

Two values defined with the FILE attribute are equal if they identify the same file constant.

Label Data

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

Offset Data

Two offset values are equal if they identify the same storage location or if they are both null.

Pointer Data

Two pointer values are equal if they identify the same storage location or if they are both null.

6.2.4. Concatenation Operator

The concatenation operator produces a single string from two strings specified as operands. The concatenation operator is two vertical bars (| |).

The operands must both be character strings or both be bit strings. (If not, the appropriate conversion is performed, and you get a warning message about the conversion. The result of the operation is a string of the same type as the operands.

Examples

CONCAT: PROCEDURE OPTIONS(MAIN);
DECLARE OUTFILE STREAM OUTPUT PRINT FILE;

       PUT FILE(OUTFILE) SKIP LIST('ABC' || 'DEF');
       PUT FILE(OUTFILE) SKIP LIST('001'B || '110'B);
       PUT FILE(OUTFILE) SKIP LIST((3)'001'B !! '07'B3);

END CONCAT;

The program CONCAT writes the following output to the file OUTFILE.DAT:

ABCDEF
'001110'B
'001001001000111'B

Note that the exclamation point can be used in place of the vertical bar, for compatibility with other PL/I implementations.

6.3. Precedence of Operators and Expression Evaluation

The precedence, or priority, of operators defines the order in which expressions are evaluated when they contain more than one operator. Table 6.4, “Precedence of Operators” gives the priority of PL/I operators. Low numbers indicate high priority. For example, the exponentiation operator (**) has the highest priority (1), so it is performed first, and the OR ELSE operator (| :) has the lowest priority, so it is performed last.

Table 6.4. Precedence of Operators
OperatorPriorityLeft/Right AssociativeOrder of Evaluation
()0N/Adeepest first
**1rightleft to right
+ (prefix)1N/AN/A
- (prefix)1N/AN/A
^ (prefix)1N/AN/A
*2leftleft to right
/2leftleft to right
+ (infix)3leftleft to right
- (infix)3leftleft to right
| |4leftleft to right
>5leftleft to right
<5leftleft to right
^>5leftleft to right
^<5leftleft to right
=5leftleft to right
^=5leftleft to right
<=5leftleft to right
>=5leftleft to right
&6leftleft to right
|7leftleft to right
^ (infix)7leftleft to right
&:8leftleft to right across entire expression
|:9leftleft to right across entire expression

Expressions are evaluated from left to right, with the following qualifications:

  • Some PL/I operators take precedence over others used in the same expression. Operations with higher precedence are evaluated first, and their results are used as single operands. The rules of precedence usually guarantee an algebraically correct result without the use of parentheses. All built-in functions are of equal precedence.

  • Any expression can be enclosed in parentheses to override the usual rules of precedence. Expressions at the deepest level of nested parentheses are always evaluated first, and their results are used as single operands.

    Consider the expression:

A |: B &: C

It should be parenthesized according to the rules of associativity as:

(A |: (B &: C))

However, the semantics of the OR ELSE (|:) and AND THEN (&:) operators dictate that the operands be evaluated in the order A, B, C as necessary. This means that the B &: C will be evaluated before A which might not be the intent of the programmer and might not conform to the semantic rules of the OR ELSE (|:) operator.

When PL/I determines which to evaluate first, (1) the deeply nested B &: C (consistent with the order of evaluation for parentheses), or (2) the A |: (consistent with the order of evaluation of |:), (1) the deeply nested B &: C is chosen.

Whenever an expression that contains any combination of two or more &: or |: operators, the order of operand evaluation will be performed in the order dictated by the associativity of the operators. This may or may not be the desired behavior. To work around this, you will have to construct similar program sequences using IF THEN constructs in conjunction with either the AND (&) operators to achieve the desired behavior.

  • Exponential operations of the form A **B **C are evaluated from right to left.

  • The run-time evaluation of a logical expression can be terminated as soon as its result is known. For instance:

A & USER_FUNCTION(ALPHA,BETA)

Evaluation of this expression can be terminated without the USER_FUNCTION reference being evaluated if the evaluation of A results in a false Boolean value. However, the evaluation of A might not occur first, because the order of evaluations is not guaranteed in AND operations. To ensure that the first operand is evaluated first, use &:, which is the AND THEN operator, instead of &.

  • The compiler may evaluate the subexpressions of an expression in any order that produces an algebraically correct result. For example:

A + B + FUNC(I) + C

The subexpression A+B might not be evaluated and the result stored before FUNC(I) is evaluated. Therefore, if FUNC(I) alters A, B, or C, results may not be as expected.

  • If a function referenced in an expression executes a nonlocal GOTO statement, the expression is not evaluated further.

6.4. Data Type Conversion of Operands and Expressions

Conversion is the changing of a data item from one data type to another. Data conversion in PL/I takes place in many contexts, not all of them obvious ones. Program results that seem improper may in fact be caused by data conversion at some point during program execution. This section discusses the following topics:

  • When PL/I converts data

  • How arithmetic operands of different types are converted to a single derived type during expression evaluation

  • How nonarithmetic operands of different types are converted to the same type

  • How you can control conversions precisely by using conversion built-in functions designed for that purpose

  • Assignments to arithmetic variables

    • From any arithmetic data type to any other arithmetic data type

    • From pictured to any arithmetic type

    • From bit-string to any arithmetic data type

    • From character-string to any arithmetic data type

  • Assignments to bit-string variables

    • From any arithmetic data type to bit-string

    • From pictured to bit-string

    • From character-string to bit-string

  • Assignments to character-string variables

    • From any arithmetic data type to character-string

    • From pictured to character-string

    • From bit-string to character-string

  • Assignments to pictured variables

    • From any computational type to pictured

  • Conversions between offsets and pointers

6.4.1. Contexts in which PL/I Converts Data

PL/I can perform data conversions in the following contexts:

  • Assignment statements

  • Arguments passed to a procedure

  • Values specified in a RETURN statement

  • An argument converted by the built-in function FIXED, FLOAT, BINARY, DECIMAL, BIT, or CHARACTER

  • Conversions to and from character strings performed by the PUT and GET statements, respectively

If an attempt is made to assign a value to a target for which there is no defined conversion, the compiler generates a diagnostic message. For example:

F = '133.45';

If F is a variable with the attributes FIXED DECIMAL (5,2), then the statement assigns the numeric value 133.45 to F, as expected, although the compiler issues a WARNING message about the implicit conversion, stating that the constant '133.45' has been converted to a FIXED DECIMAL target. The warning does not prevent you from linking and running the program. However, note the following example:

F = 'ABC';

This statement results not only in a compiler WARNING message but, if you go on to link and run the program, you also receive a CONVERSION condition. This is normally fatal unless it is handled with an ON CONVERSION ON-unit.

Table 6.5, “Contexts in Which PL/I Converts Data” describes the contexts in which PL/I converts data. The table also lists the built-in conversion functions, such as BINARY and CHARACTER, which you can use when you want to explicitly indicate a conversion and to specify such characteristics as the precision or string length of the converted result.

Table 6.5. Contexts in Which PL/I Converts Data
ContextConversion Performed
target = expression;In an assignment statement, the given expression is converted to the data type of the target.
entry-name
RETURNS (attribute ...);
⋮
RETURN (value);
In a RETURN statement, the specified value is converted to the data type specified by the RETURNS option on the PROCEDURE or ENTRY statement.

x + y

x - y

x * y

x / y

x**y

x | | y

x & y

x | y

x&:y

x | :y

x ^ y

x > y

x < y

x = y

x^=y

In any expression, if operands do not have the required data type, they are converted to a common data type before the operation. For most operators, the data types of all operands must be identical. A warning message is issued in the case of a concatenation conversion.

BINARY (expression)

BIT (expression) CHARACTER (expression)

DECIMAL (expression)

DECODE (expression)

ENCODE (expression)

FIXED (expression)

FLOAT (expression)

OFFSET (variable)

POINTER (variable)

PL/I provides built-in functions that perform specific conversions.
PUT LIST (item, ...);Items in a PUT LIST statement are converted to character- string data.
GET LIST (item, ...);Character-string input data is converted to the data type of the target item.

PAGESIZE (expression)

LINESIZE (expression)

SKIP (expression)

LINE (expression)

COLUMN (expression)

format items A, B, E, F, and X

TAB (expression)

Values specified for various options to PL/I statements must be converted to integer values.
DO control-variable ...Values are converted to the attributes of the control variable.
parameterActual parameters are converted to the type of the formal parameter, if necessary.
INITIAL attributeInitial values are converted to the type of the variable being initialized.

6.4.2. Derived Data Types for Arithmetic Operations

Even though arithmetic operands can be of different arithmetic types, all operations will be performed on objects of the same type. Any set of operands of different arithmetic types has an associated derived type, as follows:

  • If any operand has the attribute BINARY, the derived type is BINARY. Otherwise, the derived type is DECIMAL.

  • If any operand has the attribute FLOAT, the derived type is FLOAT. Otherwise, the derived type is FIXED.

Table 6.6, “Derived Data Types” gives the derived data type for two arithmetic operands of different types. (Note that the types derived from FIXED DECIMAL in Table 6.6, “Derived Data Types” are also derived when one operand is pictured.)

Table 6.6. Derived Data Types
Type of Operand 1Type of Operand 2Derived Type
FIXED BINARYFLOAT BINARYFLOAT BINARY
FIXED BINARYFLOAT DECIMALFLOAT BINARY
FIXED DECIMALFLOAT DECIMALFLOAT DECIMAL
FIXED DECIMALFLOAT BINARYFLOAT BINARY
FIXED BINARYFIXED DECIMALFIXED BINARY

Table 6.7, “Converted Precision as a Function of Target and Source Attributes” gives the precision resulting from the conversion of an operand to its derived type. The values p and q are known as the converted precision of an operand and are based on the values p and q of the source operand.

Table 6.7. Converted Precision as a Function of Target and Source Attributes
Target Data TypeBinary Fixed Source[a]Decimal Fixed Source[a]Binary Float Source ???Decimal Float Source ???
Binary Fixedp qmin(ceil(p*3.32)+1,31) min(ceil(q*3.32),31)N/A N/AN/A N/A
Decimal Fixedmin(ceil(p/3.32)+1,31) max(0,min(ceil(q*3.32),31))p qN/A N/AN/A N/A
Binary Floatmin(p,53)min(ceil(p*3.32),53)pmin(ceil(p*3.32), 53)
Decimal Floatmin(ceil(p/3.32),15)min(p,15)min(ceil(p/3.32),15)p

[a] The constant 3.32 is an approximation of log2(10), the number of bits required to represent a decimal digit.


All arithmetic operations except exponentiation are performed in the derived type of the two operands. Exponential operations are performed in a data type that is based on the derived type of the operands. All operations, including exponentiation, have results of the same type as that in which they are performed.

The result of an arithmetic operation can be assigned to a target variable of any computational type. The result is converted to the target type, following the rules in Section 6.4.5, “Implicit Conversion During Assignment”.

6.4.3. Conversion of Operands in Nonarithmetic Operations

As operations must be performed on operands of the same type, the following conversions are performed when operands do not match in nonarithmetic operations:

  • PICTURE is converted to CHARACTER.

  • DECIMAL is converted to CHARACTER.

  • FIXED BINARY is converted to BIT.

  • If either operand is CHARACTER, after other conversions have been performed, the noncharacter operand is converted to CHARACTER.

PL/I issues a warning message about a conversion in a concatenation expression, except when converting from picture to character.

6.4.4. Built-In Conversion Functions

The built-in conversion functions can take arguments that are either arithmetic or string expressions. They are often used to convert an operand to the type required in a certain context—for instance, to convert a bit string to an arithmetic value for use as an arithmetic operand.

For the purpose of these functions, and in a few other contexts, derived arithmetic attributes are also defined for bit- and character-string expressions:

  • The derived type of a bit string is fixed-point binary. Its converted precision is 31, with a scale factor of 0.

  • The derived type of a character string is fixed-point decimal. Its converted precision is 31, with a scale factor of 0.

PL/I uses these derived attributes to determine the precision of values returned by the conversion functions if no precision is specified in the functions' argument lists. Note that the value of a string argument must also be convertible to the result type; for instance, '1.333' is convertible to arithmetic, but 'XYZ' is not.

Table 6.8, “Built-In Functions for Conversions Between Arithmetic and Nonarithmetic Types” indicates which built-in functions you should use for each conversion between an arithmetic and a nonarithmetic type. In addition, you can use the BINARY, DECIMAL, FIXED, and FLOAT built-in conversion functions to control conversions between two arithmetic types.

Table 6.8. Built-In Functions for Conversions Between Arithmetic and Nonarithmetic Types
ConversionFunction
Arithmetic to bitBIT
Arithmetic to characterCHARACTER
Arithmetic or character to fixed-point arithmeticFIXED
Bit to arithmeticBINARY
Bit to characterCHARACTER
Character to bitBIT
Character to decimalDECIMAL
Character to floatFLOAT
Arithmetic or character to binaryBINARY
Character to fixed binaryDECODE
Decimal integer to characterENCODE
Integer (non-negative) to characterBYTE

6.4.5. Implicit Conversion During Assignment

During assignment, PL/I automatically converts the derived data type of an expression to the data type of a target, if necessary. In assignments, conversions are defined between the noncomputational types POINTER and OFFSET, and between any two computational types. However, a conversion during assignment results in an error if PL/I cannot perform it in a meaningful way. For example, you can assign the string '123.4' to a fixed decimal variable; you cannot, however, assign the string 'ABCD' to the same variable. Similarly, an assignment of an arithmetic type to a fixed variable results in the FIXEDOVERFLOW condition if integral digits are lost.

Although PL/I performs conversions in assignment statements, such conversions may represent programming errors and are in violation of the PL/I G subset standard. Therefore, the compiler issues a warning message that an implicit conversion is taking place. These messages do not terminate the compilation and may not indicate errors; they simply alert you to the fact that your program converts one data type to another in a way that may cause a problem when the program is run. You can prevent such warning messages in two ways:

  • Use the built-in conversion functions to convert data types explicitly. This method is recommended. Section 6.4.4, “Built-In Conversion Functions” summarizes the functions.

  • Use the -w or --nowarn option on the PLI command to suppress diagnostic warning messages. (The compiler will continue to print messages of greater severity.) However, you run the risk of missing important diagnostic information.

For example:

DECLARE (A,B) FIXED DECIMAL (5,2);
       A = '123.45';   /* Warning message */
       B = FIXED('123.45',5,2);        /* No warning */

Both assignment statements assign the same value to their targets; however, the first statement causes a warning message from the compiler, while the second statement does not.

6.4.6. Assignment to Arithmetic Variables

Expressions of any computational type can be assigned to arithmetic variables. The conversion rules for each source type are described in the following sections.

6.4.6.1. Arithmetic to Arithmetic Conversions

A source expression of any arithmetic type can be assigned to a target variable of any arithmetic type. Note the following qualifications:

  • If the target is a variable of type FIXED BINARY or FIXED DECIMAL, then the FIXEDOVERFLOW condition is signaled when the source value has a larger number of integral digits than are specified in the precision of the target. If the target is a fixed- point binary variable, FIXEDOVERFLOW is signaled if the source value exceeds the storage allocated for the target, which can be larger than the declared precision of the target.

  • If the target is a variable of type FIXED DECIMAL(p,q) or FIXED BINARY(p,q) and the source value has more than q fractional digits, then the excess fractional digits of the source are truncated, and no condition is signaled. If the source has fewer than q fractional digits, the source value is padded on the right with zeros.

  • If the target value is floating point and the absolute source value is too large to be represented by a floating-point type, then the OVERFLOW condition is signaled, and the value of the target is undefined.

Conversions to Fixed Point

In the following examples, the specified source values are converted to FIXED DECIMAL(4,1):

Source ValueConverted Value
25.50525.5
-2.562-2.5
101101.0
5365FIXEDOVERFLOW - value undefined
Conversions to Floating Point

Let p be the precision of the floating-point target. If the source value is an integer that can be represented exactly in p digits, then the source value is converted to floating-point binary with no loss of accuracy.

Otherwise, the source value is converted to floating-point binary with rounding to precision p. For example, the constant 479 will be converted to FLOAT BINARY(24) without loss of accuracy, while the constant 16777217, which cannot be represented exactly in 24 bits, will be rounded during conversion.

Conversions from FIXED BINARY to Other Data Types

Conversions from FIXED BINARY to other data types follow the rules outlined below. Notice that these rules assume both precision and scale.

Precisions of the source and target are (p,q) and (p1,q1), respectively. The precision of the result is (p2,q2).

Table 6.9. Conversion from Fixed Binary
TargetResult
FIXED DECIMAL(p1,q1)p2=1+CEIL(p1/3.32) and q2=CEIL(q1/3.32).
FIXED BINARY(p1,q1)Precision and scale of the source are maintained during conversion; therefore, padding or truncation can occur. If nonzero bits are lost on the left, the result is undefined.
FLOAT DECIMAL(p1)p2=CEIL(p1/3.32). The exponent indicates any fractional value.
FLOAT BINARY(p1)p2=p1. The mantissa indicates any fractional value.
PICTUREThe target implies FIXED DECIMAL and is converted accordingly.
CHARACTERThe binary precision (p,q) is converted to a FIXED DECIMAL with precision (p1,q1), where p1=1+CEIL(p/3.32) and q1=CEIL(q/3.32). Then the rules for conversion from FIXED DECIMAL to CHARACTER are in effect.
BITThe binary precision (p,q) is converted to an intermediate bit string where the size or precision is MIN(31,p-q). Then the intermediate bit string is converted to BIT(n). If (p-q) is negative or zero, the result is a null bit string.

If the scale factor is negative, substitute the FLOOR value for CEIL in the above calculations which contain q's.

6.4.6.2. Pictured to Arithmetic Conversions

In PL/I all pictured values have the associated attributes FIXED DECIMAL(p,q), where p is the total number of characters in the picture specification that specify decimal digits, and q is the total number of these digits that occur to the right of the V character. If the picture specification does not include a V character, then q is zero. This value is assigned to the target, following the PL/I rules for arithmetic to arithmetic conversion.

6.4.6.3. Bit-String to Arithmetic Conversions

When a bit-string value is assigned to an arithmetic variable, PL/I treats the bit string as a fixed-point binary value. A string of type BIT(n) is converted to FIXED BINARY(m,0), where m = min(n,31).

If the converted value is greater than or equal to 2 31 then FIXEDOVERFLOW is signaled. The leftmost bit in the bit string (as output by PUT LIST) is the most significant bit in the fixed-point binary value, not its sign. If the bit string is null, the fixed- point binary value is zero.

The intermediate fixed-point binary value is then converted to the target arithmetic type.

Note that bit strings are stored internally with the leftmost bit in the lowest address. The conversion to an arithmetic type must reverse the bits from this representation; therefore, you should avoid this conversion when performance is a consideration.

Examples
CONVTB: PROCEDURE OPTIONS(MAIN);

DECLARE STATUS FIXED BINARY(8);
DECLARE STATUS_D FIXED DECIMAL(10);
DECLARE OUT PRINT FILE;

OPEN FILE(OUT) TITLE('CONVTB.OUT');
ON FIXEDOVERFLOW PUT SKIP FILE(OUT)
LIST('Fixedoverflow:');

STATUS = '1001101'B;
PUT SKIP FILE(OUT) LIST(STATUS);

STATUS_D = '001101'B;
PUT SKIP FILE(OUT) LIST(STATUS_D);

STATUS = '1232'B2;
PUT SKIP FILE(OUT) LIST(STATUS);

STATUS = 'FF'B4;
PUT SKIP FILE(OUT) LIST(STATUS);

STATUS_D = '10111111111111111111111111111111'B;
END CONVTB;

Note that because the program CONVTB performs implicit conversions, the compiler issues WARNING messages. (Linking and running are accomplished successfully because the conversions are valid.)

The program CONVTB produces the following output:

       77
               13
       110
       255

Fixedoverflow:

The leftmost bit of all the bit-string constants is treated as the most significant numeric bit, not as a sign. For instance, the hexadecimal constant 'FF'B4 is converted to 255 instead of -127. The last assignment to STATUS_D signals the FIXEDOVERFLOW condition because the bit-string constant, when represented as a binary integer, is greater than 2 31 . The resulting value of STATUS_D is undefined.

6.4.6.4. Character-String to Arithmetic Conversions

When a character string is assigned to an arithmetic value, PL/I creates an intermediate numeric value based on the characters in the string. The type of this intermediate value is the same as that of an ordinary arithmetic constant comprising the same characters; for example, 342.122E-12 and '342.122E-12' are both floating-point decimal.

The character string can contain any series of characters that describes a valid arithmetic constant. That is, the character string can contain any of the numeric digits 0 through 9, a plus (+) or minus (-) sign, a decimal point (.), and the letter E. If the character string contains any invalid characters, the CONVERSION condition is signaled. See the following examples.

If the implied data type of the character string does not match the data type of the arithmetic target, PL/I converts the intermediate value to the data type of the target, following the PL/I rules for arithmetic to arithmetic conversions. In conversions to fixed point, FIXEDOVERFLOW is signaled if the character string specifies too many integral digits. Excess fractional digits are truncated without signaling a condition.

If the source character string is null or contains all spaces, the resulting arithmetic value is zero.

Examples
DECLARE SPEED FIXED DECIMAL (9,4);
SPEED = '23344.3882';
       /* string converted to 23344.3882 */

SPEED = '32423.23SD';
       /* CONVERSION condition */

SPEED = '4324324.3933';
       /* FIXEDOVERFLOW condition */

SPEED = '1.33336';
       /* string converted to 1.3333 */

6.4.7. Assignments to Bit-String Variables

In the conversion of any data type to a bit string, PL/I first converts the source data item to an intermediate bit-string value. Then, based on the length of the target string, it does the following:

  • If the length of the target bit-string value is greater than the length of the intermediate string, the target bit string (as represented by PUT LIST) is padded with zeros on the right.

  • If the length of the target bit-string value is less than the length of the intermediate string, the intermediate bit string (as represented by PUT LIST) is truncated on the right.

The next sections describe how PL/I arrives at the intermediate bit-string value for each data type.

6.4.7.1. Arithmetic to Bit-String Assignments

In converting an arithmetic value sv to a bit-string value, PL/I performs the following steps:

  1. Let v = abs(sv) .

  2. Determine a precision p as follows:

    SourcePrecision p
    FIXED BINARY(r,s)min(31,r-s)
    FLOAT BINARY(r)min(31,r)
    FIXED DECIMAL(r,s)min(31,ceil((r-s)*3.32))
    FLOAT DECIMAL(r)min(31,ceil(r*3.32))
  3. If p=0 (for example, when r=s), the intermediate string is a null bit string. Otherwise, the value v is converted to an integer n of type FIXED BINARY(p,0). If n>=2 p , the FIXEDOVERFLOW condition is signaled; otherwise, the intermediate bit string is of length p, and each of its bits represents a binary digit of n.

Bit strings are stored internally with the leftmost bit in the lowest address. The conversion must reverse the bits from this representation and should therefore be avoided when performance is a consideration. Note also that during the conversion, the sign of the arithmetic value and any fractional digits are lost.

Examples
CONVB: PROCEDURE OPTIONS(MAIN);

DECLARE NEW_STRING BIT(10);
DECLARE LONGSTRING BIT(16);
DECLARE OUT PRINT FILE;

OPEN FILE(OUT) TITLE('CONVB1.OUT');

NEW_STRING = 35;
PUT FILE(OUT) SKIP
       LIST('35 converted to BIT(10):',NEW_STRING);

NEW_STRING = -35;
PUT FILE(OUT) SKIP
       LIST('-35 converted to BIT(10):',NEW_STRING);

NEW_STRING = 23.12;
PUT FILE(OUT) SKIP
       LIST('23.12 converted to BIT(10):',NEW_STRING);
NEW_STRING = .2312;
PUT FILE(OUT) SKIP
       LIST('.2312 converted to BIT(10):',NEW_STRING);

NEW_STRING = 8001;
PUT FILE(OUT) SKIP
       LIST('8001 converted to BIT(10):',NEW_STRING);

LONGSTRING = 8001;
PUT FILE(OUT) SKIP
       LIST('8001 converted to BIT(16):',LONGSTRING);
END CONVB;

Note that because the program CONVB performs implicit conversions, the compiler issues WARNING messages. (Linking and running are accomplished successfully because the conversions are valid.)

The program CONVB produces the following output:

35       converted to BIT(10):  '0100011000'B
-35      converted to BIT(10):  '0100011000'B
23.12    converted to BIT(10):  '0010111000'B
.2312    converted to BIT(10):  '0000000000'B
8001     converted to BIT(10):  '0111110100'B
8001     converted to BIT(16):  '0111110100000100'B

The values 35 and -35 produce the same bit string because the sign is lost in the conversion. In the first assignment, 35, which is FIXED DECIMAL(2,0), is converted to FIXED BINARY(7,0) and then to a 7-bit string ('0100011'B). Three additional bits are appended to this intermediate bit string when it is assigned to NEW_STRING. Notice that the low-order bit of 8001 is lost when the constant is assigned to a BIT(10) variable.

6.4.7.2. Pictured to Bit-String Conversions

If the source value is pictured, its associated fixed-point decimal value is extracted. The fixed-point decimal value is then converted to a bit string, following the previous rules for arithmetic to bit-string conversion.

6.4.7.3. Character-String to Bit-String Conversions

PL/I can convert a character string of 0s and 1s to a bit string. Any character in the character string other than 0 or 1, including spaces, will signal the CONVERSION condition.

PL/I converts each 0 or 1 character in the character string to a 0 or a 1 bit in the corresponding position (as represented by PUT LIST) in the intermediate bit string.

If the source is a null character string, the intermediate string is a null bit string.

Examples
DECLARE NEW_STRING BIT(4);

NEW_STRING = '0010';
       /* NEW_STRING = '0010'B */

NEW_STRING = '11';
       /* NEW_STRING = '1100'B */

NEW_STRING = 'AS110';
       /* CONVERSION condition */

6.4.8. Assignments to Character-String Variables

In the conversion of any data type to a character string, PL/I first converts the source value to an intermediate character-string value. Then it does one of the following:

  • If the length of the intermediate string is zero, a null string is assigned to the target.

  • If the target is a parameter or return value with an asterisk extent (as in RETURNS CHAR(*)), the intermediate string is assigned to the target.

  • If the target is of type CHARACTER, and the intermediate string is shorter than the maximum length of the target, the target is assigned the value of the intermediate string without trailing spaces if the target has the VARYING attribute. If the target does not have the VARYING attribute, the string is padded with trailing spaces.

  • If the maximum length of the target character string is less than the length of the intermediate string, the intermediate string is truncated.

The rules for how PL/I arrives at the intermediate string for conversion of each data type are described below. Examples illustrate the intermediate value as well as the resulting value.

6.4.8.1. Arithmetic to Character-String Conversions

The manner in which PL/I converts an arithmetic data item depends on the data type of the item, as described below.

Conversion from Fixed-Point Binary or Fixed-Point Decimal

If the data item source value is of type FIXED BINARY(p1,q1), PL/I first converts it to type FIXED DECIMAL(p2,q2), where:

p2 = min(ceil(p1/3.32)+1,31)

q2 = max(0,min(ceil(q1/3.32),31))

PL/I converts a value with attributes FIXED DECIMAL(p,q) to an intermediate string of length p+3. The numeric value is right-justified in the string. If the value is negative, a minus sign immediately precedes the value. If q is greater than zero, the value contains a decimal point followed by q digits. When p equals q, a 0 character precedes the decimal point. When q equals zero, a value of zero is represented by the 0 character.

Alternatively, the format of the intermediate string can be described by picture specifications, as follows:

  1. If q=0, the intermediate string is the string created by the following picture specification:

'BB(p)-9'

That is, the first two characters of the string are spaces. The last p characters in the string are the digit characters representing the integer; leading zeros are replaced by spaces except in the last position. If the integer is negative, a minus sign immediately precedes the first digit; if the number is not negative, this position contains a space. At least one digit always appears in the last position in the string.

  1. If p=q, the intermediate string is the string created by the following picture specification:

'-9V.(q)9'

That is, the first three characters are (in order) an optional minus sign if the fraction is negative, the digit 0, and a decimal point. If the number is not negative, the first character is a space. The last q characters in the string are the fractional digits of the number.

  1. If p > q, the intermediate string is the string created by the following picture specification:

'B(p-q)-9V.(q)9'

That is, the first character is always a space; the last q characters are the fractional digits of the number and are preceded by a decimal point; the decimal point is always preceded by at least one digit, which can be zero; all integral digits appear before the decimal point, and leading zeros are replaced by spaces; a minus sign precedes the first integral digit if the number is negative; if the number is not negative, then the minus sign is replaced by a space.

Examples
DECLARE STRING_1 CHARACTER (8),
       STRING_2 CHARACTER (4);

STRING_1 = 283472.;
       /* intermediate string = ' 283472',
       STRING_1 = ' 28347' */

STRING_2 = 283472.;
       /* intermediate string = ' 283472',
       STRING_2 = ' 2' */

STRING_2 = -283472.;
       /* intermediate string = ' -283472',
       STRING_2 = ' -2' */

STRING_2 = -.003344;
       /* intermediate string = '-0.003344',
       STRING_2 = '-0.0' */

STRING_2 = -283.472;
       /* intermediate string = ' -283.472',
       STRING_2 = ' -28' */

STRING_2 = 283.472;
       /* intermediate string = ' 283.472',
       STRING_2 = ' 28' */
Conversion from Floating-Point Binary or Floating-Point Decimal

If the data item source value is of type FLOAT BINARY(p1), it is converted to FLOAT DECIMAL(p2), where:

p2 = min(ceil(p1/3.32),15)

For a value of type FLOAT DECIMAL(p), where p is less than or equal to 15, the intermediate string is of length p+6; this allows extra characters for the sign of the number, the decimal point, the letter E, the sign of the exponent, and the 2-digit exponent.

If the number is negative, the first character is a minus sign; otherwise, the first character is a space. The subsequent characters are a single digit (which can be 0), a decimal point, p-1 fractional digits, the letter E, the sign of the exponent (always + or -), and the exponent digits. The exponent field is of fixed length, and the zero exponent is shown as all zeros in the exponent field.

Examples
CONCH: PROCEDURE OPTIONS(MAIN);

DECLARE OUT PRINT FILE;
OPEN FILE(OUT) TITLE('CONCH.OUT');

PUT SKIP FILE(OUT) EDIT('''',25E25,'''') (A);
PUT SKIP FILE(OUT) EDIT('''',-25E25,'''') (A);
PUT SKIP FILE(OUT) EDIT('''',1.233325E-5,'''') (A);
PUT SKIP FILE(OUT) EDIT('''',-1.233325E-5,'''') (A);

END CONCH;

The program CONCH produces the following output:

'2.5E+26'
'-2.5E+26'
' 1.233325E-05'
'-1.233325E-05'

The PUT statement converts its output sources to character strings, following the rules described in this section. (The output strings are surrounded with apostrophes to make the spaces distinguishable.) In each case, the width of the quoted output field (that is, the length of the converted character string) is the precision of the floating-point constant plus 6.

6.4.8.2. Pictured to Character-String Conversion

If the source value is pictured, its internal, character-string representation is used without conversion as the intermediate character string.

6.4.8.3. Bit-String to Character-String Conversion

When PL/I converts a bit string to a character string, it converts each bit in the bit string (as represented by PUT LIST) to a 0 or 1 character in the corresponding position of the intermediate character string.

If the bit string is a null string, the intermediate character string is also a null string.

Examples
DECLARE STRING_1 CHARACTER (4),
       STRING_2 CHARACTER (8);

STRING_1 = '1010'B;
       /* STRING_1 = '1010' */

STRING_2 = '1010'B;
       /* STRING_2 = '1010 ' */

STRING_1 = '010011'B;
       /* STRING_1 = '0100' */

6.4.9. Assignments to Pictured Variables

A source expression of any computational type can be assigned to a pictured variable. The target pictured variable has a precision (p), which is defined as the number of characters in the picture specification that specify decimal digits. The target also has a scale factor (q) which is defined as the number of picture characters that specify digits and occur to the right of the V character in the picture specification. If the picture specification contains no V character, or if all digit-specification characters are to the left of V, then q is zero.

The source expression is converted to a fixed-point decimal value v of precision (p,q), following the PL/I rules for the source data type. This value is then edited to a character string s, as specified by the picture specification, and the value s is assigned to the pictured target.

When the value v is being edited to the string s, the CONVERSION condition is signaled if the value of v is less than zero and the picture specification does not contain one of the characters S, +, -, T, I, R, CR, or DB. The value of s is then undefined. FIXEDOVERFLOW is signaled if the value v has more integral digits than are specified by the picture specification of the target.

6.4.10. Conversions Between Offsets and Pointers

Offset variables are given values by assignment from existing offset values or from conversion of pointer values. Pointer variables are given values by assignment from existing pointer values or from conversion of offset values.

The OFFSET built-in function converts a pointer value to an offset value. The POINTER built-in function converts an offset value to a pointer.

PL/I also automatically converts a pointer value to an offset value, and vice versa, in an assignment statement. The following assignments are valid:

pointer-variable = pointer-value;
offset-variable = offset-value;
pointer-variable = offset-variable;
offset-variable = pointer-value;

In the third and fourth assignments above, the offset variable must have been declared with an area reference.