IBM TSO/E REXX User Manual

z/OS
TSO/E REXX User’s Guide

SA22-7791-00
z/OS
TSO/E REXX User’s Guide

SA22-7791-00
Note
Before using this information and the product it supports, be sure to read the general information under “Appendix D. Notices” on page 205.
This edition applies to Version 1 Release 1 of z/OS (5694-A01) and to all subsequent releases and modifications until otherwise indicated in new editions.
Order publications through your IBM representative or the IBM branch office serving your locality. Publications are not stocked at the address below.
IBM welcomes your comments. A form for readers’ comments may be provided at the back of this publication, or you may address your comments to the following address:
International Business Machines Corporation Department 55JA, Mail Station P384 2455 South Road Poughkeepsie, NY 12601-5400 United States of America
FAX (United States & Canada): 1+845+432-9405 FAX (Other Countries):
Your International Access Code +1+845+432-9405
IBMLink (United States customers only): IBMUSM10(MHVRCFS) Internet e-mail: mhvrcfs@us.ibm.com World Wide Web: http://www.ibm.com/servers/eserver/zseries/zos/webqs.html
If you would like a reply, be sure to include your name, address, telephone number, or FAX number.
Make sure to include the following in your comment or note:
v Title and order number of this book v Page number or topic related to your comment
When you send information to IBM, you grant IBM a nonexclusive right to use or distribute the information in any way it believes appropriate without incurring any obligation to you.
© Copyright International Business Machines Corporation 1988, 2001. All rights reserved.
US Government Users Restricted Rights – Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.

Contents

Figures............................ix
Tables ............................xi
About This Book .......................xiii
Who Should Use This Book ....................xiii
How This Book Is Organized ....................xiii
Terminology .........................xiii
Purpose of Each Chapter ....................xiv
Examples ..........................xiv
Exercises ..........................xiv
Where to Find More Information ..................xiv
Accessing Licensed Books on the Web ...............xiv
Using LookAt to Look Up Message Explanations ...........xv
Part 1. Learning the REXX Language......................1
Chapter 1. Introduction ......................3
What is REXX? .........................3
Features of REXX ........................3
Ease of use .........................3
Free format .........................3
Convenient built-in functions ...................4
Debugging capabilities .....................4
Interpreted language ......................4
Extensive parsing capabilities ...................4
Components of REXX.......................4
The SAA Solution ........................4
Benefits of Using a Compiler ....................5
Improved Performance .....................5
Reduced System Load .....................5
Protection for Source Code and Programs ..............6
Improved Productivity and Quality .................6
Portability of Compiled Programs..................6
SAA Compliance Checking ....................6
Chapter 2. Writing and Running a REXX Exec .............7
Before You Begin ........................7
What is a REXX Exec? ......................8
Syntax of REXX Instructions ....................9
The Character Type of REXX Instructions ..............9
The Format of REXX Instructions .................10
Types of REXX Instructions ...................12
Execs Using Double-Byte Character Set Names ............14
Running an Exec ........................16
Running an Exec Explicitly ...................16
Running an Exec Implicitly ...................17
Interpreting Error Messages ....................19
Preventing Translation to Uppercase .................20
From Within an Exec......................20
As Input to an Exec ......................20
Passing Information to an Exec ...................21
Using Terminal Interaction ....................21
© Copyright IBM Corp. 1988, 2001 iii
Specifying Values when Invoking an Exec ..............22
Preventing Translation of Input to Uppercase .............23
Passing Arguments ......................24
Chapter 3. Using Variables and Expressions .............25
Using Variables.........................25
Variable Names .......................26
Variable Values........................27
Exercises - Identifying Valid Variable Names .............27
Using Expressions .......................28
Arithmetic Operators ......................28
Comparison Operators .....................30
Logical (Boolean) Operators ...................32
Concatenation Operators ....................34
Priority of Operators ......................35
Tracing Expressions with the TRACE Instruction ............37
Tracing Operations ......................37
Tracing Results........................38
Chapter 4. Controlling the Flow Within an Exec............41
Using Conditional Instructions ...................42
IF/THEN/ELSE Instructions ...................42
Nested IF/THEN/ELSE Instructions ................43
SELECT/WHEN/OTHERWISE/END Instruction ............44
Using Looping Instructions ....................47
Repetitive Loops .......................47
Conditional Loops .......................52
Combining Types of Loops ...................55
Nested DO Loops .......................55
Using Interrupt Instructions ....................56
EXIT Instruction .......................57
CALL/RETURN Instructions ...................57
SIGNAL Instruction ......................58
Chapter 5. Using Functions ...................61
What is a Function? .......................61
Example of a Function .....................62
Built-In Functions ........................63
Arithmetic Functions ......................63
Comparison Functions .....................63
Conversion Functions .....................64
Formatting Functions......................64
String Manipulating Functions ..................64
Miscellaneous Functions ....................65
Testing Input with Built-In Functions ................66
Chapter 6. Writing Subroutines and Functions ............69
What are Subroutines and Functions? ................69
When to Write Subroutines vs. Functions ...............70
Writing a Subroutine .......................70
Passing Information to a Subroutine ................72
Receiving Information from a Subroutine ..............75
Writing a Function ........................77
Passing Information to a Function .................79
Receiving Information from a Function ...............83
Summary of Subroutines and Functions................83
iv z/OS V1R1.0 TSO/E REXX Users Guide
Chapter 7. Manipulating Data ...................85
Using Compound Variables and Stems ................85
What is a Compound Variable? ..................85
Using Stems .........................86
Parsing Data..........................87
Instructions that Parse .....................88
Ways of Parsing .......................89
Parsing Multiple Strings as Arguments ...............92
Part 2. Using REXX .............................95
Chapter 8. Entering Commands from an Exec ............97
Types of Commands .......................97
Issuing TSO/E Commands from an Exec ...............98
Using Quotations Marks in Commands ...............98
Using Variables in Commands ..................99
Causing Interactive Commands to Prompt the User ..........100
Invoking Another Exec as a Command...............100
Issuing Other Types of Commands from an Exec ............101
What is a Host Command Environment? ..............101
Changing the Host Command Environment .............106
Chapter 9. Diagnosing Problems Within an Exec ...........111
Debugging Execs .......................111
Tracing Commands with the TRACE Instruction ...........111
Using REXX Special Variables RC and SIGL ............112
Tracing with the Interactive Debug Facility .............113
Chapter 10. Using TSO/E External Functions ............119
TSO/E External Functions ....................119
Using the GETMSG Function ..................120
Using the LISTDSI Function ..................120
Using the MSG Function ....................122
Using the MVSVAR Function ..................123
Using the OUTTRAP Function ..................123
Using the PROMPT Function ..................124
Using the SETLANG Function ..................125
Using the STORAGE Function..................126
Using the SYSCPUS Function ..................126
Using the SYSDSN Function ..................126
Using the SYSVAR Function ..................127
Additional Examples ......................130
Function Packages .......................133
Search Order for Functions ...................134
Chapter 11. Storing Information in the Data Stack ..........135
What is a Data Stack? .....................135
Manipulating the Data Stack ...................136
Adding Elements to the Data Stack ................136
Removing Elements from the Stack ................137
Determining the Number of Elements on the Stack ..........137
Processing of the Data Stack ...................139
Using the Data Stack ......................140
Passing Information Between a Routine and the Main Exec .......140
Passing Information to Interactive Commands ............142
Issuing Subcommands of TSO/E Commands ............142
Contents v
Creating a Buffer on the Data Stack.................142
Creating a Buffer with the MAKEBUF Command ...........143
Dropping a Buffer with the DROPBUF Command ...........144
Finding the Number of Buffers with the QBUF Command ........144
Finding the Number of Elements In a Buffer .............145
Protecting Elements in the Data Stack ................147
Creating a New Data Stack with the NEWSTACK Command ......148
Deleting a Private Stack with the DELSTACK Command ........149
Finding the Number of Stacks ..................149
Chapter 12. Processing Data and Input/Output Processing .......153
Types of Processing ......................153
Dynamic Modification of a Single REXX Expression ...........153
Using the INTERPRET Instruction ................153
Using EXECIO to Process Information to and from Data Sets .......154
When to Use the EXECIO Command ...............154
Using the EXECIO Command ..................154
Return Codes from EXECIO ..................159
When to Use the EXECIO Command ...............159
Chapter 13. Using REXX in TSO/E and Other MVS Address Spaces ...171
Services Available to REXX Execs .................171
Running Execs in a TSO/E Address Space ..............173
Running an Exec in the Foreground................173
Running an Exec in the Background ...............176
Running Execs in a Non-TSO/E Address Space ............177
Using an Exec Processing Routine to Invoke an Exec from a Program 177
Using IRXJCL to Run an Exec in MVS Batch ............178
Using the Data Stack in TSO/E Background and MVS Batch ......180
Summary of TSO/E Background and MVS Batch ............180
CAPABILITIES .......................180
REQUIREMENTS ......................181
Defining Language Processor Environments .............181
What is a Language Processor Environment? ............181
Customizing a Language Processor Environment ...........182
Part 3. Appendixes .............................183
Appendix A. Allocating Data Sets .................185
What is Allocation? .......................185
Where to Begin ........................186
Preliminary Checklist ......................186
Checklist #1: Creating and Editing a Data Set Using ISPF/PDF ......187
Checklist #2: Creating a Data Set with the ALLOCATE Command......190
Checklist #3: Writing an Exec that Sets up Allocation to SYSEXEC .....191
Checklist #4: Writing an Exec that Sets up Allocation to SYSPROC .....192
Appendix B. Specifying Alternate Libraries with the ALTLIB Command 195
Specifying Alternative Exec Libraries with the ALTLIB Command ......195
Using the ALTLIB Command ..................195
Stacking ALTLIB Requests ...................196
Using ALTLIB with ISPF ....................196
Examples of the ALTLIB Command .................196
Appendix C. Comparisons Between CLIST and REXX .........197
Accessing System Information ...................198
vi z/OS V1R1.0 TSO/E REXX Users Guide
Controlling Program Flow ....................199
Debugging ..........................200
Execution ..........................200
Interactive Communication ....................201
Passing Information.......................201
Performing File I/O .......................202
Syntax ...........................202
Using Functions ........................203
Using Variables ........................203
Appendix D. Notices ......................205
Programming Interface Information .................207
Trademarks..........................207
Bibliography .........................209
TSO/E Publications .......................209
Related Publications ......................209
Index ............................211
Contents vii
viii z/OS V1R1.0 TSO/E REXX Users Guide

Figures

1. EXECIO Example 1 .............................164
2. EXECIO Example 2 .............................164
3. EXECIO Example 3 .............................165
4. EXECIO Example 4 .............................165
5. EXECIO Example 5 .............................166
6. EXECIO Example 5 (continued) .........................167
7. EXECIO Example 6 .............................168
8. EXECIO Example 6 (continued) .........................169
9. EXECIO Example 6 (continued) .........................170
© Copyright IBM Corp. 1988, 2001 ix
x z/OS V1R1.0 TSO/E REXX Users Guide

Tables

1. Language Codes for SETLANG Function That Replace the Function Call .........125
© Copyright IBM Corp. 1988, 2001 xi
xii z/OS V1R1.0 TSO/E REXX Users Guide

About This Book

This book describes how to use the TSO/E Procedures Language MVS/REXX processor (called the language processor) and the REstructured eXtended eXecutor (REXX) language. Together, the language processor and the REXX language are known as TSO/E REXX. TSO/E REXX is the implementation of the Systems Application Architecture (SAA) Procedures Language on the MVS system.

Who Should Use This Book

This book is intended for anyone who wants to learn how to write REXX programs. More specifically, the audience is programmers who may range from the inexperienced to those with extensive programming experience, particularly in writing CLISTs for TSO/E. Because of the broad range of experience in readers, this book is divided into two parts.
v Part 1. Learning the REXX Language is for inexperienced programmers who are
somewhat familiar with TSO/E commands and have used the Interactive System
Productivity Facility/Program Development Facility (ISPF/PDF) in TSO/E.
Programmers unfamiliar with TSO/E should first read the z/OS TSO/E Primer.
Experienced programmers new to REXX can also read this section to learn the
basics of the REXX language. v Part 2. Using REXX is for programmers already familiar with the REXX language
and experienced with the workings of TSO/E. It describes more complex aspects
of the REXX language and how they work in TSO/E as well as in other MVS
address spaces.
If you are a new programmer, you might want to concentrate on the first part. If you are an experienced TSO/E programmer, you might want to read the first part and concentrate on the second part.

How This Book Is Organized

In addition to the two parts described in the preceding paragraphs, there are three appendixes at the end of the book.
v “Appendix A. Allocating Data Setson page 185 contains checklists for the tasks
of creating and editing a data set and for allocating a data set to a system file. v “Appendix B. Specifying Alternate Libraries with the ALTLIB Commandon
page 195 describes using the ALTLIB command. v “Appendix C. Comparisons Between CLIST and REXXon page 197 contains
tables that compare the CLIST language with the REXX language.

Terminology

Throughout this book a REXX program is called an exec to differentiate it from other programs you might write, such as CLISTs. The command to run an exec in TSO/E is the EXEC command. To avoid confusion between the two, this book uses lowercase and uppercase to distinguish between the two uses of the term "exec". References to the REXX program appear as exec and references to the TSO/E command appear as EXEC.
© Copyright IBM Corp. 1988, 2001 xiii

Purpose of Each Chapter

At the beginning of each chapter is a statement about the purpose of the chapter. Following that are headings and page numbers where you can find specific information.

Examples

Throughout the book, you will find examples that you can try as you read. If the example is a REXX keyword instruction, the REXX keyword is in uppercase. Information that you can provide is in lowercase. The following REXX keyword instruction contains the REXX keyword SAY, which is fixed, and a phrase, which can vary.
SAY 'This is an example of an instruction.'
Similarly, if the example is a TSO/E command, the command name and keyword operands, which are fixed, are in uppercase. Information that can vary, such as a data set name, is in lowercase. The following ALLOCATE command and its operands are in uppercase and the data set and file name are in lowercase.
"ALLOCATE DATASET(rexx.exec) FILE(sysexec) SHR REUSE"
This use of uppercase and lowercase is intended to make a distinction between words that are fixed and words that can vary. It does not mean that you must type REXX instructions and TSO/E commands with certain words in uppercase and others in lowercase.

Exercises

Periodically, you will find sections with exercises you can do to test your understanding of the information. Answers to the exercises are included when appropriate.

Where to Find More Information

Please see z/OS Information Roadmap for an overview of the documentation associated with z/OS, including the documentation available for z/OS TSO/E.

Accessing Licensed Books on the Web

z/OS licensed documentation in PDF format is available on the Internet at the IBM Resource Link Web site at:
http://www.ibm.com/servers/resourcelink
Licensed books are available only to customers with a z/OS license. Access to these books requires an IBM Resource Link Web userid and password, and a key code. With your z/OS order you received a memo that includes this key code.
To obtain your IBM Resource Link Web userid and password log on to:
http://www.ibm.com/servers/resourcelink
To register for access to the z/OS licensed books:
1. Log on to Resource Link using your Resource Link userid and password.
2. Click on User Profiles located on the left-hand navigation bar.
3. Click on Access Profile.
4. Click on Request Access to Licensed books.
5. Supply your key code where requested and click on the Submit button.
xiv z/OS V1R1.0 TSO/E REXX Users Guide
If you supplied the correct key code you will receive confirmation that your request is being processed. After your request is processed you will receive an e-mail confirmation.
Note: You cannot access the z/OS licensed books unless you have registered for
access to them and received an e-mail confirmation informing you that your request has been processed.
To access the licensed books:
1. Log on to Resource Link using your Resource Link userid and password.
2. Click on Library.
3. Click on zSeries.
4. Click on Software.
5. Click on z/OS.
6. Access the licensed book by selecting the appropriate element.

Using LookAt to Look Up Message Explanations

LookAt is an online facility that allows you to look up explanations for z/OS messages and system abends.
Using LookAt to find information is faster than a conventional search because LookAt goes directly to the explanation.
LookAt can be accessed from the Internet or from a TSO command line.
You can use LookAt on the Internet at:
http://www.ibm.com/servers/eserver/zseries/zos/bkserv/lookat/lookat.html
To use LookAt as a TSO command, LookAt must be installed on your host system. You can obtain the LookAt code for TSO from the LookAt Web site by clicking on News and Help or from the z/OS Collection, SK3T-4269 .
To find a message explanation from a TSO command line, simply enter: lookat message-id as in the following example:
lookat iec192i
This results in direct access to the message explanation for message IEC192I.
To find a message explanation from the LookAt Web site, simply enter the message ID. You can select the release if needed.
Note: Some messages have information in more than one book. For example,
IEC192I has routing and descriptor codes listed in z/OS MVS Routing and Descriptor Codes. For such messages, LookAt prompts you to choose which book to open.
About This Book xv
xvi z/OS V1R1.0 TSO/E REXX Users Guide

Part 1. Learning the REXX Language

