# Software Engineers Handbook/Language Dictionary/PLI
## PL/I

Here is the Wikipedia entry.

### Type

PL/I is a full procedural language.

### Execution Entry Point

The program has its entry point specified as OPTIONS(MAIN), in a procedure statement, as in:

### Column specialties

There are no column specialities.

### General Syntax

An assignment example:
In this numeric assignment statement, d is subtracted from c, and the result multiplied by the value of b, before storing in variable a.
In this example string assignment, string u is joined to the end of string t, and the composite string is stored in string variable s.
Note: Using a compile-time option the concatenation operator || may be replaced by another pair of symbols, for being compatible with existing PL/I programs often !! is used.

### Comments

Every comment commences with the pair /* and terminates with the pair */. Comments may span lines.

### Variable Declarations

Declarations are not compulsory, though most PL/I compilers provide a compiler option to force declarations, while some of the subset compilers insist that every variable be declared.
To declare i as an binary:
To declare i as an binary and give it an initial value of 0
To declare a variable as decimal,
The first declaration is of an integer D stored in decimal format, while the second is of a variable E capable of storing ten digits having 4 digits after the decimal point. To initialize E, write:
Note that values such as 0.1 are stored exactly.
To define a floating-point variable:
that uses single precision hardware; and double precision:
and extended precision:
(typical declarations for the PC). The numbers 15 and 18 indicate the number of decimal digits that will be stored. (Although the values are actually held in binary, the decimal precisions are more convenient to recall than specifying the precisions in binary.) To specify a complex variable, simply include the word COMPLEX in the declaration, thus:
The assignment includes the complex constant 5.2+8i where 5.2 is the real part and 8 is the imaginary part.
The arithmetic data attributes for base (binary or decimal), scale (fixed or float) and mode (real or complex) may appear in any order, the attribute for precision (e.g. (15)) must not be the first one.
The following definitions are equivalent, except for the last one.
To declare a variable having the picture attribute:
describes variable P as having as total of 7 decimal digits, with three digits after the decimal point. The decimal point is held in storage. The letter V indicates the position of the actual decimal point. For Europe, the specification may include a comma:
To declare variable S as a character string:
String S can store exactly 10 characters.
To declare variable V as a character string capable of storing up to 100 characters:
A simple assignment:
V holds the three characters abc.
V holds the 8 characters friendly.
PL/I also permits bit strings:
permits bit strings to be stored, of length ten. The assignment statement:
stores the bits in the given order. Such bit strings can be searched, etc., just like character strings.
Data structures, or aggregates, may be declared:
Arrays are declared by one of the above means, along with dimension information:
specifies an array of ten elements, x(1) through x(10). The default lower bound is unity. To specify a different lower bound:
declares a 16-element array Y(0) through Y(15) of floating-point elements.
Multi-dimension array are declared by separating the dimensions with commas
defines a 2-dimensional array of 4 elements: M (1, 4), M (1, 5), M (2, 4), M (2, 5)
To handle dates given as 2-digit years and as 4-digit years, possibly intermixed in the same program, the DATE attribute may be used.
The keywords DECLARE and INITIAL may abbreviated as DCL and INIT, many attributes may abbreviated, too.
| Attribute | Abbreviation |
| BINARY | BIN |
| DECIMAL | DEC |
| CHARACTER | CHAR |
| VARYING | VAR |
| PICTURE | PIC |
| POINTER | PTR |

### Output Statements

The first example writes Hello world! on the standard output (a screen or printer or file). The words are printed after any output already on that line. The second example starts a new line (the word SKIP) before printing.

### Method Declaration/Implementation

Describe how methods/functions/procedures are declared and implemented. The following example is of a complete PL/I program containing a function.
The above program contains some typical input and output statements of the list-directed form. The first PUT statement prints the date. The second requests the reader to type three values representing the parameters of some triangle. The third echoes the inputs as confirmation. The last PUT statement contains a function reference, area(b, c, angle), which invokes the function. When it has been computed, the current PUT statement prints that area. The definition of the function AREA includes a PROCEDURE statement that lists the parameters required from the calling program, namely, b, c, and angle. These parameters are defined in the next statement (DECLARE). The PROCEDURE statement also states the type of the result to be returned to the calling program, namely, a floating-point value. This is indicated by RETURNS (FLOAT). The RETURN statement contains the formula to be used in calculating the area of the triangle. It then returns control to the calling program. A RETURN statement typically includes the name of a variable, but may include an expression (as is the case here).

### Scope

The scope of PL/I variables is confined to procedures in which they are declared. The scope extends into any procedures contained within that procedure (except of course any procedures in which a new declaration of the same name occurs).
In the event that a variable is not declared, then the scope of that variable is the whole program. Again, if a declaration (for a variable of the same name) appears in a block that is subordinate to the one(s) where the variable is (are) used, then the scope is excluded from the block containing the declaration.
PL/I has two kinds of blocks. One is the PROCEDURE block that is used for subroutines and functions. The other is the BEGIN block (BEGIN; ... END;). The BEGIN block behaves as a PROCEDURE block, except that a BEGIN block has no parameters nor does it have to have a label. It is entered in normal sequential execution, whereas a PROCEDURE block can be executed only by executing a CALL statement or function reference.

