SAS Interface to REXX

Overview of the SAS Interface to REXX

REXX, the procedure language for computing platforms that conform to the IBM Systems Application Architecture (SAA), is well known for combining powerful programming features with ease of use. By enabling SAS users to supplement the SAS language with REXX, the SAS interface to REXX provides new SAS programming possibilities in the z/OS environment.

Enabling the Interface

The SAS system options REXXMAC and REXXLOC control the REXX interface.
  • The REXXMAC option enables or disables the REXX interface. If REXXMAC is in effect, then the REXX interface is enabled. When SAS encounters an unrecognized statement, it searches for a REXX exec whose name matches the first word of the unrecognized statement. If the default, NOREXXMAC, is in effect, then the REXX interface is disabled. When SAS encounters an unrecognized statement, a "statement is not valid" error occurs. You can specify this option in the configuration file, when you invoke SAS, or in the OPTIONS statement.
  • When the REXXMAC option is in effect, the REXXLOC= option specifies the ddname of the REXX exec library to be searched for any SAS REXX execs. The default is REXXLOC=SASREXX. You can specify this option either in the configuration file or when you invoke SAS, or in the OPTIONS statement.

Invoking a REXX Exec

SAS REXX execs are REXX programs. They are stored in a library that is allocated to the SASREXX ddname (or to another ddname, as specified by the SAS system option REXXLOC=). A REXX exec is submitted as part of a SAS program in the same way as any other global SAS statement.
To run a REXX exec from within SAS, do the following:
  1. Put the REXX exec in a partitioned data set and allocate that PDS to the ddname SASREXX.
  2. Either invoke SAS with the REXXMAC option or specify the REXXMAC option later in an OPTIONS statement.
  3. Code a statement that begins with the name of the REXX exec.
    Note: You can invoke a REXX exec from an SCL program, but you should enclose the statement in a SUBMIT block. Otherwise, the exec is executed at compile time rather than at run time.