The REXX language is a versatile general-purpose programming language that can be used by new and experienced programmers. This part of the book is for programmers who want to learn the REXX language. The chapters in this part cover the following topics.
v “Chapter 1. Introductionon page 3 The REXX language has many features
that make it a powerful programming tool. v “Chapter 2. Writing and Running a REXX Execon page 7 Execs are easy to
write and have few syntax rules. v “Chapter 3. Using Variables and Expressionson page 25 Variables,
expressions, and operators are essential when writing execs that do arithmetic
and comparisons. v “Chapter 4. Controlling the Flow Within an Execon page 41 You can use
instructions to branch, loop, or interrupt the flow of an exec. v “Chapter 5. Using Functionson page 61 A function is a sequence of
instructions that can perform a specific task and must return a value. v “Chapter 6. Writing Subroutines and Functionson page 69 You can write
internal and external routines that are called by an exec. v “Chapter 7. Manipulating Dataon page 85 Compound variables and parsing
are two ways to manipulate data.
Note: Although you can write a REXX exec to run in a non-TSO/E address space
in MVS, the chapters and examples in this part assume the exec will run in a TSO/E address space. If you want to write execs that run outside of a TSO/E address space, keep in mind the following exceptions to information in Part 1:
v An exec that runs outside of TSO/E cannot include TSO/E commands,
unless you use the TSO/E environment service (see note).
v In TSO/E, several REXX instructions either display information on the
terminal or retrieve information that the user enters at the terminal. In a non-TSO/E address space, these instructions get information from the input stream and write information to the output stream. – SAY this instruction sends information to the output DD whose
default is SYSTSPRT.
– PULL this instruction gets information from the input DD whose
default is SYSTSIN.
– TRACE this instruction sends information to the output DD whose
default is SYSTSPRT.
– PARSE EXTERNAL this instruction gets information from the input
DD whose default is SYSTSIN.
v The USERID built-in function, instead of returning a user identifier, might
return a stepname or jobname.
Note: You can use the TSO/E environment service, IKJTSOEV, to create a TSO/E
environment in a non-TSO/E address space. If you run a REXX exec in the TSO/E environment you created, the exec can contain TSO/E commands, external functions, and services that an exec running in a TSO/E address space can use. That is, the TSO host command environment (ADDRESS TSO) is available to the exec. For more information about the TSO/E environment service and the different considerations for running REXX execs within the environment, see z/OS TSO/E Programming Services.
© Copyright IBM Corp. 1988, 2001 1
2 z/OS V1R1.0 TSO/E REXX Users Guide

Chapter 1. Introduction

What is REXX? .........................3
Features of REXX ........................3
Ease of use .........................3
Free format .........................3
Convenient built-in functions ...................4
Debugging capabilities .....................4
Interpreted language ......................4
Extensive parsing capabilities ...................4
Components of REXX.......................4
The SAA Solution ........................4
Benefits of Using a Compiler ....................5
Improved Performance .....................5
Reduced System Load .....................5
Protection for Source Code and Programs ..............6
Improved Productivity and Quality .................6
Portability of Compiled Programs..................6
SAA Compliance Checking ....................6
This chapter describes the REXX programming language and some of its features.

What is REXX?

REXX is a programming language that is extremely versatile. Aspects such as common programming structure, readability, and free format make it a good language for beginners and general users. Yet because the REXX language can be intermixed with commands to different host environments, provides powerful functions and has extensive mathematical capabilities, it is also suitable for more experienced computer professionals.
The TSO/E implementation of the REXX language allows REXX execs to run in any MVS address space. You can write a REXX exec that includes TSO/E services and run it in a TSO/E address space, or you can write an application in REXX to run outside of a TSO/E address space. For more information, see Chapter 13. Using REXX in TSO/E and Other MVS Address Spaceson page 171.

Features of REXX

In addition to its versatility, REXX has many other features, some of which are:

Ease of use

The REXX language is easy to read and write because many instructions are meaningful English words. Unlike some lower-level programming languages that use abbreviations, REXX instructions are common words, such as SAY, PULL, IF... THEN... ELSE..., DO... END, and EXIT.

Free format

There are few rules about REXX format. You need not start an instruction in a particular column, you can skip spaces in a line or skip entire lines, you can have an instruction span many lines or have multiple instructions on one line, variables
© Copyright IBM Corp. 1988, 2001 3
Features of REXX
do not need to be predefined, and you can type instructions in upper, lower, or mixed case. The few rules about REXX format are covered in Syntax of REXX Instructionson page 9.

Convenient built-in functions

REXX supplies built-in functions that perform various processing, searching, and comparison operations for both text and numbers. Other built-in functions provide formatting capabilities and arithmetic calculations.

Debugging capabilities

When a REXX exec running in TSO/E encounters an error, messages describing the error are displayed on the screen. In addition, you can use the REXX TRACE instruction and the interactive debug facility to locate errors in execs.

Interpreted language

TSO/E implements the REXX language as an interpreted language. When a REXX exec runs, the language processor directly processes each language statement. Languages that are not interpreted must be compiled into machine language and possibly link-edited before they are run. You can use the IBM licensed product, IBM Compiler and Library for REXX/370, to provide this function.

Extensive parsing capabilities

REXX includes extensive parsing capabilities for character manipulation. This parsing capability allows you to set up a pattern to separate characters, numbers, and mixed input.

Components of REXX

The various components of REXX are what make it a powerful tool for programmers. REXX is made up of:
v Instructions There are five types of instructions. All but commands are
processed by the language processor.
KeywordAssignmentLabelNullCommand (both TSO/E REXX commands and host commands)
v Built-in functions These functions are built into the language processor and
provide convenient processing options.
v TSO/E external functions These functions are provided by TSO/E and interact
with the system to do specific tasks for REXX.
v Data stack functions A data stack can store data for I/O and other types of
processing.

The SAA Solution

The SAA solution is based on a set of software interfaces, conventions, and protocols that provide a framework for designing and developing applications.
The SAA Procedures Language has been defined as a subset of the REXX language. Its purpose is to define a common subset of the language that can be used in several environments. TSO/E REXX is the implementation of the SAA Procedures Language on the MVS system.
4
z/OS V1R1.0 TSO/E REXX Users Guide
The SAA Solution
The SAA solution: v Defines a common programming interface you can use to develop applications
that can be integrated with each other and transported to run in multiple SAA
environments. v Defines common communications support that you can use to connect
applications, systems, networks, and devices. v Defines a common user access that you can use to achieve consistency in
panel layout and user interaction techniques. v Offers some applications and application development tools written by IBM.
Several combinations of IBM hardware and software have been selected as SAA environments. These are environments in which IBM will manage the availability of support for applicable SAA elements, and the conformance of those elements to SAA specifications. The SAA environments are the following:
v MVS
TSO/E
CICS
IMS
v VM CMS v Operating System/400 (OS/400) v Operating System/2 (OS/2)

Benefits of Using a Compiler

The IBM Compiler for REXX/370 (Program Number 5695-013) and the IBM Library for REXX/370 (Program Number 5695-014) provide significant benefits for programmers during program development and for users when a program is run. The benefits are:
v Improved performance v Reduced system load v Protection for source code and programs v Improved productivity and quality v Portability of compiled programs v Checking for compliance to SAA

Improved Performance

The performance improvements that you can expect when you run compiled REXX programs depend on the type of program. A program that performs large numbers of arithmetic operations of default precision shows the greatest improvement. A program that mainly enters commands to the host shows minimal improvement because REXX cannot decrease the time taken by the host to process the commands.

Reduced System Load

Compiled REXX programs run faster than interpreted programs. Because a program has to be compiled only once, system load is reduced and response time is improved when the program is run frequently.
For example, a REXX program that performs many arithmetic operations might take 12 seconds to run interpreted. If the program is run 60 times, it uses about 12 minutes of processor time. The same program when compiled might run six times faster, using only about 2 minutes of processor time.
Chapter 1. Introduction 5
Benefits of Using a Compiler

Protection for Source Code and Programs

Your REXX programs and algorithms are assets that you want to protect.
The Compiler produces object code, which helps you protect these assets by discouraging people from making unauthorized changes to your programs. You can distribute your REXX programs in object code only.
Load modules can be further protected by using a security server, such as RACF.

Improved Productivity and Quality

The Compiler can produce source listings, cross-reference listings, and messages, which help you more easily develop and maintain your REXX programs.
The Compiler identifies syntax errors in a program before you start testing it. You can then focus on correcting errors in logic during testing with the REXX interpreter.

Portability of Compiled Programs

A REXX program compiled under MVS/ESA can run under CMS. Similarly, a REXX program compiled under CMS can run under MVS/ESA.

SAA Compliance Checking

The Systems Application Architecture (SAA) definitions of software interfaces, conventions, and protocols provide a framework for designing and developing applications that are consistent within and across several operating systems.
The SAA Procedures Language is a subset of the REXX language supported by the interpreter under TSO/E, and can be used in this operating environment.
To help you write programs for use in all SAA environments, the Compiler can optionally check for SAA compliance. With this option in effect, a warning message is issued for each non-SAA item found in a program.
For more information, see IBM Compiler and Library for REXX/370; Introducing the Next Step in REXX Programming.
6
z/OS V1R1.0 TSO/E REXX Users Guide

Chapter 2. Writing and Running a REXX Exec

Before You Begin ........................7
What is a REXX Exec? ......................8
Syntax of REXX Instructions ....................9
The Character Type of REXX Instructions ..............9
Using Quotation Marks in an Instruction ..............9
The Format of REXX Instructions .................10
Beginning an instruction ...................10
Continuing an instruction ...................10
Continuing a literal string without adding a space ..........11
Ending an instruction.....................11
Types of REXX Instructions ...................12
Keyword .........................13
Assignment ........................13
Label ..........................14
Null ...........................14
Command.........................14
Execs Using Double-Byte Character Set Names ............14
Running an Exec ........................16
Running an Exec Explicitly ...................16
Running an Exec Implicitly ...................17
Allocating a PDS to a System File ................17
Exercises - Running the Example Execs .............18
Interpreting Error Messages ....................19
Preventing Translation to Uppercase .................20
From Within an Exec......................20
As Input to an Exec ......................20
Exercises - Running and Modifying the Example Execs ........21
Passing Information to an Exec ...................21
Using Terminal Interaction ....................21
Specifying Values when Invoking an Exec ..............22
Specifying Too Few Values ..................22
Specifying Too Many Values ..................22
Preventing Translation of Input to Uppercase .............23
Exercises - Using the ARG Instruction ..............23
Passing Arguments ......................24
Passing Arguments Using the CALL Instruction or REXX Function Call 24
Passing Arguments Using the EXEC Command ...........24
This chapter introduces execs and their syntax, describes the steps involved in writing and running an exec, and explains concepts you need to understand to avoid common problems.

Before You Begin

Before you can write a REXX program, called an exec, you need to create a data set to contain the exec. The data set can be either sequential or partitioned, but if you plan to create more than one exec, it is easier to create a REXX library as a partitioned data set (PDS) with execs as members.
To create a PDS, allocate a data set with your prefix (usually your user ID) as the first qualifier, any name as the second qualifier, and preferably "exec" as the third qualifier. You can allocate the PDS with the Utilities option in ISPF/PDF or with the
© Copyright IBM Corp. 1988, 2001 7
Before You Begin
TSO/E ALLOCATE command. For specific information about allocating a data set for an exec, see Appendix A. Allocating Data Setson page 185.

What is a REXX Exec?

A REXX exec consists of REXX language instructions that are interpreted directly by the REXX interpreter or compiled directly by a REXX language compiler and executed by a Compiler Runtime Processor. An exec can also contain commands that are executed by the host environment.
An advantage of the REXX language is its similarity to ordinary English. This similarity makes it easy to read and write a REXX exec. For example, an exec to display a sentence on the screen uses the REXX instruction SAY followed by the sentence to be displayed.
Example of a Simple Exec
/**************************** REXX *********************************/
SAY 'This is a REXX exec.'
Note that this simple exec starts with a comment line to identify the program as a REXX exec. A comment begins with /* and ends with */. To prevent
incompatibilities with CLISTs, IBM recommends that all REXX execs start with a comment that includes the characters “REXX” within the first line (line 1) of the exec. Failure to do so can lead to unexpected or unintended results in your REXX exec. More about comments and why you might need a REXX exec
identifier appears later 14.
When you run the exec, you see on your screen the sentence:
This is a REXX exec.
Even in a longer exec, the instructions flow like ordinary English and are easy to understand.
Example of a Longer Exec
/**************************** REXX *********************************/ /* This exec adds two numbers and displays their sum. */ /*******************************************************************/
SAY 'Please enter a number.' PULL number1 SAY 'Now enter a number to add to the first number.' PULL number2 sum = number1 + number2 SAY 'The sum of the two numbers is' sum'.'
When you run the example, the exec interacts with you at the terminal. First you see on your screen:
Please enter a number.
8
z/OS V1R1.0 TSO/E REXX Users Guide
When you type a number, for example 42, and press the Enter key, the variable
number1 is assigned the value 42. You then see another sentence on the screen.
Now enter a number to add to the first number.
When you enter another number, for example 21, the variable number2 is assigned the value 21. Then the values in number1 and number2 are added and the total is assigned to sum. You see a final sentence on the screen displaying the sum.
The sum of the two numbers is 63.
Before you actually try these examples, please read the next two sections:
v Syntax of REXX Instructions v Running an Execon page 16

Syntax of REXX Instructions

Some programming languages have rigid rules about how and where characters are entered on each line. For example, CLIST statements must be entered in uppercase, and assembler statements must begin in a particular column. REXX, on the other hand, has simple syntax rules. There is no restriction on how characters are entered and generally one line is an instruction regardless of where it begins or where it ends.
What is a REXX Exec?

The Character Type of REXX Instructions

You can enter a REXX instruction in lowercase, uppercase, or mixed case. However, alphabetic characters are changed to uppercase, unless you enclose them in single or double quotation marks.
Using Quotation Marks in an Instruction
A series of characters enclosed in matching quotation marks is called a literal string. The following examples both contain literal strings.
SAY 'This is a REXX literal string.' /* Using single quotes */
SAY "This is a REXX literal string." /* Using double quotes */
You cannot enclose a literal string with one each of the two types of quotation marks. The following is not a correct example of an enclosed literal string.
SAY 'This is a REXX literal string." /* Using mismatched quotes */
When you omit the quotation marks from a SAY instruction as follows:
SAY This is a REXX string.
you see the statement in uppercase on your screen.
THIS IS A REXX STRING.
Note: If any word in the statement is the name of a variable that has already been
assigned a value, REXX substitutes the value. For information about variables, see Using Variableson page 25.
Chapter 2. Writing and Running a REXX Exec 9
Syntax of REXX Instructions
If a string contains an apostrophe, you can enclose the literal string in double quotation marks.
SAY "This isn't a CLIST instruction."
You can also use two single quotation marks in place of the apostrophe, because a pair of single quotation marks is processed as one.
SAY 'This isn't a CLIST instruction.'
Either way, the outcome is the same.
This isn't a CLIST instruction.

The Format of REXX Instructions

The REXX language uses a free format. This means you can insert extra spaces between words and blank lines freely throughout the exec without causing an error. A line usually contains one instruction except when it ends with a comma (,) or contains a semicolon (;). A comma is the continuation character and indicates that the instruction continues to the next line. The comma, when used in this manner, also adds a space when the lines are concatenated. A semicolon indicates the end of the instruction and is used to separate multiple instructions on one line.
Beginning an instruction
An instruction can begin in any column on any line. The following are all valid instructions.
SAY 'This is a literal string.'
SAY 'This is a literal string.'
SAY 'This is a literal string.'
This example appears on the screen as follows:
This is a literal string. This is a literal string. This is a literal string.
Continuing an instruction
A comma indicates that the instruction continues to the next line. Note that a space is added between extendedand REXXwhen it appears on the screen.
SAY 'This is an extended',
'REXX literal string.'
This example appears on the screen as one line.
This is an extended REXX literal string.
Also note that the following two instructions are identical and yield the same result when displayed on the screen:
SAY 'This is',
'a string.'
is functionally identical to:
SAY 'This is' 'a string.'
These examples appear on the screen as:
10
z/OS V1R1.0 TSO/E REXX Users Guide
Syntax of REXX Instructions
This is a string.
In the first example, the comma at the end of line 1 adds a space when the two lines are concatenated for display. In the second example, the space between the two separate strings is preserved when the line is displayed.
Continuing a literal string without adding a space
If you need to continue an instruction to a second or more lines but do not want REXX to add spaces when the line appears on the screen, use the concatenation operand (two single OR bars, ||).
SAY 'This is an extended literal string that is bro'||,
'ken in an awkward place.'
This example appears on the screen as one line without adding a space within the word broken.
This is an extended literal string that is broken in an awkward place.
Also note that the following two instructions are identical and yield the same result when displayed on the screen:
SAY 'This is' ||,
'a string.'
is functionally identical to:
SAY 'This is' || 'a string.'
These examples appear on the screen as:
This isa string.
In the first example, the concatenation operator at the end of line 1 causes the deletion of any spaces when the two lines are concatenated for display. In the second example, the concatenation operator also concatenates the two strings without space when the line is displayed.
Ending an instruction
The end of the line or a semicolon indicates the end of an instruction. If you put more than one instruction on a line, you must separate each instruction with a semicolon. If you put one instruction on a line, it is best to let the end of the line delineate the end of the instruction.
SAY 'Hi!'; say 'Hi again!'; say 'Hi for the last time!'
This example appears on the screen as three lines.
Hi! Hi again! Hi for the last time!
The following example demonstrates the free format of REXX.
Chapter 2. Writing and Running a REXX Exec 11
Syntax of REXX Instructions
Example of Free Format
/************************* REXX ************************************/ SAY 'This is a REXX literal string.' SAY 'This is a REXX literal string.'
SAY 'This is a REXX literal string.' SAY, 'This', 'is', 'a', 'REXX', 'literal', 'string.'
SAY'This is a REXX literal string.';SAY'This is a REXX literal string.' SAY ' This is a REXX literal string.'
When the example runs, you see six lines of identical output on your screen followed by one indented line.
This is a REXX literal string. This is a REXX literal string. This is a REXX literal string. This is a REXX literal string. This is a REXX literal string. This is a REXX literal string.
This is a REXX literal string.
Thus you can begin an instruction anywhere on a line, you can insert blank lines, and you can insert extra spaces between words in an instruction because the language processor ignores blank lines and spaces that are greater than one. This flexibility of format allows you to insert blank lines and spaces to make an exec easier to read.
Only when words are parsed do blanks and spaces take on significance. More about parsing is covered in Parsing Dataon page 87.

Types of REXX Instructions