### Conditional Statements: IF..THEN..ELSE

Consider the two examples of conditional statements:
The first example illustrates one optionally-executed statement c = d;
The second example shows two optionally-executed statements, the first of which is executed when a > b, and the second of which is executed if a <= b;
When multiple statements are to be executed conditionally, statement brackets do and end are used.

### Multi-branch Conditionals: SELECT

The select-group offers a multi-branch evaluation, it may be written in one of the 2 following syntax schemes:
* SELECT ( var_or_expr ); WHEN ( val_1 ) unit_1; .... OTHERWISE unit_other; END;
* SELECT ; WHEN ( expr_1 ) unit_1; .... OTHERWISE unit_other; END;
A select-group of scheme type 1 has the form
var_or_expr and val_I ( I = 1..n ) may be variables or expressions.
unit_I ( I = 1..n ) and unit_other may be single statements or do-groups.
The select-group is evaluated as (pseudo code):
The OTHERWISE clause (which may be abbreviated OTHER) is optional, but if this clause is omitted and none of val_I equals TEMP a run time error will occur.
A WHEN clause may contain more than 1 value, e.g.
A select-group of scheme type 2 has the form
expr_I ( I = 1..n ) may be logical expressions or logical variables. unit_I ( I = 1..n ) and unit_other may be single statements or do-groups.
The select-group is evaluated as (pseudo code):
An example:

### Looping Statements

