Let's continue our look at the PL/I language.
There are four storage classes in PL/I.
AUTOMATIC (the default) and
STATIC are much like in C:
CONTROLLED variables are assigned space dynamically with
ALLOCATE and released with
FREE. Unlike C
free, allocations are stacked so you can reallocate space and the program will remember the last allocation after it is freed. For example, the below will print 20 then 10.
TEST: PROCEDURE OPTIONS(MAIN); DECLARE A FIXED BINARY(16) CONTROLLED; ALLOCATE A; A = 10; ALLOCATE A; A = 20; PUT FILE (SCARDS) LIST(A); FREE A; PUT FILE (SCARDS) LIST(A); FREE A; END TEST;
Use of controlled variables before they are allocated or after they are freed will lead to a runtime error.
BASED variables are similar to
CONTROLLED variables but also allow pointer style access.
Variables (and procedures) can also be declared
EXTERNAL if they are defined elsewhere in the program.
Procedures and functions
Procedures can be declared at file level, within other procedures, or even within DO blocks. They are introduced with
PROCEDURE and executed using
CALL. Parameters are passed by name so the procedure can alter them; you can also pass an expression and the compiler will introduce a temporary variable. The below will print 41.
TEST: PROCEDURE OPTIONS(MAIN); DECLARE A FIXED BINARY(16); A = 41; CALL INCR(A); CALL INCR(A+1); PUT FILE (SCARDS) LIST(A); INCR: PROCEDURE(X); DECLARE X FIXED BINARY(16); X = X + 1; END INCR; END TEST;
A function is a procedure that returns a value, so the above could also be written as:
TEST: PROCEDURE OPTIONS(MAIN); DECLARE A FIXED BINARY(16); A = 41; A = INCR(A); PUT FILE (SCARDS) LIST(A); INCR: PROCEDURE(X) RETURNS(FIXED BINARY(16)); DECLARE X FIXED BINARY(16); RETURN(X + 1); END INCR; END TEST;
Note that brackets are needed around the expression being returned.
The source file can be augmented at compile time by using preprocessor directives, which start with
%. On MTS, to use this facility you must set the
MACRO parameter in the compiler command (eg
$run *pl1f scards=in.pl1 spunch=-load par=macro).
%INCLUDE otherfile copies the contents of
otherfile into the file currently being compiled.
%DECLARE can be used for macro replacement.
%DEACTIVATE will undefine a macro variable allowing it to be used by the program again. The following will print 42.
%DECLARE A CHARACTER, B FIXED; %A = 'B + 2'; %B = 40; TEST: PROCEDURE OPTIONS(MAIN); DECLARE X FIXED BINARY(16); X = A; PUT FILE (SCARDS) LIST(A); END TEST;
So far so much like the C preprocessor. But you can also do compile time programming using labels,
%GOTO. The below will substitute the middle section with
X = X + 1;,
X = X + 2; etc and prints 10.
TEST: PROCEDURE OPTIONS(MAIN); DECLARE X FIXED BINARY(16); X = 0; %DECLARE N FIXED; %N = 1; %LABEL1:; X = X + N; %N = N + 1; %IF N < 5 %THEN %GO TO LABEL1; PUT FILE (SCARDS) LIST(X); END TEST;
There is also a
%DO loop and the ability to create compile time
There's a lot more we haven't covered. PL/I has extensive I/O operations in both stream and record formats. There is support for multi-tasking, although much of this is not available on MTS.