How to REXXSKEL

How to REXXSKEL

REXXSKEL is the kernel around which all of my tools are built.  Some minimal understanding of what REXXSKEL is and what it does is a prerequisite for understanding or maintaining the code you'll find here.

REXXSKEL, unfortunately, is not a static entity.  It changes over time, and it is normal to find a dozen different versions in current use throughout the codebase.  I try very hard to keep REXXSKEL 'backward-compatible' so that retrofitting does not become necessary but I have no compunctions about improving it when and as necessary.  The current version is '20260528' (266 lines).

All code which has been fitted for REXXSKEL exhibits a certain behavior:

  1. if the first argument passed to the routine is a question mark ("?"), any available HELP-text is displayed and the routine ends;

  2. arguments passed to these routines are logically divided by the presence of a double open parenthesis ("((") into "parms" before the "((" and "opts" after.  These may be thought of, respectively, as "what shall we do" and "how shall we do it".


KEYWD and SWITCH

Key to the operation of REXXSKEL and independently usable by the application code itself are several internal subroutines, among which are KEYWD and SWITCH.  All such subroutines examine the contents of variable "info" which must be populated prior to calling any of them.

KEYWD examines "info" for the presence of the token which has been passed as its sole argument.  (The 'token' may actually be more than one word, but spacing between words then becomes significant.)  If that token exists in "info", the token which follows it immediately (in the string of "info") is returned as the function value, and both tokens are removed from "info" to prevent duplicate processing.

SWITCH examines "info" for the presence of the token which has been passed as its sole argument.  If that token exists in "info", a '1' bit is returned as the function value and the token is removed from "info" to prevent duplicate processing; if the token does not exist, a '0' bit is returned.

TOOLKIT_INIT establishes "info" by loading "opts", so that TV, TRAPOUT, BRANCH, MONITOR, and NOUPDT (the items parsed-out in TOOLKIT_INIT) are all derived by default from "opts", the portion of the argument following the "((".  Before it returns control to the mainline, TOOLKIT_INIT calls LOCAL_PREINIT, a stub routine which may be used by the application programmer to process any locally-defined opts-values.  (LOCAL_PREINIT is placed before HELP in the standard REXXSKEL to indicate that it is not intended to be replaced when upgrading to a more recent version.)

On return from TOOLKIT_INIT (into the mainline), "info" is refreshed from "parms", so that all other switches and keyword values will be determined from that portion of the argument preceeding the "((".


KEYPHRS

This variant of KEYWD exists for passing multiple values.  Naturally, the syntax of KEYPHRS is a little different than KEYWD: KEYPHRS expects to find a 2-character marker immediately following the KEYPHRS argument in "info"; it also expects to find this same marker further along in info.  The text between the markers is returned as the function.  The marker can be any two characters except, obviously, '40'x.

A parameter might include the string

TEXT :{ this is text to be parsed :{
which would be parsed out by
text_phrase = KEYPHRS("TEXT")


CLKWD

This variant of KEYWD handles parameters passed as for CLISTs, where the text is passed within parentheses. 

A parameter might include the string

TEXT( this is text to be parsed )
which would be parsed out by
text_phrase = CLKWD("TEXT")


HELP

A pro-forma HELP paragraph is provided as a guide.  Most of it is commented out; the only section which is active in the unaltered REXXSKEL writes "helpmsg" if it is not blank.  Pro-forma blocks are provided for functional description, syntax, and parameters, and the nature and uses of the standard diagnostic parameters is also covered.


SYNTAX

Debugging tools can be accessed in the following manner:

 TSO exec_name  parameters  ((  debug-options

                                BRANCH
                                MONITOR
                                NOUPDT
                                TRAPOUT
                                TRACE tv
                                'exec specific'


OPERANDS

BRANCH an indicator that causes the name of any internal subroutine to be printed as control is transferred to it;
MONITOR an indicator which may be used by the application code to control the display of diagnostic messages and progress notes during execution;
NOUPDT an indicator which may be used by the application code to suppress WRITE operations to its outputs;
TRAPOUT an indicator that routine TRAPOUT is to be started as a shell around this routine; TRAPOUT will produce a dataset under the caller's ID containing "TRACE R" output;
tv a value used by the application code to set up tracing; specifying (e.g.) "trace ?r" will cause the called routine to begin tracing in 'interactive-results' mode immediately after its return from TOOLKIT_INIT
exec-specific Programmer-provided facilities designed to be customized debugging features.


REXXSKEL adjuncts

There is a family of macros that work in conjunction with the canonical REXXSKEL and that make it easy for you to groom your REXXSKEL-based code to have a uniform, recognizable format that enhances the ability of your teammates to jump in and handle your code as if they wrote it.

CR CR is the first macro in the stable.   It Copies REXXSKEL from its source location to the empty member you've just created to get you started.   As it ends, it positions the cursor on the "..." at the first 'address' specification, encouraging you to specify the address environment for the mainline code.   They follow in roughly the order in which you will want to execute them.
WB Next, you want to fill in the 'Written by' line.   WB will get its marching orders from your personal copy of WBNAME.
WBNAME This little stub routine sends back to WB your personal information for the 'Written by' line.
IDENT IDENT places the name of this member on the first line and also on the 'exit' line that ends the mainline.
MAKEPARA You've written the mainline of your routine, barely more than CALLs to the next-level routines, or you're in one of those routines that issue CALLs to routines further down the hierarchy.   Put an 'A' or a 'B' on some line to indicate where your want the paragraph for that CALL to be located, place the cursor on the line with the CALL, and issue 'MAKEPARA', preferably via a dedicated PFKey.   The text of member '$EXAMPLE' will be copied to the position you specified and altered to take the form of a standard paragraph.   The cursor is positioned at the paragraph's 'address' line as an invitation to specify the default address setting for the subroutine code.   If the CALL statement had a line-comment, that comment is replicated to the paragraph's header.
$EXAMPLE $EXAMPLE is the baseline text of a canonical REXXSKEL paragraph.   MAKEPARA copies this text in at the location you specify and customizes it appropriately.
MARK REXXSKEL protocol is that every CALL statement has a comment line (filled or empty) and ends with "-*/".   MARK places the dash at the end-comment marker.

You will also need to have RUNDATA and TRAPOUT in your SYSEXEC concatenation.   They're already available, right?


Philosophy

REXXSKEL developed over a long period starting, as you might expect, as a very simple, straight-forward cluster of diagnostic and parsing subroutines.  Various people have contributed various improvements as it evolved and I am indebted to them for their innovations.  But always the thrust has been to provide a compact package of easily understood and broadly-useful routines that will enable the application programmer to quickly generate and easily debug routines of any arbitrary complexity.  Naturally, this requires a certain discipline.

While REXX itself allows the programmer to "get away with" many shortcuts, a complex or elaborate program will quickly grow fragile if such shortcuts are tolerated.  REXXSKEL, therefore, begins with a "signal on novalue"; that is: uninitialized variables are not permitted.  Good programmers don't rely on defaults.  It also issues a "signal on syntax" to trap the odd development error.  Both SYNTAX and NOVALUE invoke SHOW_SOURCE to display the failing line.  SHOW_SOURCE calls DUMP_QUEUE to clear any outstanding stacks.  These filigrees are not absolutely necessary, but their inclusion as part of REXXSKEL means the programmer doesn't have to write them and, more importantly, doesn't have to worry about leaving them out. 

It is better to have and not need than to need and not have.  That, in a nutshell, is the basic philosophy of REXXSKEL.