It frequently happens that a routine needs a local memory i.e. requires the value of some variable be preserved between calls to the routine. Classic reasons for doing this are to have the routine perform initialisation on the first call or so that the routine can increment a count each time it is called. To do this the variable must explicitly or implicitly be declared in a SAVE statement and must be initialised with a DATA statement unless the routine has some other method of initialising it.
During optimisation a compiler may move a variable into a register even if it is declared in a SAVE; the compiler is only obliged to copy it back to memory before returning. Unfortunately this can lead to a conflict with the ZEBRA error recovery routine ZTELL. As explained in the SNOMAN User Manual, error recovery results in interruption of the current routine and resumption of the application by a call QNEXT again. Thus there is no guarantee that the latest values of any local variables for any routine on the CALL stack between the call of ZTELL and QNEXT will be in memory. Recalling any such a routine may pick up an out of date value.
The solution is to move all local memory variables into COMMON blocks for then the compiler must return the values to memory before executing any CALL and the correct values will be in memory even if error recovery occurs. This then raises further questions:-
The answer is to have a private COMMON for each routine that requires it. The naming convention is PCxxxx (PC -- Private COMMON, xxxx -- the first 4 letters of the routine name). Although these can be initialised by BLOCK DATA this is not recommend as they can get overlooked during linking if SNOMAN is set up as a library. Instead the following scheme is recommended.
The routine is given an ENTRY point whose name is INxxxx and whose function is to initialise the local memory variables. By making it an ENTRY point it shares the local definition of the /PCxxxx/ COMMON and there is no need to create an INCLUDE file for the COMMON. The ENTRY point should have a single parameter - the error flag (see the software standards for the SUBROUTINE statement) e.g.:-
ENTRY INEVAN(IRETC)as an entry point for EVANAL. You must pass on a request to the SNOMAN Coordinator explaining:-
Remember, all this complication is only necessary if the routine calls ZTELL directly, or indirectly (e.g. any request for ZEBRA memory may end in ZTELL reporting store full) or calls any routine that may. Simple routines may use SAVE and DATA.