0% found this document useful (0 votes)
20 views

Basics of Rexx

The document provides information about the REXX programming language including: - REXX is an interactive programming language that can execute system commands and allows requesting information from terminals, displaying output, executing TSO commands under program control, developing utilities, and reading/writing files. - Key features of REXX include ease of use, free format, convenient built-in functions, debugging capabilities, and being an interpreted language. - The mandatory statement in REXX is /*REXX*/ and statements use free format and can be terminated with a semicolon or end-of-line. - Programs are called REXX EXECs and are created by allocating a dataset, with

Uploaded by

Nitin Garg
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
20 views

Basics of Rexx

The document provides information about the REXX programming language including: - REXX is an interactive programming language that can execute system commands and allows requesting information from terminals, displaying output, executing TSO commands under program control, developing utilities, and reading/writing files. - Key features of REXX include ease of use, free format, convenient built-in functions, debugging capabilities, and being an interpreted language. - The mandatory statement in REXX is /*REXX*/ and statements use free format and can be terminated with a semicolon or end-of-line. - Programs are called REXX EXECs and are created by allocating a dataset, with

Uploaded by

Nitin Garg
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 80

Basics of Rexx

REXX (Restructured EXtended eXecutor) is a powerful interactive programming


language that can execute system commands, such as TSO, ISPF etc. It allows
you to:

 Request information from the terminal and Display output on terminal.


 Execute TSO commands under program control.
 Develop custom-made utilities.
 Read and write files.

REXX is more modern, powerful interpreted command language, and is


procedural language that allows programs and algorithms to be written in a
clear and structured way. It is easy to use by experts and casual users alike.

REXX has the capability to issue commands to its host environment and to call
programs and function written in other languages.

Features of REXX:
The features of REXX are as follows:

 Ease of use
 Free Format
 Convenient built-in functions
 Debugging capabilities
 Interpreted language
 Extensive parsing capabilities

General Format of REXX Statements:


The mandatory statement in REXX is /*REXX*/ . This statement should be
included at the beginning of every REXX programs. REXX supports free-format
statements:

 Which can appear anywhere between columns 1 and 72.


 Can have any number of embedded blanks.
 Can be terminated with either an end-of-line character or a semicolon (;).
 More than one statement can be included in one line separated from each
other by a semicolon.
 One statement can span more than one line, in which case a comma at
the end of the line indicates a continuation of the statement.
 Comments appear between the delimiters /* and */ and can span one or
more lines.

The general form of a REXX statement is [Label:] term [;] where term is either
a comment or an expression.

Example:
/*REXX*/
/* Simple Statement*/ Say ‘Hi’

/*Statement using comma to span two lines*/ Say ‘Using comma’,


‘To span two lines’

/*Statements using semicolon in a single line*/


Say ‘Semicolon’; Say ‘used to write multiple statements in a single line’.

Creation of REXX EXEC:


Before you can write a REXX program called EXEC, you need to create a dataset
to contain the exec. The dataset may 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).

It is recommended to allocate the dataset with your prefix as the first qualifier,
any name as the second qualifier and preferably exec as the third qualifier.

For Example, RACFID.SOURCE.EXEC

Tips and Tricks:

Always it is better to call REXX programs as REXX exec.

Instructions in REXX EXEC:


REXX instructions are categorized as follows:

 Keyword
 Assignment
 Label
 Null
 Command

Keyword:
A keyword instruction tells the language processor to perform some operation.
It begins with a REXX keyword that identifies what the language processor is to
do. For example (SAY displays a string on the screen).

Assignment:
An assignment gives a value to a variable or changes the current value of the
variable.

For example (A=4).

Label:
A label is a symbolic name followed by a colon. A label can contain either single-
or double- byte characters or a combination of both. A label identifies a portion
of the exec and is commonly used in subroutines and functions, and with the
signal instruction.

NULL:
A null is a comment or a blank line, which is ignored by the language processor
but make an exec easier to read.

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 ("TIME").


Summary:
 The only mandatory statement in REXX is '/* REXX */'.
 REXX statements are delimited by ';' and Comma is used the continuation
character.

Terminal Input-Output
Terminal Input:
The Terminal instruction 'PULL' is used to receive input from the terminal. PULL
opens an input field on the terminal and waits for you to press Enter. This
instruction takes information from the data stack, and when the data stack is
empty.

