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.  To resolve this dilemma, the compiler was divided into a large number of "phases." 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. 
- Each phase's error messages were in terms of the program as modified to that point. 
- 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?
 Circa spring 1967.
 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]
 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.
 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.
 A misguided policy that has been adopted by too many of its successors.
 To compound the difficulty, I don't believe it said what changes it made, you had to infer them.