There are five types of REXX instructions: keyword, assignment, label, null, and command. The following example is an ISPF/PDF Edit panel that shows an exec with various types of instructions. A description of each type of instruction appears after the example. In most of the descriptions, you will see an edit line number (without the prefixed zeroes) to help you locate the instruction in the example.
12
z/OS V1R1.0 TSO/E REXX Users Guide
Syntax of REXX Instructions
EDIT ---- USERID.REXX.EXEC(TIMEGAME)------------------- COLUMNS 009 080 COMMAND ===> SCROLL ===> HALF ****** ************************ TOP OF DATA ************************************ 000001 /************************** REXX ****************************/ 000002 /* This is an interactive REXX exec that asks a user for the*/ 000003 /* time and then displays the time from the TIME command. */ 000004 /************************************************************/ 000005 Game1: 000006 000007 SAY 'What time is it?' 000008 PULL usertime /* Put the user's response 000009 into a variable called 000010 "usertime" */ 000011 IF usertime = '' THEN /* User didn't enter a time */ 000012 SAY "O.K. Game's over." 000013 ELSE 000014 DO 000015 SAY "The computer says:" 000016 /* TSO system */ TIME /* command */ 000017 END 000018 000019 EXIT ****** *********************** BOTTOM OF DATA **********************************
Keyword
A keyword instruction tells the language processor to do something. It begins with a REXX keyword that identifies what the language processor is to do. For example, SAY (line 7) displays a string on the screen and PULL (line 8) takes one or more words of input and puts them into the variable usertime.
IF, THEN (line 11) and ELSE (line 13) are three keywords that work together in one instruction. Each keyword forms a clause, which is a subset of an instruction. If the expression that follows the IF keyword is true, the instruction that follows the THEN keyword is processed. Otherwise, the instruction that follows the ELSE keyword is processed. If more than one instruction follows a THEN or an ELSE, the instructions are preceded by a DO (line 14) and followed by an END (line 17). More information about the IF/THEN/ELSE instruction appears in Using Conditional Instructionson page 42.
The EXIT keyword (line 19) tells the language processor to end the exec. Using EXIT in the preceding example is a convention, not a necessity, because processing ends automatically when there are no more instructions in the exec. More about EXIT appears in EXIT Instructionon page 57.
Assignment
An assignment gives a value to a variable or changes the current value of a variable. A simple assignment instruction is:
number = 4
In addition to giving a variable a straightforward value, an assignment instruction can also give a variable the result of an expression. An expression is something that needs to be calculated, such as an arithmetic expression. The expression can contain numbers, variables, or both.
number=4+4
number = number + 4
Chapter 2. Writing and Running a REXX Exec 13
Syntax of REXX Instructions
In the first of the two examples, the value of number is 8. If the second example directly followed the first in an exec, the value of number would become 12. More about expressions is covered in Using Expressionson page 28.
Label
A label, such as Game1: (line 5), is a symbolic name followed by a colon. A label can contain either single- or double-byte characters or a combination of single- and double-byte characters. (Double-byte characters are valid only if you have included OPTIONS ETMODE as the first instruction in your exec.) A label identifies a portion of the exec and is commonly used in subroutines and functions, and with the SIGNAL instruction. More about the use of labels appears in Chapter 6. Writing Subroutines and Functionson page 69 and SIGNAL Instructionon page 58.
Null
A null is a comment or a blank line, which is ignored by the language processor but make an exec easier to read.
v Comments (lines 1 through 4, 8 through 11, 16)
A comment begins with /* and ends with */. Comments can be on one or more lines or on part of a line. You can put information in a comment that might not be obvious to a person reading the REXX instructions. Comments at the beginning can describe the overall purpose of the exec and perhaps list special considerations. A comment next to an individual instruction can clarify its purpose.
Note: To prevent incompatibilities with CLISTs, IBM recommends that all
REXX execs start with a comment that includes the characters REXXwithin the first line (line 1) of the exec. Failure to do so can lead to unexpected or unintended results in your REXX exec. This
type of comment is called the REXX exec identifier and immediately identifies the program to readers as a REXX exec and also distinguishes it from a CLIST. It is necessary to distinguish execs from CLISTs when they are both stored in the system file, SYSPROC. For more information about where and how execs are stored, see Running an Exec Implicitlyon page 17.
v Blank lines (lines 6, 18)
Blank lines help separate groups of instructions and aid readability. The more readable an exec, the easier it is to understand and maintain.
Command
An instruction that is not a keyword instruction, assignment, label, or null is processed as a command and is sent to a previously defined environment for processing. For example, the word "TIME" in the previous exec (line 16), even though surrounded by comments, is processed as a TSO/E command.
/* TSO system */ TIME /* command */
More information about issuing commands appears in Chapter 8. Entering Commands from an Execon page 97.

Execs Using Double-Byte Character Set Names

You can use double-byte character set (DBCS) names in your REXX execs for literal strings, labels, variable names, and comments. Such character strings can be single-byte, double-byte, or a combination of both single- and double-byte names. To use DBCS names, you must code OPTIONS ETMODE as the first instruction in the exec. ETMODE specifies that those strings that contain DBCS characters are to
14
z/OS V1R1.0 TSO/E REXX Users Guide
Execs Using Double-Byte Character Set Names
be checked as being valid DBCS strings. DBCS characters must be enclosed within shift-out (X'0E') and shift-in (X'0F') delimiters. In the following example, the shift-out (SO) and shift-in (SI) delimiters are represented by the less than symbol ( < ) and the greater than symbol ( > ) respectively. <.D.B.C.S.R.T.N> represent DBCS symbols in the following examples.
Example 1
The following is an example of an exec using a DBCS variable name and a DBCS subroutine label.
/* REXX */ OPTIONS 'ETMODE' /* ETMODE to enable DBCS variable names */ j=1 <.S.Y.M.D> = 10 /* Variable with DBCS characters between
CALL <.D.B.C.S.R.T.N> /* Invoke subroutine with DBCS name */ . . .
<.D.B.C.S.R.T.N>: /* Subroutine with DBCS name */ DOi=1TO10
IF x.i = <.S.Y.D.M> THEN /* Does x.i match the DBCS variable's
SAY 'Value of the DBCS variable is : ' <.S.Y.D.M> END EXIT 0
shift-out (<) and shift-in (>) */
value? */
1
For example, <.S.Y.M.D> and
Example 2
The following example shows some other uses of DBCS variable names with the EXECIO stem option, as DBCS parameters passed to a program invoked through LINKMVS, and with built-in function, LENGTH.
/* REXX */ OPTIONS 'ETMODE' /* ETMODE to enable DBCS variable names */
"ALLOC FI(INDD) DA('DEPTA29.DATA') SHR REU"
/*******************************************************************/ /* Use EXECIO to read lines into DBCS stem variables */ /*******************************************************************/
"EXECIO * DISKR indd (FINIS STEM <.d.b.c.s__.s.t.e.m>."
IF rc = 0 THEN /* if good return code from execio */
/*****************************************************************/ /* Say each DBCS stem variable set by EXECIO */ /*****************************************************************/
DOi=1TO<.d.b.c.s__.s.t.e.m>.0
SAY "Line " i "==> " <.d.b.c.s__.s.t.e.m>.i
END
line1_<.v.a.l.u.e> = <.d.b.c.s__.s.t.e.m>.1 /* line 1 value */
line_len = length(line1_<.v.a.l.u.e>) /* Length of line */
/*******************************************************************/ /* Invoke LINKMVS command "proca29" to process a line. */ /* Two variable names are used to pass 2 parameters, one of */
1. The SO and SI characters are non-printable.
Chapter 2. Writing and Running a REXX Exec 15
Execs Using Double-Byte Character Set Names
/* which is a DBCS variable name. The LINKMVS host command */ /* environment routine will look up the value of the two */ /* variables and pass their values to the address LINKMVS */ /* command, "proca29". */ /*******************************************************************/
ADDRESS LINKMVS "proca29 line_len line1_<.v.a.l.u.e>"
"FREE FI(INDD)"
EXIT 0

Running an Exec

After you have placed REXX instructions in a data set, you can run the exec explicitly by using the EXEC command followed by the data set name and the "exec" keyword operand, or implicitly by entering the member name. You can run an exec implicitly only if the PDS that contains it was allocated to a system file. More information about system files appears in the Running an Exec Implicitlyon page 17.

Running an Exec Explicitly

The EXEC command runs non-compiled programs in TSO/E. To run an exec explicitly, enter the EXEC command followed by the data set name that contains the exec and the keyword operand "exec" to distinguish it from a CLIST.
You can specify a data set name according to the TSO/E data set naming conventions in several different ways. For example the data set name USERID.REXX.EXEC(TIMEGAME) can be specified as:
v A fully-qualified data set, which appears within quotation marks.
EXEC 'userid.rexx.exec(timegame)' exec
v A non fully-qualified data set, which has no quotation marks can eliminate your
profile prefix (usually your user ID) as well as the third qualifier, exec.
EXEC rexx.exec(timegame) exec /* eliminates prefix */ EXEC rexx(timegame) exec /* eliminates prefix and exec */
For information about other ways to specify a data set name, see the EXEC command in z/OS TSO/E Command Reference.
You can type the EXEC command in the following places: v At the READY prompt
READY
EXEC rexx.exec(timegame) exec
v From the COMMAND option of ISPF/PDF
----------------------------- TSO COMMAND PROCESSOR ------------------------­ENTER TSO COMMAND OR CLIST BELOW:
===> exec rexx.exec(timegame) exec
v On the COMMAND line of any ISPF/PDF panel as long as the EXEC command
is preceded by the word "tso".
16
z/OS V1R1.0 TSO/E REXX Users Guide
ENTER SESSION MANAGER MODE ===> NO (YES or NO)
------------------------------ EDIT - ENTRY PANEL ---------------------------
COMMAND ===> tso exec rexx.exec(timegame) exec
ISPF LIBRARY:
PROJECT ===> PREFIX GROUP ===> REXX ===> ===> ===> TYPE ===> EXEC MEMBER ===> TIMEGAME (Blank for member selection list)
OTHER PARTITIONED OR SEQUENTIAL DATA SET:
DATA SET NAME ===> VOLUME SERIAL ===> (If not cataloged)
DATA SET PASSWORD ===> (If password protected)
PROFILE NAME ===> (Blank defaults to data set type)
INITIAL MACRO ===> LOCK ===> YES (YES, NO or NEVER)
FORMAT NAME ===> MIXED MODE ===> NO (YES or NO)

Running an Exec Implicitly

Running an exec implicitly means running an exec by simply entering the member name of the data set that contains the exec. Before you can run an exec implicitly, you must allocate the PDS that contains it to a system file (SYSPROC or SYSEXEC).
Running an Exec
SYSPROC is a system file whose data sets can contain both CLISTs and execs. (Execs are distinguished from CLISTs by the REXX exec identifier, a comment at the beginning of the exec the first line of which includes the word "REXX".) SYSEXEC is a system file whose data sets can contain only execs. (Your installation might have changed the name to something other than SYSEXEC, but for the purposes of this book, we will call it SYSEXEC.) When both system files are available, SYSEXEC is searched before SYSPROC.
Allocating a PDS to a System File
To allocate the PDS that contains your execs to a system file, you need to do the following:
v Decide if you want to use the separate file for execs (SYSEXEC) or combine
CLISTs and execs in the same file (SYSPROC). For information that will help you decide, see Things to Consider When Allocating to a System File (SYSPROC or SYSEXEC)on page 174.
v Use one of the following two checklists for a step-by-step guide to writing an
exec that allocates a PDS to a system file. –“Checklist #3: Writing an Exec that Sets up Allocation to SYSEXECon
page 191
–“Checklist #4: Writing an Exec that Sets up Allocation to SYSPROCon
page 192
After your PDS is allocated to the system file, you can then run an exec by simply typing the name of the data set member that contains the exec. You can type the member name in any of the following locations: – At the READY prompt
READY
timegame
– From the COMMAND option of ISPF/PDF
Chapter 2. Writing and Running a REXX Exec 17
Running an Exec
----------------------------- TSO COMMAND PROCESSOR ------------------------­ENTER TSO COMMAND OR CLIST BELOW:
===> timegame
ENTER SESSION MANAGER MODE ===> NO (YES or NO)
– On the COMMAND line of any ISPF/PDF panel as long as the member name
is preceded by "tso".
------------------------------ EDIT - ENTRY PANEL --------------------------­COMMAND ===> tso timegame
ISPF LIBRARY:
PROJECT ===> PREFIX GROUP ===> REXX ===> ===> ===> TYPE ===> EXEC MEMBER ===> TIMEGAME (Blank for member selection list)
OTHER PARTITIONED OR SEQUENTIAL DATA SET:
DATA SET NAME ===> VOLUME SERIAL ===> (If not cataloged)
DATA SET PASSWORD ===> (If password protected)
PROFILE NAME ===> (Blank defaults to data set type)
INITIAL MACRO ===> LOCK ===> YES (YES, NO or NEVER)
FORMAT NAME ===> MIXED MODE ===> NO (YES or NO)
To reduce the search time for an exec that is executed implicitly and to differentiate it from a TSO/E command, precede the member name with a %:
READY
%timegame
When a member name is preceded by %, TSO/E searches a limited number of system files for the name, thus reducing the search time. Without the %, TSO/E searches several files before it searches SYSEXEC and SYSPROC to ensure that the name you entered is not a TSO/E command.
Exercises - Running the Example Execs
Create a PDS exec library using Checklist #1 or Checklist #2 in Appendix A. Allocating Data Setson page 185. Then try the example execs from the beginning of this chapter. Run them explicitly with the EXEC command and see if the results you get are the same as the ones in this book. If they are not, why arent they the same?
Now write an exec to allocate your PDS to SYSPROC or SYSEXEC using Checklist #3 on page 191 or Checklist #4 on page 192. Then run the example execs implicitly. Which way is easier?
18
z/OS V1R1.0 TSO/E REXX Users Guide

Interpreting Error Messages

When you run an exec that contains an error, an error message often displays the line on which the error occurred and gives an explanation of the error. Error messages can result from syntax errors and from computational errors. For example, the following exec has a syntax error.
Example of an Exec with a Syntax Error
/************************** REXX ***********************************/ /* This is an interactive REXX exec that asks the user for a */ /* name and then greets the user with the name supplied. It */ /* contains a deliberate error. */ /*******************************************************************/
SAY "Hello! What's your name?" PULL who /* Get the person's name. IF who = '' THEN
SAY 'Hello stranger'
ELSE
SAY 'Hello' who
When the exec runs, you see the following on your screen:
Interpreting Error Messages
Hello! What's your name?
7 +++ PULL who /* Get the person's name.IF who = '' THEN SAY 'Hello stranger'ELSE SAY 'Hello' who IRX0006I Error running REXX.EXEC(HELLO), line 7: Unmatched "/*" or quote ***
The exec runs until it detects the error, a missing */ at the end of the comment. As a result, the SAY instruction displays the question, but doesnt wait for your response because the next line of the exec contains the syntax error. The exec ends and the language processor displays error messages.
The first error message begins with the line number of the statement where the error was detected, followed by three pluses (+++) and the contents of the statement.
7 +++ PULL who /* Get the person's name.IF who =
'' THEN SAY 'Hello stranger'ELSE SAY 'Hello' who
The second error message begins with the message number followed by a message containing the exec name, line where the error was found, and an explanation of the error.
IRX0006I Error running REXX.EXEC(HELLO), line 7: Unmatched "/*" or quote
For more information about the error, you can go to the message explanations in z/OS TSO/E Messages, where information is arranged by message number.
To fix the syntax error in this exec, add */ to the end of the comment on line 7.
PULL who /* Get the person's name.*/
Chapter 2. Writing and Running a REXX Exec 19

Preventing Translation to Uppercase

Preventing Translation to Uppercase
As a rule, all alphabetic characters processed by the language processor are translated to uppercase before they are processed. These alphabetic characters can be from within an exec, such as words in a REXX instruction, or they can be external to an exec and processed as input. You can prevent this translation to uppercase in two ways depending on whether the characters are read as parts of instructions from within an exec or are read as input to an exec.

From Within an Exec

To prevent translation of alphabetic characters to uppercase from within an exec, simply enclose the characters in single or double quotation marks. Numbers and special characters, whether or not in quotation marks, are not changed by the language processor. For example, when you follow a SAY instruction with a phrase containing a mixture of alphabetic characters, numbers, and special characters, only the alphabetic characters are changed.
SAY The bill for lunch comes to $123.51!
results in:
THE BILL FOR LUNCH COMES TO $123.51!
Quotation marks ensure that information from within an exec is processed exactly as typed. This is important in the following situations:
v For output when it must be lowercase or a mixture of uppercase and lowercase. v To ensure that commands are processed correctly. For example, if a variable
name in an exec is the same as a command name, the exec ends in error when the command is issued. It is good programming practice to avoid using variable names that are the same as commands, but just to be safe, enclose all commands in quotation marks.

As Input to an Exec

When reading input from a terminal or when passing input from another exec, the language processor also changes alphabetic characters to uppercase before they are processed. To prevent translation to uppercase, use the PARSE instruction.
For example, the following exec reads input from the terminal screen and re-displays the input as output.
Example of Reading and Re-displaying Input
/************************** REXX ***********************************/ /* This is an interactive REXX exec that asks a user for the name */ /* of an animal and then re-displays the name. */ /*******************************************************************/
SAY "Please type in the name of an animal." PULL animal /* Get the animal name.*/ SAY animal
If you responded to the example with the word tyrannosaurus, you would see on your screen:
20
z/OS V1R1.0 TSO/E REXX Users Guide
TYRANNOSAURUS
To cause the language processor to read input exactly as it is presented, use the PARSE PULL instruction.
PARSE PULL animal
Then if you responded to the example with TyRannOsauRus, you would see on the screen:
TyRannOsauRus
Exercises - Running and Modifying the Example Execs
Write and run the preceding Example of Reading and Re-displaying Input. Try various input and observe the output. Now change the PULL instruction to a PARSE PULL instruction and observe the difference.

Passing Information to an Exec

When an exec runs, you can pass information to it in several ways, two of which are:
v Through terminal interaction v By specifying input when invoking the exec.
Preventing Translation to Uppercase

Using Terminal Interaction

