A PL/I program consists of a series of statements, which perform the following tasks:
A statement comprises user-specified identifiers, constants, and PL/I keywords, separated by blanks, comments, and punctuation marks. You can organize statements into structural sequences of groups or blocks. Example 1-1 shows the structure of a PL/I program.
|Example 1-1 Structure of a PL/I Program|
Key to Example 1-1
The source text of a PL/I program is freeform. As long as you terminate every statement with a semicolon (;), individual statements can begin in any column, be on additional lines, or be written with more than one statement to a line.
Individual keywords or identifiers of a statement, however, must be confined to one line. Only a character-string constant (which must be enclosed in apostrophes) can be on more than one line.
PL/I programs are easier to read and comprehend if you follow a standard pattern in formatting. For example:
Two or more declarations of the same name are not allowed in a single block unless one or more of the declarations are of structure members.
Two declarations of the same name in different blocks denote distinct objects unless both specify the EXTERNAL attribute. All EXTERNAL declarations of a particular name denote the same variable or constant, and all must agree as to the properties of the variable or constant, otherwise unpredictable results will occur. Note that EXTERNAL is the default for declarations of ENTRY and FILE constants. It must be specified explicitly for variables.
The following example shows the scope of internal names:
|DECLARE Q STATIC FIXED;||Q||MAINP, ALPHA, BETA, and CALC|
|MAINP: PROCEDURE OPTIONS (MAIN);||MAINP||MAINP, ALPHA, BETA, and CALC|
|DECLARE (X, Y, Z) FIXED;||
Z in MAINP
MAINP, ALPHA, BETA, and CALC
MAINP, ALPHA, and CALC
|ALPHA: PROCEDURE;||ALPHA||MAINP, ALPHA, BETA, and CALC|
|BETA: BEGIN;||BETA||ALPHA, BETA|
|DECLARE Z FLOAT;||Z in BETA||BETA|
|CALC: PROCEDURE;||CALC||MAINP, ALPHA, and CALC|
|DECLARE (SUM, TOTAL) FLOAT;||SUM, TOTAL||CALC|
Declarations can appear outside procedures and, if contained within the same block, have meaning throughout all procedures contained in the block. However, if there are multiple blocks, declarations outside procedures must have the EXTERNAL attribute if they are to be recognized by all blocks and procedures in the program. For example:
DECLARE X FIXED EXTERNAL STATIC; A: PROCEDURE OPTIONS(MAIN); DECLARE B ENTRY; . . . END A;
B: PROCEDURE; . . . END B;
In this example, the variable X has meaning in both procedures. Because
the two procedures are in two different files, X must be declared with
the EXTERNAL attribute. If X is declared with the INTERNAL attribute, X
is recognized only in the first procedure.
1.4.1 Begin Blocks
A begin block is a sequence of statements headed by a BEGIN statement (see Section 8.2) and terminated by an END statement (see Section 8.3). In general, you can use a begin block wherever a single PL/I statement would be valid. In some contexts, such as an ON-unit, a begin block is the only way to perform several statements instead of one. A primary use of begin blocks is to localize variables. Because execution of a begin block causes a block activation, automatic variables declared within the begin block are local to it, and their storage disappears when the block completes execution.
Another way to allow your program to perform several statements in
place of one is to use a DO group (see Section 8.1). You should choose
it when possible because it does not incur the overhead associated with
block activation. Use a begin block when there are declarations present
or when you require multiple statements in an ON unit.
1.4.2 Procedure Blocks
A procedure is a sequence of statements (possibly including begin blocks and other procedures) headed by a PROCEDURE statement and terminated by an END statement. Unlike a begin block, which executes when control reaches it, a procedure executes only when it is specifically invoked. Invocation occurs in the following ways:
A PL/I program must have at least one procedure, the main procedure. Any procedure, including the main procedure, can contain others; these are called internal procedures. A procedure that is not contained within any other is called an external procedure. The main procedure is always an external procedure.
As an example, block B is said to be contained in another block A if all of B's source text, from label (if any) to END statement inclusive, is between A's BEGIN or PROCEDURE statement and A's END statement. If block B is not contained in any other block within block A, then B is said to be immediately contained in A. For example:
A: PROCEDURE OPTIONS(MAIN); B: PROCEDURE; END B; . . . BEGIN; CALL B; END; /* of begin block */ END A;
The procedures B and the begin block all are immediately contained in A.
If block B is contained in block A, then B is said to be nested in A.
The maximum nesting level is 64.
1.4.4 Block Activation
A block is activated when program execution flows into it. Then, all automatic variables declared in the block become active. When control leaves the block, the variables become undefined and inaccessible.
You can only enter a procedure block with a CALL statement (see Section 7.4) or a function reference. If an internal procedure is declared within a source program, control flows around the internal procedure during the normal sequence of execution.
A begin block is entered when it is encountered during the normal flow
1.4.5 Relationship of Block Activations
During the execution of a program, many blocks can be simultaneously active. Two different relationships can be defined among block activations; they are the immediate dynamic descendance and the immediate parent activation. For example:
B: PROCEDURE OPTIONS(MAIN); A: PROCEDURE; CALL Q; . . . END A; Q: PROCEDURE; . . . END Q; BEGIN; CALL A; END; /* of begin block */ END B;
Figure 1-1 shows these relationships.
Figure 1-1 Relationship of Block Activations
In the immediate dynamic descendance relationship, a block activation is the immediate dynamic descendant of the block that invoked it. At a given time, the chain of immediate dynamic descendants includes all existing block activations, starting with the activation of the main procedure and terminating in the current block activation. For example, in Figure 1-1, the begin block is the immediate dynamic descendant of procedure B; the complete chain is B, begin block, A, Q. This chain is used for finding the applicable ON-unit when a condition is signaled.
The other relationship shown in Figure 1-1 applies to activations of nested blocks. An activation of a block X that is a begin block or internal procedure has an immediate parent activation, which is an activation of the block that immediately contains X. The chain of immediate parent activations extends back to an activation of the external procedure containing X. In Figure 1-1, the parent chain for the begin block, procedure A, and procedure Q leads directly back to the activation of B, because each of these blocks is immediately contained in B. This chain is used in interpreting references.
When a block is activated, its immediate parent activation is determined as follows:
When a block terminates normally, that is, when an END statement or a
RETURN statement is executed, the current block is released and control
goes to the preceding block activation. If a nonlocal GOTO statement is
executed that transfers control out of the current block, the current
block and any blocks between it and the block containing the label that
is the target of the GOTO statement are released.
1.5 Data and Variables
The statements in a PL/I program process data, generally in the form of variables that take on different values as the result of program execution. In PL/I, you must declare variables in a DECLARE statement before you can use them in other statements. Declaring a variable associates an identifier with a set of attributes and with a region of storage. Thus, when you declare a variable you must usually specify one or more data type attributes to be associated with it. (The concept of an attribute is more basic to PL/I than the concept of a data type.) Furthermore, you can specify how the variable is to be allocated by supplying a storage-class attribute in the declaration.
A few examples of PL/I attributes are BIT, CHARACTER, BINARY, DECIMAL, FILE, FLOAT, PRINT, UPDATE, and VALUE. For a complete alphabetic list of the PL/I attributes with their uses, see Section 2.2.
An identifier can refer to a single variable (called a scalar variable) or to a collection of related variables. Such a collection is called an aggregate. There are two kinds of aggregates:
The following chapters provide information on these topics:
PL/I supports an embedded lexical preprocessor, which recognizes a specific set of statements that are executed at compile time. These statements cause the PL/I compiler to include additional text in the source program or to change the values of constant identifiers at compile time.
Preprocessor statements are identified by a leading unquoted percent sign (%) and are terminated by an unquoted semicolon (;), except for %THEN and %IF statements. You can freely intermix preprocessor statements with the rest of the source program statements.