Jump to content

PL/I

From Alfawiki
PL/I
Company typeProgramming language
IndustrySoftware, Computer programming
Founded1964
FounderIBM
Headquarters
Armonk, New York
,
United States
ProductsPL/I programming language
ParentIBM

PL/I (short for Programming Language One, pronounced , and occasionally spelled PL/1) is a procedural programming and imperative programming language originally created by IBM. It was designed to serve scientific, engineering, business, and system programming needs, and has been actively utilized by academic institutions, commercial enterprises, and industrial sectors since the 1960s.

The language was standardized by the American National Standards Institute (ANSI) with the publication of standard X3.53-1976 in 1976.

PL/I is aimed at applications in data processing, numerical computation, scientific computing, and system programming. It offers support for recursion, structured programming techniques, linked data structures, fixed-point and floating-point arithmetic, complex number operations, string manipulation, and bit-level processing. Its syntax, resembling English, is well-suited for handling intricate data formats and provides extensive capabilities for data validation and transformation.

Early history

During the 1950s and early 1960s, distinct programming languages were favored by business and scientific users: business programmers transitioned from Autocoders through COMTRAN to COBOL, whereas scientific programmers primarily used Fortran, ALGOL, among others. The introduction of the IBM System/360 architecture (announced in 1964 and released in 1966) unified hardware platforms for these diverse user groups. IBM aimed to develop a single language to accommodate all users, initially attempting to enhance Fortran with commercial features.

In October 1963, a committee comprising IBM personnel and members from the SHARE scientific user group was established to propose extensions to Fortran. However, given Fortran’s inherent limitations, they opted to create a new language initially named NPL, briefly renamed MPPL (MultiPurpose Programming Language), before adopting the name PL/I in 1965. The first formal specification appeared in April 1964.

IBM advanced NPL by completing its design and creating the initial compiler; the original NPL specification was not fully developed. Oversight of PL/I was handled by IBM’s New York Programming Center and subsequently by the IBM UK Laboratory located at Hursley. User communities such as SHARE and GUIDE contributed to language enhancements and influenced IBM’s governance through PL/I Projects.

To address the challenges in defining PL/I precisely, IBM’s Vienna Laboratory launched an initiative in 1967 to produce an unambiguous language specification. This project played a role in the early evolution of formal methods, including the Vienna Development Method (VDM).

Key figures involved include Fred Brooks, who introduced the CHARACTER data type, and Christopher J. Date, who incorporated relational database extensions inspired by Edgar Codd’s research.

The comprehensive PL/I reference manual "C28-6571" was released in New York in 1965 and later replaced by "GY33-6003" from Hursley in 1967. IBM continued refining PL/I throughout the late 1960s into the early 1970s. The initial compiler became available in 1966; the ANSI standard followed a decade later in 1976.

Goals and principles

From its inception, PL/I aimed to rival COBOL’s capabilities in record management and report generation while broadening its scope to include system programming and event-driven programming. Additional objectives encompassed:

  • Achieving performance comparable to Fortran (although this goal was not entirely met)
  • Ensuring extensibility to accommodate emerging hardware platforms and application domains
  • Enhancing programmer efficiency by delegating complexity to the compiler
  • Providing machine independence across primary hardware systems and operating environments

To fulfill these ambitions, PL/I integrated features from contemporary languages alongside novel functionalities within a concise and readable syntax. Fundamental design principles included:

  • Implementation of a block-structured design influenced by Algol 60, supporting recursion; arguments were primarily passed by reference with provisions for dummy variables enabling value passing (call by value)
  • A comprehensive set of data types covering computational and control needs with strong typing enforcement
  • Support for dynamic extents of arrays and strings that are inherited by procedure parameters
  • Syntax designed for brevity with allowed abbreviations compatible with a character set of 60 glyphs, reducible to a subset of 48
  • Extensive use of default values in statements and declarations to streamline coding efforts and facilitate language expansion
  • Robust iterative constructs supporting structured programming paradigms
  • Absence of reserved words—even keywords such as IF, THEN, ELSE, and DO were not reserved—to enable seamless introduction of new attributes or statements without disrupting existing programs
  • Emphasis on orthogonality, allowing independent features to be combined wherever logically applicable, thereby maximizing language expressiveness
  • Built-in exception handling mechanisms for managing runtime anomalies
  • Program structure divided into independently compilable units with powerful compile-time facilities (macros), permitting customized source integration; external identifiers link separately compiled modules
  • Integrated debugging support embedded within the language environment

Language overview

This programming language is crafted to address the requirements of developers working in scientific calculations, business data management, and systems programming within a unified language framework. The following overview is derived from the ANSI PL/I Standard and its General-Purpose Subset.

A PL/I program is composed of procedures, which are sequences of executable statements. The %INCLUDE directive allows for inserting external code during the compilation phase. Statements are categorized as follows:

Category Statement
Structural PROCEDURE, ENTRY, BEGIN, DO, END
Declaration DECLARE, DEFAULT, FORMAT
Control flow CALL, IF, SELECT, GO TO, RETURN, STOP, Null statement
Category Statement
Interrupt handling ON, SIGNAL, REVERT
Memory management ALLOCATE, FREE, Assignment statement
Input/Output management OPEN, CLOSE
Stream I/O GET, PUT
Record I/O READ, WRITE, REWRITE, LOCATE, DELETE

(Some implementations support features such as multitasking and a PL/I preprocessor; however, these are not part of the official Standard.)

Identifiers correspond to data types that can represent either single elements or collections like arrays and structures:

  • Arithmetic
  • CHARACTER
  • PICTURE for Arithmetic data
  • PICTURE for Character data
  • AREA
  • BIT
  • ENTRY
  • FILE
  • < code >FORMAT< / code >
  • < code >LABEL< / code >
  • < code >OFFSET< / code >
  • < code >POINTER< / code >