The PULL instruction is one way for an exec to receive input as shown by a previous example repeated here.
Example of an Exec that Uses PULL
/**************************** REXX *********************************/ /* This exec adds two numbers and displays their sum. */ /*******************************************************************/
SAY 'Please enter a number.' PULL number1 SAY 'Now enter a number to add to the first number.' PULL number2 sum = number1 + number2 SAY 'The sum of the two numbers is' sum'.'
The PULL instruction can extract more than one value at a time from the terminal by separating a line of input, as shown in the following variation of the previous example.
Variation of an Example that Uses PULL
/**************************** REXX *********************************/ /* This exec adds two numbers and displays their sum. */ /*******************************************************************/
SAY 'Please enter two numbers.' PULL number1 number2 sum = number1 + number2 SAY 'The sum of the two numbers is' sum'.'
Chapter 2. Writing and Running a REXX Exec 21
Passing Information to an Exec
Note: For the PULL instruction to extract information from the terminal, the data
stack must be empty. More information about the data stack appears in Chapter 11. Storing Information in the Data Stackon page 135.

Specifying Values when Invoking an Exec

Another way for an exec to receive input is through values specified when you invoke the exec. For example to pass two numbers to an exec named "add", using the EXEC command, type:
EXEC rexx.exec(add) '42 21' exec
To pass input when running an exec implicitly, simply type values (words or numbers) after the member name.
add 42 21
These values are called an argument. For information about arguments, see Passing Argumentson page 24.
The exec "add" uses the ARG instruction to assign the input to variables as shown in the following example.
Example of an Exec that Uses the ARG Instruction
/**************************** REXX *********************************/ /* This exec receives two numbers as input, adds them, and */ /* displays their sum. */ /*******************************************************************/
ARG number1 number2 sum = number1 + number2 SAY 'The sum of the two numbers is' sum'.'
ARG assigns the first number, 42, to number1 and the second number, 21, to number2.
If the number of values is fewer or more than the number of variable names after the PULL or the ARG instruction, errors can occur as described in the following sections.
Specifying Too Few Values
When you specify fewer values than the number of variables following the PULL or ARG instruction, the extra variables are set to null. For example, you pass only one number to "add".
EXEC rexx.exec(add) '42' exec
The first variable following the ARG instruction, number1, is assigned the value 42. The second variable, number2, is set to null. In this situation, the exec ends with an error when it tries to add the two variables. In other situations, the exec might not end in error.
Specifying Too Many Values
When you specify more values than the number of variables following the PULL or ARG instruction, the last variable gets the remaining values. For example, you pass three numbers to "add".
22
z/OS V1R1.0 TSO/E REXX Users Guide
EXEC rexx.exec(add) '42 21 10' exec
The first variable following the ARG instruction, number1, is assigned the value 42. The second variable gets both '21 10'. In this situation, the exec ends with an error when it tries to add the two variables. In other situations, the exec might not end in error.
To prevent the last variable from getting the remaining values, use a period (.) at the end of the PULL or ARG instruction.
ARG number1 number2 .
The period acts as a "dummy variable" to collect unwanted extra information. If there is no extra information, the period is ignored. You can also use a period as a place holder within the PULL or ARG instruction as follows:
ARG . number1 number2
In this case, the first value, 42, is discarded and number1 and number2 get the next two values, 21 and 10.

Preventing Translation of Input to Uppercase

Like the PULL instruction, the ARG instruction changes alphabetic characters to uppercase. To prevent translation to uppercase, precede ARG with PARSE as demonstrated in the following example.
Passing Information to an Exec
Example of an Exec that Uses PARSE ARG
/**************************** REXX *********************************/ /* This exec receives the last name, first name, and score of */ /* a student and displays a sentence reporting the name and */ /* score. */ /*******************************************************************/
PARSE ARG lastname firstname score SAY firstname lastname 'received a score of' score'.'
Exercises - Using the ARG Instruction
The left column shows the input values sent to an exec. The right column is the ARG statement within the exec that receives the input. What value does each variable assume?
Input Variables Receiving Input
1. 115 -23 66 5.8 ARG first second third
2. .2 0 569 2E6 ARG first second third fourth
3. 13 13 13 13 ARG first second third fourth fifth
4. Weber Joe 91 ARG lastname firstname score
5. Baker Amanda Marie 95 PARSE ARG lastname firstname score
6. Callahan Eunice 88 62 PARSE ARG lastname firstname score
ANSWERS
1. first = 115, second = -23, third = 66 5.8
2. first = .2, second = 0, third = 569, fourth = 2E6
Chapter 2. Writing and Running a REXX Exec 23
Passing Information to an Exec
3. first = 13, second = 13, third = 13, fourth = 13, fifth = null
4. lastname = WEBER, firstname = JOE, score = 91
5. lastname = Baker, firstname = Amanda, score = Marie 95
6. lastname = Callahan, firstname = Eunice, score = 88

Passing Arguments

Values passed to an exec are usually called arguments. Arguments can consist of one word or a string of words. Words within an argument are separated by blanks. The number of arguments passed depends on how the exec is invoked.
Passing Arguments Using the CALL Instruction or REXX Function Call
When you invoke a REXX exec using either the CALL instruction or a REXX function call, you can pass up to 20 arguments to an exec. Each argument must be separated by a comma.
Passing Arguments Using the EXEC Command
When you invoke a REXX exec either implicitly or explicitly using the EXEC command, you can pass either one or no arguments to the exec. Thus the ARG instruction in the preceding examples received only one argument. One argument can consist of many words. The argument, if present, will appear as a single string.
If you plan to use commas within the argument string when invoking a REXX exec using the EXEC command, special consideration must be given. For example, if you specify:
GETARG 1,2
or
ex 'sam.rexx.exec(getarg)' '1,2'
the exec receives a single argument string consisting of 1,2. The exec could then use a PARSE ARG instruction to break the argument string into the comma-separated values like the following:
PARSE ARG A ',' B SAY 'A is ' A /* Will say 'A is 1' */ SAY 'B is ' B /* Will say 'B is 2' */
However, because commas are treated as separator characters in TSO/E, you cannot pass an argument string that contains a leading comma using the implicit form of the EXEC command. That is, if you invoke the exec using:
GETARG ,2
the exec is invoked with an argument string consisting of 2. The leading comma separator is removed before the exec receives control. If you need to pass an argument string separated by commas and the leading argument is null (that is, contains a leading comma), you must use the explicit form of the EXEC command. For example:
ex 'sam.rexx.exec(getarg)' ',2'
In this case, the exec is invoked with an argument string consisting of ,2.
For more information about functions and subroutines, see Chapter 6. Writing Subroutines and Functionson page 69. For more information about arguments, see Parsing Multiple Strings as Argumentson page 92.
24
z/OS V1R1.0 TSO/E REXX Users Guide

Chapter 3. Using Variables and Expressions

Using Variables.........................25
Variable Names .......................26
Variable Values........................27
Exercises - Identifying Valid Variable Names .............27
Using Expressions .......................28
Arithmetic Operators ......................28
Division .........................29
Order of Evaluation .....................29
Using Arithmetic Expressions..................30
Exercises - Calculating Arithmetic Expressions ...........30
Comparison Operators .....................30
The Strictly Equal and Equal Operators ..............31
Using Comparison Expressions .................31
Exercises - Using Comparison Expressions ............32
Logical (Boolean) Operators ...................32
Using Logical Expressions...................33
Exercises - Using Logical Expressions ..............34
Concatenation Operators ....................34
Using Concatenation Operators .................34
Priority of Operators ......................35
Exercises - Priority of Operators ................36
Tracing Expressions with the TRACE Instruction ............37
Tracing Operations ......................37
Tracing Results........................38
Exercises - Using the TRACE Instruction .............38

Using Variables

This chapter describes variables, expressions, and operators, and explains how to use them in REXX execs.
One of the most powerful aspects of computer programming is the ability to process variable data to achieve a result. The variable data could be as simple as two numbers, the process could be subtraction, and the result could be the answer.
answer = number1 - number2
Or the variable data could be input to a series of complex mathematical computations that result in a 3-dimensional animated figure.
Regardless of the complexity of a process, the premise is the same. When data is unknown or if it varies, you substitute a symbol for the data, much like the "x" and "y" in an algebraic equation.
x=y+29
The symbol, when its value can vary, is called a variable. A group of symbols or numbers that must be calculated to be resolved is called an expression.
A variable is a character or group of characters that represents a value. A variable can contain either single- or double-byte characters, or a combination of single- and double-byte characters. (Double-byte characters are valid only if you include OPTIONS ETMODE as the first instruction of your exec.) The following variable big represents the value one million or 1,000,000.
© Copyright IBM Corp. 1988, 2001 25
Using Variables

Variable Names

big = 1000000
Variables can refer to different values at different times. If you assign a different value to big, it gets the value of the new assignment, until it is changed again.
big = 999999999
Variables can also represent a value that is unknown when the exec is written. In the following example, the users name is unknown, so it is represented by the variable who.
SAY "Hello! What's your name?"
PARSE PULL who /* Put the person's name in the variable "who" */
A variable name, the part that represents the value, is always on the left of the assignment statement and the value itself is on the right. In the following example, the word "variable1" is the variable name:
variable1 = 5 SAY variable1
As a result of the above assignment statement, variable1 is assigned the value "5", and you see on the terminal screen:
5
Variable names can consist of:
A...Z uppercase alphabetic
a...z lowercase alphabetic
0...9 numbers
@#$¢?!._ special characters
X'41' ... X'FE' double-byte character set (DBCS) characters.
(ETMODE must be on for these characters to be valid in a variable name.)
Restrictions on the variable name are:
v The first character cannot be 0 through 9 or a period (.) v The variable name cannot exceed 250 bytes. For names containing DBCS
characters, count each DBCS character as two bytes, and count the shift-out (SO) and shift-in (SI) as one byte each.
v DBCS characters within a DBCS name must be delimited by SO (X'0E') and SI
(X'0F'). Also note that:
SO and SI cannot be contiguous.Nesting of SO / SI is not permitted.A DBCS name cannot contain a DBCS blank (X'4040').
v The variable name should not be RC, SIGL, or RESULT, which are REXX special
variables. More about special variables appears later in this book.
Examples of acceptable variable names are:
ANSWER ?98B X Word3 number the_ultimate_value
26
z/OS V1R1.0 TSO/E REXX Users Guide

Variable Values

Using Variables
Also, if ETMODE is set on, the following are valid DBCS variable names, where < represents shift-out, and > represents shift-in, .X, .Y, and .Zrepresent DBCS characters, and lowercase letters and numbers represent themselves.
<.X.Y.Z> number_<.X.Y.Z> <.X.Y>1234<.Z>
The value of the variable, which is the value the variable name represents, might be categorized as follows:
v A constant, which is a number that is expressed as:
An integer (12) A decimal (12.5) A floating point number (1.25E2) A signed number (-12) A string constant (' 12')
v A string, which is one or more words that may or may not be enclosed in
quotation marks, such as:
This value is a string. 'This value is a literal string.'
v The value from another variable, such as:
variable1 = variable2
In the above example, variable1 changes to the value of variable2, but variable2 remains the same.
v An expression, which is something that needs to be calculated, such as:
variable2 = 12 + 12 - .6 /* variable2 becomes 23.4 */
Before a variable is assigned a value, the variable displays the value of its own name translated to uppercase. In the following example, if the variable new was not assigned a previous value, the word "NEW" is displayed.
SAY new /* displays NEW */

Exercises - Identifying Valid Variable Names

Which of the following are valid REXX variable names?
1. 8eight
2. $25.00
3. MixedCase
4. nine_to_five
5. result
ANSWERS
1. Invalid, because the first character is a number
2. Valid
3. Valid
4. Valid
5. Valid, but it is a reserved variable name and we recommend that you use it only to receive results from a subroutine
Chapter 3. Using Variables and Expressions 27

Using Expressions

Using Expressions
An expression is something that needs to be calculated and consists of numbers, variables, or strings, and one or more operators. The operators determine the kind of calculation to be done on the numbers, variables, and strings. There are four types of operators: arithmetic, comparison, logical, and concatenation.

Arithmetic Operators

Arithmetic operators work on valid numeric constants or on variables that represent valid numeric constants.
Types of Numeric Constants
12 A whole number has no decimal point or commas. Results of
12.5 A decimal number includes a decimal point. Results of arithmetic
arithmetic operations with whole numbers can contain a maximum of nine digits unless you override the default with the NUMERIC DIGITS instruction. For information about the NUMERIC DIGITS instruction, see z/OS TSO/E REXX Reference. Examples of whole numbers are: 123456789 0 91221 999
operations with decimal numbers are limited to a total maximum of nine digits (NUMERIC DIGITS default) before and after the decimal. Examples of decimal numbers are: 123456.789
0.888888888
1.25E2 A floating point number in exponential notation, is sometimes called scientific notation. The number after the "E" represents the number of places the decimal point moves. Thus 1.25E2 (also written as 1.25E+2) moves the decimal point to the right two places and results in 125. When an "E" is followed by a minus (-), the decimal point moves to the left. For example, 1.25E-2 is .0125.
Floating point numbers are used to represent very large or very small numbers. For more information about floating point numbers, see z/OS TSO/E REXX Reference.
-12 A signed number with a minus (-) next to the number represents a negative value. A plus next to a number indicates that the number should be processed as it is written. When a number has no sign, it is processed as a positive value.
The arithmetic operators you can use are as follows:
Operator Meaning
+ Add
- Subtract
* Multiply
/ Divide
% Divide and return a whole number without a remainder
// Divide and return the remainder only
** Raise a number to a whole number power
-number Negate the number
+number Add the number to 0
28
z/OS V1R1.0 TSO/E REXX Users Guide
Using Expressions
Using numeric constants and arithmetic operators, you can write arithmetic expressions as follows:
7 + 2 /* result is 9 */ 7 - 2 /* result is 5 */ 7 * 2 /* result is 14 */ 7 ** 2 /* result is 49 */ 7 ** 2.5 /* result is an error */
Division
Notice that three operators represent division. Each operator displays the result of a division expression in a different way.
/ Divide and express the answer possibly as a decimal number. For example:
7 / 2 /* result is 3.5 */ 6 / 2 /* result is 3 */
% Divide and express the answer as a whole number. The remainder is
ignored. For example:
7 % 2 /* result is 3 */
// Divide and express the answer as the remainder only. For example:
7 // 2 /* result is 1 */
Order of Evaluation
When you have more than one operator in an arithmetic expression, the order of numbers and operators can be critical. For example, in the following expression, which operation does the language processor perform first?
7+2*(9/3)-1
Proceeding from left to right, it is evaluated as follows:
v Expressions within parentheses are evaluated first. v Expressions with operators of higher priority are evaluated before expressions
with operators of lower priority.
Arithmetic operator priority is as follows, with the highest first:
Arithmetic Operator Priority
-+ Prefix operators
** Power (exponential)
*/%// Multiplication and division
+- Addition and subtraction
Thus the preceding example would be evaluated in the following order:
1. Expression in parentheses
7+2*(9/3)-1
\___/
3
2. Multiplication
7+2*3-1
\___/
6
3. Addition and subtraction from left to right
7+6-1=12
Chapter 3. Using Variables and Expressions 29
Using Expressions
Using Arithmetic Expressions
You can use arithmetic expressions in an exec many different ways. The following example uses several arithmetic operators to round and remove extra decimal places from a dollar and cents value.
Example Using Arithmetic Expressions
/****************************** REXX *******************************/ /* This exec computes the total price of an item including sales */ /* tax rounded to two decimal places. The cost and percent of the */ /* tax (expressed as a decimal number) are passed to the exec when */ /* it is run. */ /*******************************************************************/
PARSE ARG cost percent_tax
total = cost + (cost * percent_tax) /* Add tax to cost. */ price = ((total * 100 + .5) % 1) / 100 /* Round and remove */
/* extra decimal places.*/
SAY 'Your total cost is $'price'.'
Exercises - Calculating Arithmetic Expressions
1. What will the following program display on the screen?
Exercise
/***************************** REXX ****************************/
pa=1 ma=1 kids = 3 SAY "There are" pa + ma + kids "people in this family."
2. What is the value of:
a. 6-4+1 b. 6-(4+1) c. 6*4+2 d. 6*(4+2) e. 24%5/2
ANSWERS
1. There are 5 people in this family.
2. The values are as follows:
a. 3 b. 1 c. 26 d. 36 e. 2

Comparison Operators

