You are here: Home > Knowledge Refreshers

KR-220* REXX Day 9 (parsing)

 

REXX provides a strong parsing feature (way to extract and format data) wherein we can define a template and extract data based on the template. Some examples will make it clear. The PULL statement itself is actually a PARSE PULL statement.

 

Code Output
/* REXX */
INFO = "CHECK THIS OUT"
PARSE VAR INFO PART1 PART2
SAY PART1
SAY PART2
EXIT
CHECK
THIS OUT

 

PART1 gets the first word separated by a space and the rest of the data is dumped into PART2; this is a technique to remove unwanted data.

Let’s cover all types of parsing with a single example.

Code Output
/* REXX */
DATE = "MON,DEC 24,2007,12:42"
COM = ','
PARSE VAR DATE DAY (COM) 5 MONTH +4 DD (COM) YEAR (COM) HH ':' MM
SAY "THE DATE:" DATE
SAY DAY
SAY MONTH
SAY DD
SAY YEAR
SAY HH
SAY MM
EXIT
THE DATE: MON,DEC 24,2007,12:42
MON
DEC
24
2007
12
42

 

Let’s analyze the code:

DATE = "MON,DEC 24,2007,12:42"
COM = ','
PARSE VAR DATE DAY (COM) 5 MONTH +4 DD (COM) YEAR (COM) HH ':' MM

PARSE VAR is the command. DATE is the variable that has to be parsed. The type of parsing is mentioned in italics.

  • (Matching string variable pattern)
    DAY (COM) -> first variable into which everything will go till the first comma is encountered (because COM is a variable defined as ,)
  • (Absolute positional pattern)
    5 MONTH -> From position 5 of the variable DATE extract everything till the next delimiter/parsing instruction is reached. At position 5 the D is encountered so everything from here is put in MONTH. Where to stop?
  • (Relative positional pattern) +4 DD (COM) -> This is relative positioning; in previous step we started at 5 and here we do a +4 so the starting position here is 9. So everything from 5 to 8 is dumped in MONTH and from 9 onwards is dumped into the variable DD till the next comma is encountered.
  • (Matching string variable pattern)
    YEAR (COM) -> the year 2007 is extracted – it lies between the commas.
  • (Matching string – literal pattern)
    HH ‘:’ MM -> after the comma following the year everything is dumped into the variable HH till the first colon is encountered (since we’ve said : is the delimiter). Everything following the colon is dumped into the variable MM.

KR-221* DAY 10 of REXX (file handling)

 

DSN="TEST.SS.DUMMY"
"ALLOCATE F(MEMDD) DSN('"DSN"') SHR"
"EXECIO 2 DISKR MEMDD 2 (FINIS STEM TEXT."

 

EXECIO syntax:

  • "EXECIO n DISKR ddname start-count (options variable" EXECIO -> used for IO processing; can read /write to a file or to the stack (we’ll see the stack later).
  • n -> number of records to extract (can use * also; can give 0 if you just want to open the file but not read anything)
  • DISKR -> read from file (DISKW for writing to a file; DISKRU if you want to do an update on the record just read).
  • ddname -> can use any DD name; just need to ensure that this DD name is mapped to a physical file before using it here. In our example we used the ALLOC statement for this purpose and ddname was MEMDD.
  • start-count -> optional; to specify the record number from which to start reading.

Everything after ( are options for EXECIO. The various options we can give are:

  • FINIS -> closes the file after execio is over; optional – if you want next EXECIO to continue with the file then don’t close it here.
  • OPEN – just to open the dataset (give count as 0).
  • SKIP – skip the number of records specified by n without storing them anywhere (no need to give variable).
  • LIFO/FIFO -> in case you are reading into the stack then this decides how it is stored.
  • variable -> can be a single variable name – in which case one record is stored in that variable or a stem variable where all the records read are stored. Keyword STEM required to indicate a stem variable (like in our example).
  • To create an empty file – write 0 records to the file and use FINIS
  • Explanation for our example:
    "EXECIO 2 DISKR MEMDD 2 (FINIS STEM TEXT."
    Read 2 records starting from 2nd record into the stem variable TEXT.
    TEXT.0 will have the count of records (2)
    TEXT.1 and TEXT.2 will have the first and second records of the file.
  • After an EXECIO operation the variable RC will contain the status of the operation. 0 is success and 20 is severe error.



KR-222* DAY 11 of REXX (executing external commands and substituting variables)

 

  • To execute commands of other environments – like ISPF commands, TSO commands etc. in REXX we use the ADDRESS keyword to switch into the respective address space and then execute these commands.
  • Commands that should not be interpreted by REXX are enclosed within double quotes – so REXX will simply pass these instructions to the other environment. For instance ALLOCATE is a TSO command. To execute this we should code:
      ADDRESS TSO "ALLOCATE F(MEMDD) DSN('"DSN"') SHR MOD"

ADDRESS TSO will ensure it executes as a TSO command. All external environment commands will be enclosed within double quotes. By default in MVS environment the environment is TSO. So
  "ALLOCATE F(MEMDD) DSN('"DSN"') SHR MOD"
will work fine.

If you have a bunch of external environment commands to execute then give a single ADDRESS command to switch address space and issue all commands.

ADDRESS "TSO"
"ALLOCATE F(MEMDD) DSN('"DSN"') SHR MOD"
"ALLOCATE F(MEMDD1) DSN('"DSN1"') SHR MOD"
"ALLOCATE F(MEMDD2) DSN('"DSN2"') SHR MOD"

One frequent confusion for programmers is how to tell REXX to substitute variable values in an external command before it passes the command to the other environment. Single quote, double quote or no quotes?

Simple example:

  • I want to allocate a dataset to a DD name using the ALLOC command but the dataset name is a variable – say FILE.
    FILE="TEST.SS.DUMMY"
  • If I hardcoded the allocate it would be like:
    "ALLOCATE F(MEMDD) DSN('TEST.SS.DUMMY') SHR MOD"
  • But I want a variable value inside – how do I tell REXX to substitute a variable inside the external command? Use double quotes surrounding the variable.
    "ALLOCATE F(MEMDD) DSN('"FILE"') SHR MOD"
  • REXX will now substitute the value in variable FILE before passing the command to TSO. In fact in ISPF while editing the member if you have the HI ON command active (highlight on) then you can find the colour variation between rexx variables and the rest of the string.



KR-223* DAY 12 of REXX (my own front end?)

A glimpse into something that everyone working on mainframes tend to ask “Can I create my own front end?” Well, why not? We can add our own spice to mainframes!

Panels are part of ISPF; so strictly speaking panels will fall under ISPF programming (ISPF is like a front-end for TSO).

So we first create a panel and then use REXX to display the panel on the screen and also to capture the data entered by the user on the screen.

We’ll create a simple panel application (that does nothing!). We’ll just capture the input keyed by the user and display it in REXX. So here we go with panel programming.

Create a member in a PDS with the following:

)ATTR
# TYPE(TEXT) INTENS(LOW) SKIP(ON)
! TYPE(TEXT) INTENS(HIGH) SKIP(ON) COLOR(YELLOW) )
BODY %
!********************************************************************
!************* THIS PANEL DOES NOTHING ****************************
!********************************************************************
% +ENTER SOMETHING HERE ===>_VARIABLE#
%
%_MSG1
%                                                                   PF3=EXIT
)INIT
.CURSOR=VARIABLE
)PROC
&PFPRSD = .PFKEY
)END

