Basics of Rexx
Basics of Rexx
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
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’
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.
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.
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.
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
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).
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 */
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.
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.
Executing Explicitly:
To execute explicitly, we have to use EXEC command followed by the data set
name, which is done as follows
Executing Implicitly:
The implicit execution is done as follows:
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'
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
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 */
Comparison Operators:
Comparison operators can compare numbers or strings and ask questions, such
as
(A = B) Does 4 = 3? 0 (False)
(A > B) Is 4 > 3? 1 (True)
(A < B) Is 4 < 3? 0 (False)
== Strictly Equal
= Equal
\= Not Equal
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.
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 */
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 */
/****************************** REXX
**********************************/
/* This exec formats data into columns for output. */
/
*********************************************************************
*/
sport = 'base'
equipment = 'ball'
column = ' '
cost = 5
SAY sport||equipment column '$' cost
Operator Precedence:
When more than one type of operator appears in an expression, what operation
does the language processor do first?
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
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.
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.
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?
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!
SELECT/WHEN/OTHERWISE/END Instruction:
To select one of any number of choices, use the
SELECT/WHEN/OTHERWISE/END instruction.
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.
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.
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
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.
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.
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
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.
DO outer = 1 TO 2
DO inner = 1 TO 2
IF inner > 1 THEN
LEAVE inner
ELSE
SAY 'HIP'
END
SAY 'HURRAH'
END
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 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.
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'
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
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
Example 2:
Write a program that shows the difference in functioning of the various ways of
looping.
/* 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
Summary:
Interrupt instructions interrupt the flow of an execution.
STEM variables can be used as an array and can be populated using
looping constructs.
Yesterday's Today's
Lunch Lunch
4.42 3.75
3.50 3.50
3.75 4.42
"Apples" = "Oranges"
" Apples" = "Apples"
" Apples" == "Apples"
100 = 1E2
100 \= 1E2
100 \== 1E2
DO outer = 1 TO 3
SAY /* Write a blank line */
DO inner = 1 TO 3
SAY 'Outer' outer 'Inner' inner
END
END
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.
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.
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
Blank Function( )
Constant Function(55)
Symbol Function(symbol_name)
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.
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:
Comparison functions:
Conversion functions:
These functions convert one type of data representation to another type
of data representation.
Formatting functions:
Miscellaneous functions:
These functions do not clearly fit into any of the other categories.
Arithmetic Functions:
Function Description
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.
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
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
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
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
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.
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.
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:
In the earlier call, SUBR is the subroutine being called and ARG1 & ARG2 denote
the arguments passed to the subroutine.
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.
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:
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.
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.
Here arguments ARG1, ARG2 and ARG3 are passed to the subroutine SUBR.
Similarly, a function passing arguments can be visualized as
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.
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.
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.
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;
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.
Subroutines Functions
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
Might return a value to the caller. Must return a value 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.
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 */
/**********************************************************************/
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:
EXIT 0
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.
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.
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)
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.
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.
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.
After executing the earlier two instructions the stack will look like this,
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'.
Example:
/* REXX */
PUSH 'A'
PUSH 'E'
PUSH 'I'
PUSH 'O'
PUSH 'U'
number = queued ()
Do number
PULL element
SAY element
END
EXIT 0
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:
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.
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.
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:
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.
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.
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
Because of the data stack‘s unique characteristics, the data stack can be used
specifically to:
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.
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.
For example:
ADDRESS TSO
“COPY {source dataset} {destination dataset}” and
“TSO COPY {source dataset} {destination dataset}”
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
GETMSG
LISTDSI
MSG
MVSVAR
OUTTRAP
PROMPT
SETLANG
STORAGE
SYSCPUS
SYSDSN
SYSVAR
GETMSG:
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.
{HLQ}.SAMPLE.DATA
--RECFM-LRECL-BLKSIZE-DSORG
FB 80 32720 PO
--VOLUMES--
SLGMD0
--MEMBERS--
MEM1
MEM2
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:
SYSCPUS:
Returns in a stem variable information about all CPUs that are online.
For example:
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.
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}"
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)
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.
After completing this chapter, you will be able to perform file operations.
File operations:
REXX can perform file operations using TSO commands,
0 Successful Execution
1 Data truncation
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.
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.
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:
To open a data set at line 100 without reading lines to the data stack, the
following command can be used:
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.