Expressions that use comparison operators do not return a number value as do arithmetic expressions. Comparison expressions return either a true or false response in terms of 1 or 0 as follows:
1 True
0 False
30
z/OS V1R1.0 TSO/E REXX Users Guide
Using Expressions
Comparison operators can compare numbers or strings and ask questions, such as:
Are the terms equal? (A = B) Is the first term greater than the second? (A > B) Is the first term less than the second? (A < B)
For example, if A = 4 andB=3,then the results of the previous comparison questions are:
(A=B)Does4=3? 0 (False) (A>B)Is4>3? 1 (True) (A<B)Is4<3? 0 (False)
The more commonly used comparison operators are as follows:
Operator Meaning
== Strictly Equal
= Equal
\== Not strictly equal
\= Not equal
> Greater than
< Less than
>< Greater than or less than (same as not equal)
>= Greater than or equal to
\< Not less than
<= Less than or equal to
\> Not greater than
Note: The not character, "¬", is synonymous with the backslash ("\"). The two
characters may be used interchangeably according to availability and personal preference. This book uses the backslash ("\") character.
The Strictly Equal and Equal Operators
When two expressions are strictly equal, everything including the blanks and case (when the expressions are characters) is exactly the same.
When two expressions are equal, they are resolved to be the same. The following expressions are all true.
'WORD' = word /* returns 1 */ 'word ' \== word /* returns 1 */ 'word' == 'word' /* returns 1 */
4e2 \== 400 /* returns 1 */ 4e2 \= 100 /* returns 1 */
Using Comparison Expressions
Often a comparison expression is used in IF/THEN/ELSE instructions. The following example uses an IF/THEN/ELSE instruction to compare two values. For more information about this instruction, see IF/THEN/ELSE Instructionson page 42.
Chapter 3. Using Variables and Expressions 31
Using Expressions
Example Using A Comparison Expression
/****************************** REXX *******************************/ /* This exec compares what you paid for lunch for two */ /* days in a row and then comments on the comparison. */ /*******************************************************************/ SAY 'What did you spend for lunch yesterday?' SAY 'Please do not include the dollar sign.'
PARSE PULL last
SAY 'What did you spend for lunch today?' SAY 'Please do not include the dollar sign.'
PARSE PULL lunch
IF lunch > last THEN /* lunch cost increased */
SAY "Today's lunch cost more than yesterday's."
ELSE /* lunch cost remained the same or decreased */
SAY "Today's lunch cost the same or less than yesterday's."
Exercises - Using Comparison Expressions
1. In the preceding example of using a comparison expression, what appears on
the screen when you respond to the prompts with the following lunch costs?
Yesterdays Lunch Todays Lunch
4.42 3.75
3.50 3.50
3.75 4.42
2. What is the result (0 or 1) of the following expressions?
a. Apples= Oranges b. Apples= Apples c. Apples== Apples d. 100 = 1E2 e. 100 \= 1E2 f. 100 \== 1E2
ANSWERS
1. The following sentences appear.
a. Todays lunch cost the same or less than yesterdays. b. Todays lunch cost the same or less than yesterdays. c. Todays lunch cost more than yesterdays.
2. The expressions result in the following. Remember 0 is false and 1 is true.
a. 0 b. 1 c. 0 (The first Appleshas a space.) d. 1 e. 0 f. 1

Logical (Boolean) Operators

Logical expressions, like comparison expressions, return a true (1) or false (0) value when processed. Logical operators combine two comparisons and return the true (1) or false (0) value depending on the results of the comparisons.
32
z/OS V1R1.0 TSO/E REXX Users Guide
The logical operators are:
Operator Meaning
& AND
Returns 1 if both comparisons are true. For example:
(4 > 2) & (a = a) /* true, so result is 1 */
(2 > 4) & (a = a) /* false, so result is 0 */
| Inclusive OR
Returns 1 if at least one comparison is true. For example:
(4 > 2) | (5 = 3) /* at least one is true, so result is 1 */
(2 > 4) | (5 = 3) /* neither one is true, so result is 0 */
&& Exclusive OR
Returns 1 if only one comparison (but not both) is true. For example:
(4 > 2) && (5 = 3) /* only one is true, so result is 1 */
(4 > 2) && (5 = 5) /* both are true, so result is 0 */
(2 > 4) && (5 = 3) /* neither one is true, so result is 0 */
Using Expressions
Prefix \ Logical NOT
Returns the opposite response. For example:
\ 0 /* opposite of 0, so result is 1 */
\ (4 > 2) /* opposite of true, so result is 0 */
Using Logical Expressions
Logical expressions are used in complex conditional instructions and can act as checkpoints to screen unwanted conditions. When you have a series of logical expressions, for clarification, use one or more sets of parentheses to enclose each expression.
IF ((A < B) | (J < D)) & ((M = Q) | (M = D)) THEN ...
The following example uses logical operators to make a decision.
Example Using Logical Expressions
/***************************** REXX ********************************/ /* This exec receives arguments for a complex logical expression */ /* that determines whether a person should go skiing. The first */ /* argument is a season and the other two can be 'yes' or 'no'. */ /*******************************************************************/
PARSE ARG season snowing broken_leg
IF ((season = 'winter') | (snowing ='yes')) & (broken_leg ='no')
THEN SAY 'Go skiing.'
ELSE
SAY 'Stay home.'
When arguments passed to this example are "spring yes no", the IF clause translates as follows:
Chapter 3. Using Variables and Expressions 33
Using Expressions
IF ((season = 'winter') | (snowing ='yes')) & (broken_leg ='no') THEN
\______________/ \____________/ \_____________/
false true true
\___________________/ /
true /
\_____________________________/
true
As a result, when you run the exec, you see the message:
Go skiing.
Exercises - Using Logical Expressions
A student applying to colleges has decided to pick ones according to the following specifications:
IF (inexpensive | scholarship) & (reputable | nearby) THEN
SAY "I'll consider it."
ELSE
SAY "Forget it!"
A college is inexpensive, did not offer a scholarship, is reputable, but is over 1000 miles away. Should the student apply?
ANSWER
Yes. The conditional instruction works out as follows:
IF (inexpensive | scholarship) & (reputable | nearby) THEN ...
\___________/ \___________/ \_________/ \______/
true false true false
\___________/ \_________/

Concatenation Operators

Concatenation operators combine two terms into one. The terms can be strings, variables, expressions, or constants. Concatenation can be significant in formatting output.
The operators that indicate how to join two terms are as follows:
Operator Meaning
blank Concatenate terms and place one blank in between. Terms that are
|| Concatenate terms and place no blanks in between. For example:
abuttal Concatenate terms and place no blanks in between. For example:
true true
\_________________________/
true
separated by more than one blank default to one blank when read. For example:
SAY true blue /* result is TRUE BLUE */
(8 / 2)||(3 * 3) /* result is 49 */
per_cent'%' /* if per_cent = 50, result is 50% */
Using Concatenation Operators
One way to format output is to use variables and concatenation operators as in the following example. A more sophisticated way to format information is with parsing and templates. Information about parsing appears in Parsing Dataon page 87.
34
z/OS V1R1.0 TSO/E REXX Users Guide
Example using Concatenation Operators
/****************************** REXX *******************************/ /* This exec formats data into columns for output. */ /*******************************************************************/
sport = 'base' equipment = 'ball' column = ' ' cost = 5
SAY sport||equipment column '$' cost
The result of this example is:

Priority of Operators

When more than one type of operator appears in an expression, what operation does the language processor do first?
IF (A > 7**B) & (B < 3) | (A||B = C) THEN ...
Using Expressions
baseball $ 5
Like the priority of operators within the arithmetic operators, there is an overall priority that includes all operators. The priority of operators is as follows with the highest first.
Overall Operator Priority
\or¬ -+ Prefix operators
** Power (exponential)
*/%// Multiply and divide
+- Add and subtract
blank || abuttal Concatenation operators
== = >< etc. Comparison operators
& Logical AND
|&& Inclusive OR and exclusive OR
Thus the previous example presented again below:
IF (A > 7**B) & (B < 3) | (A||B = C) THEN ...
given the following values:
A=8 B=2 C=10
would be evaluated as follows:
1. Convert variables to values
IF (8 > 7**2) & (2 < 3) | (8||2 = 10) THEN ...
2. Compute operations of higher priority within parentheses
Chapter 3. Using Variables and Expressions 35
Using Expressions
v Exponential operation
IF (8 > 7**2) & (2 < 3) | (8||2 = 10) THEN ...
\____/
49
v Concatenation operation
IF (8 > 49) & (2 < 3) | (8||2 = 10) THEN ...
\____/
82
3. Compute all operations within parentheses from left to right
IF (8 > 49) & (2 < 3) | (82 = 10) THEN ...
\____/ \___/ \_____/
01 0
4. Logical AND
0&1| 0
\_______/
0
5. Inclusive OR
0|0
\_____________/
0
Exercises - Priority of Operators
1. What are the answers to the following examples?
a. 22 + (12 * 1) b. -6/-2>(45%7/2)-1 c. 10*2-(5+1)//5*2+15-1
2. In the example of the student and the college from Exercises - Using Logical
Expressionson page 34, if the parentheses were removed from the students formula, what would be the outcome for the college?
IF inexpensive | scholarship & reputable | nearby THEN
SAY "I'll consider it."
ELSE
SAY "Forget it!"
ANSWERS
1. The results are as follows:
2. Ill consider it.
36
z/OS V1R1.0 TSO/E REXX Users Guide
Remember the college is inexpensive, did not offer a scholarship, is reputable, but is 1000 miles away.
a. 34 (22 + 12 = 34) b. 1 (true) (3>3-1) c. 32 (20-2+15-1)
The & operator has priority, as follows, but the outcome is the same as the previous version with the parentheses.
IF inexpensive | scholarship & reputable | nearby THEN
\_________/ \_________/ \_______/ \____/
true false true false
\ \___________/ /
\ false /
\_________________/ /
true /
\____________________/
true

Tracing Expressions with the TRACE Instruction

Tracing Expressions with the TRACE Instruction
You can use the TRACE instruction to display how the language processor evaluates each operation of an expression as it reads it, or to display the final result of an expression. These two types of tracing are useful for debugging execs.

Tracing Operations

To trace operations within an expression, use the TRACE I (TRACE Intermediates) form of the TRACE instruction. All expressions that follow the instruction are then broken down by operation and analyzed as:
>V> - Variable value - The data traced is the contents
>L> - Literal value - The data traced is a literal
>O> - Operation result - The data traced is the result
The following example uses the TRACE I instruction.
EDIT ---- USERID.REXX.EXEC(SAMPLE) ---------------------- COLUMNS 009 080 COMMAND ===> SCROLL ===> HALF ******* ************************** TOP OF DATA **************************** 000001 /************************* REXX *****************************/ 000002 /* This exec uses the TRACE instruction to show how an */ 000003 /* expression is evaluated, operation by operation. */ 000004 /********************************************************* */ 000005 x = 9 000006 y = 2 000007 TRACE I 000008 000009 IF x+1>5*yTHEN 000010 SAY 'x is big enough.' 000011 ELSE NOP /* No operation on the ELSE path */ ******* ********************** BOTTOM OF DATA *****************************
of a variable.
(string, uninitialized variable, or constant).
of an operation on two terms.
When you run the example, you see on your screen:
9*-*IFx+1>5*y
>V> "9" >L> "1" >O> "10" >L> "5" >V> "2" >O> "10" >O> "0"
First you see the line number (9 *-*) followed by the expression. Then the expression is broken down by operation as follows:
>V> "9" (value of variable x) >L> "1" (value of literal 1) >O> "10" (result of operationx+1) >L> "5" (value of literal 5) >V> "2" (value of variable y) >O> "10" (result of operation5*y) >O> "0" (result of final operation 10 > 10 is false)
Chapter 3. Using Variables and Expressions 37
Tracing Expressions with the TRACE Instruction

Tracing Results

To trace only the final result of an expression, use the TRACE R (TRACE Results) form of the TRACE instruction. All expressions that follow the instruction are analyzed and the results are displayed as:
>>> Final result of an expression
If you changed the TRACE instruction operand in the previous example from an I to an R, you would see the following results.
9*-*IFx+1>5*y
>>> "0"
In addition to tracing operations and results, the TRACE instruction offers other types of tracing. For information about the other types of tracing with the TRACE instruction, see z/OS TSO/E REXX Reference.
Exercises - Using the TRACE Instruction
Write an exec with a complex expression, such as:
IF(A>B)|(C<2*D)THEN ...
Define A, B, C, and D in the exec and use the TRACE I instruction.
ANSWER
Possible Solution
/****************************** REXX *******************************/ /* This exec uses the TRACE instruction to show how an expression */ /* is evaluated, operation by operation. */ /*******************************************************************/
A=1 B=2 C=3 D=4
TRACE I
IF(A>B)|(C<2*D)THEN
SAY 'At least one expression was true.'
ELSE
SAY 'Neither expression was true.'
When this exec is run, you see the following:
38
z/OS V1R1.0 TSO/E REXX Users Guide
Tracing Expressions with the TRACE Instruction
12*-*IF(A>B)|(C<2*D)
>V> "1" >V> "2" >O> "0" >V> "3" >L> "2" >V> "4" >O> "8" >O> "1" >O> "1" *-* THEN
13 *-* SAY 'At least one expression was true.'
>L> "At least one expression was true."
At least one expression was true.
Chapter 3. Using Variables and Expressions 39
Tracing Expressions with the TRACE Instruction
40
z/OS V1R1.0 TSO/E REXX Users Guide

Chapter 4. Controlling the Flow Within an Exec

Using Conditional Instructions ...................42
IF/THEN/ELSE Instructions ...................42
Nested IF/THEN/ELSE Instructions ................43
Exercise - Using the IF/THEN/ELSE Instruction ...........44
SELECT/WHEN/OTHERWISE/END Instruction ............44
Exercises - Using the SELECT/WHEN/OTHERWISE/END Instruction . . . 46
Using Looping Instructions ....................47
Repetitive Loops .......................47
Infinite Loops .......................48
DO FOREVER Loops ....................49
LEAVE Instruction ......................50
ITERATE Instruction .....................50
Exercises - Using Loops ...................51
Conditional Loops .......................52
DO WHILE Loops ......................52
Exercise - Using a DO WHILE Loop ...............53
DO UNTIL Loops ......................53
Exercise - Using a DO UNTIL Loop ...............54
Combining Types of Loops ...................55
Nested DO Loops .......................55
Exercises - Combining Loops .................56
Using Interrupt Instructions ....................56
EXIT Instruction .......................57
CALL/RETURN Instructions ...................57
SIGNAL Instruction ......................58
This chapter introduces instructions that alter the sequential execution of an exec and demonstrates how those instructions are used.
Generally when an exec runs, one instruction after another executes, starting with the first and ending with the last. The language processor, unless told otherwise, executes instructions sequentially.
You can alter the order of execution within an exec by using specific REXX instructions that cause the language processor to skip some instructions, repeat others, or jump to another part of the exec. These specific REXX instructions can be classified as follows:
v Conditional instructions, which set up at least one condition in the form of an
expression. If the condition is true, the language processor selects the path following that condition. Otherwise the language processor selects another path. The REXX conditional instructions are:
IF expression/THEN/ELSE SELECT/WHEN expression/OTHERWISE/END.
v Looping instructions, which tell the language processor to repeat a set of
instructions. A loop can repeat a specified number of times or it can use a condition to control repeating. REXX looping instructions are:
DO expression/END DO FOREVER/END DO WHILE expression=true/END DO UNTIL expression=true/END
© Copyright IBM Corp. 1988, 2001 41
Controlling the Flow Within an Exec
v Interrupt instructions, which tell the language processor to leave the exec entirely
or leave one part of the exec and go to another part, either permanently or temporarily. The REXX interrupt instructions are:
EXIT SIGNAL label CALL label/RETURN

Using Conditional Instructions

There are two types of conditional instructions. IF/THEN/ELSE can direct the execution of an exec to one of two choices. SELECT/WHEN/OTHERWISE/END can direct the execution to one of many choices.

IF/THEN/ELSE Instructions

The examples of IF/THEN/ELSE instructions in previous chapters demonstrated the two-choice selection. In a flow chart, this appears as follows:
IF
False True
ELSE THEN
instruction instruction
expression
As a REXX instruction, the flowchart example looks like:
IF expression THEN instruction
ELSE instruction
You can also arrange the clauses in one of the following ways to enhance readability:
IF expression THEN
instruction
ELSE
instruction
or
IF expression
THEN
instruction
ELSE
instruction
When you put the entire instruction on one line, you must separate the THEN clause from the ELSE clause with a semicolon.
IF expression THEN instruction; ELSE instruction
Generally, at least one instruction should follow the THEN and ELSE clauses. When either clause has no instructions, it is good programming practice to include NOP (no operation) next to the clause.
42
z/OS V1R1.0 TSO/E REXX Users Guide
IF expression THEN
instruction
ELSE NOP
If you have more than one instruction for a condition, begin the set of instructions with a DO and end them with an END.
IF weather = rainy THEN
SAY 'Find a good book.'
ELSE
DO
SAY 'Would you like to play tennis or golf?' PULL answer
END
Without the enclosing DO and END, the language processor assumes only one instruction for the ELSE clause.

Nested IF/THEN/ELSE Instructions

Sometimes it is necessary to have one or more IF/THEN/ELSE instructions within other IF/THEN/ELSE instructions. Having one type of instruction within another is called nesting. With nested IF instructions, it is important to match each IF with an ELSE and each DO with an END.
IF weather = fine THEN
DO
SAY 'What a lovely day!' IF tenniscourt = free THEN
SAY 'Shall we play tennis?'
ELSE NOP
END
ELSE
SAY 'Shall we take our raincoats?'
Using Conditional Instructions
Not matching nested IFs to ELSEs and DOs to ENDs can have some surprising results. If you eliminate the DOs and ENDs and the ELSE NOP, as in the following example, what is the outcome?
Example of Missing Instructions
/******************************** REXX *****************************/ /* This exec demonstrates what can happen when you do not include */ /* DOs, ENDs, and ELSEs in nested IF/THEN/ELSE instructions. */ /*******************************************************************/
weather = 'fine' tenniscourt = 'occupied'
IF weather = 'fine' THEN
SAY 'What a lovely day!' IF tenniscourt = 'free' THEN
SAY 'Shall we play tennis?'
ELSE
SAY 'Shall we take our raincoats?'
By looking at the exec you might assume the ELSE belongs to the first IF. However, the language processor associates an ELSE with the nearest unpaired IF. The outcome is as follows:
What a lovely day! Shall we take our raincoats?
Chapter 4. Controlling the Flow Within an Exec 43
Using Conditional Instructions
Exercise - Using the IF/THEN/ELSE Instruction
Write the REXX instructions for the following flowchart:
IF
False
False
IF
B=2
False
A=3
True
IF
C=3
True
A=1
A=0
False
True
IF
C=2
True
B=1
ANSWER
Possible Solution
IF A = 0 THEN
IF C = 2 THEN
B=1
ELSE NOP
ELSE
IF B = 2 THEN
IF C = 3 THEN
A=1
ELSE
A=3
ELSE NOP

SELECT/WHEN/OTHERWISE/END Instruction

To select one of any number of choices, use the SELECT/WHEN/OTHERWISE/END instruction. In a flowchart it appears as follows:
44
z/OS V1R1.0 TSO/E REXX Users Guide
SELECT
Using Conditional Instructions
WHEN
WHEN
WHEN
OTHERWISE
END
True
False
True
False
True
False
THEN
instruction
THEN
instruction
THEN
instruction
instruction(s)
As a REXX instruction, the flowchart example looks like:
SELECT
WHEN expression THEN instruction WHEN expression THEN instruction WHEN expression THEN instruction
. . .
OTHERWISE
instruction(s)
END
The language processor scans the WHEN clauses starting at the beginning until it finds a true expression. After it finds a true expression, it ignores all other possibilities, even though they might also be true. If no WHEN expressions are true, it processes the instructions following the OTHERWISE clause.
As with the IF/THEN/ELSE instruction, when you have more than one instruction for a possible path, begin the set of instructions with a DO and end them with an END. However, if more than one instruction follows the OTHERWISE keyword, DO and END are not necessary.
Chapter 4. Controlling the Flow Within an Exec 45
Using Conditional Instructions
Example Using SELECT/WHEN/OTHERWISE/END
/******************************** REXX *****************************/ /* This exec receives input with a person's age and sex. In */ /* reply it displays a person's status as follows: */ /* BABIES - under 5 */ /* GIRLS - female 5 to 12 */ /* BOYS - male 5 to 12 */ /* TEENAGERS - 13 through 19 */ /* WOMEN - female 20 and up */ /* MEN - male 20 and up */ /*******************************************************************/
PARSE ARG age sex .
SELECT
WHEN age < 5 THEN /* person younger than 5 */
status = 'BABY'
WHEN age < 13 THEN /* person between 5 and 12 */
DO
IF sex = 'M' THEN /* boy between 5 and 12 */
ELSE /* girl between 5 and 12 */
END
WHEN age < 20 THEN /* person between 13 and 19 */
status = 'TEENAGER'
OTHERWISE
IF sex = 'M' THEN /* man 20 or older */
status = 'MAN'
ELSE /* woman 20 or older */
status = 'WOMAN'
END
status = 'BOY'
status = 'GIRL'
SAY 'This person should be counted as a' status '.'
Each SELECT must end with an END. Indenting each WHEN makes an exec easier to read.
Exercises - Using the SELECT/WHEN/OTHERWISE/END Instruction
"Thirty days hath September, April, June, and November; all the rest have thirty-one, save February alone ..."
Write an exec that provides the number of days in a month. First have the exec ask the user for a month specified as a number from 1 to 12 (with January being 1, February 2, and so forth). Then have the exec reply with the number of days. For month "2", the reply can be "28 or 29".
ANSWER
46
z/OS V1R1.0 TSO/E REXX Users Guide
Using Conditional Instructions
Possible Solution
/******************************** REXX *****************************/ /* This exec requests the user to enter a month as a whole number */ /* from 1 to 12 and responds with the number of days in that */ /* month. */ /*******************************************************************/
SAY 'To find out the number of days in a month,' SAY 'Enter the month as a number from 1 to 12.' PULL month
SELECT
WHEN month = 9 THEN
days = 30
WHEN month = 4 THEN
days = 30
WHEN month = 6 THEN
days = 30
WHEN month = 11 THEN
days = 30
WHEN month = 2 THEN
days = '28 or 29'
OTHERWISE
days = 31
END
SAY 'There are' days 'days in Month' month '.'

Using Looping Instructions

There are two types of looping instructions, repetitive loops and conditional loops. Repetitive loops allow you to repeat instructions a certain number of times,
and conditional loops use a condition to control repeating. All loops, regardless of the type, begin with the DO keyword and end with the END keyword.

Repetitive Loops

The simplest loop tells the language processor to repeat a group of instructions a specific number of times using a constant following the keyword DO.
DO 5
SAY 'Hello!'
END
When you run this example, you see five lines of Hello!.
Hello! Hello! Hello! Hello! Hello!
You can also use a variable in place of a constant as in the following example, which gives you the same results.
number = 5 DO number
SAY 'Hello!'
END
Chapter 4. Controlling the Flow Within an Exec 47
Using Looping Instructions
A variable that controls the number of times a loop repeats is called a control variable. Unless you specify otherwise, the control variable increases by 1 each
time the loop repeats.
DO number=1TO5
SAY 'Loop' number SAY 'Hello!'
END
SAY 'Dropped out of the loop when number reached' number
This example results in five lines of Hello! preceded by the number of the loop. The number increases at the bottom of the loop and is tested at the top.
Loop 1 Hello! Loop 2 Hello! Loop 3 Hello! Loop 4 Hello! Loop 5 Hello! Dropped out of the loop when number reached 6
You can change the increment of the control variable with the keyword BY as follows:
DO number=1TO10BY2
SAY 'Loop' number SAY 'Hello!'
END
SAY 'Dropped out of the loop when number reached' number
This example has results similar to the previous example except the loops are numbered in increments of two.
Loop 1 Hello! Loop 3 Hello! Loop 5 Hello! Loop 7 Hello! Loop 9 Hello! Dropped out of the loop when number reached 11
Infinite Loops
What happens when the control variable of a loop cannot attain the last number? For example, in the following exec segment, count does not increase beyond 1.
DO count=1to10
SAY 'Number' count count = count - 1
END
The result is called an infinite loop because count alternates between 1 and 0 and an endless number of lines saying Number 1 appear on the screen.
48
z/OS V1R1.0 TSO/E REXX Users Guide
Using Looping Instructions
IMPORTANT - Stopping An Infinite Loop
When you suspect an exec is in an infinite loop, you can end the exec by pressing the attention interrupt key, sometimes labeled PA1. You will then see message IRX0920I. In response to this message, type HI for halt interpretation and press the Enter key. If that doesnt stop the loop, you can press the attention interrupt key again, type HE for halt execution, and press the Enter key.
HI will not halt an infinitely looping or long running external function, subroutine, or host command written in a language other than REXX and that was called by your exec. The HI condition is not checked by the REXX interpreter until control returns from the function, subroutine, or host command.
Example of EXEC1, an exec that calls an external function
/********************* REXX ****************************************/ /* Invoke a user-written external function, 'myfunct'. */ /* not written in REXX. For example, it might have been coded */ /* in PL/I or assembler. */ /*******************************************************************/ x = myfunct(1) exit
If myfunct enters an infinite loop, pressing the attention interrupt key and entering HI will not stop myfunct. However, pressing the attention interrupt key and then entering HE will stop the function and the exec (EXEC1) that called it. HE does not automatically stop any exec that called EXEC1, unless you are running under ISPF. For more information about the HE condition, see z/OS TSO/E REXX Reference.
Note: HE does not alter the halt condition, which is raised by HI. If you entered HI
before you entered HE (for example, you may have first issued HI and it failed to end your exec), the halt condition will remain set for the exec and all calling execs. HE will stop your exec, and then the halt condition, raised when you entered HI, will be recognized by any exec that called your exec.
DO FOREVER Loops
Sometimes you might want to purposely write an infinite loop; for instance, in an exec that reads records from a data set until it reaches end of file, or in an exec that interacts with a user until the user enters a particular symbol to end the loop. You can use the EXIT instruction to end an infinite loop when a condition is met, as in the following example. More about the EXIT instruction appears in EXIT Instructionon page 57.
Chapter 4. Controlling the Flow Within an Exec 49
Using Looping Instructions
Example Using a DO FOREVER Loop
/****************************** REXX *******************************/ /* This exec prints data sets named by a user until the user enters*/ /* a null line. */ /*******************************************************************/
DO FOREVER
SAY 'Enter the name of the next data set or a blank to end.' PULL dataset_name IF dataset_name = '' THEN
ELSE
END
This example sends data sets to the printer and then issues a message that the data set was printed. When the user enters a blank, the loop ends and so does the exec. To end the loop without ending the exec, use the LEAVE instruction, as described in the following topic.
LEAVE Instruction
The LEAVE instruction causes an immediate exit from a repetitive loop. Control goes to the instruction following the END keyword of the loop. An example of using the LEAVE instruction follows:
EXIT
DO
"PRINTDS DA("dataset_name")"
SAY dataset_name 'printed.'
END
Example Using the LEAVE Instruction
/******************************** REXX *****************************/ /* This exec uses the LEAVE instruction to exit from a DO FOREVER */ /* loop that sends data sets to the printer. */ /*******************************************************************/
DO FOREVER
SAY 'Enter the name of the next data set.' SAY 'When there are no more data sets, enter QUIT.' PULL dataset_name IF dataset_name = 'QUIT' THEN
LEAVE
ELSE
DO
"PRINTDS DA("dataset_name")"
SAY dataset_name 'printed.'
END END SAY 'Good-bye.'
ITERATE Instruction
Another instruction, ITERATE, stops execution from within the loop and passes control to the DO instruction at the top of the loop. Depending on the type of DO instruction, a control variable is increased and tested and/or a condition is tested to determine whether to repeat the loop. Like LEAVE, ITERATE is used within the loop.
DO count=1TO10
IF count = 8
THEN
50
z/OS V1R1.0 TSO/E REXX Users Guide
Using Looping Instructions
ITERATE
ELSE
SAY 'Number' count
END
This example results in a list of numbers from 1 to 10 with the exception of number
8.
Number 1 Number 2 Number 3 Number 4 Number 5 Number 6 Number 7 Number 9 Number 10
Exercises - Using Loops
1. What are the results of the following loops?
DO digit=1TO3
a.
SAY digit END SAY 'Digit is now' digit
b. DO count = 10 BY -2 TO 6
SAY count END SAY 'Count is now' count
c. DO index = 10 TO 8
SAY 'Hup! Hup! Hup!'
END SAY 'Index is now' index
2. Sometimes an infinite loop can occur when input to end the loop doesnt match what is expected. For instance, in the previous example using the LEAVE Instructionon page 50, what happens when the user enters Quit and the PULL instruction is changed to a PARSE PULL instruction?
PARSE PULL dataset_name
ANSWERS
1. The results of the repetitive loops are as follows: a.
1 2 3 Digit is now 4
b.
10
8 6 Count is now 4
c.
(blank) Index is now 10
2. The user would be unable to leave the loop because "Quit" is not equal to "QUIT". In this case, omitting the PARSE keyword is preferred because
Chapter 4. Controlling the Flow Within an Exec 51
Using Looping Instructions
regardless of whether the user enters "quit", "QUIT", or "Quit", the language processor translates the input to uppercase before comparing it to "QUIT".

Conditional Loops

There are two types of conditional loops, DO WHILE and DO UNTIL. Both types of loops are controlled by one or more expressions. However, DO WHILE loops test the expression before the loop executes the first time and repeat only when the expression is true. DO UNTIL loops test the expression after the loop executes at least once and repeat only when the expression is false.
DO WHILE Loops
DO WHILE loops in a flowchart appear as follows:
DO WHILE
expression
False
END
True
instruction(s)
As REXX instructions, the flowchart example looks like:
DO WHILE expression /* expression must be true */
instruction(s)
END
Use a DO WHILE loop when you want to execute the loop while a condition is true. DO WHILE tests the condition at the top of the loop. If the condition is initially false, the loop is never executed.
You can use a DO WHILE loop instead of the DO FOREVER loop in the example using the LEAVE Instructionon page 50. However, you need to initialize the loop with a first case so the condition can be tested before you get into the loop. Notice the first case initialization in the beginning three lines of the following example.
Example Using DO WHILE
/******************************** REXX *****************************/ /* This exec uses a DO WHILE loop to send data sets to the system */ /* printer. */ /*******************************************************************/
SAY 'Enter the name of a data set to print.' SAY 'If there are no data sets, enter QUIT.' PULL dataset_name DO WHILE dataset_name \= 'QUIT'
"PRINTDS DA("dataset_name")" SAY dataset_name 'printed.' SAY 'Enter the name of the next data set.' SAY 'When there are no more data sets, enter QUIT.'
PULL dataset_name END SAY 'Good-bye.'
52
z/OS V1R1.0 TSO/E REXX Users Guide
Using Looping Instructions
Exercise - Using a DO WHILE Loop
Write an exec with a DO WHILE loop that asks passengers on a commuter airline if they want a window seat and keeps track of their responses. The flight has 8 passengers and 4 window seats. Discontinue the loop when all the window seats are taken. After the loop ends, display the number of window seats taken and the number of passengers questioned.
ANSWER
Possible Solution
/******************************** REXX *****************************/ /* This exec uses a DO WHILE loop to keep track of window seats in */ /* an 8-seat commuter airline. */ /*******************************************************************/
window_seats = 0 /* Initialize window seats to 0 */ passenger = 0 /* Initialize passengers to 0 */
DO WHILE (passenger < 8) & (window_seats \= 4)
/****************************************************************/ /* Continue while you have not questioned all 8 passengers and */ /* while all the window seats are not taken. */ /****************************************************************/
SAY 'Do you want a window seat? Please answer Y or N.' PULL answer passenger = passenger + 1
IF answer = 'Y' THEN
window_seats = window_seats + 1
ELSE NOP
END
SAY window_seats 'window seats were assigned.' SAY passenger 'passengers were questioned.'
/* Increase the number of passengers by 1 */
/* Increase the number of window seats by 1 */
DO UNTIL Loops
DO UNTIL loops in a flowchart appear as follows:
DO UNTIL
instruction(s)
False
END
expression
Tru e
As REXX instructions, the flowchart example looks like:
Chapter 4. Controlling the Flow Within an Exec 53
Using Looping Instructions
DO UNTIL expression /* expression must be false */
instruction(s)
END
Use DO UNTIL loops when a condition is not true and you want to execute the loop until the condition is true. The DO UNTIL loop tests the condition at the end of the loop and repeats only when the condition is false. Otherwise the loop executes once and ends. For example:
Example Using DO UNTIL
/******************************** REXX *****************************/ /* This exec uses a DO UNTIL loop to ask for a password. If the */ /* password is incorrect three times, the loop ends. */ /*******************************************************************/
password = 'abracadabra' time = 0 DO UNTIL (answer = password) | (time = 3)
SAY 'What is the password?'
PULL answer
time = time + 1
END
Exercise - Using a DO UNTIL Loop
Change the exec in the previous exercise, Exercise - Using a DO WHILE Loopon page 53, from a DO WHILE to a DO UNTIL loop and achieve the same results. Remember that DO WHILE loops check for true expressions and DO UNTIL loops check for false expressions, which means their logical operators are often reversed.
ANSWER
Possible Solution
/******************************** REXX *****************************/ /* This exec uses a DO UNTIL loop to keep track of window seats in */ /* an 8-seat commuter airline. */ /*******************************************************************/
window_seats = 0 /* Initialize window seats to 0 */ passenger = 0 /* Initialize passengers to 0 */
DO UNTIL (passenger >= 8) | (window_seats = 4)
/****************************************************************/ /* Continue until you have questioned all 8 passengers or until */ /* all the window seats are taken. */ /****************************************************************/
SAY 'Do you want a window seat? Please answer Y or N.' PULL answer passenger = passenger + 1
IF answer = 'Y' THEN
window_seats = window_seats + 1
ELSE NOP END SAY window_seats 'window seats were assigned.' SAY passenger 'passengers were questioned.'
/* Increase the number of passengers by 1 */
/* Increase the number of window seats by 1 */
54
z/OS V1R1.0 TSO/E REXX Users Guide

Combining Types of Loops

You can combine repetitive and conditional loops to create a compound loop. The following loop is set to repeat 10 times while a certain condition is met, at which point it stops.
quantity = 20 DO number=1TO10WHILE quantity < 50
quantity = quantity + number SAY 'Quantity = 'quantity ' (Loop 'number')'
END
The result of this example is as follows:
Quantity = 21 (Loop 1)
Quantity = 23 (Loop 2)
Quantity = 26 (Loop 3)
Quantity = 30 (Loop 4)
Quantity = 35 (Loop 5)
Quantity = 41 (Loop 6)
Quantity = 48 (Loop 7)
Quantity = 56 (Loop 8)
You can substitute a DO UNTIL loop, change the comparison operator from < to >, and get the same results.
quantity = 20 DO number=1TO10UNTIL quantity > 50
quantity = quantity + number SAY 'Quantity = 'quantity ' (Loop 'number')'
END
Using Looping Instructions

Nested DO Loops

Like nested IF/THEN/ELSE instructions, DO loops can also be within other DO loops. A simple example follows:
DO outer=1TO2
END
The output from this example is:
If you need to leave a loop when a certain condition arises, use the LEAVE instruction followed by the control variable of the loop. If the LEAVE instruction is for the inner loop, you leave the inner loop and go to the outer loop. If the LEAVE instruction is for the outer loop, you leave both loops.
To leave the inner loop in the preceding example, add an IF/THEN/ELSE instruction that includes a LEAVE instruction after the IF instruction.
DO outer=1TO2
DO inner=1TO2
SAY 'HIP' END SAY 'HURRAH'
HIP
HIP
HURRAH
HIP
HIP
HURRAH
DO inner=1TO2
IF inner > 1 THEN
LEAVE inner
Chapter 4. Controlling the Flow Within an Exec 55
Using Looping Instructions
ELSE
SAY 'HIP' END SAY 'HURRAH'
END
The result is as follows:
HIP HURRAH HIP HURRAH
Exercises - Combining Loops
1. What happens when the following exec runs?
DO outer=1TO3
SAY /* Write a blank line */ DO inner=1TO3
END
END
2. Now what happens when the LEAVE instruction is added?
DO outer=1TO3
SAY /* Write a blank line */ DO inner=1TO3
END
END
SAY 'Outer' outer 'Inner' inner
IF inner = 2 THEN
LEAVE inner
ELSE
SAY 'Outer' outer 'Inner' inner
ANSWERS
1. When this example runs, you see on your screen the following:
Outer 1 Inner 1 Outer 1 Inner 2 Outer 1 Inner 3
Outer 2 Inner 1 Outer 2 Inner 2 Outer 2 Inner 3
Outer 3 Inner 1 Outer 3 Inner 2 Outer 3 Inner 3
2. The result is one line of output for each of the inner loops.
Outer 1 Inner 1
Outer 2 Inner 1
Outer 3 Inner 1

Using Interrupt Instructions

Instructions that interrupt the flow of an exec can cause the exec to:
v Terminate (EXIT) v Skip to another part of the exec marked by a label (SIGNAL)
56
z/OS V1R1.0 TSO/E REXX Users Guide

EXIT Instruction

Using Interrupt Instructions
v Go temporarily to a subroutine either within the exec or outside the exec
(CALL/RETURN).
The EXIT instruction causes an exec to unconditionally end and return to where the exec was invoked. If the exec was initiated from the PROC section of an ISPF selection panel, EXIT returns to the ISPF panel. If the exec was called by a program, such as another exec, EXIT returns to the program. More about calling external routines appears later in this chapter and in Chapter 6. Writing Subroutines and Functionson page 69.
In addition to ending an exec, EXIT can also return a value to the invoker of the exec. If the exec was invoked as a subroutine from another REXX exec, the value is received in the REXX special variable RESULT. If the exec was invoked as a function, the value is received in the original expression at the point where the function was invoked. Otherwise, the value is received in the REXX special variable RC. The value can represent a return code and can be in the form of a constant or an expression that is computed.
Example Using the EXIT Instruction
/******************************** REXX *****************************/ /* This exec uses the EXIT instruction to end the exec and return */ /* a value that indicates whether or not a job applicant gets the */ /* job. A value of 0 means the applicant does not qualify for */ /* the job, but a value of 1 means the applicant gets the job. */ /* The value is placed in the REXX special variable RESULT. */ /*******************************************************************/ SAY 'How many months of experience do you have? Please enter' SAY 'the months as a number.' PULL month
SAY 'Can you supply 3 references? Please answer Y or N.' PULL reference
SAY 'Are you available to start work tomorrow? Please answer Y or N.' PULL tomorrow
IF (month > 24) & (reference = 'Y') & (tomorrow = 'Y') THEN
job = 1 /* person gets the job */
ELSE
job = 0 /* person does not get the job */
EXIT job

CALL/RETURN Instructions

The CALL instruction interrupts the flow of an exec by passing control to an internal or external subroutine. An internal subroutine is part of the calling exec. An external subroutine is another exec. The RETURN instruction returns control from a subroutine back to the calling exec and optionally returns a value.
When calling an internal subroutine, CALL passes control to a label specified after the CALL keyword. When the subroutine ends with the RETURN instruction, the instructions following CALL are executed.
Chapter 4. Controlling the Flow Within an Exec 57
Using Interrupt Instructions
instruction(s) CALL sub1
instruction(s) EXIT
sub1: instruction(s) RETURN
When calling an external subroutine, CALL passes control to the exec name that is specified after the CALL keyword. When the external subroutine completes, you can use the RETURN instruction to return to where you left off in the calling exec.
REXX.EXEC(MAIN)
instruction(s) CALL sub2
instruction(s)
. . .
REXX.EXEC(SUB2)
For more information about calling subroutines, see Chapter 6. Writing Subroutines and Functionson page 69.

SIGNAL Instruction

The SIGNAL instruction, like CALL, interrupts the normal flow of an exec and causes control to pass to a specified label. The label to which control passes can appear before or after the SIGNAL instruction. Unlike CALL, SIGNAL does not return to a specific instruction to resume execution. When you use SIGNAL from within a loop, the loop automatically ends; and when you use SIGNAL from an internal routine, the internal routine will not return to its caller.
In the following example, if the expression is true, then the language processor goes to the label Emergency: and skips all instructions in between.
instruction(s) RETURN
58
z/OS V1R1.0 TSO/E REXX Users Guide
Using Interrupt Instructions
IF expression THEN
SIGNAL Emergency
ELSE
instruction(s)
Emergency: instruction(s)
SIGNAL is useful for testing execs or to provide an emergency course of action. It should not be used as a convenient way to move from one place in an exec to another. SIGNAL does not provide a way to return as does the CALL instruction described in CALL/RETURN Instructionson page 57.
For more information about the SIGNAL instruction, see page 113, and z/OS TSO/E REXX Reference.
Chapter 4. Controlling the Flow Within an Exec 59
60 z/OS V1R1.0 TSO/E REXX Users Guide

Chapter 5. Using Functions

What is a Function? .......................61
Example of a Function .....................62
Built-In Functions ........................63
Arithmetic Functions ......................63
Comparison Functions .....................63
Conversion Functions .....................64
Formatting Functions......................64
String Manipulating Functions ..................64
Miscellaneous Functions ....................65
Testing Input with Built-In Functions ................66
Exercise - Writing an Exec with Built-In Functions ..........66
This chapter defines what a function is and describes how to use the built-in functions.

What is a Function?

Afunction is a sequence of instructions that can receive data, process that data, and return a value. In REXX, there are several kinds of functions:
v Built-in functions These functions are built into the language processor. More
about built-in functions appears later in this chapter.
v User-written functions These functions are written by an individual user or
supplied by an installation and can be internal or external. An internal function is part of the current exec that starts at a label. An external function is a self-contained program or exec outside of the calling exec. More information about user-written functions appears in Writing a Functionon page 77.
v Function packages These are groups of functions and subroutines written by
an individual user or supplied by an installation. They are link-edited into load modules and categorized as user, local, and system. TSO/E external functions are provided in a system function package. More information about TSO/E external functions appears in TSO/E External Functionson page 119.
Regardless of the kind of function, all functions return a value to the exec that issued the function call. To call a function, type the function name directly followed by one or more arguments within parentheses. There can be no space between
the function name and the left parenthesis.
function(arguments)
A function call can contain up to 20 arguments separated by commas. Each argument can be one or more of the following.
v Blank
function( )
v Constant
function(55)
v Symbol
function(symbol_name)
v Literal string
function('With a literal string')
v Option recognized by the function
© Copyright IBM Corp. 1988, 2001 61
What is a Function?
function(option)
v Another function
function(function(arguments))
v Combination of argument types
function('With a literal string', 55, option)
When the function returns a value, and all functions must return values, the value replaces the function call. In the following example, the value returned is added to 7 and the sum is displayed.
SAY 7 + function(arguments)
A function call generally appears in an expression. Therefore a function call, like an expression, does not usually appear in an instruction by itself.

Example of a Function

Calculations represented by functions often require many instructions. For instance, the simple calculation for finding the highest number in a group of three numbers, might be written as follows:
Finding a Maximum Number
/***************************** REXX ********************************/ /* This exec receives three numbers from a user and analyzes which */ /* number is the greatest. */ /*******************************************************************/
PARSE ARG number1, number2, number3 .
IF number1 > number2 THEN
IF number1 > number3 THEN
greatest = number1
ELSE
greatest = number3
ELSE
IF number2 > number3 THEN
greatest = number2
ELSE
greatest = number3
RETURN greatest
Rather than writing multiple instructions every time you want to find the maximum of a group of three numbers, you can use a built-in function that does the calculation for you and returns the maximum number. The function is called MAX and is used as follows:
MAX(number1,number2,number3,...)
To find the maximum of 45, -2, number, 199, and put the maximum into the symbol
biggest, write the following instruction:
biggest = MAX(45,-2,number,199)
62
z/OS V1R1.0 TSO/E REXX Users Guide

Built-In Functions

Over 50 functions are built into the language processor. The built-in functions fall into the following categories:
v Arithmetic functions
v Comparison functions
v Conversion functions
v Formatting functions
v String manipulating functions
v Miscellaneous functions
Built-In Functions
These functions evaluate numbers from the argument and return a particular value.
These functions compare numbers and/or strings and return a value.
These functions convert one type of data representation to another type of data representation.
These functions manipulate the characters and spacing in strings supplied in the argument.
These functions analyze a string supplied in the argument (or a variable representing a string) and return a particular value.
These functions do not clearly fit into any of the other categories.
The following tables briefly describe the functions in each category. For a complete description of these functions, see z/OS TSO/E REXX Reference.

Arithmetic Functions

Function Description
ABS Returns the absolute value of the input number.
DIGITS Returns the current setting of NUMERIC DIGITS.
FORM Returns the current setting of NUMERIC FORM.
FUZZ Returns the current setting of NUMERIC FUZZ.
MAX Returns the largest number from the list specified, formatted according
MIN Returns the smallest number from the list specified, formatted according
RANDOM Returns a quasi-random, non-negative whole number in the range
SIGN Returns a number that indicates the sign of the input number.
TRUNC Returns the integer part of the input number, and optionally a specified

Comparison Functions

to the current NUMERIC settings.
to the current NUMERIC settings.
specified.
number of decimal places.
Function Description
COMPARE Returns 0 if the two input strings are identical. Otherwise, returns the
position of the first character that does not match.
DATATYPE Returns a string indicating the input string is a particular data type, such
as a number or character.
Chapter 5. Using Functions 63
Built-In Functions
Function Description
SYMBOL Returns this state of the symbol (variable, literal, or bad).

Conversion Functions

Function Description
B2X Returns a string, in character format, that represents the input binary
C2D Returns the decimal value of the binary representation of the input
C2X Returns a string, in character format, that represents the input string
D2C Returns a string, in character format, that represents the input decimal
D2X Returns a string, in character format, that represents the input decimal
X2B Returns a string, in character format, that represents the input
X2C Returns a string, in character format, that represents the input
X2D Returns the decimal representation of the input hexadecimal string.
string converted to hexadecimal. (Binary to hexadecimal)
string. (Character to Decimal)
converted to hexadecimal. (Character to Hexadecimal)
number converted to binary. (Decimal to Character)
number converted to hexadecimal. (Decimal to Hexadecimal)
hexadecimal string converted to binary. (Hexadecimal to binary)
hexadecimal string converted to character. (Hexadecimal to Character)
(Hexadecimal to Decimal)

Formatting Functions

Function Description
CENTER/ CENTRE
COPIES Returns the specified number of concatenated copies of the input string.
FORMAT Returns the input number, rounded and formatted.
JUSTIFY * Returns a specified string formatted by adding pad characters between
LEFT Returns a string of the specified length, truncated or padded on the right
RIGHT Returns a string of the specified length, truncated or padded on the left
SPACE Returns the words in the input string with a specified number of pad
* Indicates a non-SAA built-in function provided only by TSO/E.
Returns a string of a specified length with the input string centered in it, with pad characters added as necessary to make up the length.
words to justify to both margins.
as needed.
as needed.
characters between each word.

String Manipulating Functions

Function Description
ABBREV Returns a string indicating if one string is equal to the specified number
of leading characters of another string.
DELSTR Returns a string after deleting a specified number of characters, starting
at a specified point in the input string.
64
z/OS V1R1.0 TSO/E REXX Users Guide
Built-In Functions
Function Description
DELWORD Returns a string after deleting a specified number of words, starting at a
specified word in the input string.
FIND * Returns the word number of the first word of a specified phrase found
within the input string.
INDEX * Returns the character position of the first character of a specified string
found in the input string.
INSERT Returns a character string after inserting one input string into another
string after a specified character position.
LASTPOS Returns the starting character position of the last occurrence of one
string in another.
LENGTH Returns the length of the input string.
OVERLAY Returns a string that is the target string overlaid by a second input
string.
POS Returns the character position of one string in another.
REVERSE Returns a character string, the characters of which are in reverse order
(swapped end for end).
STRIP Returns a character string after removing leading or trailing characters
or both from the input string.
SUBSTR Returns a portion of the input string beginning at a specified character
position.
SUBWORD Returns a portion of the input string starting at a specified word number.
TRANSLATE Returns a character string with each character of the input string
translated to another character or unchanged.
VERIFY Returns a number indicating whether an input string is composed only of
characters from another input string or returns the character position of the first unmatched character.
WORD Returns a word from an input string as indicated by a specified number.
WORDINDEX Returns the character position in an input string of the first character in
the specified word.
WORDLENGTH Returns the length of a specified word in the input string.
WORDPOS Returns the word number of the first word of a specified phrase in the
input string.
WORDS Returns the number of words in the input string.
* Indicates a non-SAA built-in function provided only by TSO/E.

Miscellaneous Functions

Function Description
ADDRESS Returns the name of the environment to which commands are currently
ARG Returns an argument string or information about the argument strings to
BITAND Returns a string composed of the two input strings logically ANDed
BITOR Returns a string composed of the two input strings logically ORed
being sent.
a program or internal routine.
together, bit by bit.
together, bit by bit.
Chapter 5. Using Functions 65
Built-In Functions
Function Description
BITXOR Returns a string composed of the two input strings eXclusive ORed
together, bit by bit.
CONDITION Returns the condition information, such as name and status, associated
with the current trapped condition.
DATE Returns the date in the default format (dd mon yyyy) or in one of various
optional formats.
ERRORTEXT Returns the error message associated with the specified error number.
EXTERNALS * Returns the number of elements in the terminal input buffer. In TSO/E,
this function always returns a 0.
LINESIZE * Returns the current terminal line width minus 1.
QUEUED Returns the number of lines remaining in the external data queue at the
time when the function is invoked.
SOURCELINE Returns either the line number of the last line in the source file or the
source line specified by a number.
TIME Returns the local time in the default 24-hour clock format (hh:mm:ss)or
in one of various optional formats.
TRACE Returns the trace actions currently in effect.
USERID * Returns the TSO/E user ID, if the REXX exec is running in the TSO/E
address space.
VALUE Returns the value of a specified symbol and optionally assigns it a new
value.
XRANGE Returns a string of all 1-byte codes (in ascending order) between and
including specified starting and ending values.
* Indicates a non-SAA built-in function provided only by TSO/E.

Testing Input with Built-In Functions

Some of the built-in functions provide a convenient way to test input. When an interactive exec requests input, the user might respond with input that is not valid. For instance, in the example Using Comparison Expressionson page 31, the exec requests a dollar amount with the following instructions.
SAY 'What did you spend for lunch yesterday?' SAY 'Please do not include the dollar sign.' PARSE PULL last
If the user responds with a number only, the exec will process that information correctly. If the user responds with a number preceded by a dollar sign or with a word, such as nothing, the exec will return an error. To avoid getting an error, you can check the input with the DATATYPE function as follows:
DO WHILE DATATYPE(last) \= 'NUM'
SAY 'Please enter the lunch amount again.' SAY 'The amount you entered was not a number without a dollar sign.' PARSE PULL last
END
Other useful built-in functions to test input are WORDS, VERIFY, LENGTH, and SIGN.
Exercise - Writing an Exec with Built-In Functions
Write an exec that checks a data set member name for a length of 8 characters. If a member name is longer than 8 characters, the exec truncates it to 8 and sends
66
z/OS V1R1.0 TSO/E REXX Users Guide
Built-In Functions
the user a message indicating the shortened name. Use the LENGTH and the SUBSTR built-in functions as described in z/OS TSO/E REXX Reference.
ANSWER
Possible Solution
/**************************** REXX *********************************/ /* This exec tests the length of a name for a data set member. If */ /* the name is longer than 8 characters, the exec truncates the */ /* extra characters and sends the user a message indicating the */ /* shortened member name. */ /*******************************************************************/ SAY 'Please enter a member name.' PULL membername
IF LENGTH(membername) > 8 THEN /* Name is longer than 8 characters*/
DO
membername = SUBSTR(membername,1,8) /* Shorten the name to */
SAY 'The member name you entered was too long.' SAY membername 'will be used.'
END
ELSE NOP
/* the first 8 characters*/
Chapter 5. Using Functions 67
Built-In Functions
68
z/OS V1R1.0 TSO/E REXX Users Guide

Chapter 6. Writing Subroutines and Functions

What are Subroutines and Functions? ................69
When to Write Subroutines vs. Functions ...............70
Writing a Subroutine .......................70
Passing Information to a Subroutine ................72
Passing Information by Using Variables ..............72
Passing Information by Using Arguments .............74
Receiving Information from a Subroutine ..............75
Example - Writing an Internal and an External Subroutine .......76
Writing a Function ........................77
Passing Information to a Function .................79
Passing Information by Using Variables ..............79
Passing Information by Using Arguments .............81
Receiving Information from a Function ...............83
Exercise - Writing a Function ..................83
Summary of Subroutines and Functions................83
This chapter shows how to write subroutines and functions and compares their differences and similarities.

What are Subroutines and Functions?

Subroutines and functions are routines made up of a sequence of instructions that can receive data, process that data, and return a value. The routines can be:
Internal The routine is within the current exec, marked by a label and used
only by that exec.
External A program or exec in a member of a partitioned data set that can
be called by one or more execs. In order for an exec to call the routine, the exec and the routine must be allocated to a system file, for example SYSEXEC or SYSPROC, or be in the same PDS. For more information about allocating to a system file, see Appendix A. Allocating Data Setson page 185.
In many aspects, subroutines and functions are the same; yet they are different in a few major aspects, such as the way they are called and the way they return values.
v Calling a subroutine
To call a subroutine, use the CALL instruction followed by the subroutine name (label or exec member name) and optionally followed by up to 20 arguments separated by commas. The subroutine call is an entire instruction.
CALL subroutine_name argument1, argument2,...
Issuing a CALL to internal label names for REXX subroutines and functions that are greater than eight characters, may have unintended results. Label names will be truncated to eight characters.
v Calling a function
To call a function, use the function name (label or exec member name) immediately followed by parentheses that can contain arguments. There can be no space between the function name and the parentheses. The function call is part of an instruction, for example, an assignment instruction.
x = function(argument1, argument2,...)
v Returning a value from a subroutine
© Copyright IBM Corp. 1988, 2001 69
What are Subroutines and Functions?
A subroutine does not have to return a value, but when it does, it sends back the value with the RETURN instruction.
RETURN value
The calling exec receives the value in the REXX special variable named RESULT.
SAY 'The answer is' RESULT
v Returning a value from a function
A function must return a value. When the function is a REXX exec, the value is returned with either the RETURN or EXIT instruction.
RETURN value
The calling exec receives the value at the function call. The value replaces the function call, so that in the following example, x = value.
x = function(argument1, argument2,...)

When to Write Subroutines vs. Functions

The actual instructions that make up a subroutine or a function can be identical. It is the way you want to use them in an exec that turns them into either a subroutine or a function. For example, the built-in function SUBSTR can be called as either a function or a subroutine. As a function, you invoke it as follows to shorten a word to its first eight characters:
x = SUBSTR('verylongword',1,8) /* x is set to 'verylong' */
As a subroutine, you would get the same results with the following instructions:
CALL SUBSTR 'verylongword', 1, 8 /* x is set to 'verylong' */ x = RESULT
When deciding whether to write a subroutine or a function, ask yourself the following questions:
v Is a returned value optional? If so, write a subroutine. v Do I need a value returned as an expression within an instruction? If so, write a
function.
The rest of this chapter describes how to write subroutines, how to write functions, and finally summarizes the differences and similarities between the two.

Writing a Subroutine

A subroutine is a series of instructions that an exec invokes to perform a specific task. The instruction that invokes the subroutine is the CALL instruction. The CALL instruction may be used several times in an exec to invoke the same subroutine.
When the subroutine ends, it can return control to the instruction that directly follows the subroutine call. The instruction that returns control is the RETURN instruction.
70
z/OS V1R1.0 TSO/E REXX Users Guide
Writing a Subroutine;
instruction(s) CALL sub1
instruction(s) EXIT
sub1: instruction(s) RETURN
Subroutines may be internal and designated by a label, or external and designated by the data set member name that contains the subroutine. The preceding example illustrates an internal subroutine named "sub1".
IMPORTANT NOTE
Because internal subroutines generally appear after the main part of the exec, when you have an internal subroutine, it is important to end the main part of the exec with the EXIT instruction.
The following illustrates an external subroutine named "sub2". To determine whether to make a subroutine internal or external, you might consider
REXX.EXEC(MAIN)
instruction(s) CALL sub2
instruction(s)
. . .
REXX.EXEC(SUB2)
instruction(s) RETURN
factors, such as: v Size of the subroutine. Very large subroutines often are external, whereas small
subroutines fit easily within the calling exec.
v How you want to pass information. It is quicker to pass information through
variables in an internal subroutine. This method is described in Passing Information by Using Variableson page 72.
v Whether the subroutine might be of value to more than one exec or user. If so,
an external subroutine is preferable.
Chapter 6. Writing Subroutines and Functions 71
Writing a Subroutine;

Passing Information to a Subroutine

An internal subroutine can share variables with its caller. Therefore you can use commonly shared variables to pass information between caller and internal subroutine. You can also use arguments to pass information to and from an internal subroutine. External subroutines, however, cannot share the same variables, and information must pass between them through arguments or some other external way, such as the data stack.
Passing Information by Using Variables
When an exec and its internal subroutine share the same variables, the value of a variable is what was last assigned, regardless of whether the assignment was in the main part of the exec or in the subroutine. In the following example, the value of answer is assigned in the subroutine and displayed in the main part of the exec. The variables number1, number2, and answer are shared.
Example of Passing Information in a Variable
/******************************* REXX ******************************/ /* This exec receives a calculated value from an internal */ /* subroutine and displays that value. */ /*******************************************************************/
number1 = 5 number2 = 10 CALL subroutine SAY answer /* Displays 15 */ EXIT
subroutine: answer = number1 + number2 RETURN
Using the same variables in an exec and its internal subroutine can sometimes create problems. In the following example, the main part of the exec and the subroutine use the same control variable, "i", for their DO loops. As a result, the DO loop repeats only once in the main exec because the subroutine returns to the main exec withi=6.
72
z/OS V1R1.0 TSO/E REXX Users Guide
Writing a Subroutine;
Example of a Problem Caused by Passing Information in a Variable
/******************************* REXX ******************************/ /* NOTE: This exec contains an error. */ /* It uses a DO loop to call an internal subroutine and the */ /* subroutine also uses a DO loop with same control variable as */ /* the main exec. The DO loop in the main exec repeats only once. */ /*******************************************************************/
number1 = 5 number2 = 10 DOi=1TO5
CALL subroutine
SAY answer /* Displays 105 */ END EXIT
subroutine: DOi=1TO5
answer = number1 + number2
number1 = number2
number2 = answer END RETURN
To avoid this kind of problem in an internal subroutine, you can use:
v The PROCEDURE instruction as described in the next topic. v Different variable names in a subroutine and pass arguments on the CALL
instruction as described in Passing Information by Using Argumentson page 74.
Protecting Variables with the PROCEDURE Instruction: When you use the PROCEDURE instruction immediately after the subroutine label, all variables used in the subroutine become local to the subroutine and are shielded from the main part of the exec. You can also use the PROCEDURE EXPOSE instruction to protect all but a few specified variables.
The following two examples show the differing results when a subroutine uses the PROCEDURE instruction and when it doesnt.
Example Using the PROCEDURE Instruction
/******************************* REXX ******************************/ /* This exec uses a PROCEDURE instruction to protect the variables */ /* within its subroutine. */ /*******************************************************************/
number1 = 10 CALL subroutine SAY number1 number2 /* displays 10 NUMBER2 */ EXIT
subroutine: PROCEDURE number1 = 7 number2 = 5 RETURN
Chapter 6. Writing Subroutines and Functions 73
Writing a Subroutine;
Exposing Variables with PROCEDURE EXPOSE: To protect all but specific variables, use the EXPOSE option with the PROCEDURE instruction, followed by the variables that are to remain exposed to the subroutine.
Example Without the PROCEDURE Instruction
/******************************* REXX ******************************/ /* This exec does not use a PROCEDURE instruction to protect the */ /* variables within its subroutine. */ /*******************************************************************/
number1 = 10 CALL subroutine SAY number1 number2 /* displays 7 5 */ EXIT
subroutine: number1 = 7 number2 = 5 RETURN
Example Using PROCEDURE EXPOSE
/****************************** REXX *******************************/ /* This exec uses a PROCEDURE instruction with the EXPOSE option to*/ /* expose one variable, number1, in its subroutine. The other */ /* variable, number2, is set to null and displays its name in */ /* uppercase. */ /*******************************************************************/
number1 = 10 CALL subroutine SAY number1 number2 /* displays 7 NUMBER2 */ EXIT
subroutine: PROCEDURE EXPOSE number1 number1 = 7 number2 = 5 RETURN
For more information about the PROCEDURE instruction, see z/OS TSO/E REXX Reference.
Passing Information by Using Arguments
A way to pass information to either internal or external subroutines is through arguments. You can pass up to 20 arguments separated by commas on the CALL instruction as follows:
CALL subroutine_name argument1, argument2, argument3,......
Using the ARG Instruction: The subroutine can receive the arguments with the ARG instruction. Arguments are also separated by commas in the ARG instruction.
ARG arg1, arg2, arg3, .....
The names of the arguments on the CALL and the ARG instructions do not have to be the same because information is not passed by argument name but by position. The first argument sent becomes the first argument received and so forth. You can also set up a template in the CALL instruction, which is then used in the corresponding ARG instruction. For information about parsing with templates, see Parsing Dataon page 87.
74
z/OS V1R1.0 TSO/E REXX Users Guide
Writing a Subroutine;
The following exec sends information to an internal subroutine that computes the perimeter of a rectangle. The subroutine returns a value in the variable perim that is specified after the RETURN instruction. The main exec receives the value in the special variable "RESULT".
Example of Passing Arguments on the CALL Instruction
/******************************** REXX ********************************/ /* This exec receives as arguments the length and width of a */
/* rectangle and passes that information to an internal subroutine. */ /* The subroutine then calculates the perimeter of the rectangle. */ /**********************************************************************/
PARSE ARG long wide CALL perimeter long, wide SAY 'The perimeter is' RESULT 'inches.' EXIT
perimeter: ARG length, width perim = 2 * length + 2 * width RETURN perim
Notice the positional relationships between long and length, and wide and width. Also notice how information is received from variable perim in the special variable RESULT.
Using the ARG Built-in Function: Another way for a subroutine to receive arguments is with the ARG built-in function. This function returns the value of a particular argument specified by a number that represents the argument position.
For instance, in the previous example, instead of the ARG instruction,
ARG length, width
you can use the ARG function as follows:
length = ARG(1) /* puts the first argument into length */ width = ARG(2) /* puts the second argument into width */
More information about the ARG function appears in z/OS TSO/E REXX Reference.

Receiving Information from a Subroutine

Although a subroutine can receive up to 20 arguments, it can specify only one expression on the RETURN instruction. That expression can be:
v A number
RETURN 55
v One or more variables whose values are substituted or when no values were
assigned, return their names
RETURN value1 value2 value3
v A literal string
RETURN 'Work complete.'
v An arithmetic, comparison, or logical expression whose value is substituted.
RETURN 5 * number
Chapter 6. Writing Subroutines and Functions 75
Writing a Subroutine;
Example - Writing an Internal and an External Subroutine
Write an exec that plays a simulated coin toss game of heads or tails between the computer and a user and displays the accumulated scores. Start off with the message, "This is a game of chance. Type 'heads', 'tails', or 'quit' and press the Enter key."
This means that there are four possible inputs:
v HEADS v TAILS v QUIT v None of these three (not valid response).
Write an internal subroutine without arguments to check for valid input. Send valid input to an external subroutine that compares the valid input with a random outcome. Use the RANDOM built-in function as, RANDOM(0,1), and equate HEADS = 0, TAILS = 1. Return the result to the main program where results are tallied and displayed.
Good luck!
ANSWER
Possible Solution (Main Exec)
/**************************** REXX *********************************/ /* This exec plays a simulated coin toss game between the computer */ /* and a user. The user enters heads, tails, or quit. The user */ /* is first checked for validity in an internal subroutine. */ /* An external subroutine uses the RANDOM build-in function to */ /* obtain a simulation of a throw of dice and compares the user */ /* input to the random outcome. The main exec receives */ /* notification of who won the round. Scores are maintained */ /* and displayed after each round. */ /*******************************************************************/
SAY 'This is a game of chance. Type "heads", "tails", or "quit" SAY ' and press ENTER.' PULL response computer = 0; user = 0 /* initialize scores to zero */ CALL check /* call internal subroutine, check */ DO FOREVER
CALL throw response /* call external subroutine, throw */
IF RESULT = 'machine' THEN /* the computer won */
computer = computer + 1 /* increase the computer score */
ELSE /* the user won */
user = user + 1 /* increase the user score */
SAY 'Computer score = ' computer ' Your score = ' user SAY 'Heads, tails, or quit?' PULL response
CALL check /* call internal subroutine, check */ END EXIT
76
z/OS V1R1.0 TSO/E REXX Users Guide
Writing a Subroutine;
Possible Solution (Internal Subroutine named CHECK)
check: /*******************************************************************/ /* This internal subroutine checks for valid input of "HEADS", */ /* "TAILS", or "QUIT". If the user entered anything else, the */ /* subroutine tells the user that it is an invalid response and */ /* asks the user to try again. The subroutine keeps repeating */ /* until the user enters valid input. Information is returned to */ /* the main exec through commonly used variables. */ /*******************************************************************/
DO UNTIL outcome = 'correct'
SELECT
WHEN response = 'HEADS' THEN
outcome = 'correct'
WHEN response = 'TAILS' THEN
outcome = 'correct'
WHEN response = 'QUIT' THEN
EXIT
OTHERWISE
outcome = 'incorrect' SAY "That's not a valid response. Try again!" SAY "Heads, tails, or quit?" PULL response
END END RETURN
/****************************** REXX *******************************/ /* This external subroutine receives the valid input from the user,*/ /* analyzes it, gets a random "throw" from the computer and */ /* compares the two values. If they are the same, the user wins. */ /* If they are different, the computer wins. The outcome is then */ /* returned to the calling exec. */ /*******************************************************************/

Writing a Function

A function is a series of instructions that an exec invokes to perform a specific task and return a value. As was described in Chapter 5. Using Functionson page 61, a function may be built-in or user-written. An exec invokes a user-written function the same way it invokes a built-in function by the function name immediately
Possible Solution (External Subroutine named THROW)
ARG input IF input = 'HEADS' THEN
userthrow = 0 /* heads = 0 */ ELSE
userthrow = 1 /* tails = 1 */
compthrow = RANDOM(0,1) /* choose a random number between */
/*0and1*/
IF compthrow = userthrow THEN
outcome = 'human' /* user chose correctly */ ELSE
outcome = 'machine' /* user didn't choose correctly */
RETURN outcome
Chapter 6. Writing Subroutines and Functions 77
Writing a Function
followed by parentheses with no blanks in between. The parentheses can contain up to 20 arguments or no arguments at all.
function(argument1, argument2,...)
or
function()
A function requires a returned value because the function call generally appears in an expression.
x = function(arguments1, argument2,...)
When the function ends, it may use the RETURN instruction to send back a value to replace the function call.
instruction(s)
x=func1(arg1,arg2)
instruction(s) EXIT
Func1: instruction(s) RETURN value
Functions may be internal and designated by a label, or external and designated by the data set member name that contains the function. The previous example illustrates an internal function named "func1".
IMPORTANT NOTE
Because internal functions generally appear after the main part of the exec, when you have an internal function, it is important to end the main part of the exec with the EXIT instruction.
The following illustrates an external function named "func2".
78
z/OS V1R1.0 TSO/E REXX Users Guide
Writing a Function
REXX.EXEC(MAIN)
instruction(s)
x=func2(arg1) instruction(s) . . . exit
REXX.EXEC(FUNC2)
ARG var1 instruction(s) RETURN value
To determine whether to make a function internal or external, you might consider factors, such as:
v Size of the function. Very large functions often are external, whereas small
functions fit easily within the calling exec.
v How you want to pass information. It is quicker to pass information through
variables in an internal function. This method is described in the next topic under Passing Information by Using Variables.
v Whether the function might be of value to more than one exec or user. If so, an
external function is preferable.
v Performance. The language processor searches for an internal function before it
searches for an external function. For the complete search order of functions, see Search Order for Functionson page 134.

Passing Information to a Function

When an exec and its internal function share the same variables, you can use commonly shared variables to pass information between caller and internal function. The function does not need to pass arguments within the parentheses that follow the function call. However, all functions, both internal and external, must return a value.
Passing Information by Using Variables
When an exec and its internal function share the same variables, the value of a variable is what was last assigned, regardless of whether the assignment was in the main part of the exec or in the function. In the following example, the value of answer is assigned in the function and displayed in the main part of the exec. The variables number1, number2, and answer are shared. In addition, the value of answer replaces the function call because answer follows the RETURN instruction.
Chapter 6. Writing Subroutines and Functions 79
Writing a Function
Example of Passing Information in a Variable
/****************************** REXX *******************************/ /* This exec receives a calculated value from an internal */ /* function and displays that value. */ /*******************************************************************/
number1 = 5 number2 = 10 SAY add() /* Displays 15 */ SAY answer /* Also displays 15 */ EXIT
add: answer = number1 + number2 RETURN answer
Using the same variables in an exec and its internal function can sometimes create problems. In the following example, the main part of the exec and the function use the same control variable, "i", for their DO loops. As a result, the DO loop repeats only once in the main exec because the function returns to the main exec with i =
6.
Example of a Problem Caused by Passing Information in a Variable
/****************************** REXX *******************************/ /* This exec uses an instruction in a DO loop to call an internal */ /* function. A problem occurs because the function also uses a DO */ /* loop with the same control variable as the main exec. The DO */ /* loop in the main exec repeats only once. */ /*******************************************************************/
number1 = 5 number2 = 10 DOi=1TO5
SAY add() /* Displays 105 */ END EXIT
add: DOi=1TO5
answer = number1 + number2
number1 = number2
number2 = answer END RETURN answer
To avoid this kind of problem in an internal function, you can use:
v The PROCEDURE instruction as described in the next topic. v Different variable names in a function.
Protecting Variables with the PROCEDURE Instruction: When you use the PROCEDURE instruction immediately following the function label, all variables used in the function become local to the function and are shielded from the main part of the exec. You can also use the PROCEDURE EXPOSE instruction to protect all but a few specified variables.
80
z/OS V1R1.0 TSO/E REXX Users Guide
Writing a Function
The following two examples show the differing results when a function uses the PROCEDURE instruction and when it doesnt.
Example Using the PROCEDURE Instruction
/****************************** REXX *******************************/ /* This exec uses a PROCEDURE instruction to protect the variables */ /* within its function. */ /*******************************************************************/
number1 = 10 SAY pass() number2 /* Displays 7 NUMBER2 */ EXIT
pass: PROCEDURE number1 = 7 number2 = 5 RETURN number1
Example Without the PROCEDURE Instruction
/******************************** REXX *****************************/ /* This exec does not use a PROCEDURE instruction to protect the */ /* variables within its function. */ /*******************************************************************/
number1 = 10 SAY pass() number2 /* displays 7 5 */ EXIT
pass: number1 = 7 number2 = 5 RETURN number1
Exposing Variables with PROCEDURE EXPOSE: To protect all but specific variables, use the EXPOSE option with the PROCEDURE instruction, followed by the variables that are to remain exposed to the function.
Example Using PROCEDURE EXPOSE
/****************************** REXX *******************************/ /* This exec uses a PROCEDURE instruction with the EXPOSE option to*/ /* expose one variable, number1, in its function. */ /*******************************************************************/
number1 = 10 SAY pass() number1 /* displays 5 7 */ EXIT
pass: PROCEDURE EXPOSE number1 number1 = 7 number2 = 5 RETURN number2
For more information about the PROCEDURE instruction, see z/OS TSO/E REXX Reference.
Passing Information by Using Arguments
A way to pass information to either internal or external functions is through arguments. You can pass up to 20 arguments separated by commas in a function call.
Chapter 6. Writing Subroutines and Functions 81
Writing a Function
function(argument1,argument2,argument3,..........)
Using the ARG Instruction: The function can receive the arguments with the ARG instruction. Arguments are also separated by commas in the ARG instruction.
ARG arg1,arg2,arg3 .......
The names of the arguments on the function call and the ARG instruction do not have to be the same because information is not passed by argument name but by position. The first argument sent becomes the first argument received and so forth. You can also set up a template in the function call, which is then used in the corresponding ARG instruction. For information about parsing templates, see Parsing Dataon page 87.
The following exec sends information to an internal function that computes the perimeter of a rectangle. The function returns a value in the variable perim that is specified after the RETURN instruction. The main exec uses the value in perim to replace the function call.
Example of an Internal Function
/******************************** REXX *********************************** / /* This exec receives as arguments the length and width of a */
/* rectangle and passes that information to an internal function */ /* named perimeter. The function then calculates the perimeter of */ /* the rectangle. */ /*************************************************************************** /
PARSE ARG long wide SAY 'The perimeter is' perimeter(long,wide) 'inches.' EXIT
perimeter: ARG length, width perim = 2 * length + 2 * width RETURN perim
Notice the positional relationships between long and length, and wide and width. Also notice that information is received from variable perim to replace the function call.
Using the ARG Built-in Function: Another way for a function to receive arguments is with the ARG built-in function. This built-in function returns the value of a particular argument specified by a number that represents the argument position.
For instance, in the previous example, instead of the ARG instruction,
ARG length, width
you can use the ARG function as follows:
length = ARG(1) /* puts the first argument into length */ width = ARG(2) /* puts the second argument into width */
More information about the ARG function appears in z/OS TSO/E REXX Reference.
82
z/OS V1R1.0 TSO/E REXX Users Guide
Loading...