For example (PARSE UPPER PULL causes the same result as PULL in that it will
changes character information to uppercase before assigning it to one or more
variables

ARG Instruction: Takes information passed as arguments to an exec, function,


or subroutine, and puts it into one or more variable names.

For example (PARSE UPPER ARG causes the same result as ARG in that it will
changes character information to uppercase before assigning it to one or more
variables).

PARSE VALUE…. WITH INSTRUCTION: Parses a specified expression, such as a


literal string, into one or more variable names that follow the WITH sub
keyword.

Example:
PARSE VALUE 'Knowledge is Power' WITH word1 word2 word3

For the above statement the word1 contains 'Knowledge', word2 contains 'is'
and word3 contains 'Power'.

Terminal Output:
The Terminal instruction 'SAY' is used to display output or displays the line on
the terminal.

Example:
Say 'Enter your Age'
Pull Age /* What ever you type as your age is converted into upper case
and stored in age */
Parse Pull Age /* same as above, but input is not converted to upper
case */

Say 'Enter your First and Last name'


Pull fname lname /* REXX assumes variables are delimited by spaces */

Passing Arguments:
The values which are passed to an exec are usually called arguments.
Arguments can consist of one word or a string of words separated by blanks.
Each argument should be separated by a comma.

ARG number1, number2


Sum = number1 + number2
Say 'Sum of two numbers is ' Sum

Summary:
 PULL & SAY are the basic I-O statements in REXX.
 PARSE command is used for string manipulation.
 Special keywords such as SIGNAL, VAR, RC cannot be used as variable
name.
 Data types of variables need not be declared in REXX.

Execution of Rexx program


There are two ways to execute the REXX exec.
1. Executing Explicitly
2. Executing Implicitly

Executing Explicitly:
To execute explicitly, we have to use EXEC command followed by the data set
name, which is done as follows

TSO EX 'RACFID.SOURCE.EXEC(SAMPLE)' where 'RACFID.SOURCE.EXEC' is the


PDS name and 'SAMPLE' is the REXX exec name.

Executing Implicitly:
The implicit execution is done as follows:

TSO SAMPLE where SAMPLE is the exec name

Implicit execution can be done only if the PDS containing REXX programs has
allocated to the system files (SYSEXEC or SYSPROC) using the TSO alloc
command or the PDS is allocated to an application CLIST or EXEC using TSO
ALTLIB command.

Example:
/*******REXX**********/
Say 'This is the sample REXX exec'

TSO EX 'RACFID.SOURCE.EXEC(SAMPLE)' EX – EXECUTING


EXPLICITLY
TSO SAMPLE – EXECUTING IMPLICITLY

SAMPLE OUTPUT: This is the sample REXX exec

Rexx Example:
REXX program which uses the basics of REXX, so far we explained.
/* REXX */
SAY 'ENTER THE FIRST NUMBER:' PULL NUMBER1
SAY 'ENTER THE SECOND NUMBER:' PULL NUMBER2
SAY 'ENTER THE THIRD NUMBER:' PULL NUMBER3
GREAT = VALUES (NUMBER1, NUMBER2, NUMBER3)
SAY 'GREATEST NUMBER IS:' GREAT
EXIT 0
VALUES:
IF NUMBER1 > NUMBER2 THEN
IF NUMBER1 > NUMBER3 THEN
XE=NUMBER1
ELSE
XE=NUMBER3
ELSE
IF NUMBER2 > NUMBER3 THEN
XE=NUMBER2
ELSE
XE=NUMBER3
RETURN XE

Explanation:
 This exec will get the input of three numbers from the user.
 And displays the greatest of three numbers.
 Coding standards that needs to be followed.
 Provide proper comments as needed.
 Indent the code, since REXX instructions can begin in any column.

Rexx Operators
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:
The arithmetic operators used in REXX numeric expressions are as follows.
Arithmetic operators work on valid numeric constants or on variables that
represent valid numeric constants.

Operator Meaning

+ Add

- Subtract

* Multiply

/ Divide

% Divide and return a whole number without a remainder

// Divide and return the whole number only

** Raise a number to a whole number power

- -number (Negate the number)

+ +number (Add the number to 0)

Example:
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 */

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
*/
/* 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'.'

Comparison Operators:
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 and B = 3, then the results of the previous comparison


questions are:

 (A = B) Does 4 = 3? 0 (False)
 (A > B) Is 4 > 3? 1 (True)
 (A < B) Is 4 < 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

>= 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.

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 Instructions.

Example Using Comparison Expressions:


/
**********************************REXX******************************
**/
/* This exec compares what you paid for lunch for two days in a row
*/
/* and then comments on the comparison the exec when it is run
*/
/
********************************************************************
**/
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."

Logical (Boolean) Operators:


The logical operators are as follows.

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 */

Logical NOT
Returns the opposite response. For example:
Prefix \
\ 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.'
IF ((season = 'winter') | (snowing ='yes')) & (broken_leg ='no') THEN
\______/ \______/ \_______/
ELSE false true
true SAY 'Stay home.'
\_____________________/ /
true /
\______________________________________/
true

Explanation:
When arguments passed to this example are "spring yes no", the IF clause
translates as follows.

As a result, when you run the exec, you see the message - 'Go skiing.'

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

Concatenate terms and place one blank in between. Terms that are separated by
blank more than one blank default to one blank when read. For example:
SAY true blue /* result is TRUE BLUE */

Concatenate terms and place no blanks in between. For example:


||
(8 / 2) || (3 * 3) /* result is 49 */

Concatenate terms and place no blanks in between. For example:


abuttal
per_cent'%' /* if per_cent = 50, result is 50% */
Example 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.

/****************************** 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: baseball $5

Operator Precedence:
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 ...

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.

1. Prefix operators
2. Power (exponential)
3. Multiply and divide
4. Add and subtract
5. Concatenation operators
6. Comparison operators
7. Logical AND
8. 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. And, the result of the expersion is
0.

Summary:
 Various operators like arithmetic, logical, comparative and concatenation
operators are available for developing applications.

Conditional Instructions

After completing this chapter, you will be able to describe the conditional
statements and it's different types with examples.

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:
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 semi-colon.

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.

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?'

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 Using Missing Instructions:


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.
/********************************* REXX
*******************************/
/* This exec demonstrates what can happen when you do not include
DOs,*/
/* END's and ELSEs in nested IF/THEN/ELSE instructions. */
/
**********************************************************************/
weather = 'fine'
equipment = 'ball'
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:

Output:
What a lovely day!

Shall we take our raincoats?

SELECT/WHEN/OTHERWISE/END Instruction:
To select one of any number of choices, use the
SELECT/WHEN/OTHERWISE/END instruction.

The syntax of SELECT/WHEN/OTHERWISE/END instruction as follows:


sasasass
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. Each SELECT must end with an END.
Indenting each WHEN makes an exec easier to read.

Example Using SELECT/WHEN/OTHERWISE/END:


/*************************** REXX ************************************/
/* This exec receives input with a person's age and sex. In reply it */
/* display a person's status as follows */
/* BABIES – under 5. */
/* GIRLS – female 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 */
status = 'BOY'
ELSE
status = 'GIRL' /* girl between 5 and 12 */
END
WHEN age < 20 THEN
status = 'TEENAGER' /* person between 13 and 19 */
OTHERWISE
IF sex = 'M' THEN /* man 20 or older */
status = 'MAN'
ELSE /* woman 20 or older */
status = 'WOMEN'
END
SAY 'This person should be counted as a' status '.'

Summary:
 SELECT case structure and IF..ELSE conditional statements are used for
conditional processing.
 DO..END are used to execute a block of statements.

Looping Instructions
After completing this chapter, you will be able to describe the Looping and
Iteration and Stem variables available in REXX to develop simple applications.

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
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 = 1 TO 5
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 = 1 TO 10 BY 2
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 = 1 to 10
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.

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 doesn't stop the loop, you can press the
attention interrupt key again, type HE for halt execution, and press the Enter
key.
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

Example Using a DO FOREVER Loop:


/******************************* REXX *********************************/
/* This 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
EXIT
ELSE
DO
"PRINTDS DA("dataset_name")"
SAY dataset_name 'printed.'
END
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:
Example Using the LEAVE Instruction:
/******************************** REXX ********************************/
/* This exec uses the LEAVE instruction to exit from a DO FOREVER loop*/
/* that sends data set 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.'
EXIT

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 = 1 TO 10
IF count = 8 THEN
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

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.

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 Instruction. 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 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.'

DO UNTIL Loops:
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.

Example Using DO UNTIL:


/****************************** REXX ***********************************/
/*This exec uses a DO UNTIL loop to ask for a password. If the password*/
/* is incorrect password three times, the loop ends */
/***********************************************************************/
password = 'abracadabra'
time = A
DO UNTIL (answer = password) | (time = 3)
SAY 'What is the password?'
PULL answer
time = time + 1
END

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 = 1 TO 10 WHILE quantity < 5A
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 = 3A (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 = 1 TO 10 UNTIL quantity > 5A
quantity = quantity + number
SAY 'Quantity = 'quantity ' (Loop 'number')'
END

Nested DO Loops:
Like nested IF/THEN/ELSE instructions, DO loops can also be within other DO
loops. A simple example follows:

DO outer = 1 TO 2
DO inner = 1 TO 2
SAY 'HIP'
END
SAY 'HURRAH'
END

The output from this example is as follows:


HIP
HIP
HURRAH
HIP
HIP
HURRAH

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 = 1 TO 2
DO inner = 1 TO 2
IF inner > 1 THEN
LEAVE inner
ELSE
SAY 'HIP'
END
SAY 'HURRAH'
END

The result is as follows:

HIP
HURRAH
HIP
HURRAH

Summary:
 The following model of DO..END may be used for looping purpose
DO modifiers
instruction(s)
END


 Modifiers can be WHILE, UNTIL, FORVER, VARIABLE or a NUMBER.

Interrupt Instructions

After completing this chapter, you will be able to describe the following.

1. Interrupt instructions
2. Stem variables available in REXX to develop simple applications

Instructions that interrupt the flow of an exec can cause the exec to.

 Terminate (EXIT)
 Skip to another part of the exec marked by a label (SIGNAL)
 Go temporarily to a subroutine either within the exec or outside the exec
(CALL/RETURN).

EXIT Instruction:
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.

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.

/*********************************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 A 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 = A /* 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.

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.

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.

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.

Stem Variables:
When working with compound variables, it is often useful to initialize an entire
collection of variables to the same value. You can do this easily with a stem.A
stem is the first variable name and first period of the compound variable.Thus
every compound variable begins with a stem. The following are stems:

1. FRED
2. Array
3. employee

You can alter all the compound variables in an array through the stem. you can
alter all the compound variables in an array through the stem.assignment
instruction:

employee. = 'Nobody'

As a result, all compound variables beginning with employee. , whether or not


they were previously assigned, return the value Nobody. Compound variables
that are assigned after the stem assignment are not affected

SAY employee.5/* Displays 'Nobody' */

REXX EXECIO and some TSO functions return information in compound


variables. In the following example, OUTTRAP function doing this, in which
OUTTRAP sets the compound variables LINE.1 through LINE.n, where n is the
number of lines returned. In order to tell you how many lines were returned,
OUTTRAP sets LINE.0 to that number.
Some other functions and EXECIO do this as well, but please don‘t assume that
the 0th element always tells you how many elements there are.

CALL OUTTRAP ('LINE.')


“LISTC”
DO I = 1 TO LINE.0
SAY LINE.I
END

Example of STEM variable:


/*This exec uses stem variable to store students name and their marks */
/*and displays them respectively */
/********************************REXX**********************************/
SAY 'ENTER THE NUMBER OF STUDENT IN THE CLASS'
PULL NUM

DO I = 1 TO NUM
SAY 'ENTER THE NAME OF THE STUDENT'
PULL NAME
STUDENT.I = NAME

DO J=1 TO 3
SAY 'ENTER THE MARKS FOR SUBJECT' J
PULL MARKS
STUDENT.I.J = MARKS
END
END

/* DISPLAYING THE NAME AND MARKS OF THE STUDENTS */


DO I = 1 TO NUM
SAY 'STUDENT NAME :-' STUDENT.I

DO J=1 TO 3
SAY 'MARKS FOR SUBJECT' J 'IS :-' STUDENT.I.J
END
END

Example 1:
Write a program that adds, subtracts, multiplies, divides, finds the integer
quotient, remainder, exponential two numbers A and B where A = 5 and B = 2.
The same program must use "strictly equal" comparative operator to compare
between "Jacob" and "JACOB".

Also, use concatenation operators on three strings and display the result.

Code:
/********************************REXX********************************/
A = 5
B = 2
SAY 'THE VALUE OF A IS ' A
SAY 'THE VALUE OF B IS ' B
ADDITION = A + B
SAY 'ADDITION OF A AND B GIVES:' ADDITION

SUBTRACTION = A - B
SAY 'SUBTRACTION OF A AND B GIVES:' SUBTRACTION

MULTIPLICATION = A * B
SAY 'MULTIPLICATION OF A AND B GIVES:' MULTIPLICATION

DECIMALQUOTIENT = A / B
INTEGERQUOTIENT = A % B
SAY 'DIVISION OF A and B GIVES: ' DECIMALQUOTIENT
SAY 'INTEGER QUOTIENT OF A AND B IS:' INTEGERQUOTIENT
REMAINDER = A // B
EXPONENTIAL = A ** B
SAY 'REMAINDER WHEN A IS DIVIDED BY B IS : ' REMAINDER
SAY 'EXPONENTIAL OF A AND B IS:' EXPONENTIAL
NAME = 'JACOB'
NAME1 = 'Jacob'
say 'names are : ' name name1
if name == name1 then
say 'names are strictly equal'
else
say 'names are not strictly equal'

I = IBM
M = MAINFRAME
T = TUTORIAL
IMT = I || M || T
SAY 'IMT:' IMT
EXIT
Explanation:
 The program uses the SELECT case structure and IF..ELSE conditional
statements for conditional processing
 Comments can be introduced, if needed, for better understanding of the
program
 The code can be written in blocks to enhance the readability of the
program

Coding Standards followed:

 Proper comments must be used for better understanding


 Indentation must be appropriate for better readability

Example 2:
Write a program that shows the difference in functioning of the various ways of
looping.

/******************************* REXX *********************************/


DO 3 /* REPEATS 3 TIMES */
SAY 'I AM IN COGNIZANT'
END
DO I = 3 TO 0 BY -1/* Decrement the counter by 1 */
SAY 'VALUE OF I IS:' I
END

DO K = 1 TO 8 BY 2 FOR 3 /* LOOP WILL BE EXECUTED 3 TIMES */


SAY 'VALUE OF K IS:' K /* SINCE FOR 3 OVERRIDES THE */
END /* K=1 TO 8 BY 2 */

/* THIS LOOP WOULD DISPLAY: 1, 3, 5, 7 */


/*Note that condition is checked after executing the loop */
DO I = 1 TO 20 BY 2 UNTIL I > 6
SAY 'VALUE OF I IS:'' I
END

/* THIS LOOP WOULD DISPLAY 1 TO 7*/


/* The condition is evaluated before executing the loop */
SWITCH = 1 /* SWITCH IS A LOGICAL VARIABLE */
DO I = 1 TO 20 WHILE SWITCH
SAY 'VALUE OF I IS:' I
IF I = 7 THEN
SWITCH = 0
END

/* THIS LOOPS EXECUTES FORVER. TO EXIT FROM THE LOOP USE LEAVE */
M=0
DO FOREVER
SAY 'EXECUTE THIS LOOP FOREVER'
M = M+1
IF M=10 THEN
LEAVE
END
EXIT

Explanation:
 The various looping constructs are used to execute a certain statement in
a loop.
 Comments can be introduced, if needed, for better understanding of the
program
 The code can be written in blocks to enhance the readability of the
program
 Avoid using SIGNAL from looping constructs

Coding Standards followed:

 Proper comments must be used for better understanding


 Indentation must be appropriate for better readability

Summary:
 Interrupt instructions interrupt the flow of an execution.
 STEM variables can be used as an array and can be populated using
looping constructs.

Test Your Understanding:


1. What will the following program display on the screen?

/********************************* REXX ******************************


Father = 1
Mother = 1
Children = 3
SAY "There are" Father + Mother + Children "people in this family."

2. What is the value of:


1. 6 - 4 + 1
2. 6 - (4 + 1)
3. 6 * 4 + 2
4. 6 * (4 + 2)
5. 24 % 5 / 2
3. 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?

Yesterday's Today's
Lunch Lunch
4.42 3.75
3.50 3.50
3.75 4.42

4. What is the result (0 or 1) of the following expressions?

"Apples" = "Oranges"
" Apples" = "Apples"
" Apples" == "Apples"
100 = 1E2
100 \= 1E2
100 \== 1E2

5. 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!"

6. A college is inexpensive, did not offer a scholarship, is reputable, but is


over 1000 miles away. Should the student apply?
7. What are the answers to the following examples?
1. 22 + (12 * 1)
2. -6 / -2 > (45 % 7 / 2) - 1
3. 10 * 2 - (5 + 1) // 5 * 2 + 15 – 1
8. What happens when the following exec runs?

DO outer = 1 TO 3
SAY /* Write a blank line */
DO inner = 1 TO 3
SAY 'Outer' outer 'Inner' inner
END
END

Rexx User Functions

After completing this chapter, you will be able to define and apply user defined
function.

Function:
A function can be termed as a common routine which when invoked performs a
pre-defined set of instructions and returns a value to the place from where it is
invoked.

Normally a function call is performed by issuing the function name followed by


parentheses within which the arguments passed to the function can be
specified.

For example,

SUM(A,B)

Where SUM is the function and A & B are the arguments passed to the function.
Note:

There should be no space between the function name and the left parenthesis.

Following are the general characteristics of a function:

1. A function may or may not receive input arguments.


2. Any function must return a value.
3. After executing the function, the function call is replaced by the value
returned by the function.

For example,

SAY 7 + SUM(7,9)

Let us say, the function SUM(7,9) returns a value of 16. After executing the
function, the above statement will be treated as

SAY 7 + 16

And 23 will be displayed.

A function call can contain up to 20 arguments separated by commas. Each


argument can be one or more of the following:

Type of Argument Sample

Blank Function( )

Constant Function(55)

Symbol Function(symbol_name)

Literal String Function(“Literal String”)

Another Function Function(Function(Arguments

Combination of argument types Function('Literal String', 55)


A function call generally appears in an expression. Therefore a function call, like
an expression, does not usually appear in an instruction by itself.

User Defined Functions:


The arguments passed to the subroutine can be received by ARG or PARSE ARG
command. A maximum of 20 arguments can be received. After performing the
user-designated task, the function returns a value to the calling module through
RETURN command. As soon as RETURN command is encountered, the control
will transfer back to the place where function call is made.

Set of instructions which might have to be performed often in a REXX module


can be grouped together to form a function, which can be executed whenever it
is needed.

For example, it may be needed to find maximum of three numbers multiple


times in a REXX module. The logic to find the maximum of three numbers can
be formulated as a common routine MAX which can be invoked as a function as
follows:

HIGH(number1,number2,number3)

To find the maximum of 45, -2, number, 199, and assign the maximum value
into a variable by name 'MAXVAL', the following instruction could be used:

MAXVAL = HIGH(45,-2,199)

Example:
/* REXX */
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

Summary:
 A function can be termed as a common routine which when invoked
performs a pre-defined set of instructions and returns a value to the place
from where it is invoked.
 Functions are similar to subroutines except for the way in which they are
called and the way the values are returned.
 Functions are classified as user-defined functions and built-in functions.

Rexx Built-in Functions

After completing this chapter, you will be able to describe how to apply built-in
functions.

There are over 50 functions built into the language processor. The built-in
functions fall into the following categories:

 Arithmetic functions:

These functions evaluate numbers from the argument and return a


particular value.

 Comparison functions:

These functions compare numbers and/or strings and return a value.

 Conversion functions:
These functions convert one type of data representation to another type
of data representation.

 Formatting functions:

These functions manipulate the characters and spacing in strings supplied


in the Argument.

 String manipulating functions:

These functions analyze a string supplied in the argument (or a variable


representing a string) and return a particular value.

 Miscellaneous functions:

These functions do not clearly fit into any of the other categories.

The following tables briefly describe the functions in each category.

Arithmetic Functions:
Function Description

ABS Returns the absolute value of the input number.

MAX Returns the largest number from the list specified formatted according to the current NUMERIC set

MIN Returns the smallest number from the list specified formatted according to the current NUMERIC s

RAND
Returns a quasi-random, non-negative whole number in the range specified.
OM

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 number of decimal places.

Comparison Functions:
Function Description

COMPARE Returns 0 if the two input strings are identical. Otherwise, returns the position of the first cha
DATATYPE Returns a string indicating the input string is a particular data type, such as a number or chara

Conversion Functions:
Function Description

B2X Returns a string, in character format, that represents the input binary string converted to hexadecima

C2D Returns the decimal value of the binary representation of the input string. (Character to Decimal)

C2X Returns a string, in character format, that represents the input string converted to hexadecimal. (Cha

D2C Returns a string, in character format, that represents the input decimal number converted to binary.

D2X Returns a string, in character format, that represents the input decimal number converted to hexadec

X2B Returns a string, in character format, that represents the input hexadecimal string converted to binar

X2C Returns a string, in character format, that represents the input hexadecimal string converted to chara

X2D Returns the decimal representation of the input hexadecimal string. (Hexadecimal to Decimal)

Formatting Functions:
Function Description

CENTER /
Returns a string of a specified length with the input string centered in it, with pad characters adde
CENTRE

COPIES Returns the specified number of concatenated copies of the input string.

FORMAT Returns the input number, rounded and formatted.

LEFT Returns a string of the specified length, truncated or padded on the right as needed.

RIGHT Returns a string of the specified length, truncated or padded on the left as needed.

SPACE Returns the words in the input string with a specified number of pad characters between each wo

String Manipulating Functions:


Function Description

ABBRE
Returns a string indicating if one string is equal to the specified number of leading characters of another string.
V

DELSTR Returns a string after deleting a specified number of characters, starting at a specified point in the input string.

DEL
Returns a string after deleting a specified number of words, starting at a specified word in the input string.
WORD

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.

LASTPO
Returns the starting character position of the last occurrence of one string in another.
S

LENGT
Returns the length of the input string.
H

POS Returns the character position of one string in another.

REVERS
Returns a character string, the characters of which are in reverse order (swapped end for end).
E

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.

SUBWO
Returns a portion of the input string starting at a specified word number.
RD

WORD Returns a word from an input string as indicated by a specified number.

WORDI
Returns the character position in an input string of the first character in the specified word.
NDEX

WORDL
Returns the length of a specified word in the input string.
ENGTH

WORDP
Returns the word number of the first word of a specified phrase in the input string.
OS

WORDS Returns the number of words in the input string


Miscellaneous Functions:
Function Description

ADDRESS Returns the name of the environment to which commands are currently being sent.

ARG Returns an argument or information about the argument strings passed to a program or internal routine.

BITAND Returns a string composed of the two input strings logically ANDed together, bit by bit.

BITOR Returns a string composed of the two input strings logically ORed together, bit by bit.

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.

QUEUED Returns the number of lines remaining in the external data queue at the time when the function is invoked.

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.

Example:
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 the user a message indicating the shortened name. Use LENGTH and
SUBSTR built-in functions.

/**************************REXX****************************************/
/* This Exec tests the length of a name for a dataset member. If the */
/* name exceeds 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 first 8 characters */
SAY 'THE MEMBER NAME YOU ENTERED WAS TOO LONG'
SAY MEMBERNAME 'WILL BE USED'
END
ELSE NOP
EXIT 0

Explanation:
 Program receives member name as input.
 The LENGTH(membername) In Built function gets the length of the input.
 If length is greater than 8, use SUBSTR function to retrieve the first 8
characters of the member name.
 Proper comments must be used for better understanding.
 Indentation must be appropriate for better readability.

Summary:
 There are different types of Build-in functions available in Rexx.

Rexx Subroutines

After completing this chapter, you will be able to explain how to write and apply
subroutines.

Subroutines are similar to functions which are invoked to perform a specific


task. When a subroutine execution is completed successfully, the control returns
back to the instruction that follows the subroutine call.

In many ways subroutines and functions are similar except the way in which
they are called and the way values are returned back.
Following are the characteristics of a subroutine:

 A Subroutine may or may not receive arguments.


 A Subroutine may or may not return any values.
 Unlike functions, CALL statements are used to invoke subroutines. CALL
statement should be followed by subroutine name which is optionally
followed by arguments. Similar to functions, a maximum of 20 arguments
can be passed to subroutine.

CALL SUBR ARG1 ARG2

In the earlier call, SUBR is the subroutine being called and ARG1 & ARG2 denote
the arguments passed to the subroutine.

 Once the necessary instructions are executed in the subroutine, RETURN


statements are used to transfer the control back to the calling module.
 In the calling exec, the value returned by a subroutine will be received in
a special variable called RESULT.

Subroutines can be broadly classified as internal and external subroutines.

Internal Subroutines:
Internal subroutines are coded within the current exec, marked by a label and
used only by that exec. As 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.

Example:
/* REXX */
CALL INTSUBR
EXIT 0

INTSUBR:
SAY 'YOU ARE INSIDE INTERNAL SUBROUTINE'
RETURN
Note:

Issuing a CALL to internal label names for subroutines and functions that are
greater than eight characters, may have unintended results. Label names will
be truncated to eight characters.

External Subroutines:
External subroutine is a program or an exec in a member of a partitioned data
set that can be called by one or more execs.

Whenever a CALL statement is encountered in REXX, internal labels will be


searched first. If no internal labels match the subroutine name, it will be treated
as an external subroutine and the subroutine will be picked up from the
partitioned dataset allocated to DDnames SYSEXEC or SYSPROC. The order of
search will be SYSEXEC followed by SYSPROC.

Passing Arguments across Subroutine / Function Calls:


An internal routine can share variables with its caller. As a result, commonly
shared variables can be used to pass information between calling exec and
internal routine. Arguments can also be used to pass information to and from an
internal routine.

However, external routines, however, cannot share the same variables, and
information must pass between them through arguments or some other
external way, such as data stack.

Note:

Here routine refers to both subroutines and functions.

Call by Variable:
When an exec and its internal routine 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 internal routine.
In the following example, the value of ANS is assigned in the subroutine and
displayed in the main part of the exec. The variables NUM1, NUM2, and ANS are
shared across internal subroutine and the calling exec.

Example of passing information in a variable


/*******************************REXX *********************************/
/* This exec receives a calculated value from an internal subroutine */
/* displays that value. */
/*********************************************************************/

/* CALL AS INTERNAL SUBROUTINE */


NUM1 = 5
NUM2 = 10
CALL ANS_SUBR
SAY ANS /* DISPLAYS 15 */
NUM1 = 5
NUM2 = 12

/* CALL AS INTERNAL USER-DEFINED FUNCTION */


X=ANS_SUBR()
SAY ANS /* DISPLAYS 17 */

ANS_SUBR:
ANS = NUM1 + NUM2

RETURN 0
/* ENABLE ANS_SUBR TO BE CALLED AS FUNCTION DUMMY VALUE IS RETURNED */

Call by Arguments:
Arguments can be used to pass information to both internal and external
subroutines / functions. As mentioned earlier, a maximum of 20 arguments can
be passed to the subroutines functions.

For example, a call statement passing arguments can be visualized as

CALL SUBR ARG1 ARG2 ARG3.

Here arguments ARG1, ARG2 and ARG3 are passed to the subroutine SUBR.
Similarly, a function passing arguments can be visualized as

X = FUNC(ARG1, ARG2, ARG3)

Here arguments ARG1, ARG2 and ARG3 are passed to the function FUNC.

The subroutines can receive the arguments passed from the calling exec using
ARG or PARSE ARG instruction, where the arguments can be delimited by
commas or spaces.

ARG ARG1 ARG2 ARG3

The names of the arguments on the CALL and the ARG instructions do not have
to be same as the information is not passed by name but by value.

CALL SUBR ARG1 ARG2 ARG3.

The names of the arguments on the CALL and the ARG instructions do not have
to be same as the information is not passed by name but by value.

In the subroutine / function values are returned to the calling exec using
RETURN statement. Although a subroutine can receive up to 20 arguments, it
can specify only one expression on the RETURN instruction.

For example, 'RETURN ans' statement returns the value 'ans' to the calling exec.

Receive parameters from Function / Subroutines:


The value returned due to a function call substitutes the function call itself.

For example,

X = MAX(1,2,3) + 2;
Here the in-built function MAX will return a value of 3, which will be substituted
in the above statement as

X = 3 + 2;

Thus X will be assigned a value of 5.

Whereas, in case of subroutines the value returned from a subroutine will be


available in a special variable called RESULT.

Example of receiving value from a subroutine:


/*******************************REXX *********************************/
/* This exec receives the maximum value between two numbers */
/* from a subroutine and displays that value. */
/*********************************************************************/

/* CALL AS INTERNAL SUBROUTINE */


NUM1 = 5
NUM2 = 2
CALL PERSUBR NUM1 NUM2
SAY 'PERIMETER IS : ' RESULT /* DISPLAYED AS 20 */
EXIT 0

/* CALL AS INTERNAL USER-DEFINED FUNCTION */


PERSUBR:
ARG LEN WID
PER = 2*(LEN+WID)
RETURN PER

Summary:
 A Subroutine is used as a common structure when the sequence of
instructions is repeatedly used in a main program, which results in ease
of use and understanding.
 The subroutines are broadly classified as internal and external
subroutines.
 Internal subroutines are coded with in the current exec and external
subroutines are coded outside the exec and are accessible by other execs
as well.
 Internal subroutines can share the variables used by main exec where as
external subroutines cannot.
 Both external and internal subroutines can receive the information
through arguments.

Difference Between Functions &


Subroutines.

Functions versus Subroutines:


Functions and Subroutines can be internal or external.

Subroutines Functions

Invoked by using the CALL instruction


Invoked by specifying the function's name immediately followed
followed by the subroutine name and
by parentheses that optionally contain up to 20 arguments.
optionally up to 20 arguments

Can be internal or external Can an be internal or external

Internal: Internal:

Can pass information by using common Can pass information by using common variables
variables
Can protect variables with the PROCEDURE instruction
Can protect variables with the
PROCEDURE instruction Can pass information by using arguments

Can pass information by using External:


arguments
Must pass information by using arguments
External:
Can use the ARG instruction or the ARG built-in function to
Must pass information by using
arguments receive arguments.

Can use the ARG instruction or the ARG


built-in function to receive arguments.

Might return a value to the caller. Must return a value to the caller.

Returns a value by placing it into the


Returns a value by replacing the function call with the value.
REXX special variable RESULT.

Uses the RETURN instruction to return


Uses the RETURN instruction to return to the caller.
to the caller.

Example 1:
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."

There are four possible inputs namely, HEADS, TAILS, QUIT, 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.

Code – Main Module:


/*******************************REXX **********************************/
/* This exec plays a simulated coin toss game between the computer */
/* and a user. The user can enters one of the options namely */
/* heads, tails, or quit. The user is first checked for validity in */
/* an internal subroutine. An external subroutine uses the RANDOM */
/* built-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 /* INITIALIZE SCORES TO ZERO */
USER = 0
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 0

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 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 IS NOT A VALID RESPONSE. TRY AGAIN!'
SAY 'HEADS, TAILS, OR QUIT'
PULL RESPONSE
END
END
RETURN
Code – External Subroutine:
/*******************************REXX *********************************/
/* This external subroutine receives 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 */
/* the same, the user wins. If they are different, computer wins. */
/* The outcome is returned to the calling exec. */
/*********************************************************************/
ARG INPUT
IF INPUT = 'HEADS' THEN
USERTHROW = 0 /* HEADS = 0*/
ELSE
USERTHROW = 1 /* TAILS = 1*/

COMPTHROW = RANDOM(0,1) /* CHOOSE A RANDOM NUMBER */


/* BETWEEN 0 AND 1
IF COMPTHROW = USERTHROW THEN
OUTCOME = 'HUMAN' /* USER CHOSE CORRECTLY */
ELSE
OUTCOME = 'MACHINE' /* USER DIDN‟T CHOOSE CORRECTLY */

RETURN OUTCOME

Explanation:
 Program receives HEADS, TAILS or QUIT input.
 Internal subroutine CHECK verifies whether the user input is valid. In case
of invalid inputs, user is prompted again to enter valid input.
 Valid input is passed to an External subroutine THROW that compares the
valid input with a random outcome.
 RANDOM built-in function is used as, RANDOM(0,1), and equate HEADS =
0, TAILS= 1. External Subroutine returns the result to the main program
where results are tallied and displayed.
 Proper comments must be used for better understanding
 Indentation must be appropriate for better readability

Example 2:
Write a function named "AVG" that receives a list of numbers separated by
blanks, and computes their average as a decimal number. The function is called
as follows:

AVG(number1 number2 number3 ...)

Code – Main module:


/*******************************REXX *********************************/
/* This exec receives three numbers from the user and call external */
/* subroutine to calculate the average of three numbers */
/*********************************************************************/
SAY 'ENTER FIRST NUMBER'
PULL FIRST
SAY 'ENTER SECOND NUMBER'
PULL SECOND
SAY 'ENTER THIRD NUMBER'
PULL THIRD
AVG = ELTAVG(FIRST,SECOND,THIRD)
SAY 'THE AVERAGE IS :'AVG

EXIT 0

Code - External Function:


/*******************************REXX *********************************/
/* This exec receives numbers, adds them, computers their average */
/* and returns the average to the calling exec. */
/*********************************************************************/
ARG A, B, C
SUM = A+B+C
AVERAGE = SUM / 3
RETURN AVERAGE

Explanation:
 This exec receives three numbers from the user and call external
subroutine to calculate the average of the three numbers.
 The external function ELTAVG receives numbers, adds them, computes
their average and returns in to the calling exec.
 Proper comments must be used for better understanding
 Indentation must be appropriate for better readability

Summary:
 A Subroutine is used as a common structure when the sequence of
instructions is repeatedly used in a main program, which results in ease
of use and understanding.
 Functions are similar to subroutines except for the way in which they are
called and the way the values are returned.
 Functions are classified as user-defined functions and built-in functions.
 The subroutines are broadly classified as internal and external
subroutines.
 Internal subroutines are coded with in the current exec and external
subroutines are coded outside the exec and are accessible by other execs
as well.
 Internal subroutines can share the variables used by main exec where as
external subroutines cannot.
 Both external and internal subroutines can receive the information
through arguments.

Rexx Stacks and Queues

After completing this chapter, you will be able to:

 Define Stacks and Queues


 Manipulate the data stack
 Create a buffer on the data stack
 Drop a Buffer
 Perform other related functions performed on Buffer
 Describe Private stack
 Explain application of stacks

Introduction to Stacks and Queues:


REXX in TSO/E uses an expandable data structure called a data stack to store
information. The data stack combines characteristics of a conventional stack
and queue.

Stacks and queues are similar types of data structures used to temporarily hold
data items until needed. When elements are needed, they are removed from
the top of the data structure. The basic difference between a stack and a queue
is how the elements are added. Elements are added to the top of a stack and to
the bottom of a queue.

Let’s consider an example for a data stack:

Using a stack, the last element added to the stack (elem6) is the first removed.
As the elements are placed on the top of a stack and removed from the top, the
newest elements on a stack are the ones processed first. The technique is called
LIFO (last in first out)

Let’s consider an example for a Queue:


Using a queue, the first element added to the queue (elem1) is the first
removed. Because elements are placed on the bottom of a queue and removed
from the top, the oldest elements on a queue are the ones processed first. The
technique is called FIFO (first in first out).

The data stack that REXX uses combines the techniques used in adding
elements to stacks and queues. Elements can be placed on the top or the
bottom of a data stack. Removal of elements from the data stack, however,
occurs from the top of the stack only.

Manipulating the Data Stack:


There are several REXX instructions that manipulate the data stack. There are
two instructions to add elements to the data stack and one to remove elements
from the data stack.

Adding Elements to the Data Stack:


Information can be stored on the data stack with two instructions, PUSH and
QUEUE.

PUSH: This puts one item of data on the top of the data stack. There is virtually
no limit to the length of the data item.

Elem1 = 'String 1 for the data stack'


Elem2 = 'String 2 for the data stack'
PUSH Elem1
PUSH Elem2

Note:

Some people find it less confusing when adding elements in a particular order to
the data stack, to consistently use the same instruction, either PUSH or QUEUE,
but not both

QUEUE: This puts one item of data on the bottom of the data stack. Again,
there is virtually no limit to the length of the data item.

ElemB = 'String B for the data stack'


QUEUE ElemA
QUEUE ElemB

After executing the earlier two instructions the stack will look like this,

Retrieving Elements from the Stack:


As and when an element is retrieved from stack, it will be permanently removed
from the stack. To retrieve information from the data stack, use the PULL and
PARSE PULL instructions.

PULL and PARSE PULL - remove one element from the top of the data stack.

PULL stackitem command contains the value of Elem2 (in the variable
stackitem) with the characters translated to uppercase.
For example, after execution of PULL command 'stackitem' will hold a value of
'STRING 1 FOR THE DATA STACK'.

PARSE PULL stackitem command contains the value of elem1 (in the variable
stackitem) with the characters not translated to uppercase

For example, after execution of PARSE PULL command, 'stackitem' will hold a
value of 'String 1 for the data stack'.

Determining Number of Elements on the Stack:


The QUEUED built-in function returns the total number of elements on a data
stack. For example, to find out how many elements are on the data stack,
QUEUED function can be used with no arguments.

SAY QUEUED() command will return the number of elements in a stack


(displays a decimal number).

Example:
/* REXX */
PUSH 'A'
PUSH 'E'
PUSH 'I'
PUSH 'O'
PUSH 'U'
number = queued ()
Do number
PULL element
SAY element
END
EXIT 0

Creating a Buffer on the Data Stack:


When an exec calls a routine (subroutine or function) and both the exec and the
routine use the data stack, the stack becomes a way to share information.
However, execs and routines that do not purposely share information from the
data stack, might unintentionally do so and end in error.
To help prevent this, TSO/E provides the MAKEBUF command that creates a
buffer, which can be used for an extension to the stack, and the DROPBUF
command that deletes the buffer and all elements within it.

Although the buffer does not prevent the PULL instruction from accessing
elements placed on the stack before the buffer was created, it is a way for an
exec to create a temporary extension to the stack. The buffer allows an exec to:

 Use the QUEUE instruction to insert elements in FIFO order on a stack


that already contains elements.
 Have temporary storage that it can be deleted easily with the DROPBUF
command.
 Ensure that the elements placed in the stack buffer are accessible only to
the current exec.

An exec can create multiple buffers before dropping them. Every time MAKEBUF
creates a new buffer, the REXX special variable RC is set with the number of the
buffer created. Thus if an exec issues three MAKEBUF commands, RC is set to 3
after the third MAKEBUF command.

Note:

To protect elements on the stack, an exec can create a new stack with the
NEWSTACK command.

Creating Buffer using MAKEBUF command:


To create a buffer on the data stack before adding more elements to the stack,
use the TSO/E REXX MAKEBUF command. All elements added to the data stack
after the MAKEBUF commands are placed in the buffer.

Below the buffer, stack contains the elements placed before issuing the
MAKEBUF command.

Example:
/* REXX */
PUSH 'a'
PUSH 'b'
'MAKEBUF'
PUSH 'c'
EXIT 0
In the above example, Element 'a' and 'b' will be placed directly in the stack and
'c' will be placed in the buffer. Thus element 'c'' will be accessible only to the
current exec where as 'a' & 'b' are universally accessible.

Retrieving elements from a Stack with Buffer:


The buffer created by MAKEBUF does not prevent an exec from accessing
elements below it. After an exec removes the elements added after the
MAKEBUF command, it starts removing the elements which are added before
the MAKEBUF command was issued.

Dropping a Buffer using DROPBUF Command:


When an exec has no more need for a buffer on the data stack, it can use the
TSO/E REXX DROPBUF command to remove the buffer (and its contents). The
DROPBUF command removes the most recently created buffer.

To drop a specific buffer on the data stack and all buffers created after it, issue
the DROPBUF command with the number of the buffer. The first MAKEBUF
creates buffer 1, the second creates buffer 2, and so on. For example, if an exec
issued three MAKEBUF commands that created three buffers, when you issue
DROPBUF 2, the second and third buffers and all elements within them are
removed.

To remove all elements from the entire data stack including elements placed on
the data stack before buffers were added, issue DROPBUF 0. DROPBUF 0
creates an empty data stack and should be used with caution.

Note:

Use DROPBUF 0 selectively, as it will result in an empty data stack

Other related functions performed on Buffer:


Finding the Number of Buffers:
To find out how many buffers were created with the MAKEBUF command, use
the TSO/E REXX QBUF command. QBUF returns the number of buffers created
in a special variable RC.

QBUF returns the total number of buffers created, not just the ones created by
a single exec. Thus if an exec issued two MAKEBUF commands and called a
routine that issued two more, when the routine issues a QBUF command, RC
returns the total number of buffers created, which is four.

Finding the Number of elements in a buffer:


To find out how many elements are in the most recently created buffer, use the
TSO/E REXX QELEM command. QELEM returns in the REXX special variable RC,
the number of elements in the most recently created buffer.

QELEM does not return the number of elements on a data stack which doesn‘t
contain any buffers created by the MAKEBUF command. If QBUF returns 0, no
matter how many elements are on the stack and subsequently QELEM also
returns 0.

Example:
/* REXX */
PUSH a;
PUSH b;
'MAKEBUF'
PUSH c;
PUSH d;
'QBUF'
SAY RC
'QELEM'
SAY RC
EXIT 0

In the above example, QBUF returns a value of 1 and QELEM returns a value of
2.

Private Stack:
Unlike normal stack, a private stack is accessible only to the current exec.
Creating a private Stack with the NEWSTACK Command:
The TSO/E REXX NEWSTACK command creates a private data stack that is
completely isolated from the original data stack. The elements on the original
data stack cannot be accessed by an exec or the routines that it calls until a
DELSTACK command is issued. Before DELSTACK is issued, PULL statement
retrieves the date from the terminal when there are no more elements in the
new data stack.

All elements added to the data stack after the NEWSTACK command, are placed
in the new private data stack. The original stack contains the elements placed
on the stack before the NEWSTACK command.

Deleting a Private Stack with the DELSTACK Command:


When an exec wants to delete the new stack and remove all elements placed on
the new stack, it can issue the TSO/E REXX DELSTACK command. The
DELSTACK command removes the most recently created data stack. If no stack
was previously created with the NEWSTACK command, DELSTACK removes all
the elements from the original stack.

Finding the Number of Stacks:


To find out how many stacks exist, use the TSO/E REXX QSTACK command.
QSTACK returns in the REXX special variable RC, the total number of stacks
including the original data stack.

QSTACK returns the total number of stacks, not just the ones created for a
single exec. Thus if an exec issued two NEWSTACK commands and called a
routine that issued two more, when the routine issues a QSTACK command, RC
returns the total number of stacks, which is five.

Example:
/* REXX */
ADDRESS MVS "NEWSTACK"
PUSH 'a'
PUSH 'b'
PUSH 'c'
PUSH 'd'
number = queued()
Do number
PULL number
Say number
End
ADDRESS MVS "QSTACK"
SAY RC
ADDRESS MVS "DELSATCK"
EXIT 0

In the above example RC returns the value of 2 (If no other stacks are running
in other EXECs)

Application of stacks:
The data stack has some unique characteristics, such as

 It can contain a virtually unlimited number of data items of virtually


unlimited size.
 It can contain commands to be issued after the exec ends.
 It can pass information between REXX execs and other types of programs
in a TSO/E or non-TSO/E address space.

Because of the data stack‘s unique characteristics, the data stack can be used
specifically to:

 Store a large number of Data items for a single exec‘s use.


 Pass a large number of arguments or an unknown number of arguments
between a routine (subroutine or function) and the main exec.
 Pass responses to an interactive command that can run after the exec
ends.
 Store data items from an input data set, which were read by the EXECIO
command.
 Share information between an exec and any program running in MVS.
 Execute subcommands of a TSO/E command issued from a REXX exec.

Example:
Get five inputs (names) from the user in the order of getting their entrance
tickets for the dance show and display the person‘s name (as per the order)
coming out from that show?
/* REXX */
DROP INREC.
DO I = 1 TO 5
SAY 'ENTER THE NAME OF THE PERSON 'I':'
PULL NAME
INREC.I = NAME
END
DO I = 1 TO 5
QUEUE INREC.I
END
Say 'Order of persons coming out from the show '
NUMBER = QUEUED()
DO NUMBER
PULL NUMBER
SAY NUMBER
END
EXIT 0

Explanation:
 QUEUE command: the first element added to the queue is the first
removed. Because elements are placed on the bottom of a queue and
removed from the top, the oldest elements on a queue are the ones
processed first.
 QUEUED () contains the number of elements in a stack
 PULL command will retrieve the data from the stack
 Display the element in the PULL by the Command 'SAY'
 Proper comments must be used for better understanding
 Indentation must be appropriate for better readability

Summary:
 Stack is a memory area used as a means of data transfer.
 The scope of public stacks is global. It can be accessed by all the
applications running at that time.
 Stacks can hold seamless amount of data which enables transfer of huge
amount of data across modules.
 There are three types of stacks namely public stacks, stack buffers and
private stacks.
 Scope of stack buffers and Private stacks is local to the modules where
they are created.
 Any number of stack buffers and private stacks can be created.
 Stack buffers will be created on top of the public stacks. Once all the
elements from stack buffers are retrieved, public stacks will be accessed.
 Private stacks will be created as a fresh stack. When the private stacks
are active Public stacks can be accessed only when the private stack is
deleted.

Test Your Understanding:


1. What will be the value stored in 'item'?

QUEUE A
QUEUE B
'MAKEBUF'
QUEUE C
PULL item

2.
3. What will be the value stored in 'element‘?

PUSH 'a'
PUSH 'b'
'MAKEBUF'
PUSH 'c'
PUSH 'd'
'DROPBUF'
PARSE PULL element

4.
5. What will be the value stored in RC?

QUEUE A
QUEUE B
QUEUE C
'QELEM'
SAY RC

6.
7. What is returned to the function SAY QUEUED ()?
8. Name two instructions that can potentially clear all elements in a stack.

TSO/E & ISPF Commands

After completing this chapter, you will be able to:

 Describe the overview of TSO/E Commands


 Execute the common TSO commands
 Write the miscellaneous TSO commands
 Execute ISPF commands
 Execute Rexx programs

Overview of TSO/E Commands:


TSO/E commands overview

 In addition to the built-in functions, REXX supports the execution of


external TSO commands. Some of these functions perform the same
services as control variables do in CLIST language.
 REXX can interact with the external TSO environment through TSO/E
commands.
 REXX can interact with external ISPF environment through ISPF
commands.
 TSO/E commands return the result in specific system variables through
which REXX can access the attributes and track the status of datasets,
user, and terminal and console session.

Common TSO commands:


REXX can be used to perform basic TSO commands. Any TSO command can be
performed in REXX by enclosing it within the double quotes prefixed by the
word TSO.
For example:
 Copy: "TSO COPY {source dataset} {destination dataset}"
 Rename: "TSO RENAME {source dataset name} {destination dataset
name}"
 Delete: "TSO DELETE {dataset name}"
 List Members: "TSO LISTDS {PDS dataset name} MEMBERS"

ADDRESS command will transfer the control to the respective external


environment. For example, ADDRESS TSO will transfer the control to TSO
environment.

Once ADDRESS TSO command is issued in a REXX program, all other


commands enclosed in quotes will be considered as TSO commands.

For example:
ADDRESS TSO
“COPY {source dataset} {destination dataset}” and
“TSO COPY {source dataset} {destination dataset}”

will result in the same outcome.

Example:
/* REXX */
/* Performing some basic TSO commands on PS file */
SRCFILE = {HLQ}.SAMPLE.FILE
DESTFILE = {HLQ}.SAMPLE.FILE1 ADDRESS TSO
"COPY '"SRCFILE"' '"DESTFILE"'"
EXIT 0

Miscellaneous TSO Commands:


Some of the miscellaneous TSO commands in REXX are as follows:

 GETMSG
 LISTDSI
 MSG
 MVSVAR
 OUTTRAP
 PROMPT
 SETLANG
 STORAGE
 SYSCPUS
 SYSDSN
 SYSVAR

GETMSG:

Returns in variables a system message issued during an extended MCS console


session. It also returns associated information about the message in variables.
The function call is replaced by a function code that indicates whether or not the
call was successful.

LISTDSI:

Returns in variables the data set attributes of a specified data set. The function
call is replaced by a function code that indicates whether or not the call was
successful.

MSG:

Controls the display of TSO/E messages. The function returns the previous
setting of MSG.

MVSVAR:

Uses specific argument values to return information about MVS, TSO/E, and the
current session.

OUTTRAP:

Traps lines of TSO/E command output into a specified series of variables. When
any TSO command is executed from REXX, the output can be stored in a stem
variable using OUTTRAP command.

Let us say, {HLQ}.SAMPLE.DATA contains two members MEM1 & MEM2.

The TSO command LISTDS "{HLQ}.SAMPLE.DATA" MEMBERS will result in the


following output.

{HLQ}.SAMPLE.DATA
--RECFM-LRECL-BLKSIZE-DSORG
FB 80 32720 PO
--VOLUMES--
SLGMD0
--MEMBERS--
MEM1
MEM2

The above output can be stored in a stem variable TRAP. as follows,

ADDRESS TSO
X=OUTTRAP(TRAP.)
"LISTDS '{HLQ}.SAMPLE.DATA' MEMBERS"

PROMPT:

Sets the prompt option on or off for TSO/E interactive commands. The function
returns the previous setting of prompt.

SETLANG:

Retrieves and optionally changes the language in which REXX messages are
displayed. The function returns the previous language setting

STORAGE:

Retrieves and optionally changes the value in a storage address.

SYSCPUS:

Returns in a stem variable information about all CPUs that are online.

For example:

SYSDSN("'{HLQ}.SAMPLE.DATA'") results in 'OK' if the data set exists,


otherwise results in 'DATASET NOT FOUND'

SYSVAR:
Uses specific argument values to return information about the user, terminal,
language, exec, system, and console session.

ISPF Commands:
REXX can be used to perform basic ISPF commands.

Any ISPF command can be performed in REXX by enclosing it within the double
quotes prefixed by the word ISPEXEC.

 View: "ISPEXEC VIEW {dataset name>”


 Edit: "ISPEXEC EDIT {dataset name>"
 Save: "ISPEXEC SAVE"
 Close: "ISPEXEC END"

ADDRESS command will transfer the control to the respective external ISPF
environment. For example, ADDRESS ISPEXEC will transfer the control to ISPF
environment.

Once ADDRESS ISPEXEC command is issued in the REXX program, all other
commands that are enclosed in double quotes will be considered as ISPF
commands.

For example,
ADDRESS ISPEXEC
"VIEW {dataset name}" and
"ISPEXEC VIEW {dataset name}"

will result in the same outcome.

Example:
/* REXX */
/* Performing some basic ISPF commands on PS file */
SRCFILE = {HLQ}.SAMPLE.FILE
ADDRESS ISPEXEC
"VIEW SRCFILE"
EXIT 0
Running REXX Exec from TSO:
Any REXX program can be executed from TSO by issuing the command,

TSO EX REXXLIB(member)

Where, REXXLIB: PDS in which the REXX program is stored as a member.

If the Partitioned dataset (where the REXX program resides) is externally


allocated to SYSEXEC/SYSPROC, REXX can be executed without specifying the
library name "TSO member".

Summary:
 Apart from in-built functions, REXX can invoke external TSO commands.
 The results of TSO commands will be returned to system variables or can
be trapped through REXX stem variables.
 ISPF commands can be invoked from REXX.

Rexx File Operations

After completing this chapter, you will be able to perform file operations.

File operations:
REXX can perform file operations using TSO commands,

 Datasets can be created, allocated, read and written using REXX.


 ALLOC command is used to create / allocate datasets.
 EXECIO command is used to read and write datasets.
 FREE command is used to free the dataset allocation, so that the lock
held by the REXX program on the particular dataset used will be released.

Create and Allocate Datasets:


Create Dataset: A new dataset can be created and allocated by using ALLOC
with disposition as 'NEW'. Other dataset properties such as record length,
record format, space parameters, type of dataset, block size, unit parameters
and so on can be specified. Following is a sample ALLOC command to create a
fixed block Partial Sequential dataset with record length as 80.

"TSO ALLOC F({DD name}) DA({dataset name}) NEW DIR(20)


SPACE(10,10) DSORG(PS) RECFM(FB) LRECL(80) BLKSIZE(0)"

An existing dataset can be allocated to a DD name by allocating it in share


mode as,

"TSO ALLOC F({DD name}) DA({dataset name}) SHR"

Input – Output operations:


Input-Output file operations are performed through EXECIO command.

The read operation can be performed in the file by the command.

"EXECIO [linenum or *] DISKR or DISKRU ddname (FINIS STEM stemvar.”

The write operation can be performed in the file by the command

"EXECIO [linenum or *] DISKW ddname (FINIS STEM stemvar."


 DISKR – Read operation
 DISKW – Write Operation
 DISKRU – Read operation for Update
 Linenum – Record number from where the read operation should
commence
 FINIS – Close the file after Read/Write operation
 STEM - Specifies the name of compound variable to which data is
retrieved (or) from which data is read.
 Stemvar. – Stem variable on to which the records read will be stored (or)
or on to which the records to be written into the file will be present.

On execution of EXECIO command system variable RC will represent the status


of the command execution.

Return Code (RC) Interpretation

0 Successful Execution

1 Data truncation

2 End of file is reached

20 Fatal Error

Sample EXECIO commands: To open a data set without reading any records, a
zero has to be added immediately following EXECIO command and OPEN
operand should be specified.

"EXECIO 0 DISKR mydd (OPEN"

To read a specific number of lines, number of lines to be read should be


specified immediately following EXECIO command.

"EXECIO 25 DISKR mydd (FINIS STEM STEMVAR."

The above command will read first 25 records and store them in the stem
variable STEMVAR.
To read the entire dataset, an asterisk immediate following the EXECIO
command.

"EXECIO * DISKR TEMP (FINIS STEM A"

Here EXECIO performs a disk read operation of a pre-allocated file using a TSO
ALLOC instruction and all the records are placed in the stem variable A. FINIS
option should not be used if the next EXECIO statement continues reading at
the line immediately following the last line read.

To read just 5 lines to the data stack starting at line 100, write the following:

"EXECIO 5 DISKR myindd 100 (FINIS"

To open a data set at line 100 without reading lines to the data stack, the
following command can be used:

"EXECIO 0 DISKR myindd 100 (OPEN"

If the dataset is already open, no operation is performed for OPEN.

Note:

Users should be selective in using FREE ALL command, as it will free all existing
dataset allocations.

De-allocate datasets:
Deallocation of files: Once the dataset is closed and no more operations need to
be performed on the dataset, it can be de-allocated so that the lock held on the
file can be released. The command used to de-allocate a dataset which was
allocated to the ddname DDN is
“TSO FREE F(DDN)”

“TSO FREE ALL” command is used to free up all the dataset allocations including
system dataset allocations.

Example 1:
Rename the input file name with .Bkup as a final qualifier using TSO command.

/* REXX */
/* Performing some basic TSO commands on PS file */
SAY "ENTER THE HIGHLEVEL QUALIFIER"
PULL HLQ
SRCFILE = HLQ||'.SAMPLE.FILE'
DSTFILE = HLQ||'.SAMPLE.FILE.BKUP'
ADDRESS TSO
"RENAME '"SRCFILE"' '"DSTFILE"' "
EXIT 0

Explanation:
 Address TSO command will transfer the control to TSO environment.
 Rename command is used to rename the input file name.

Example 2:
Copy the contents of one file to another, using file operations.

/* REXX */
/* COPYING THE DATA FROM ONE FILE TO ANOTHER */
SAY "ENTER THE HIGHLEVEL QUALIFIER"
PULL HLQ
INFILE = HLQ||".SAMPLE.REXX"
OUTFILE = HLQ||".SAMPLE.OUTPUT"
ADDRESS TSO
"ALLOC F(INDD) DA('"||INFILE||"') SHR"
IF SYSDSN("'"OUTFILE"'") = 'OK' THEN
DO
"ALLOC F("OUTDD") DA('"OUTFILE"') SHR REUSE"
END
ELSE
DO
"ALLOC F("OUTDD") DA("||"'"||OUTFILE||"'",
||") NEW SPACE (100,200) TRACK LRECL(80) RECFM(F) ",
||" BLKSIZE(0)"
END
"EXECIO * DISKR INDD(FINIS STEM INREC."
"EXECIO * DISKW OUTDD(FINIS STEM INREC."
"FREE F(INDD)"
"FREE F(OUTDD)"
EXIT 0

Explanation:
 Allocate the input file in share mode.
 Check if the output file is present. If exists, allocate it in share mode.
Otherwise, create and allocate.
 Read the input file using EXECIO… DISKR command.
 Write the output file using EXECIO DISKW command.
 De-allocate input and output files.
 Proper comments must be used for better understanding.
 Indentation must be appropriate for better readability.

Summary:
 Datasets can be created and / or allocated using ALLOC command.
 Input-Output operations can be performed on the datasets through
EXECIO command.
 Datasets can be de-allocated using FREE command.

Test Your Understanding:


 Which function is used to retrieve data from a particular address in
Storage?
 Which function is used to retrieve the detailed information about a
dataset attributes?

You might also like