Attributes associated with the arithmetic type include:

  • base (< code >BINARY< / code > or DECIMAL),
  • scale (FIXED or FLOAT),
  • mode (REAL or COMPLEX),
  • precision (digits and scale factor for fixed-point numbers)

The picture-for-arithmetic type encodes base, scale, precision, and scale factor; the mode applies to both real and imaginary components.

Expressions involve operators and intrinsic functions applicable to both aggregates and individual values. Assignment statements are used to assign values to variables.

PL/I does not reserve keywords; statements conclude with semicolons. Comments are enclosed within /* ... */ delimiters. Statements may be prefixed by labels (such as entry names or labels) and condition prefixes (e.g., (NOSIZE)). Groups consist of statement sequences enclosed by DO ... END or BEGIN ... END blocks, allowing nested groups and local declarations. Procedures start with PROCEDURE and terminate with END, encompassing blocks, groups, statements, as well as local or external declarations.

An ON-unit specifies statements to execute when certain conditions arise:

Computational conditions include:

  • CONVERSION (CONV)
  • FIXEDOVERFLOW (FOFL)
  • OVERFLOW (OFL)
  • SIZE
  • STRINGRANGE (STRG)
  • STRINGSIZE (STRZ)
  • SUBSCRIPTRANGE (SUBRG)
  • UNDERFLOW (UFL)
  • ZERODIVIDE (ZDIV)

Input/Output conditions include:

  • ENDFILE(file)
  • ENDPAGE(file)
  • KEY(file)
  • NAME(file)
  • RECORD(file)
  • TRANSMIT(file)
  • UNDEFINEDFILE(file) (UNDF)

Additional conditions include AREA, CONDITION(identifier), ERROR, and FINISH.

When declaring identifiers, the following attributes may be specified:

Data attributes Input/output attributes Other attributes
ALIGNED DIRECT AUTOMATIC or AUTO
AREA[(area-size)] ENVIRONMENT(options) BASED[(reference)]
BINARY[(precision)] INPUT BUILTIN
BIT[(maximum-length)] KEYED CONDITION or COND
CHARACTER[(maximum-length)] OUTPUT CONSTANT
COMPLEX[(precision)] PRINT CONTROLLED or CTL
DECIMAL[(precision)] SEQUENTIAL or SEQL DEFINED[(reference)]
(dimension-attribute) STREAM EXTERNAL or EXT
ENTRY[(parameter descriptor list)] UPDATE GENERIC(criteria list)
FILE RECORD INITIAL(value-list) or INIT...

Modern compilers from vendors such as Micro Focus and IBM provide numerous enhancements beyond the standard specification. IBM’s additions are documented in its compiler’s Implementation section. Due to the absence of a current universal standard, interoperability between different compilers cannot be assured.

Standardization

The process of language standardization commenced in Europe in April 1966 under the auspices of the ECMA Technical Committee 10. Subsequently, in 1969, the ANSI formed the "Composite Language Development Committee" (CLDG), which was later renamed X3J1 PL/I. The initial task of CLDG/X3J1 involved evaluating PL/I’s potential for formal standardization, reviewing more than 3,500 proposals concerning language features and textual modifications. Standardization efforts evolved into a collaborative venture between ECMA TC/10 and ANSI X3J1, adopting a subset of IBM’s GY33-6003 specification as the foundational document, deliberately excluding multitasking and program optimization elements such as NORMAL and ABNORMAL.

Both committees conducted votes on suggested amendments to the base document, with any disagreements resolved by the respective chairs, Michael Marcotty from General Motors and C.A.R. Hoare of ICL. Beyond IBM, participants in the process included companies like Honeywell, CDC, Data General, Digital Equipment Corporation, Prime Computer, Burroughs, RCA, and Univac. Major end-users such as Eastman Kodak, MITRE, Union Carbide, and Bell Laboratories were also involved. The standards committees continued refining the language to improve structured programming capabilities and consistency, while intentionally omitting less commonly used features.

Towards the conclusion of development, X3J1 and TC10 recognized deficiencies in the English prose format of the standard—repeated discussions were scattered unevenly across sections, complicating error identification. To resolve this, a team consisting of David Beech (IBM), Robert Freiburghouse (Honeywell), Milton Barber (CDC), M. Donald MacLaren (Argonne National Laboratory), Craig Franklin (Data General), Lois Frampton (Digital Equipment Corporation), along with editor D.J. Andrews (IBM), undertook a complete rewrite of the standard. They employed a formal definition approach based on a "PL/I Machine" model to rigorously specify semantic aspects. This marked the first instance of a programming language standard being presented through a semi-formal specification.

In 1981, ANSI released the "PL/I General-Purpose Subset" ("Subset-G") standard, later updated in 1987. This subset gained widespread acceptance as the foundational core for PL/I implementations.

IBM PL/I F and D compilers

IBM’s initial PL/I implementation took place at its Hursley Laboratories in the United Kingdom during the System/360 project development phase. The first production compiler was PL/I F for OS/360, developed by John Nash’s group at Hursley, with I.M. (Nobby) Clarke leading the runtime library team. Entirely written in System/360 assembly language, PL/I F Release 1 debuted in 1966. It was engineered to function on systems equipped with as little as 64 KB of real memory. The compiler operated through a control phase followed by nearly 100 modular phases loaded from disk; each module handled specific language constructs by making a single pass over the program data stored in memory.