With that you are done with your first panel in mainframes! There are different sections to a panel:

1.) Attributes section )ATTR
Attributes of fields are determined based on the special character used. For example we have defined # as low intensity field on which the cursor position will be skipped. % + and _ are already defined but if required we can override them. _ is used for input fields.

2.) Main body )BODY
The main layout is defined here

3.) Initialization section )INIT
Here we’ve asked for the cursor to be positioned on the field variable when the screen is first displayed.

4.) Procedure section )PROC
Statements to be executed after the panel is displayed. Here we are trapping the value of the PFKEY pressed in the variable PFPRSD (this variable can be used in our REXX code to check for the PF key pressed).

  • Variables in this panel are: VARIABLE, MSG1, PFPRSD
  • Save this member as MYPANEL in a PDS. Ensure that you use the UNNUM command (the panel member should not have any numbering on the right or left side). How to see and play with this panel in our final edition.

 KR-224* DAY 13 of REXX (playing with your front end panel)

 

Now with the panel created we need to write a REXX code to display the panel and capture information entered by the user.

/* REXX */
ADDRESS "ISPEXEC"
"LIBDEF ISPPLIB DATASET ID('PDS.SS.REXX.PANEL')"
Changing to ISPF environment. ISPPLIB is the ISPF panel library – assuming our panel is stored in this dataset.
START:
"DISPLAY PANEL(MYPANEL)"
START is a label; DISPLAY PANEL is the ISPF command to display panels.
IF PFPRSD = 'PF03' THEN
    EXIT
Control returns back to REXX when a function key is pressed – enter/PF keys. Since we stored PFKEY pressed in the variable PFPRSD (in the panel), here we check for PF3 and if so then exit.
IF VARIABLE = " " THEN
DO
   MSG1 = 'PLEASE ENTER SOMETHING IN VARIABLE FIELD'
   SIGNAL START
END
ELSE
   MSG1 = ' '
If VARIABLE is empty then store the error message in the panel field MSG1 and display the panel again (SIGNAL START will take control back to the START label).
SAY VARIABLE
SIGNAL START
Display the value of variable entered on the panel screen.
Go back to START.

Effectively you cannot come out of the panel without pressing PF3 because of the final SIGNAL START statement (ensures that the program is always in a loop).

 

SIGNAL command

  • It is like the CALL command except that control will not return back to the caller. It is kind of like our GO TO statement in C/C++.

The official REXX User’s Guide is ideal for reference purposes.

When working in multiple languages the operators can get confusing – so here is a list for your reference.

= True if the terms are equal (numerically or when padded, and so forth)
\=, ^=, /= True if the terms are not equal (inverse of =)
> , < Greater than, less than
><, <> Greater than or less than (same as not equal)
>=, <= Greater than or equal to, Less than or equal to
\<, ¬< Not less than
\>, ¬> Not greater than
= = True if terms are strictly equal (identical)
== \==, ¬==, /== True if the terms are NOT strictly equal (inverse of ==)
>> Strictly greater than
<< Strictly less than
>>= Strictly greater than or equal to
\<<, ¬< Strictly NOT less than
<<= Strictly less than or equal to
\>>, ¬>> Strictly NOT greater than
& AND
| OR
&& EX-OR
Prefix \, ¬ Logical NOT

 

Note: Throughout the language, the not character, ¬, is synonymous with the backslash (\). You can use the two characters interchangeably, according to availability and personal preference.

That pretty much wraps the REXX in 6.5 hours series. We’ve covered most of the basic things you need to get working in REXX. So go ahead and start making some utilities for your project – it can help you avoid doing a lot of redundant manual work.