The basic form of looping statement is:
The body of the loop is executed ten times, with control variable k taking the values from 1 through 10. On loop exit, the value of k is one increment more, namely 11. The loop extends to the next END statement. Variations of looping statements are:
Multiple iterative specifications may be used:
in which the loop will be executed with control variable k taking the values 1 through 10, then 20, 25, 30, 35, ... 100, 120, 140, 160, 180, and 200.
A loop that is conditionally terminated uses the WHILE construct:
Such a loop is executed zero or more times, the test being performed at the beginning of the loop.
The loop specified by the above statement is executed at least once, the test being performed at the end of the loop.
In the following, a REPEAT is used to specify an unusual change in the value of the control variable.
In this case, the control variable k takes on the values 1, 2, 4, 8, 16, and so on, until k becomes greater than 1000.
The REPEAT form:
may be used to traverse a linked list.
WHILE and UNTIL may be combined:
(both examples are equivalent, i.e. the order of WHILE and UNTIL in the statement doesn't matter )
DO I = ... may by followed by WHILE or REPEAT or both of them:
(the last two examples are equivalent)
Order of evaluation:
is evaluated as:
* let I be 3
* if I > 9 then go to [7]
* if W = false then go to [7]
* ... some_statements ...
* if U = true then go to [7]
* let I be I + 2 and go to [2]
* put skip list ( 'I am ready' );
One more example: The following statement specifies that the do-group has to be executed eight times, with the value of I equal to 1, 3, 5, 9, 18, 36, 9, 18.

### Boolean Values

In PL/I bit (1) strings represents single boolean values:
* '1'B is interpreted as True
* '0'B is interpreted as False
Bit (1) strings may be used as boolean expressions in conditional and loop statements.
Boolean operators may be used for calculating new values:
* The prefix operator ¬ is used as logical NOT.
* The infix operator & is used as logical AND.
* The infix operator | is used as logical OR.
Note: Using compile-time options NOT operator and OR operator may be replaced by other symbols, for being compatible with existing PL/I programs often ^ is used as NOT, ! is used as OR.

### Error Handling/Recovery

PL/I provides error detection and error handling. Errors that are detected include
* floating-point overflow and underflow;
* fixed-point overflow;
* division by zero;
* subscript bound error;
* substring violation;
* string truncation.
* general errors.
The user can permit the system to report the error and perform a default action, or the user can specify a computational action to be executed when a given error is detected.
Events (including errors) are termed conditions.
For a condition to be detected, it must first be enabled. If the condition is enabled, and the corresponding condition occurs, the corresponding ON-unit (if supplied by the user) is executed.
Consider the following code:
In the event that the product b*c exceeds the maximum value permitted, the OVERFLOW condition is raised, and the ON-unit for OVERFLOW is executed. The ON-unit here is one of the simplest (go to), and merely transfers control to the statement labelled RESTART (where, perhaps, the program deals with the next set of values).
The keyword SNAP causes the running program to print an error message, along with the statement number where the error occurred.
A more general example follows:
In this example, the error detection and handling parts are shown in upper case. Subscript checking is enabled by the condition prefix SUBSCRIPTRANGE (parenthesised before the PROCEDURE statement). Before any statements are executed, the ON statement must be executed, which establishes the action to be carried out in the event of a subscript error. The next statement executed is the input statement GET, which reads in a value, say 12. The loop is entered, and initializes ten values of x. On attempting to initialize x(11), the SUBSCRIPTRANGE condition is raised, and causes the ON unit BEGIN; PUT DATA (K); STOP; END; to be executed. SNAP causes an error message to be printed along with the statement number, and then statements within the BEGIN block are executed, namely the PUT DATA statement, which prints K = 11. The program then STOPs. Some specific conditions are:
| OVERFLOW | exponent overflow |
| UNDERFLOW | exponent underflow |
| FIXEDOVERFLOW | fixed-point overflow |
| SIZE | fixed-point overflow |
| ZERODIVIDE | division by zero |
| SUBSCRIPTRANGE | subscript bound error |
| STRINGRANGE | substring error |
| STRINGSIZE | truncation of a string |
| ENDFILE | end of file |
| ENDPAGE | end of page |
| ATTENTION | request from keyboard |
Some conditions are provided to handle everyday events, for example, end of file and end of page. For example, to print a page number on the top of each page:
To detect the end of the input file IN, and to transfer to a named statement:
The programmer can invent his own conditions, and can signal them.
The SIGNAL statement is provided to test a given ON-unit (error-handler) during program testing. For example, SIGNAL ZERODIVIDE; To raise a user-defined condition called RANGE, the statement SIGNAL CONDITION(RANGE); would be used.

### Containers

<List containers or references to lists of containers available natively for this language. List ways to incorporate containers if they are not native to the language.>

### Algorithms

* Sort algorithms and an XML parser is provided by IBM for its compilers.

### Garbage collection

Any garbage collection is automatic. All variables with the automatic attribute or allocated with the automatic (auto) builtin are removed from storage at the end of the block where they are declared. All allocated storage (ALLOC statement or alloc builtin) is removed from storage at the end of the program.

### Physical Structure

The libraries of the standard functions are all automatically provided; it is unnecessary to do anything to obtain access to them, such as to specify directories or to use INCLUDE statements or the like.

### Tips

* Source programs may be written in upper or lower case. There is no difference between the cases, except within strings.
* Varying strings (declared with the attribute VARYING) are similar to C's char.
For an exact equivalent, in Enterprise PL/I for z/OS you may use the attribute VARYINGZ, in which strings are zero-terminated.
Without the attribute VARYING, strings are of fixed length. Such strings always store the specified number of characters. Thus,
stores eight characters, namely, abc followed by five blanks, whereas
requires a storage of 10 bytes: 2 bytes for the actual length of V and 8 bytes for the characters. This latter feature makes possible the assignment
which appends the word dog to what is already stored in V (up to a maximum of 8 characters in this example, of course).
is equivalent to C's int;
is equivalent to C's long int.
is equivalent to C's long long int.
* Decimal arithmetic, because it is fixed-point, needs some care.
The built-in functions ADD, SUBTRACT, MULTIPLY, and DIVIDE are provided to enable the programmer to specify the precision of each result. Thus they help to avoid overflow. For decimal fixed-point division, it is strongly recommended that the DIVIDE function be used. Thus, to divide A by B, where A has precision (10,5), and B has precision (6), the recommended form is:
In the DIVIDE reference, the arguments 10 and 5 direct that the result A/B has a total of ten digits, with 5 digits after the decimal point, respectively. This value is then stored in C. IBM PL/I permits up to 31 decimal digits for fixed-point working.
* When running PL/I programs, use the condition prefixes SIZE, STRINGRANGE, STRINGSIZE, and SUBSCRIPTRANGE, on the initial procedure statement thus:
This enables checking for fixed-point overflow, and range-checking and truncation for strings and for subscripts.
* The lower bound of arrays is unity by default, not zero.
* Division of integers (whether decimal or binary or mixed) may produce a fixed-point result having a scale factor. Thus, 9/2 produces 4.5000000, unlike Fortran which produces the integer 4. Should an integer result be required, TRUNC or DIVIDE may be used, thus: TRUNC(9/2) or - more generally - DIVIDE(J, K, 31), the latter giving 31 bits of precision for a binary integer result. Alternatively, declaring binary integer variables to have maximum precision (typically 31 bits) will ensure that the result of dividing two such integer variables will give an integer result.

### Web References

* IBM manuals: PL/I for MVS & VM
* IBM manuals: Enterprise PL/I for z/OS

### Books and Articles

* J. K. Hughes, PL/I Structured Programming, 3rd Ed., Wiley, 1986. (beginner to professional; commercial applications)
* R. Reddy & C. Ziegler, PL/I: Structured Programming and Problem Solving, West, 1986, ISBN 0-314-93915-6. (beginner to advanced)
* R. A. Barnes, PL/I for Programmers, North-Holland, 1979. (professional)
* G. F. Groner, PL/I Programming in Technological Applications, Books on Demand, Ann Arbor, MI, 1971. (professional)
* M. E. Anderson, PL/I for Programmers, Prentice-Hall, 1973. (professional)
* D. R. Stoutemyer, PL/I Programming for Engineering & Science, Prentice-Hall, 1971. (professional)
* E. Sturm, Das neue PL/I (fur PC, Workstations and Mainframe), 5th Ed., Vieweg-Verlag, 2002.

### See also

* PL/I special: bit strings
* PL/I special: arrays
* PL/I special: procedures
* PL/I special: storage classes