During PL/I F’s development lifecycle, certain language features were introduced incrementally in subsequent releases. For instance, RECORD I/O appeared in Release 2; list processing functions, based variables, pointers, areas and offsets, along with LOCATE-mode I/O were added in Release 4. Release 5 incorporated significant optimizations for DO-loops via the REORDER option to improve execution efficiency and better compete with Fortran-generated object code.

A version of PL/I F was adapted for use with the TSS/360 timesharing operating system on the System/360 Model 67 at IBM’s Mohansic Laboratory. Concurrently, IBM’s La Gaude Laboratory in France developed Language Conversion Programs that facilitated translation from Fortran, Cobol, and Algol into PL/I F level code.

The PL/I D compiler was created by IBM Germany targeting the low-end DOS/360 operating system environment, requiring only 16 KB of memory. It supported a restricted subset of PL/I that mandated fixed-length strings and arrays to simplify runtime management tasks. Due to DOS/360’s limitations, it did not include dynamic storage allocation or support for the controlled storage class. The PL/I D compiler was released within one year following PL/I F's introduction.

Multics PL/I and its derivatives

During the early 1960s, multiple teams embarked on developing PL/I compilers. The Multics initiative at MIT, which was groundbreaking in creating an operating system using a high-level language, employed Early PL/I (EPL), a subset of PL/I, as their implementation language in 1964. EPL was a collaborative creation between Bell Labs and MIT, with contributions from Douglas McIlroy, Robert Morris, among others. Initially constructed using the TMG compiler-compiler, the Multics PL/I compiler became highly influential, serving as a cornerstone for compiler technology adopted by various hardware manufacturers and software development teams. Notably, EPL extended system programming capabilities beyond those offered by the original PL/I.

Honeywell developed a PL/I compiler for the Series 60 that fully conformed to the ANSI X3J1 specification.

IBM PL/I optimizing and checkout compilers

IBM's PL/I Optimizer and Checkout compilers, created at Hursley, were designed to support a unified PL/I language standard and intended to replace the earlier PL/I F compiler. The checkout compiler, rewritten in BSL—IBM’s proprietary language similar to PL/I and later known as PL/S—served as a debugging tool prior to submitting code to the Optimizer. Although architecturally distinct, both compilers generated identical outputs, a complex objective that was successfully met.