The following example invokes a REXX exec called YOUREXEC, which resides in YOUR.REXX.LIBRARY. This example works in both batch and TSO environments.
options rexxmac;
filename sasrexx 'your.rexx.library' disp=shr;
yourexec;
In batch, you can also use a JCL DD statement to allocate the REXX library externally:
//jobname JOB  ...
//        EXEC SAS
//SASREXX  DD  DSN=YOUR.REXX.LIBRARY,DISP=SHR
//SYSIN    DD  *
options rexxmac;
yourexec;
/*
//
A REXX exec can have zero, one, or multiple arguments. You call the exec by specifying its name, followed by arguments (if any), followed by a semicolon. You can place the exec anywhere that a global SAS statement, such as an OPTIONS or TITLE statement, can be placed.
The exec can generate code that is then processed by the SAS supervisor. That code can be a partial DATA step or PROC step, or one or more complete DATA steps or PROC steps.
A Simple REXX Exec provides an example of a REXX exec called VERIFY that takes as its argument a single data set name. This REXX exec can be invoked by submitting the following statement from a SAS program:
verify data.set.name;
A SAS REXX exec submits SAS statements through the SAS subcommand environment by specifying or defaulting to 'SAS' as its address. When a REXX exec receives control, the default subcommand environment for that program is 'SAS'. As illustrated in A Simple REXX Exec, any SAS language statement can then be passed to SAS for execution.

Interacting with the SAS Session from a REXX Exec

The REXX Interface

One of the main advantages of using the REXX interface is that it provides four types of communication between the REXX exec and the SAS session:
  • The REXX exec can route messages to the SAS log.
  • You can retrieve and set the value of any variable in the submitting REXX exec by using the GETEXEC DATA step function and the PUTEXEC DATA step routine.
  • You can check the return code from a SAS step in the REXX exec that submits it.
  • If a REXX exec returns a string, the string is written to the global macro variable SYSRXRLT.

Routing Messages from REXX Execs to the SAS Log

A set of SAS directives enables a REXX exec to print to the SAS log. SAS directives use a leading ++ sequence to differentiate them from normal SAS language statements that are submitted to the SAS subcommand environment.
Three directives are available:
address SAS '++SASLOG'
causes all subsequent SAS statements to be printed to the SAS log.
address SAS '++NOLOG'
stops subsequent SAS language statements from being printed to the SAS log.
address SAS '++SASLOG message-text'
places message-text into the SAS log and causes subsequent submitted statements to be printed to the SAS log. The message text can include quoted strings or REXX variables. Strings that are enclosed in single quotation marks are converted to uppercase, whereas strings that are enclosed in double quotation marks are not. For REXX variables that are not contained in quoted strings, SAS substitutes the values of those variables.

The GETEXEC DATA Step Function

You can use the GETEXEC function in SAS statements that are submitted to the SAS subcommand environment to retrieve the value of any variable in the submitting REXX exec. The syntax of the GETEXEC function is as follows:
value = GETEXEC(REXX-variable)
where REXX-variable is a SAS expression that represents the name of a REXX variable in uppercase and value receives the value of the specified REXX variable.
For an example of the GETEXEC function, see Using the GETEXEC DATA Step Function.

The PUTEXEC DATA Step Routine

You can call the PUTEXEC routine in SAS statements that are submitted to the SAS subcommand environment to assign the value of any variable in the submitting REXX EXEC. The syntax of the PUTEXEC routine is as follows:
CALL PUTEXEC(REXX-variable, value)
where REXX-variable is a SAS expression that represents the name of a REXX variable in uppercase and value is a SAS expression representing the value to be assigned to the specified REXX variable.
For an example of the PUTEXEC routine, see Using the PUTEXEC DATA Step Routine.

Checking Return Codes in REXX Execs

The REXX special variable RC is always set when any command string is submitted to an external environment.
SAS REXX execs are slightly different from ordinary execs, however, in the way RC is set. When an ordinary exec submits z/OS commands, the RC variable is set to the command return code when control returns to REXX. The strings that are submitted to SAS, however, are not necessarily complete execution units. SAS collects SAS language elements until a RUN statement is encountered, at which point the SAS step is executed. While partial program fragments are being submitted, the RC is set to 0. The SAS return code is not assigned to the REXX variable RC until the string that contains the RUN statement is submitted.
The RC value is set to the value of the &SYSERR macro variable. For an example of how the REXX variable RC can be tested after a SAS step has been executed, see Checking the SAS Return Code in a REXX Exec.

Changing the Host Command Environment

When a REXX EXEC that is invoked under SAS receives control, the default host command environment for that program is 'SAS'. You can use the ADDRESS instruction followed by the name of an environment to change to a different host command environment:
address tso
address sas
address mvs
For an example of using the ADDRESS instruction to execute a TSO statement, see Using the GETEXEC DATA Step Function.
You can also use the ADDRESS built-in function to determine which host command environment is currently active:
hcmdenv = address()
Use the SUBCOM command to determine whether a host command environment is available before trying to issue commands to that environment. The following example checks to see whether SAS is available:
/*  REXX  */
address mvs "subcom sas"
say "subcom sas rc:" rc
if rc = 1
   then sas="not "
   else sas=""
say "sas environment is "sas"available"

Comparing the REXX Interface to the X Statement

The X statement can be used to invoke a REXX exec. For more information, see X Statement: z/OS. However, compared to the REXX interface, the X statement has the following limitations:
  • With the X statement, the command that you invoke has no way to communicate information back to the SAS session.
  • With the X statement, you have to press Enter to return to SAS.
  • The X statement is available only when SAS is running in the TSO environment. A REXX exec can be invoked from a SAS program running in the batch environment, though it cannot issue TSO commands in the batch environment.

Comparing SAS REXX Execs to ISPF Edit Macros

In their structure and invocation, SAS REXX execs are analogous to ISPF EDIT macros.
  • SAS REXX execs are REXX programs in a library that is allocated to the SASREXX ddname (or to another ddname, as specified by the SAS system option REXXLOC=). They are submitted as part of a SAS program in the same way as any other global SAS statement. A SAS REXX exec submits SAS statements through the SAS subcommand environment by specifying or defaulting to 'SAS' as its "address".
  • ISPF edit macros can be REXX programs in the standard command procedure library (SYSPROC, SYSEXEC, or other). They are started from an ISPF EDIT command line in the same way as any other ISPF EDIT subcommand. An ISPF EDIT macro submits editor subcommands through the ISREDIT subcommand environment by specifying or defaulting to 'ISREDIT' as its "address" (the destination environment for a command string).

