My first PL/I program
My first PL/I program [1] was a few dozen lines transliterated from Algol. I compiled it using IBM's PL/I F compiler for the IBM System/360.
It took some detective work to figure out what had happened. To explain my difficulties, I should mention some more characteristics of the compiler:
A later phase of the compiler noticed that the assignment statement was missing an equal sign, so it inserted one:
Of course, the variable I had not been initialized, and it happened to be zero when the program encountered this statement, so the program crashed with a divide by zero error. What could be more informative?
Notes:
[1] Circa spring 1967.
[2] More specifically, on machines with 44 KB of core storage (exclusive of storage requirements for the Operating System), without benefit of virtual memory. The FORTRAN level H compiler got more space: "A source program of about 600 cards can be compiled in 200 KB of main storage." [FORTRAN INFORMATION BULLETIN NO. 1, February 1968]
[3] I counted in the Program Logic Manual. The compiler had 112 distinct named phases. All but a dozen or so would be invoked in compiling any non-trivial program. The FORTRAN H level compiler had 5 phases, named 10, 15, 20, 25, and 30, divided into 13 overlay segments.
[4] At the Stanford help desk I once saw the output that resulted when a user who was confused about JCL compiled and executed his FORTRAN program using the PL/I F compiler. That, too, went into execution and then crashed.
[5] A misguided policy that has been adopted by too many of its successors.
[6] To compound the difficulty, I don't believe it said what changes it made, you had to infer them.
The PL/I F compiler was a wondrous beast. To borrow Brian Randell's phrase, it was "a triumph of engineering over design." PL/I was one of the largest and most complex programming languages of its time--perhaps of all time--intended to replace FORTRAN, COBOL, Algol, and most other programming languages in use at the time. But IBM's F level compilers had to run on relatively small machines. [2] To resolve this dilemma, the compiler was divided into a large number of "phases." [3]My program compiled on the first try, went into execution, and then crashed with a divide by zero, producing perhaps 100 pages of error messages and core dump. The odd thing was that I wasn't aware of any divisions in my program.
It took some detective work to figure out what had happened. To explain my difficulties, I should mention some more characteristics of the compiler:
- It always converted its input into legal PL/I; whenever it encountered an error, it modified the program to a form it could deal with; and it always executed the compiled result, no matter how many errors had been encountered. [4][5]
- Each phase's error messages were in terms of the program as modified to that point. [6]
- Error messages were printed out sorted by severity; within a severity level, by phase; within a phase, by position in the program. So messages relating to a single statement could be widely scattered.
PUT LIST("PL/I VERSION OF MSP ANALYZER");This was my first time using the 029 keypunch; unlike the 026, it had both single and double quotation mark characters. Being an American, I naturally used double quotes, but PL/I used single quotes as string delimiters. I should have punched
PUT LIST('PL/I VERSION OF MSP ANALYZER');An early phase of the compiler determined the type of a statement. Since my statement was not a valid PUT statement, it was classified by default as an assignment statement.
A later phase of the compiler noticed that the assignment statement was missing an equal sign, so it inserted one:
PUT = LIST("PL/I VERSION OF MSP ANALYZER");Because PL/I had no reserved words, this implicitly declared the variable PUT and the array variable LIST. Another phase had trouble processing the double quotes, so it deleted them:
PUT = LIST(PL/I VERSION OF MSP ANALYZER);PL and I also became implicitly declared variables, but there were no further operators in the "expression," so the rest of it was deleted:
PUT = LIST(PL/I);This was the statement that was finally compiled.
Of course, the variable I had not been initialized, and it happened to be zero when the program encountered this statement, so the program crashed with a divide by zero error. What could be more informative?
Notes:
[1] Circa spring 1967.
[2] More specifically, on machines with 44 KB of core storage (exclusive of storage requirements for the Operating System), without benefit of virtual memory. The FORTRAN level H compiler got more space: "A source program of about 600 cards can be compiled in 200 KB of main storage." [FORTRAN INFORMATION BULLETIN NO. 1, February 1968]
[3] I counted in the Program Logic Manual. The compiler had 112 distinct named phases. All but a dozen or so would be invoked in compiling any non-trivial program. The FORTRAN H level compiler had 5 phases, named 10, 15, 20, 25, and 30, divided into 13 overlay segments.
[4] At the Stanford help desk I once saw the output that resulted when a user who was confused about JCL compiled and executed his FORTRAN program using the PL/I F compiler. That, too, went into execution and then crashed.
[5] A misguided policy that has been adopted by too many of its successors.
[6] To compound the difficulty, I don't believe it said what changes it made, you had to infer them.