REXX has a very powerful tracing feature. It outperforms other compiler languages which require additional features to achieve only partly the same results (e.g. COBOL Interactive Debug, PL/I Checkout Compiler).
The fact that REXX has such elaborated tracing features is maybe the reason for its success as computer language. The tracing lets you find very quickly the syntax or logic errors in your procedures, leading to a faster development and less error prone programs.
This lesson discusses many of the aspects related to tracing and debugging REXX procedures. Most of it applies to the PC environment as well, but we will focus on the CMS environment.
Before you learn the details of tracing, you have to understand how CMS handles commands and what's meant by immediate commands.
There are 2 ways to pass commands to CMS :
At the CMS Ready; prompt. CMS has a special routine to handle terminal input interrupts.
Via the CMS SVC interface (footnote), hence from a program where SVC 202 or SVC 204 are available. This is the way REXX, XEDIT, OfficeVision, etc. pass commands to CMS.
To be complete, the SVC interface also allows to pass subcommands to specific environments, such as XEDIT. REXX does it by using the address environment statement as we have learned from previous lesson.
The commands are treated differently, depending on how they are invoked:
Commands from the console are handled by the CMS terminal interrupt handler which reads the command and queues it on the terminal input stack. The queued command(s) will then be executed one after the other.
Commands sent via the SVC interface are initiated immediately, so these commands do not pass via the terminal input stack. While the command is executing, the calling program is suspended.
Now let's explain the terminal command handling in more detail:
Just before CMS shows its Ready; message, it performs some cleanup: it closes all open files, frees storage buffers, etc. in order to restore a clean environment for the next command. It does everything a good programmer should do also before leaving a program.
Just after displaying the Ready; prompt, CMS looks for a new command:
from the program stack. If one is found, then it is pulled from the stack and initiated.
If none is found, then CMS looks for a command in the terminal input buffer.
Stacking new commands is a common technique used by many procedures, but it also generates problems if procedures leave something on the stack when terminating (abending). We find this one good reason to avoid the use of the program stack whenever possible. We will come back on this matter and give you other good reasons not to use the stack.
The differences between the terminal buffer and the program stack are summarized below:
Terminal input buffer |
- Written to from the keyboard
- Number of entries can be queried from REXX using externals() - Entries can be read with parse external... - Entries are flushed via the CMS command DESBUF. |
Program stack | - Written to by programs, such as query... (stack
- Written to by REXX via push or queue - Number of entries can be queried from REXX using queued() - Entries can be read with parse pull ... - Entries can be flushed via the CMS commands DROPBUF or DESBUF |
Terminal output buffer |
- Written to by programs, such as say in REXX
- Entries can be flushed via the CMS command DESBUF. |
Note: When the program stack is empty, parse pull results in a read from the terminal input buffer. When that is empty too, the terminal will come into a VM READ status and any input entered at that moment is not processed by the CMS terminal interrupt program, but passed directly to the reading program !
We said that the terminal interrupt handler puts the commands on the terminal input stack, but there is an exception to this : the terminal interrupt handler first looks at the command, and if it is defined as an immediate command, the command is executed immediately, it is not placed on the terminal input stack.
The most important standard immediate commands,
related to REXX, are :
TS | "Trace Start" - start REXX or EXEC2 external tracing |
TE | "Trace End" - stop REXX or EXEC2 external tracing |
HI | "Halt Interpreter" - terminate the currently active REXX or EXEC2 procedure(s) |
HT | "Halt typing" - suppress CMS command output |
RT | "Resume typing" - allow CMS command output again |
It is possible to define new immediate commands in procedures or via assembler programming. The commands to use in procedures are then:
'IMMCMD SET mycmd' /* define new Immediate command */ 'IMMCMD STATUS mycmd' /* test if user entered "mycmd" */ 'IMMCMD CLEAR mycmd' /* undefine our immed. command */
What do immediate commands do ?
Most don't do much : the standard CMS immediate commands simply set a control bit on or off. This control bit can then be tested by other programs.
For example, the HT bit is tested by the CMS terminal output program, while the HI bit is continuously watched by the REXX interpreter.
Not surprisingly there are also CMS commands to play with these bits :
SET EXECTRAC ON | OFF equates TS | TE SET CMSTYPE HT | RT equates HT | RT
The SET versions of the commands are for use in procedures because in that case, immediate commands have no effect. The commands do not pass via the terminal input buffer, and can not be intercepted by CMS.
Immediate commands declared via immcmd set in a REXX procedure also only set a bit, which can be tested via the immcmd status command.
The PC REXX interpreter has no equivalent immediate commands. The system or the programs can however define 'hot-keys' that allow some interaction. The Ctrl-Break key combination is one example. OS/2 has however the set rxtrace=on|off command that is similar to the set exectrac command of CMS.
For a short example of user defined immediate commands, see below ; for a real example you could check the MC XEDIT macro which is part of the goodies.
Sample programming of immediate commands |
---|
... 'IMMCMD SET HELA' /* define our immed cmd */ Say 'If you want to intervene, please type HELA' do i=1 for a_very_long_loop 'IMMCMD STATUS HELA' if rc=1 then call user_requested_something ... ... work on item i .... ... end exit: 'IMMCMD CLEAR HELA' /* remove our immcmd */ ... other cleanup ... exit /************************* Subroutine **********************************/ USER_REQUESTED_SOMETHING: Say 'Hi dear user, what do you want ?' Say ' enter SHOW to show the status of the work done so far.' Say ' enter MORE to request we read even more work.' Say ' enter STOP to end working now.' Parse upper external request . select when request='STOP' then signal exit ... end return |
Of course, previous procedure could define (and query) SHOW, MORE and STOP as immediate commands. It could even redefine TS, HI and HX, so that it is possible to disable the cancelling of a procedure...
This concludes our introduction to tracing in REXX. Chapter 5 will enter into the details about it.
Footnotes:
Note that if you ever have to write Assembler programs which invoke
CMS commands, you should now use the CMSCALL
macro, which is easier to use and has more complete options than the
(still available) older SVC 202 technique.
This macro will use the newer SVC 204 code.
Back to text