Examples of REXX Execs

A Simple REXX Exec

This REXX exec, called VERIFY, takes as its argument a single data set name. The REXX exec checks to see whether the data set exists. If so, the REXX exec routes a message to the SAS log to that effect. If the data set does not exist, the REXX exec creates the data set and then sends an appropriate message to the SAS log.
/*-------------- REXX exec VERIFY --------------*/
Parse Upper Arg fname .
retcode = Listdsi("'"fname"'")
If retcode = 0 Then Do
   Address SAS  "++SASLOG" fname "already exists"
   End
Else Do
   Address TSO "ALLOC FI(#TEMP#) DA('"fname"')
                RECFM(F B) LRECL(80) BLKSIZE(6160)
                DSORG(PS) SPACE(10 5) TRACK NEW"
   Address SAS  "++SASLOG" fname "created"
   Address TSO "FREE  FI(#TEMP#)"
   End
Exit

Using the GETEXEC DATA Step Function

This REXX exec executes a TSO command that generates a list of all filenames beginning with a specified prefix, and then deletes the files named in the list and places the names of the deleted files in a SAS data set.
/*------------- REXX exec DELDIR --------------*/
Parse Upper Arg file_prefx .
/*------ Execute the TSO LISTC Command --------*/
x = Outtrap('list.')
Address TSO "LISTC LVL('"FILE_PREFX"') "

/*--- Process Output from the LISTC Command ---*/
idx = 0
file_del.= ''

Do line = 1 To list.0 By 1
   Parse Var list.line word1 word2 word3
   If word1 = 'NONVSAM' Then Do
      fname = word3
      Address TSO  "DELETE '"fname"'"
      idx = idx + 1
      file_del.idx  = fname
      file_stat.idx = 'DELETED'
      End
   End

/*--- Pass a DATA step into the SAS System ----*/
Address SAS '++SASLOG'

"data results (keep = dsname status);            "
" total = getexec('IDX');                        "
" put 'Total z/OS files deleted: ' total;      "
" do i = 1 to total;                             "
"  dsnm = getexec('FILE_DEL.'  || trim(left(i)));"
"  stat = getexec('FILE_STAT.' || trim(left(i)));"
"  output;                                       "
"  end;                                          "
" run;                                           "

/*---------- Execute a SAS Procedure ----------*/
" proc print;                                    "
" run;                                           "

/*---------- Return to the SAS System ---------*/
Exit

Using the PUTEXEC DATA Step Routine

This REXX exec reads a set of high-level qualifiers from a SAS data set and writes them to REXX stem variables so that they can be processed by the REXX exec. Then the REXX exec loops through the high-level qualifiers, calling the DELDIR routine for each one in turn.
/*------------ REXX exec DELMANY -------------*/
/* Accepts as arguments up to 5 high-level    */
/* qualifiers
Parse Upper Arg arg1 arg2 arg3 arg4 arg5 .
hlq.=''
/*-=- Pass a DATA step into the SAS System ---*/
Address SAS '++SASLOG'
" data prefixes;                              "
"    input prefix $ 1-20;                     "
"    cards;                                   "
""arg1
""arg2
""arg3
""arg4
""arg5
";                                         "
" data _null_;                                "
" set prefixes;                               "
" rexxvar = 'HLQ.' || trim(left(_N_));        "
" call putexec(trim(rexxvar),prefix);         "
" call putexec('HLQ.0', trim(left(_N_)));     "
" run;                                        "
/*---------- Call the DELDIR REXX exec -------*/
Do idx = 1 To hlq.0
   pre = hlq.idx
   Call deldir pre
   End
/*------------ Return to SAS -–---------------*/
Exit rc

Checking the SAS Return Code in a REXX Exec

This REXX exec, called SHOWRC, demonstrates how the REXX variable RC can be tested after a SAS step has run:
/*-------------- REXX exec SHOWRC ------------*/
/* Accepts as argument a SAS data set         */
Parse Upper Arg ds_name .
Address SAS '++SASLOG'
"data newdata;                                "
"   set "ds_name";                            "
"   run;                                      "
If rc = 0 Then
   Say 'SAS DATA step completed successfully'
Else
   Say 'SAS DATA step terminated with rc=' rc
Exit