IBM introduced several new syntax constructs such as , case statements (//), loop control mechanisms (, ), and empty argument lists to clarify invocations like DATE().

From the 1970s through the 1990s, the optimizing compiler supplanted PL/I F as IBM’s primary compiler. It featured a multi-pass architecture with an initial 44 KB target memory footprint but reduced per-phase memory usage to 28 KB by evaluating constant expressions during compilation via runtime libraries. Developed under Tony Burbridge’s guidance using S/360 Macro Assembler, it leveraged macros to automate common services, facilitating porting across different memory models. Incorporating advanced optimization strategies derived from IBM Fortran H, it achieved execution performance comparable to programs written by expert developers. Released alongside IBM S/370 in 1970, it first became available for DOS/360 in August 1971, followed by OS/360 and later virtual memory systems such as DOS/VS, OS/VS1, OS/VS2, and VM/370. It supported both batch processing and interactive sessions under TSO and CMS, encompassing all mainframe operating systems including Japanese plug-compatible machines (PCMs).

Eventually, this compiler was replaced by "IBM PL/I for OS/2, AIX, Linux, z/OS."

The PL/I checkout compiler—known as "The Checker"—was introduced in August 1970 under Brian Marks’ leadership to expedite debugging by cutting compile times to one-quarter of those required by the F Compiler. Its three-pass design transformed source programs into an internal "H-text" representation interpreted at runtime for comprehensive error detection. Pointers carried extensive metadata allowing identification of invalid references. In interactive mode, users could examine variable contents, insert debugging instructions, and modify source code upon encountering errors. Although pioneering at its inception, many of its capabilities were later absorbed into mainframe debugging environments before it was phased out during the 1990s.

DEC PL/I

Digital Equipment Corporation’s VAX-11 PL/I, later rebranded as VAX PL/I and DEC PL/I, ranked among the most commercially successful PL/I implementations following IBM’s version. Initially launched in 1980, it conformed to "a strict superset of the ANSI X3.4-1981 PL/I General Purpose Subset" and incorporated the majority of features from the 1987 ANSI X3.74 General Purpose Subset. The compiler’s backend, known as the VAX Code Generator (VCG), was engineered under the guidance of Dave Cutler, while Robert Freiburghouse designed the front end, which was adapted from Multics to operate on VAX/VMS. This compiler functioned on VMS for both VAX and DEC Alpha architectures, as well as on Tru64 UNIX. During the 1990s, Digital transferred ownership of the compiler to UniPrise Systems, which eventually passed it on to Kednos. Kednos marketed the product as Kednos PL/I until it ceased operations in October 2016.

Teaching subset compilers

In the late 1960s and early 1970s, universities utilizing time-sharing systems sought interactive compilers tailored for teaching disciplines such as science, engineering, and computer science. PL/I was preferred due to its brevity and instructional suitability; however, IBM’s available versions were insufficient, leading academic institutions to create their own PL/I subsets and supporting tools:

  • Allen-Babcock developed the Remote Users of Shared Hardware (RUSH) system on IBM System/360 Model 50 with customized microcode and created IBM’s Conversational Programming System (CPS) for OS/360, providing a limited PL/I subset alongside BASIC.
  • PL/C, crafted at Cornell University, stood out as a teaching compiler that never failed to compile programs by automatically correcting syntax errors or translating them into output statements; it closely mirrored IBM’s PL/I and exhibited high efficiency.
  • SL/1 (Student Language/1), a PL/I subset from the late 1960s running interpretively on the IBM 1130, was primarily intended for instructional purposes.
  • PLAGO, developed at the Polytechnic Institute of Brooklyn, emphasized a streamlined PL/I subset with rapid compilation and robust diagnostic error reporting.
  • The University of Toronto's Computer Systems Research Group produced SP/k compilers supporting incremental subsets (SP/1 through SP/8) designed for teaching. Programs free of errors under SP/k yielded consistent results on other PL/I compilers such as those from IBM and Cornell.

Additional notable teaching subsets included PL0 (University of New South Wales), PLUM (University of Maryland), and PLUTO (University of Toronto).

IBM PL/I for OS/2, AIX, Linux, z/OS

In 1992, IBM’s Santa Teresa facility introduced a significant overhaul of PL/I with a new compiler initially targeting OS/2 that supported most ANSI-G specifications along with new PL/I features. Subsequent versions broadened platform compatibility to include MVS, VM, OS/390, AIX, and Windows; by 2021, support remained only for z/OS and AIX. IBM persistently evolved PL/I to maintain competitiveness with languages such as C and C++, incorporating the "IBM Language Environment" to facilitate seamless interoperability with databases, transaction systems, and applications written in C, C++, and COBOL.

The modernized PL/I preserved its foundational design while introducing new data types, statements, exception handling mechanisms, and program structures. Noteworthy improvements comprised:

  • User-defined data type capabilities through DEFINE ALIAS, ORDINAL, DEFINE STRUCTURE, HANDLE, TYPE, UNION, along with associated functions
  • Type functions analogous to built-in class methods
  • Additional data types aligned with typical PC types such as UNSIGNED and VARYINGZ
  • Enhanced code clarity by explicitly declaring implicit behaviors (e.g., BYVALUE parameters)
  • Introduction of structured programming constructs and interrupt management
  • Expanded compile-time preprocessor capabilities covering nearly all PL/I string processing features and integration with the Application Development Environment

The latest Enterprise PL/I compilers for z/OS optimize code generation for contemporary z/Architecture processors (ranging from z14 through z114) by utilizing the ARCHLVL parameter during compilation. This positioned PL/I as the second high-level language within the z/OS Language Environment to exploit this optimization after XL C/C++, followed by Enterprise COBOL version 5.

Data types

This data type resembles those found in Pascal, providing built-in operations to retrieve an ordinal value's predecessor, successor, and boundaries through FIRST and LAST.

The statement permits the creation of additional types derived from PL/I's native attributes.

The locator type HANDLE(data structure) acts as a strongly typed pointer, associating exclusively with a designated data structure. Selection of data structures via a handle is accomplished using the => operator.

The attribute, analogous to early PL/I’s , enables multiple variables, arrays, or structures to share the same memory space sized for the largest member alternative.

Competitiveness on PC and with C

Enhancements to string and arithmetic handling include:

  • String-related attributes such as VARYINGZ (strings terminated by zero), HEXADEC, WIDECHAR, and GRAPHIC.
  • Arithmetic-related attributes including UNSIGNED, SIGNED, BIGENDIAN, and LITTLEENDIAN. The UNSIGNED attribute supports the UPTHRU and DOWNTHRU options for loops controlled by counters, which is important for managing ORDINALs and enhancing loop clarity.
  • The DATE(pattern) attribute standardizes how dates are represented. Functions such as DAYS, DAYSTODATE, and DATETIME assist in date conversions and formatting tasks.
  • New string functions improve text manipulation capabilities, including centering text, picture-format editing, trimming spaces or specific characters, along with functions like VERIFYR, SEARCH, and TALLY.
  • Compound assignment operators inspired by C (e.g., +=, &=) simplify expression syntax.

Additional parameter descriptors facilitate support for omitted arguments and variable-length argument lists.

Program readability – making intentions explicit

Constants can be declared from literals or limited expressions using the attribute.

Passing methods for parameters can be explicitly defined using (for passing by address) or (for passing by value).

Attributes such as and help prevent accidental assignments.

The construct DO FOREVER; replaces less straightforward infinite loop syntax.

The statement enables the definition of user-friendly names (for instance, ) representing combinations of built-in attributes like FIXED BINARY(31,0). For example, one can create a type alias with DEFINE ALIAS INTEGER FIXED BINARY(31.0). Similarly, structured types with member declarations can be defined using DEFINE STRUCTURE, extending the capabilities of the attribute.

Structured programming additions

A LEAVE statement was introduced to allow exiting loops prematurely, along with an ITERATE statement to skip to the next iteration within a loop.

Options UPTHRU and DOWNTHRU were added for iterative groups to control loop direction more explicitly.

The package construct organizes procedures and declarations into a cohesive unit. Variables declared outside procedures within a package are local to it and may utilize storage classes such as STATIC, BASED, or CONTROLLED. Procedure identifiers are scoped locally but can be made externally accessible through the EXPORTS option in the PACKAGE declaration.

Interrupt processing

Within an ON-unit, the RESIGNAL command halts its current execution and reissues the condition to the invoking procedure, thereby redirecting control to its designated ON-unit.

The INVALIDOP condition addresses improper operation codes and forbidden arithmetic actions, such as subtracting infinite quantities.

Conditions lacking dedicated ON-units in the active procedure are captured by the ANYCONDITION.

When an ALLOCATE statement cannot secure adequate memory, the STORAGE condition is triggered.

Additional mainframe and minicomputer PL/I compilers

Throughout the 1980s, multiple vendors introduced PL/I compilers that vied with IBM's PL/I F or Optimizing compilers on mainframe and minicomputer platforms, focusing on ANSI-G subsets:

  • In 1974, Burroughs Corporation launched PL/I for their B6700 and B7700 systems.
  • UNIVAC produced UNIVAC PL/I and employed PL/I PLUS for system-level programming during the 1970s.
  • Starting in 1978, Data General offered PL/I for Eclipse and Eclipse MV machines running AOS, AOS/VS, and AOS/VS II operating systems; numerous OS utilities were developed in PL/I.
  • Paul Abrahams at NYU created CIMS PL/I in 1972, which compiled roughly 70% of PL/I for CDC 6600 computers.
  • Control Data Corporation provided an optimizing subset compiler for Cyber models 70, 170, and 6000 series.
  • Fujitsu delivered a PL/I compiler comparable to IBM’s Optimizing compiler.
  • Stratus Technologies implemented ANSI G PL/I for the VOS operating system.
  • The IBM Series/1 PL/I compiler supported an extended ANSI X3.53-1976 subset tailored for real-time applications on IBM Series/1 hardware.

PL/I compilers targeting Microsoft .NET environments

  • In 2011, Raincode released The Raincode PL/I compiler, a comprehensive legacy compiler compatible with both Microsoft .NET and .NET Core frameworks.

PL/I compilers for personal computers and Unix platforms

  • During the 1970s and 1980s, Digital Research marketed PL/I compilers for CP/M (PL/I-80), CP/M-86 (PL/I-86), and IBM PC-compatible systems running MS-DOS or IBM PC DOS. These were based on Subset G of PL/I and implemented in PL/M.
  • Through acquisition of Liant, Micro Focus developed Open PL/I for Windows as well as UNIX/Linux operating systems.
  • IBM introduced PL/I versions for OS/2 in 1994 and AIX in 1995.
  • Iron Spring launched PL/I compilers supporting OS/2 initially and later expanded to Linux in 2007.
  • The GCC incorporates a PL/I front end (pl1gcc), with its most recent update released in September 2007.

Variations of PL/I dialects

  • PL/S, a dialect created by IBM in the late 1960s, became the primary system programming language on IBM mainframes. During the 1970s and 1980s, most IBM mainframe software was authored in PL/S. Unlike standard PL/I, it lacked data type conversions and runtime support, employing fixed-size strings and arrays instead. This dialect evolved into PL/AS and subsequently into PL/X, which remains in use internally within OS/390 and z/OS, as well as certain components of z/VSE and z/VM. Additionally, IBM Db2 for z/OS is implemented in PL/X.
  • Developed at Cornell University during the 1970s, PL/C serves as an educational variant of PL/I.
  • For system software on the System/38 and AS/400, IBM utilized two dialects: PL/MP (Machine Product) targeting the IMPI instruction set for Vertical Microcode—which was largely replaced by C++ during OS/400’s transition to the IBM RS64 processors but partially retained for PowerPC/Power ISA—and PL/MI (Machine Interface), which continues to be used within IBM i environments.
  • Named for encompassing approximately 80% of standard PL/I features, PL.8 was created by IBM Research in the 1970s for the IBM 801 architecture. It later supported Motorola 68000 and System/370 platforms. This dialect remains active internally for firmware and millicode on z/Architecture, having been modernized with a 64-bit backend based on the gcc.
  • The CP-6 operating system from Honeywell, Inc. utilized a dialect known as PL-6.
  • Two distinct dialects were employed by Prime Computer as system programming languages on their PRIMOS OS: starting from version 18 with PL/P, followed by SP/L from version 19 onward.
  • Designed specifically for compiler construction using XPL techniques, XPL is a variant that introduces a heap-based string datatype.
  • The real-time aerospace language HAL/S was developed by Intermetrics in the 1970s for NASA’s Space Shuttle program; it is implemented atop XPL.
  • SPL/I was created by IBM alongside subcontractors during the early 1970s to support naval signal processing requirements.
  • The airline reservation system Sabre was programmed using SabreTalk, a real-time dialect of PL/I.
  • The Apple programming language—developed by General Motors Research Laboratories for CDC STAR-100 supercomputers—is a PL/I dialect extensively applied in graphic design tasks.

Usage

PL/I compilers first appeared on mainframe computers in the late 1960s, expanded to minicomputers during the 1970s, and later became available for personal computers throughout the 1980s and 1990s. Although its primary deployment was on mainframes, PL/I has also been implemented on platforms such as DOS, Microsoft Windows, OS/2, AIX, OpenVMS, and various Unix systems.

The language found extensive application in both business data processing and system programming, facilitating the creation of intricate software solutions including:

  • The SAS System, originally developed in PL/I, with its data step still reflecting PL/I syntax conventions.
  • The IBM S/360 version of the Sabre airline reservation platform, predominantly built using SabreTalk, a specialized subset compiler of PL/I.
  • The Multics operating system.
  • An executable formal specification utilized for interpreting IBM's System Network Architecture.
  • Portions of the OpenVMS operating system, which were subsequently rewritten in C during the IA-64 architecture transition.

Contrary to early predictions, PL/I did not replace Fortran or COBOL as the dominant mainframe languages but maintained a niche presence. Several reasons contributed to this outcome:

Initially, shifts in mainframe software ecosystems toward database management and transaction processing systems—such as CICS, IMS, and Oracle Database—along with application generators, demanded native language capabilities that limited PL/I’s applicability. Consequently, PL/I’s role became largely restricted to areas traditionally dominated by COBOL, which retained its leadership. Furthermore, as personal computers emerged as primary development environments, languages like C++, and Java surpassed legacy languages including PL/I.

In addition, IBM’s preference for a proprietary variant of PL/I known as PL/S over standard PL/I in system programming weakened PL/I’s position in that domain. The widespread adoption of PL/S within IBM and the use of C externally further eroded PL/I’s system programming relevance.

Moreover, improvements in interactive development tools reduced reliance on PL/I’s distinctive debugging capabilities.

Finally, enhancements made to COBOL and Fortran—such as support for structured programming, string manipulation, and object-oriented features—diminished the comparative advantages once held by PL/I.

Market forces also played a role: competitors of IBM had limited motivation to invest in PL/I compiler development due to high costs and IBM’s inherent market dominance. Many organizations preferred languages supported by multiple vendors to avoid dependence on a single proprietary platform like PL/I.

Evolution of the PL/I language

While this article refers to the official PL/I standard regarding language features, numerous early important capabilities were excluded from it and instead appeared in non-IBM compilers. The language continued to develop beyond the standardization phase, particularly influenced by advancements related to Personal Computer platforms.

Multithreading

Multithreading—referred to as "multitasking"—was incorporated into compilers such as PL/I F, the Checkout and Optimizing compilers, and later versions for AIX and Z/OS. This functionality included data types and , the option on the statement (fork), the statement (join), use of DELAY(delay-time), additional options for record I/O operations, and the statement designed for unlocking records on files. Event data were utilized to represent event completion status ('1'B for complete and '0'B for incomplete), while task data identified individual tasks or processes along with their priority levels.

Preprocessor

IBM's initial compile-time preprocessor was created by the Boston Advanced Programming Center and bundled with the PL/I F compiler. Although the %INCLUDE directive became standardized, other preprocessor functionalities varied. Similar capabilities, sometimes enhanced, were offered by DEC and Kednos PL/I compilers. IBM has progressively expanded these features over time.

This preprocessor analyzes source code tokens, either duplicating them or executing compile-time instructions upon encountering a % symbol. Identifiers declared with assigned compile-time values are substituted by those values during compilation. For instance, a compile-time variable might be defined as %PI='3.14159265', causing all subsequent references to be replaced accordingly.

Supported data types encompass FIXED DECIMAL integers and variable-length strings without any fixed maximum size. Key structural statements include:

  • %procedure_name: PROCEDURE (parameter list) RETURNS (type); statements...; %[label_list:]END;

Basic statements consist of:

  • and
  • Assignment commands
  • %DECLARE identifier_attribute_list
  • %GO TO label
  • %INCLUDE
  • Null statements

This preprocessor allowed identifiers to represent constants such as product part numbers or mathematical constants. Although later replaced in the standard by named constants for computational use, conditional compilation and iterative source code generation—enabled through compile-time features—were never standardized but were implemented by several vendors.

Structured programming additions

During PL/I standardization, structured programming constructs like the LEAVE statement for exiting iterative DO loops, UNTIL and REPEAT options for DO, and a case statement syntax:

were proposed but ultimately not adopted. Nevertheless, these features were incorporated into IBM's PL/I Checkout and Optimizing compilers as well as DEC PL/I.

Debug facilities

PL/I F introduced debugging enhancements such as the CHECK(variable-list) condition prefix, the CHECK on-condition, and the SNAP option. Though not standardized, these were adopted by other implementations. IBM’s compilers further enriched debugging with tools tailored for mainframe systems, including an ATTENTION condition.

Significant features developed since the standard

Efforts to accommodate variant data types resulted in additions like UNION and TYPE in various compilers, reflecting the growth of class-based programming paradigms. Originally designed for single-byte character processing, PL/I expanded its string handling to support wide international character sets such as Japanese and Chinese. Time and date functionalities were upgraded to address the millennium (Y2K) issue, introducing a flexible DATETIME function with approximately 35 formats alongside conversion utilities.

Implementation issues

Despite PL/I’s user-friendly design, its extensive language scope complicated compiler development and slowed progress, necessitating subsets until the "ANSI G" standard was established. Compared to Fortran or COBOL compilers, PL/I compilers were two to four times larger and slower—though this trade-off was considered reasonable given its productivity advantages.

Parsing PL/I is difficult because keywords are not reserved words; they can be used as variable or procedure names. This creates ambiguity between declarations and assignments until subsequent tokens are parsed, often resulting in cascading error messages—a problem mitigated in later compiler versions.

Optimizing PL/I code posed challenges due to widespread side effects and variable aliasing, further complicated by asynchronous changes through exception handlers (ON statements). Despite these obstacles, IBM released an optimizing compiler in 1971.

The language includes advanced features such as multitasking support (an IBM extension) and co-processing capabilities requiring operating system-level multithreading. Implementation of these features was optional for compiler providers.

PL/I allows implicit declaration of variables upon first use if undeclared, which can lead to errors from typographical mistakes—similar to FORTRAN. However, an attribute listing feature in PL/I(F) assists in identifying undeclared or misspelled variables.

Programmer challenges

A significant number of developers were reluctant to embrace PL/I, largely due to its perceived complexity and the early-stage development of the PL/I F compiler. The programming community was distinctly split: scientific programmers favored Fortran, while business programmers preferred COBOL, often resulting in friction between these groups. Although PL/I’s syntax merged features from both COBOL and Fortran, this hybrid approach caused Fortran users to regard it as primarily a business language and COBOL users to see it as scientific, deepening their hesitation.

Each faction tended to view PL/I as an extended variant of their own language, which created a sense of intimidation and resistance to switching. Moreover, PL/I incorporated constructs reminiscent of COBOL, Fortran, and ALGOL that behaved differently than expected, leading seasoned programmers to frustration and even active aversion toward the language. An early UNIX humor piece famously labeled PL/I a "machine-hogging, cycle-grabbing, all-encompassing monster," underscoring its complexity.

On the upside, PL/I introduced several advanced capabilities for its era: comprehensive pointer support across all data types (including structures), recursion, multitasking, sophisticated string manipulation, and a wide array of built-in functions. Despite these technical advancements, they failed to persuade the majority of programmers or organizations to adopt PL/I.

The preprocessor in the PL/I F compiler was distinctive for its time because it used the target language’s own syntax and semantics instead of separate directive symbols like the "#" used by C preprocessors.

PL/I defines multiple storage classes to control variable lifetimes: STATIC, AUTOMATIC, CONTROLLED, BASED, and AREA.

Variables declared as STATIC are allocated and initialized during load-time, similar to COBOL’s "working-storage" or early Fortran variables. This is also the default storage class for EXTERNAL variables, analogous to C’s “extern”.

The AUTOMATIC class is the default for INTERNAL variables and resembles C's "auto" or Pascal’s standard local storage. Memory allocation happens upon entering a procedure or block; if an INITIAL attribute is specified, initialization occurs at that time. The storage is released when exiting the block. Large initializations under this class may negatively affect performance.

Variables with STATIC, CONTROLLED, or BASED storage retain their values across procedure invocations.

CONTROLLED storage resides on a stack explicitly managed by the programmer through ALLOCATE and FREE operations.

Similarly, BASED storage uses ALLOCATE/FREE, but each allocation has its own lifetime and is accessed via OFFSET or POINTER. This feature enables referencing arbitrary memory areas, which is particularly useful in implementing linked lists.

The AREA attribute allows programmers to define heap areas they control directly, facilitating allocation, deallocation, and bulk operations on these memory regions.

Sharing storage types

Storage locations can be accessed through different data declarations that vary in safety guarantees.

When passing variables by reference, parameters refer directly to the argument’s storage. The attribute allows a variable’s entire or partial storage to be reused under an alternate declaration that maintains compatibility. The attribute (later renamed ) permits multiple data definitions to share the same storage area; however, early IBM compilers offered limited support for this feature. These approaches are considered safe and platform-independent.

Record input/output and list processing demand declarations that can accommodate incoming data structures before their precise types are known. Based variables and pointers assist by embedding type and size metadata within data fields. Self-defining structures place type descriptors before dependent elements consistently across different versions. The option supports self-defining extents (such as string lengths), enabling secure and platform-neutral handling of records and lists.

Most PL/I implementations do not maintain type information upon allocation (the exception being the PL/I Checkout compiler). Any declaration can access memory via pointers; however, this practice is inherently unsafe and platform-dependent but necessary for pointer arithmetic operations—such as adding offsets to addresses. This raises concerns about wild references, buffer overruns, and alignment inconsistencies across various hardware and compilers. The function provides a safer method for computing pointers within larger data structures.

Pointer arithmetic can be performed by aliasing a binary variable with a pointer:

DCL P POINTER, N FIXED BINARY(31) BASED(ADDR(P));
N=N+255;

This technique depends on pointers having the same size and alignment as FIXED BINARY(31) integers.

Influenced by C language conventions, recent IBM PL/I compilers have introduced pointer addition and subtraction operators for more straightforward syntax; nonetheless, options remain available to disable these features in favor of enhanced safety and portability.

Handling Exceptions with ON-units

During the initial design of PL/I for batch processing, errors such as division by zero led to immediate program termination with little diagnostic information. The development of ON-units introduced a mechanism for programs to manage hardware or operating system exceptions more elegantly, allowing them to retain control and preserve debugging details before exiting. However, with the rise of interactive execution environments, extensive use of exception handling was frequently minimized or disabled.

Exception management is implemented through condition prefixes applied to individual statements, code blocks (including ON-units), and procedures—for instance, (SIZE, NOSUBSCRIPTRANGE): A(I)=B(I)*C;. Operating system-generated exceptions related to input/output and memory are always active.

An ON-unit consists of either a single statement or a BEGIN-block that is activated by an ON-statement (such as ON ZERODIVIDE ON-unit). When the specified condition arises and is enabled, the corresponding ON-unit executes. These units propagate down the call stack but can be overridden by subsequent ON-statements or reset through the use of REVERT. Additionally, the SIGNAL statement can simulate exceptions to facilitate debugging. This dynamic inheritance model enables routines to address exceptions originating within their called subroutines.

If no ON-unit responds to a raised condition, a default system action occurs—typically triggering an ERROR. The original system response can be reinstated by specifying the SYSTEM option within the ON-statement. Certain conditions (for example, STRINGRANGE, UNDERFLOW, CONVERSION) permit continuation of execution following handling; however, others such as SUBSCRIPTRANGE will cause an error if resumption is attempted. An ON-unit may conclude with a GO TO statement that redirects control flow and prevents returning to the point where the interrupt occurred.

It is also essential for ON-units to manage exceptions that arise within themselves. The statement ON ERROR SYSTEM; provides nested error handling capabilities—errors encountered inside an ON-unit may transfer control back to the operating system, potentially leading to a system dump or allowing continued operation for specific conditions.

PL/I’s RECORD I/O commands utilize straightforward syntax lacking options for various file-related exceptions; instead, these situations are addressed through corresponding ON-units. This mechanism similarly applies to sub-allocation within AREA storage and its associated conditions.

The presence of exception handling via ON-units impacts optimization strategies since variables accessed or modified within these units often require persistent storage between statements rather than being kept in registers. This consideration influences performance trade-offs discussed further under Implementation Issues.

GO TO with Dynamic Targets

PL/I provides equivalents to specialized GO TO constructs found in COBOL and FORTRAN that allow for dynamic determination of jump destinations.

Notable forms include:

  • COBOL’s and FORTRAN’s statements:
    • Known respectively as “altered go to” constructs.
    • Subject to certain restrictions, particularly in programs using attributes or options.
    • Followed by (“assigned go to”).
    • An enhanced variant: limits the variable’s value strictly to a predefined set of labels.
  • Computed GO TO statements based on an index variable:
    • FORTRAN’s (“computed go to”).
    • COBOL’s (“go to depending on”).

In PL/I, statement label variables declared with the attribute can hold label values for use in subsequent statements:

LABL1: ....
.
.
LABL2: ...
.
.
.
MY_DEST = LABL1;
GO TO MY_DEST;

Developers may also define arrays consisting of static label constants indexed by subscripts:

GO TO HERE(LUCKY_NUMBER);

HERE(-1): PUT LIST ("I O U"); GO TO Lottery;
HERE(0): PUT LIST ("No Cash"); GO TO Lottery;
HERE(1): PUT LIST ("Dollar Bill"); GO TO Lottery;
HERE(2): PUT LIST ("TWO DOLLARS"); GO TO Lottery;

Furthermore, label variables can be passed as arguments between procedures, enabling dynamic control over return points during execution.

Hello world program

<syntaxhighlight lang="rexx"> Hello2: proc options(main);

    put list ('Hello, World!');

end Hello2; </syntaxhighlight>

String search example

<syntaxhighlight lang="rexx"> /* Accepts a pattern and outputs lines that include it */

find_strings: procedure options(main);

  declare pattern character(100) varying;
  declare line character(100) varying;
  declare line_no fixed binary;
  on endfile(sysin) stop;
  get edit(pattern)(L);
  line_no = 1;
  do forever;
     get edit(line)(L);
     if index(line, pattern) > 0 then
        put skip list(line_no, line);
     line_no = line_no + 1;
  end;

end find_strings; </syntaxhighlight>

See also

Textbooks

  • Neuhold, E.J.; Lawson, H.W. (1971). The PL/I Machine: An Introduction to Programming. Addison-Wesley. ISBN 978-0-2010-5275-6.
  • Barnes, R.A. (1979). PL/I for Programmers. North-Holland.
  • Hughes, Joan K. (1973). PL/I Programming. 1st ed. Wiley. ISBN 0-471-42032-8.
  • Hughes, Joan K. (1986). PL/I Structured Programming. 3rd ed. Wiley. ISBN 0-471-83746-6.
  • Groner, G.F. (1971). PL/I Programming in Technological Applications. Books on Demand, Ann Arbor, MI.
  • Anderson, M.E. (1973). PL/I for Programmers. Prentice-Hall.
  • Stoutemyer, D.R. (1971). PL/I Programming for Engineering & Science. Prentice-Hall.
  • Ziegler, R.R. & C. (1986). PL/I: Structured Programming and Problem Solving. 1st ed. West. ISBN 978-0-314-93915-9.
  • Sturm, E. (2009). The New PL/I ... for PC, Workstation and Mainframe. Vieweg-Teubner, Wiesbaden, Germany. ISBN 978-3-8348-0726-7.
  • Vowels, R.A. (1997). Introduction to PL/I, Algorithms, and Structured Programming. 3rd ed. R.A. Vowels. ISBN 978-0-9596384-9-3.
  • Abrahams, Paul (1979). The PL/I Programming Language. Courant Mathematics and Computing Laboratory, New York University.

Standards

  • ANSI X3.53-1976 (R1998) Information Systems - Programming Language - PL/I
  • ANSI X3.74-1981 (R1998) Information Systems - Programming Language - PL/I General-Purpose Subset
  • ANSI X3.74-1987 (R1998) Information Systems - Programming Language - PL/I General-Purpose Subset
  • ECMA 50 Programming Language PL/I, 1st ed., December 1976
  • ISO 6160:1979 Programming languages—PL/I
  • ISO/IEC 6522:1992 Information technology: Programming languages: PL/I general purpose subset

Reference manuals

  • Burroughs Corporation, "B 6700 / B 7700 PL/I Language Reference", Detroit, 1977.
  • CDC, R.A. Vowels, "PL/I for CDC Cyber", optimizing compiler for CDC Cyber 70 series.
  • Digital Equipment Corporation, "decsystem10 Conversational Programming Language User's Manual", Maynard, 1975.
  • Fujitsu Ltd, "Facom OS IV PL/I Reference Manual", 70SP5402E-1, 1974.
  • Honeywell Inc., "Multics PL/I Language Specification", AG94-02, 1981.
  • IBM, "Operating System/360 PL/I: Language Specifications", C28-6571, 1965.
  • IBM, "OS PL/I Checkout and Optimizing Compilers: Language Reference Manual", GC33-0009, 1976.
  • IBM, "NPL Technical Report," December 1964.
  • IBM, "Enterprise PL/I for z/OS Version 4 Release 1 Language Reference Manual," SC14-7285-00, 2010.
  • IBM, "OS/2 PL/I Version 2: Programming: Language Reference," 3rd ed., San Jose, 1994.
  • Kednos Software, "Kednos PL/I for OpenVMS Systems Reference Manual," AA-H952E-TM, Nov 2003.
  • Liant Software Corporation (1994), Open PL/I Language Reference Manual, Rev. Ed., Framingham (Mass.).
  • Nixdorf Computer, "Terminalsystem 8820 Systemtechnischer Teil PL/I-Subset," 05001.17.8.93-01, 1976.
  • Ing. C. Olivetti, "Mini PL/I Reference Manual," 1975.
  • Q1 Corporation, "The Q1/LMC Systems Software Manual," Farmingdale, 1978.

External links