Rexx
REXX (Restructured Extended Executor) is a versatile, procedural programming language designed for ease of use in scripting, macro programming, prototyping, and general application development, featuring human-like syntax, string-based data handling, and high portability across systems.[1]
Developed by Mike Cowlishaw at IBM UK Laboratories in Hursley and the Thomas J. Watson Research Center between 1979 and 1982, REXX was first implemented under the Conversational Monitor System (CMS) in IBM's Virtual Machine/System Product (VM/SP) Release 3 in 1983, evolving through extensive user feedback via the VNET network connecting over 1,400 mainframes.[1][2] Its design prioritizes readability with free-format syntax, minimal punctuation, English-like keywords (e.g., IF-THEN-ELSE, DO-END loops), and no variable declarations or strong typing—all data treated as strings for natural manipulation.[1][3]
Key features include arbitrary-precision arithmetic, robust string processing, dynamic scoping, built-in debugging and tracing, and the ability to issue system commands or interlanguage calls while remaining largely system-independent, making it suitable for applications ranging from short scripts to programs exceeding one million lines.[1][3] In environments like z/OS, REXX serves as an interpreted (or optionally compiled) language for TSO/E commands, ISPF dialogs, system automation, and rapid prototyping, often compared to the simplicity of COBOL for job control.[3]
Standardized by the American National Standards Institute (ANSI) as X3.274-1996 (later INCITS 274-1996 with reaffirmations), the language ensures consistent interpretation across compliant implementations, promoting portability and reliability.[4] Variants like NetRexx extend its capabilities for Java integration, enhancing performance and security in modern contexts.[3] Widely adopted in IBM mainframe ecosystems for over four decades, REXX remains influential for its balance of simplicity and power, influencing scripting languages and continuing use in enterprise automation.[1][5]
Introduction
Name and Origin
REXX, originally conceived as REX (Reformed Executor), emerged as a programming language designed to enhance ease of use in scripting tasks. The name REX was first noted on March 20, 1979, with the initial specification dated March 29, 1979, reflecting its intent as a reformed approach to command execution. By 1982, it was renamed Rexx with an additional "x" to distinguish it from existing products and avoid potential naming conflicts. Upon its first release in 1983 as part of IBM's VM/SP Release 3, the name was expanded to REstructured eXtended eXecutor, underscoring its restructured syntax and extended capabilities for execution in diverse environments.[6][1]
The language was developed by Mike F. Cowlishaw, an IBM engineer, primarily at the IBM United Kingdom Laboratories Limited in Hursley, England, with contributions during 1979–1982 also involving the IBM Thomas J. Watson Research Center in Yorktown Heights, New York. Cowlishaw initiated the project as a personal endeavor to address the limitations of existing scripting tools under the VM/CMS operating system, prioritizing human readability and simplicity over computational efficiency. This focus stemmed from observations of the cumbersome nature of prior languages, aiming to create a tool that felt more natural for non-expert users.[1][7]
REXX's foundational purpose was to serve as a portable, English-like replacement for the EXEC and CLIST scripting languages used by VM/CMS operators, facilitating system administration, rapid prototyping, and macro programming. By emphasizing straightforward syntax and portability across IBM systems, it sought to reduce errors and accelerate development for tasks like command automation and personal computing utilities, marking a shift toward user-centric design in procedural languages.[1][6]
Key Attributes
Rexx features a simple, English-like syntax designed for readability and ease of use, consisting of only 23 basic instructions with no globally reserved keywords, which enables free-form coding without rigid formatting requirements.[1] This approach allows developers to write code in a natural style, mixing upper and lower case letters and using optional punctuation, making it accessible even to those unfamiliar with programming conventions.[1]
The language employs dynamic typing with typeless variables that do not require declaration and treat all data as strings, automatically converting types as needed during operations.[8] Arithmetic operations support arbitrary-precision decimal calculations, defaulting to nine significant digits but configurable via the NUMERIC instruction to handle up to thousands of digits for precise computations.[9] Rexx includes over 60 built-in functions for tasks such as mathematical operations, string manipulation, and environment queries, enhancing its utility for everyday scripting needs.[10]
Portability is achieved through abstraction of the host environment, allowing Rexx programs to interact with various operating systems and applications via the ADDRESS instruction without direct platform-specific code.[11] These attributes stem from Rexx's origins at IBM, where it was engineered for versatility across mainframe systems. Key strengths include its human-readable nature, which suits non-programmers for tasks like writing macros, rapid prototyping, and educational purposes, while limitations encompass the absence of native support for include files—requiring workarounds like subroutine calls—and incomplete integration with Unix-style pipes in non-specialized environments, often necessitating external tools or extensions.[1][12][13]
In terms of popularity, Rexx maintains a low profile in general metrics, with TIOBE Index ratings historically below 0.1% as of 2018 and remaining outside the top 50 languages in subsequent years, reflecting its niche endurance in mainframe and legacy systems. Despite this, recent developments indicate renewed interest in Rexx for modern scripting, highlighted by open-source advancements and articles promoting its revival for cross-platform use in 2022.[14]
History
Early Development (1979–1989)
The development of Rexx originated in 1979 when Mike Cowlishaw, working at IBM's United Kingdom Laboratories in Hursley, England, began prototyping a scripting language initially named REX to simplify command and macro programming within IBM's mainframe environments.[1] The first specification was documented on March 29, 1979, and an initial implementation was completed later that year, allowing for internal testing and feedback through IBM's VNET network, which connected over 1,400 mainframes across 40 countries.[15] By 1980, a more stable version (2.00) was in use internally at IBM for prototyping, education, and personal programming tasks, emphasizing readability and ease of use over complex syntax.[16]
The language stabilized in 1982, with the name adjusted to REXX by adding an "X" to distinguish it from other tools, and it was formally named as such in 1984.[15] Its first production release came with VM/SP Release 3 in 1983, integrated as the System Product Interpreter for the Conversational Monitor System (CMS) under VM/CMS, marking Rexx's debut as a tool for dialog management and command scripting in virtual machine environments.[17] Prior to any public standard, Rexx remained proprietary to IBM, with early adoption focused on system administration tasks, where it began replacing older procedural languages like EXEC by offering more natural syntax for scripting host commands and automating routines.[1] Initial external awareness emerged through IBM's technical documentation and reference manuals, such as the Virtual Machine/System Product: System Product Interpreter Reference, which highlighted its role in enhancing productivity for CMS users.[15]
Expansion accelerated in the mid-to-late 1980s as Rexx was ported to additional IBM platforms. In 1988, it was introduced to MVS/TSO environments as part of TSO Extensions (TSO/E) Version 2, enabling REXX execs for batch and interactive processing on MVS systems.[18] By 1987, IBM designated Rexx as the standard procedures language within its Systems Application Architecture (SAA), promoting portability across systems like VM, MVS, and OS/400, with implementations following for OS/2 in Extended Edition 1.2 (1989) and RS/6000 running AIX (also 1989).[16] This integration solidified Rexx's proprietary status while fostering its use in cross-platform scripting, though it remained without a public standard until later efforts.[15]
Standardization and Growth (1990–2010)
The first Rexx Symposium for Developers and Users, held on June 11, 1990, at the Stanford Linear Accelerator Center (SLAC), marked a pivotal moment in the language's evolution beyond IBM's proprietary ecosystems. Organized by Cathie Dager of SLAC, the event brought together developers and users to discuss Rexx's potential for broader adoption, fostering enthusiasm that led to the formation of the Rexx Language Association (RexxLA) in 1991. This symposium highlighted the need for standardization to ensure portability across diverse platforms, setting the stage for international collaboration.[19][20]
In response to growing demand for interoperability, the American National Standards Institute (ANSI) published the X3.274-1996 standard, titled "Information Technology - Programming Language REXX," which defined the core syntax, semantics, and constraints of the language to facilitate portability. This standard, reaffirmed in 2001 with supplements addressing errata, emphasized Rexx's decimal arithmetic capabilities and ensured compatibility without introducing major syntax alterations from prior IBM implementations. Influenced by similar efforts in language standardization, such as ISO/IEC 13211:1994 for Prolog, the ANSI standard promoted Rexx's use in multi-vendor environments by focusing on compliance rather than radical changes. Early IBM implementations served as the foundational reference for this standardization, providing a stable baseline for the core language features.[21][22]
The 1990s saw significant growth through open-source implementations that extended Rexx to non-IBM platforms. Regina, an interpreter for Unix systems written in ANSI C using lex and yacc, was announced in May 1992 by Anders Christensen, enabling Rexx scripting on Linux, Solaris, and other Unix variants with full compliance to the emerging standards. Similarly, REXX/imc, developed by Ian Collier in 1992 for SunOS and later ported to other Unix systems, provided another open-source option that supported Rexx's procedural capabilities in academic and research settings. These efforts democratized access to Rexx, allowing its use in utilities, education, and system administration without reliance on proprietary hardware.[23][20]
IBM contributed to this expansion with Object REXX (ooRexx), an object-oriented extension that maintained upward compatibility with classic Rexx while adding classes, inheritance, and integration with the System Object Model (SOM). A prototype was demonstrated at the 1992 Rexx Symposium, with the first official release in 1996 as part of OS/2 Warp 4, initially targeting OS/2 but soon ported to Windows and AIX. This version enhanced Rexx's applicability in graphical user interfaces and enterprise applications, aligning with IBM's Systems Application Architecture (SAA) push to extend Rexx as a standard procedure language to non-IBM platforms like AS/400 and VSE. The RexxUtil toolkit, introduced during this period for OS/2 and Windows, provided essential extensions such as file I/O, directory manipulation, and system event handling, further bolstering practical deployment without altering the core syntax.[24][20][25]
Rexx's footprint widened through ports to additional environments, including expansions of ARexx for the Amiga platform, which was integrated into AmigaOS 2.0 in 1990 and further developed with AmigaOS 3.0 in 1992 to support inter-application scripting via ports. Implementations for Windows and Linux proliferated in the late 1990s, often leveraging Regina or ooRexx, positioning Rexx as a versatile scripting tool akin to early influences on languages like Tcl for automation and rapid prototyping. By the 2000s, Rexx had matured into a compliant, portable language used in education for teaching procedural programming and in utilities for cross-platform task automation. The 2004 International Rexx Symposium in Germany celebrated the language's 25th anniversary, underscoring its enduring relevance and community-driven growth.[26][27]
Modern Era and Recent Developments (2011–present)
In 2019, the Rexx Language Association (RexxLA) hosted its 30th annual symposium in Hursley, United Kingdom, commemorating the 40th anniversary of Rexx's initial development at IBM.[28] The event featured presentations on classic Rexx, NetRexx, and Open Object Rexx (ooRexx), underscoring the language's enduring legacy in scripting and automation.[29]
Rexx maintains significant relevance in modern computing, particularly for scripting on IBM z/OS mainframes and general-purpose automation tasks. IBM's z/OS TSO/E REXX Reference documentation, updated through 2021, details its integration for executing programs in TSO/E environments, including access to z/OS UNIX System Services for hybrid workflows.[30] Similarly, the 2022 Using REXX and z/OS UNIX System Services guide highlights its role in invoking callable services, enabling seamless interaction between mainframe and Unix-like systems.[31] Articles on Opensource.com in 2022 promoted Rexx as a versatile scripting language for contemporary open-source environments, emphasizing its simplicity for tasks like text processing and system administration.[14][32]
Recent implementations have seen active maintenance and enhancements. The Regina Rexx interpreter, hosted on SourceForge, continues ongoing updates, with file modifications as recent as March 2025, ensuring ANSI compliance and portability across Unix-like platforms, Windows, and OS/2.[33] ooRexx, the open-source object-oriented extension, released version 5.0.0 in December 2022, introducing features like annotations for classes, methods, and attributes, along with the new RexxInfo class to bolster object-oriented programming capabilities.[34] Version 5.1.0 reached general availability in 2025, with further improvements in performance, command redirection, bug fixes, and feature enhancements for integrated scripting.[35]
In 2025, the Open Mainframe Project's Winter Mentorship program advanced Rexx's tooling by developing a Language Server Protocol (LSP) extension for Visual Studio Code using the Langium framework, enhancing IDE support for syntax highlighting, autocompletion, and diagnostics in mainframe development.[36] RexxLA sustains community engagement through annual symposia, such as the 35th International Rexx Language Symposium in March 2024 in Brisbane, Australia, which included hybrid online participation to discuss portability in cloud-mainframe environments.[28] The 36th symposium, held in May 2025 in Vienna, Austria, featured updates including the ooRexx 5.1.0 release and ongoing adaptations for hybrid environments.[28] While no major updates to the ANSI Rexx standard have occurred since 1996, efforts emphasize Rexx's adaptability for hybrid cloud integrations, leveraging its cross-platform interpreters to bridge legacy mainframe applications with modern distributed systems.[4]
Implementations
Host Environments
REXX is an interpreted scripting language that is typically embedded within host operating systems and applications, allowing it to execute in environments such as IBM z/OS via TSO/E, z/VM through CMS, and various implementations on Windows, Unix, and Linux systems using dedicated interpreters.[30][37][38] In these hosts, REXX programs, known as execs, interact with the underlying system without making direct operating system calls, promoting portability across diverse platforms.[39]
A key mechanism for this portability is the abstract interface provided by host command environments, which insulate REXX from platform-specific details. The ADDRESS instruction routes commands to these environments, such as ADDRESS SYSTEM to invoke shell commands like listing files, enabling REXX to issue system-level operations indirectly through the host's defined processors.[40] For instance, in z/OS TSO/E, REXX execs can run interactively or as batch jobs using utilities like IKJEFT01, facilitating automated processing of mainframe tasks without direct MVS interactions.[41] Similarly, in the Amiga operating system, ARexx integrates with applications via message ports, allowing scripts to control programs like text editors or databases through host addresses. In IBM CICS environments, REXX serves as a scripting language for transaction processing, where execs can be invoked via CICS transactions to manage resources like temporary storage queues or automate workflows.[42]
The evolution of REXX host interactions began with IBM's Systems Application Architecture (SAA) initiative in 1987, which standardized REXX as a common procedures language across platforms like MVS, VM, and OS/2, defining consistent host command environments to enhance interoperability.[43] In modern contexts, REXX continues to adapt through integrations like Eclipse-based editors in IBM Developer for z/OS, which provide syntax highlighting and debugging for mainframe scripts, and containerized emulations using Docker with tools like Hercules to simulate z/OS environments on commodity hardware.[44][45] These advancements maintain REXX's role in hybrid cloud and DevOps pipelines while preserving its core portability principles.[44]
Rexx implementations vary across platforms, with a focus on maintaining compatibility with the ANSI X3.274-1996 standard while adding platform-specific extensions. The original IBM implementation, known as RXAPI or System Rexx, remains the reference for mainframe environments, supporting z/OS, z/VM, and VSE systems through integrated APIs for OS interaction and command stacking.[46] This version includes ongoing updates bundled with IBM operating systems, ensuring backward compatibility and support for enterprise scripting tasks like database access via DB2.[46]
Open-source alternatives emphasize portability. Regina, an ANSI-compliant interpreter, runs on Unix-like systems (Linux, macOS, BSD), Windows, and Android, with features like thread safety, interprocess communication, and extensions for stream I/O and bit operations.[38] Its latest release, version 3.9.7, continues active maintenance for cross-platform scripting.[47] Similarly, BRexx provides a lightweight, high-performance option for Linux, Windows, DOS, and emulated mainframes, incorporating dynamic linking and database functions while adhering to TRL-2 standards.[48]
Object-oriented extensions build on classic Rexx syntax. ooRexx, originally developed by IBM with contributions from Simon Nash and others in the early 1990s, introduces classes, methods, and GUI support via ooDialog, remaining fully backward-compatible with ANSI Rexx.[49] The open-source project, managed by the Rexx Language Association, released version 5.1.0 in May 2025, adding enhancements like improved concurrency and Unicode handling across Windows, Linux, and Android.[35] NetRexx, a 1996 variant with Java-like syntax, compiles to JVM bytecode for seamless integration with Java libraries, supporting web servlets and enterprise applications; its current version 5.01-GA (as of May 2025) is maintained openly for cross-platform use.[50]
Platform-specific ports include ARexx for AmigaOS and emulators like AROS and MorphOS, where it serves as the default interprocess communication tool since 1988, with ANSI compliance and ongoing use in legacy environments.[51] REXX for PHP embeds Rexx commands into PHP scripts for web development, allowing native Rexx functions in includable PHP files.[52]
Toolkits extend Rexx's capabilities without altering core syntax. RexxUtil provides cross-platform utilities for file I/O, dialogs, and system calls on Windows, VM, and Unix.[53] Rexx/Tk enables GUI development using Tcl/Tk, supporting widgets and event handling on major platforms under GNU LGPL. Rexx/SQL facilitates database connectivity via ODBC and CLI standards, compatible with interpreters like Regina and ooRexx.[54] The Rexx Language Support extension for Visual Studio Code provides LSP-based features like syntax highlighting and autocompletion for editing Rexx code (as of August 2025).[55] All major implementations target ANSI X3.274 compliance, with extensions like NetRexx diverging for specialized environments.[53]
Syntax and Language Features
Instruction Types and Basic Syntax
REXX features a free-form syntax that provides programmers with considerable flexibility in code layout. There are no restrictions on where an instruction may start within a line, and code can span multiple lines without mandatory indentation. Clauses—the fundamental units of executable code—are delimited by semicolons or by the end of a line, allowing multiple clauses to appear on a single line when separated by semicolons. The language treats keywords and symbols in a case-insensitive manner, while preserving the case of string literals.[56][57]
Comments in REXX are enclosed within /* and */ delimiters, which can encompass multiple lines and are entirely ignored during execution. These comments support nesting, with implementations required to handle at least ten levels. and are commonly used at the start of programs to describe their purpose.[57][58]
REXX instructions fall into three main categories: assignments, keyword instructions, and commands. Assignments bind the result of an expression to one or more symbols using the equals sign (=), as in total = 0 or, with templates for pattern matching, first second = "apple banana cherry", which assigns "apple" to first and "banana" to second while leaving "cherry" unassigned. Keyword instructions invoke built-in language functions, such as SAY, which directs the evaluated expression to the standard output stream: SAY "Hello, World!" produces the literal output "Hello, World!". Commands facilitate interaction with the host system and are prefixed by the ADDRESS instruction, which specifies the target environment (e.g., SYSTEM or TSO) followed by the command string, like ADDRESS SYSTEM "ls".[56][57][58]
Expressions within instructions are evaluated from left to right, subject to operator precedence that prioritizes operations such as exponentiation over addition. Parentheses can alter this order explicitly. The PARSE ARG instruction processes program arguments using a template to distribute values into variables, for example, PARSE ARG user input assigns the first argument to user and the second to input. Programs typically conclude with the EXIT instruction, which halts execution and optionally sets a return value via an expression, such as EXIT 0 to indicate successful completion.[59][57][58]
The following example illustrates a basic REXX program structure incorporating these elements:
/* Greeting program that processes an argument */
PARSE ARG name
IF name = "" THEN name = "World"
SAY "Hello," name "!"
EXIT 0
/* Greeting program that processes an argument */
PARSE ARG name
IF name = "" THEN name = "World"
SAY "Hello," name "!"
EXIT 0
This code parses an input argument into name, defaults it if absent, outputs a greeting, and exits cleanly.[58][57]
Control Structures
Rexx provides structured control mechanisms for managing program flow, including iterative loops via DO groups, conditional execution with IF statements, and multi-way branching through SELECT constructs. These features enable programmers to implement repetitive tasks, decision-making logic, and switch-like behavior in a readable and flexible manner, drawing from the language's design emphasis on simplicity and clarity.[57]
The primary looping construct in Rexx is the DO group, which encloses a block of instructions between DO and END keywords, allowing for single execution or repetition based on specified criteria. Simple DO groups execute their instructions once without iteration, serving to group multiple statements, as in DO; say 'Grouped'; say 'statements'; END;. For repetitive execution, a DO group can specify an iteration count, such as DO 5; say i; END;, which repeats the block five times while implicitly setting a counter variable i from 1 to 5. Controlled iteration uses the form DO name=initial TO final [BY increment]; ... END;, where the loop variable name advances from initial to final in steps of increment (defaulting to 1), for example, DO i=1 TO 10 BY 2; say i; END;, outputting odd numbers from 1 to 9. Conditional variants include DO WHILE condition; ... END;, which tests the condition before each iteration and continues only if true, and DO UNTIL condition; ... END;, which tests after each iteration and stops when true; both can combine with iteration specs, like DO i=1 TO 10 WHILE i<6; say i; END;. Infinite loops use DO FOREVER; ... END;, requiring explicit termination via other controls. These DO types support nesting and can mix iteration and conditions for complex loops, with the control variable's final value retained after execution.[57][53]
Conditional execution relies on the IF statement, structured as IF condition THEN instruction [ELSE instruction];, where the THEN clause executes if the condition evaluates to true (non-zero and non-null in Rexx's logical sense), and the optional ELSE provides an alternative for false conditions. For multi-statement blocks, IF uses a DO group: IF condition THEN DO; instructions; END; [ELSE DO; instructions; END;]. This supports multi-way decisions through nested IFs or chained ELSE clauses, though deeply nested forms can reduce readability. For instance, IF x > 0 THEN SAY 'Positive' ELSE SAY 'Non-positive'; demonstrates basic usage, while IF answer='YES' THEN DO; say 'OK!'; ELSE say 'Why not?'; END; handles grouped actions. ELSE clauses pair with the nearest unmatched IF, ensuring unambiguous scoping in nests.[57][53]
For switch-like multi-way branching, Rexx employs the SELECT construct: SELECT; WHEN condition THEN instruction; [WHEN condition THEN instruction; ...] [OTHERWISE instruction;] END;, which evaluates WHEN conditions in order and executes the first true one's THEN clause, falling to OTHERWISE if none match. Multi-statement WHEN or OTHERWISE blocks require DO-END, as in:
SELECT;
WHEN x=1 THEN DO; say 'One'; END;
WHEN x=2 THEN say 'Two';
OTHERWISE say 'Other';
END;
SELECT;
WHEN x=1 THEN DO; say 'One'; END;
WHEN x=2 THEN say 'Two';
OTHERWISE say 'Other';
END;
This structure promotes efficient handling of multiple discrete cases, with OTHERWISE being optional but recommended for completeness. Conditions in IF, SELECT, and DO loops involve Rexx's expression evaluation, where logical truth is any non-zero numeric or non-null string value.[57][53]
Within DO loops, flow can be altered using LEAVE and ITERATE. LEAVE [loopname]; immediately exits the innermost (or named) DO group, useful for early termination, such as in DO i=1 TO 10; if i=5 THEN LEAVE; say i; END;, which outputs 1 through 4. Conversely, ITERATE [loopname]; skips remaining instructions in the current iteration and advances to the next, for example, DO i=1 TO 4; if i=2 THEN ITERATE; say i; END;, outputting 1, 3, and 4. Rexx lacks a direct break equivalent outside loops but uses SIGNAL for broader exits, though LEAVE and ITERATE suffice for most iterative control without overlapping variable scoping issues, as loop variables are local to their DO group unless explicitly declared otherwise.[57][53]
Variables and Data Handling
In REXX, variables are typeless and require no explicit declaration; they are created implicitly upon the first assignment using the equals operator (=). For instance, the statement x = 5 creates the variable x and assigns it the value 5, which can be a string, number, or expression result. Variable names, known as symbols, consist of letters (A-Z, a-z), digits (0-9), and periods (.), starting with a letter or period, and are case-insensitive by default, though implementations may vary in preserving case.[41][53]
When a variable is referenced before assignment, its behavior depends on the context and implementation settings. In string contexts, an unassigned variable substitutes its own name in uppercase letters (e.g., referencing foo outputs "FOO"), unless the variable has been explicitly dropped, in which case it may raise the NOVALUE condition. In numeric contexts, referencing an unassigned variable raises the NOVALUE condition unless trapped with SIGNAL ON NOVALUE, allowing programmers to handle such cases gracefully without strong typing enforcement. This design promotes flexibility while encouraging explicit error handling for uninitialized data.[60][53][41]
REXX employs a dynamic typing system with no distinction between integers, floats, or other numeric types; all variables store strings internally, and type conversion occurs automatically based on usage. For example, assigning y = "123" treats y as the string "123", but using it in a numeric operation like z = y + 1 converts it to the number 123, resulting in z = 124. The DATATYPE built-in function can inspect a variable's effective type (e.g., NUM for numeric, CHAR for character string), but no compile-time or runtime type checking enforces fixed types, reducing errors from type mismatches.[41][53][60]
Expressions involving variables are evaluated from left to right, respecting operator precedence (e.g., exponentiation ** before multiplication * and division /, which precede addition + and subtraction -), with parentheses overriding the order. Numbers in expressions are interpreted as decimal unless specified otherwise (e.g., 3.14 or 1E3 for scientific notation), while non-numeric strings remain as-is. Lazy evaluation is not strictly defined, but variable substitution occurs just before operations, allowing indirect references without immediate resolution. For example:
total = price * (1 + tax_rate)
total = price * (1 + tax_rate)
Here, if price is "10.00" and tax_rate is 0.08, total becomes 10.80 after implicit conversions.[41][53]
Compound variables extend scalar handling by using a stem (a symbol followed by a period, e.g., arr.) combined with a tail (a derived symbol or expression, e.g., arr.1), forming dynamic structures like arrays or associative storage without predefined sizes. Assignment creates elements on demand, such as arr.1 = "value", and the special tail .0 often tracks the number of elements (e.g., arr.0 = 3). Tails support indirect referencing via tail notation, where the tail is another variable or expression (e.g., i = 2; word.i = "hello" sets word.2 to "hello"). This enables flexible data structures, like:
do i = 1 to 3
data.i = i * 10
end
do i = 1 to 3
data.i = i * 10
end
resulting in data.1 = 10, data.2 = 20, and data.3 = 30, with automatic indexing.[60][53][41]
Special variables provide access to runtime state without explicit assignment. The RC variable holds the return code from the previous external command, function call, or address space invocation (e.g., after ADDRESS TSO "LISTDS", RC might be 0 for success). The single dot (.) represents the current iteration index in loops or the result of the last evaluated expression in certain contexts. These, along with reserved symbols like SIGL (signal label) and RESULT (routine return value), are predefined in the variable pool and cannot be freely reassigned in standard implementations. Tail notation in compounds often interacts with these for dynamic access, such as word.RC to index by return code value. The NOVALUE condition further safeguards against unintended references to unset special or compound elements.[41][53][60]
String Processing and Evaluation
Rexx provides robust facilities for string manipulation and dynamic evaluation, primarily through the PARSE instruction and the INTERPRET instruction, enabling efficient scripting for data extraction and code generation.[61] These tools allow developers to split input strings into variables using customizable templates and to execute strings as Rexx code at runtime, making Rexx particularly suited for processing command-line arguments, user input, and generated scripts.[62][63]
The PARSE instruction assigns data from various sources to one or more variables according to specified parsing rules.[62] Its general syntax is PARSE [UPPER] [source] [WITH] template_list, where the optional UPPER clause converts the source string to uppercase before parsing, and the source can be one of several variants: ARG for program arguments, EXTERNAL for terminal input, NUMERIC for settings like DIGITS and FUZZ, PULL for data queue or input stream, SOURCE for program invocation details, VALUE followed by an expression, VAR followed by a variable name, or VERSION for language level information.[62] For instance, PARSE [ARG](/page/ARG) args extracts command-line arguments into variables, while PARSE PULL line reads the next line from input and parses it.[64] Templates consist of symbols or patterns separated by blanks, with multiple templates separated by commas; if no template is provided, the source string is prepared but not assigned.[62]
Parsing operates positionally on the source string, assigning substrings to variables based on template elements.[65] Basic templates split by default on blanks into words, but advanced patterns include wildcards for precise control: a single period (.) matches one or more characters until the next template element or end of string, .n matches exactly n characters, and .d matches a single digit.[65] String literals in templates match exact sequences, which can be case-sensitive, and relative positioning like +n skips n characters after a match.[65] Rexx does not support regular expressions in templates, relying instead on these simple yet powerful positional and wildcard rules for common parsing tasks.[65] An example is PARSE VAR line a b c, which splits a string variable line by spaces into three variables; for patterned parsing, PARSE VALUE time() WITH hours '.' mins '.' secs extracts components from a time string like "12.34.56" into hours, mins, and secs.[62] Another is PARSE UPPER ARG word1 .3 rest, which uppercases arguments, assigns the first word to word1, the next three characters to a variable, and the remainder to rest.[64] These mechanisms integrate seamlessly with variables for dynamic content handling, such as building templates from computed values.[65]
The INTERPRET instruction enables dynamic execution by evaluating a string expression as Rexx code, effectively treating it as if it were a clause in the program.[63] Its syntax is simply INTERPRET expression;, where the expression is first evaluated to a string, a semicolon is appended if absent, and the result is then executed.[63] This allows for runtime code generation, such as constructing loops or assignments from data; for example, INTERPRET 'data = 4' assigns the value 4 to the variable data.[63] More complex uses include cmd = 'DO 3; SAY "Hello!"; END'; INTERPRET cmd, which outputs "Hello!" three times.[63] However, INTERPRET has limitations: it cannot handle label clauses, partial constructs like a standalone LEAVE without a full loop, or nested dynamic instructions that alter control flow unexpectedly.[63] Due to its power, INTERPRET poses risks such as code injection if the expression incorporates untrusted input, so it should be used cautiously, often with debugging via TRACE Results or Interactive modes to inspect execution.[63] For simpler evaluations without full instruction execution, the VALUE function serves as a safer alternative.[63]
Numeric Operations and Precision
Rexx provides arbitrary-precision decimal arithmetic, allowing computations with extremely large numbers without overflow, controlled primarily through the NUMERIC instruction. This instruction sets the precision and behavior for arithmetic operations and comparisons. The NUMERIC DIGITS n clause specifies the number of significant digits for calculations, with a default of 9; conforming implementations must support at least 999, though the maximum is implementation-defined. values below 9 reduce precision and should be used cautiously to avoid unexpected rounding effects.[66][67][60]
The NUMERIC FUZZ m clause defines the tolerance for numeric comparisons by ignoring the specified number of least significant digits, with a default of 0 and a maximum equal to the current DIGITS value minus 1; during comparisons, the effective precision is temporarily reduced by the fuzz amount, treating numbers as equal if their difference falls within this tolerance.[67] The NUMERIC FORM clause determines the exponential notation for output: SCIENTIFIC (default, using powers of 10, e.g., 1.23E+4) or ENGINEERING (using powers of 1,000, e.g., 1.23E+3 for 1,230); this affects how results exceeding the displayable digits are formatted when converted to strings.[67] Omitting operands in the NUMERIC instruction displays the current settings, and built-in functions DIGITS(), FUZZ(), and FORM() return these values as strings.[68]
Arithmetic operations in Rexx include addition (+), subtraction (-), multiplication (*), division (/ for exact decimal division), integer division (% which truncates toward zero), remainder (//), and exponentiation (** with a non-negative integer exponent). All operations respect the current NUMERIC DIGITS setting for precision, handling big decimals exactly; for example, 12345678901234567890 + 1 yields the precise result without truncation. Division (/) produces results rounded to the current precision, while integer division (%) discards the fractional part toward zero, and remainder (//) follows the sign of the dividend. Invalid operations, such as division by zero, raise errors.[69][70]
Relevant built-in functions support numeric manipulation under the current settings: ABS(number) returns the absolute value, SIGN(number) returns -1 for negative, 0 for zero, or 1 for positive inputs, and TRUNC(number [, n]) truncates to the integer part (default n=0) or to n decimal places, always toward zero. These functions, along with others like FORMAT(), adhere to NUMERIC precision except where specified otherwise. For output in engineering notation, the FORMAT function can specify an exponent type of 'E' to force powers of 1,000 regardless of the NUMERIC FORM setting.[71][68]
To illustrate precision control, consider setting high accuracy for approximations: NUMERIC DIGITS 50 followed by pi = 22 / 7 retains the result as a 50-digit decimal (approximately 3.14285714285714285714285714285714285714285714286), demonstrating exact handling without premature rounding; lowering DIGITS to 5 would yield 3.1429 after rounding. Such capabilities enable precise financial or scientific computations, but users must manage DIGITS to balance accuracy and performance, as higher values increase computation time.[66][70]
Limitations include truncation toward zero in integer division and the TRUNC function, which may differ from rounding behaviors in other languages; Rexx does not natively support complex numbers or floating-point binary arithmetic, relying instead on decimal representation throughout. Errors occur for non-numeric inputs in arithmetic contexts, promoting robust numeric handling.[69][70]
Error Handling and Debugging
Rexx employs a condition-based mechanism for error handling, allowing programs to trap and respond to specific runtime events without a traditional try-catch construct. Conditions such as ERROR, FAILURE, HALT, NOVALUE, and SYNTAX can be trapped using the SIGNAL ON or CALL ON instructions, which enable or disable traps for these events.[72] When a condition occurs, control transfers to a designated internal label, where the program can handle the error, log details, or take corrective action. The SIGNAL ON variant immediately branches to the trap routine and does not return, making it suitable for fatal errors, while CALL ON invokes the routine as a subroutine, allowing execution to resume afterward.[72]
The ERROR condition is raised when a host command returns a positive return code indicating an error, unless a FAILURE trap is active.[72] FAILURE triggers on negative return codes from commands, signifying severe issues like command failures.[72] HALT occurs due to external interruptions, such as user-initiated stops.[72] NOVALUE is raised when referencing an uninitialized simple variable, helping prevent unintended behaviors in scripting.[72] SYNTAX handles parsing or runtime syntax errors, though it only works with SIGNAL ON.[72] Traps are initially off and can be specified with a label, such as SIGNAL ON NOVALUE NAME badvar, directing flow to the badvar: label upon occurrence. In the handler, the special variable RC holds the return code for command-related conditions, enabling inspection of the error severity.[72]
For example, the following code traps a NOVALUE condition:
SIGNAL ON NOVALUE NAME trap_novalue
x = y + 1 /* y is uninitialized */
trap_novalue:
SAY "Variable not set: " RC
EXIT 1 /* Terminate with [error code](/page/Error_code) */
SIGNAL ON NOVALUE NAME trap_novalue
x = y + 1 /* y is uninitialized */
trap_novalue:
SAY "Variable not set: " RC
EXIT 1 /* Terminate with [error code](/page/Error_code) */
Here, the trap routine displays a message and uses the EXIT instruction to end the program, setting the overall return code to 1, which is stored in the invoker's RC variable if applicable.[73] The EXIT instruction unconditionally terminates the exec, optionally specifying a numeric value as the return code to propagate success (0) or failure status back to the caller or environment.[73] In some implementations like Object REXX, handlers can use PROPAGATE to re-raise the condition up the call chain for further processing.[74]
Debugging in Rexx primarily relies on the TRACE instruction, which logs program execution details to aid in identifying issues. TRACE options include ALL, which displays every clause before execution; RESULTS, showing expressions and their outcomes; NORMAL, tracing only errored commands; and OFF to disable tracing.[75] For interactive debugging, the ? prefix pauses at each traced line, allowing step-by-step inspection, while ! inhibits host command execution to test logic safely.[75] Host environments often support interactive modes where TRACE can be toggled dynamically, combined with condition traps for comprehensive error diagnosis. For instance, TRACE ALL followed by SIGNAL ON SYNTAX enables full visibility into syntax errors during development.[75] This facility provides flexible, non-intrusive tools for scripting errors, emphasizing Rexx's suitability for interactive and automated tasks.[72]