I am writing a Rexx - script for my mainframe shop. This would be an ISPF Edit-Macro called MINE, which takes one PARM parameter, you can MINE IN or you can MINE OUT. In a Cobol source-program, when the cursor is positioned at a PERFORM <para> statement, a MINE IN is used to jump from calling paragraph to the called paragraph. You can keep MIN'ing in. If you want to back-up and go back to the point from where you'd left off, you can MINE OUT.
During a TSO/ISPF Edit session, an average user would MINE IN and MINE OUT several times, while analysing a source-program. Upon each MINE IN, I would like to record the current-line number and the PERFORM <para-name> into an Application Shared Pool variable, say CALLSTK. I am going to use it like a stack. Next time, when user MINE's out, this information can be used to back-up.
My problem is, when the user first logs on to the Mainframe, the CALLSTK Variable does not exist. So, the VGET CALLSTK SHARED call sets a Return-Code of 08. But, this gets reports as a Syntax Error and Rexx script just stops running. I wanted a way to handle this - if the variable's not defined, VPUT it for the first time.
MINE Utility:
/* REXX - MINE TOOL(FOR COBOL PROGRAMS) */
/*__________________________________________________________________*/
/* AUTHOR : C QUASAR. QUASAR.CHUNAWALLA@GMAIL.COM */
/* */
/* DESCRIPTION : */
/* ----------- */
/* MINE REFERS TO SOFTWARE MINING AND IS FOR ANALYSIS OF */
/* COBOL PROGRAMS. */
/* */
/* IT RUNS AS AN EDIT-MACRO. THE <PF2> KEY IS USED TO TRAVERSE */
/* DOWN FROM THE CALLING TO THE CALLED ROUTINE. THE <PF4> KEY */
/* IS USED BACK UP. <PF1> KEY HELPS TO GENERATE A CALL GRAPH. */
/* */
/* */
/*__________________________________________________________________*/
TRACE ALL
/* START OF MACRO */
ADDRESS ISREDIT
"MACRO (PARM) NOPROCESS"
SIGNAL ON ERROR
/* ADDRESS ISPEXEC "CONTROL ERRORS RETURN" */
/*__________________________________________________________________*/
MAIN:
/*----- */
/* THE MAIN ROUTINE FIRST INITIALIZES THE VARIABLES TO THE DEFAULT */
/* VALUES. NEXT, IT READS THE LONG VARIABLE PARA_STACK TO DETERMINE */
/* HOW DEEP WE ARE IN THE CALL-TREE. DEPENDING UPON THE PARAMETER */
/* PASSED, 'IN' OR 'OUT' IT WILL PROCESSING IS PERFORMED. A <PF3> */
/* KEY-PRESS IS INTERCEPTED AND THE PARA_STACK VARIABLE IS CLEARED. */
/*__________________________________________________________________*/
CALL INITIALIZATION
IF PARM = 'IN' THEN DO
CALL MINE_IN
END
IF PARM = 'OUT' THEN DO
CALL MINE_OUT
END
EXIT
/*__________________________________________________________________*/
INITIALIZATION:
/*-------------- */
/* THE INITIALIZATION ROUTINE ASSIGNS TO DEFAULT VALUES TO VARIABLES*/
/* THAT ARE USED, EACH TIME THIS EXEC IS INVOKED. */
/*__________________________________________________________________*/
LINENUM = 0
LINEDATA = ''
RACFID = ''
EDIT_DATASET = ''
PARAGRAPH = ''
LINE_NUMBER = 00
PARA_NAME = ''
CALLSTK = ''
RETURN
/*__________________________________________________________________*/
VGET_CALL_STACK:
/*-------------- */
/* THIS ROUTINE VGETS THE CALLSTK VARIABLE FROM THE ISPF SHARED */
/* POOL. */
/*__________________________________________________________________*/
ADDRESS ISPEXEC "VGET (CALLSTK) SHARED"
SAY 'VGET : ' CALLSTK
RETURN
/*__________________________________________________________________*/
VPUT_CALL_STACK:
/*-------------- */
/* THIS ROUTINE VPUTS THE CALLSTK VARIABLE TO THE ISPF SHARED */
/* POOL. */
/*__________________________________________________________________*/
ADDRESS ISPEXEC
"VPUT CALLSTK SHARED";
SAY 'VPUT : ' CALLSTK
RETURN
/*__________________________________________________________________*/
MINE_IN:
/*------- */
/* THIS ROUTINE JUMPS FROM THE CALLING <PARA> TO THE CALLED <PARA>. */
/* IT FIRST ACQUIRES THE LINE-NO, THE PERFORM PARA-NAME, THE RACFID */
/* AND THE CURRENT DATASET NAME AND APPENDS THEM TO THE CALLSTK */
/* VARIABLE IN THE BASE ISR SHARED POOL. */
/* NEXT, IT EXECUTES THE FIND ALL <PARA-NAME> 08 COMMAND TO JUMP */
/* TO THE CALLED PARAGRAPH. */
/*__________________________________________________________________*/
/* GET THE CURRENT LINE NUMBER, WHERE THE CURSOR IS POSITIONED */
ADDRESS ISREDIT
"(LINENUM) = LINENUM .ZCSR"
/* GET THE CURRENT LINE DATA */
ADDRESS ISREDIT
"(LINEDATA) = LINE .ZCSR"
/* PARSE THE CURRENT LINE-OF-CODE, TO SEE IF THIS IS A PERFORM */
PARSE VAR LINEDATA TAG 8,
AREA_A 12,
AREA_B 72,
COMMENT
/* IF AREA-B STATEMENT CONTAINS THE COBOL KEYWORD PERFORM */
IF INDEX(AREA_B,'PERFORM') > 0
THEN DO
/* THE TSO-USER RACF-ID - 8 BYTES */
RACF_ID = USERID()
RACF_ID = RACF_ID || COPIES(' ',08 - LENGTH(RACF_ID))
/* THE STATEMENT NUMBER OF PERFORM <PARA> - 08 BYTES */
LINE_NUMBER = LINENUM
/* THE COBOL PARAGRAPH NAME - 30 BYTES */
PARSE VAR AREA_B VERB PARAGRAPH .
PARAGRAPH = PARAGRAPH || COPIES(' ',30 - LENGTH(PARAGRAPH))
/* THE CURRENT DATASET OPEN IN EDIT MODE - 54 BYTES */
ADDRESS ISREDIT "(CURDSN) = DATASET"
ADDRESS ISREDIT "(MEMBER) = MEMBER"
CURDSN = CURDSN || '(' || MEMBER || ')'
CURDSN = CURDSN || COPIES(' ',54 - LENGTH(CURDSN))
/* APPEND THE DATA TO END OF THE CALLSTK */
CALL VGET_CALL_STACK
CALLSTK = CALLSTK || RACFID || LINE_NUMBER,
|| PARAGRAPH || CURDSN || '|'
CALL VPUT_CALL_STACK
/* EXECUTE THE FIND ALL <PARA-NAME> 08 COMMAND */
ADDRESS ISREDIT "FIND ALL "PARAGRAPH" 08 "
END
RETURN
/*__________________________________________________________________*/
/* AUTHOR : C QUASAR. QUASAR.CHUNAWALLA@GMAIL.COM */
/* */
/* DESCRIPTION : */
/* ----------- */
/* MINE REFERS TO SOFTWARE MINING AND IS FOR ANALYSIS OF */
/* COBOL PROGRAMS. */
/* */
/* IT RUNS AS AN EDIT-MACRO. THE <PF2> KEY IS USED TO TRAVERSE */
/* DOWN FROM THE CALLING TO THE CALLED ROUTINE. THE <PF4> KEY */
/* IS USED BACK UP. <PF1> KEY HELPS TO GENERATE A CALL GRAPH. */
/* */
/* */
/*__________________________________________________________________*/
TRACE ALL
/* START OF MACRO */
ADDRESS ISREDIT
"MACRO (PARM) NOPROCESS"
SIGNAL ON ERROR
/* ADDRESS ISPEXEC "CONTROL ERRORS RETURN" */
/*__________________________________________________________________*/
MAIN:
/*----- */
/* THE MAIN ROUTINE FIRST INITIALIZES THE VARIABLES TO THE DEFAULT */
/* VALUES. NEXT, IT READS THE LONG VARIABLE PARA_STACK TO DETERMINE */
/* HOW DEEP WE ARE IN THE CALL-TREE. DEPENDING UPON THE PARAMETER */
/* PASSED, 'IN' OR 'OUT' IT WILL PROCESSING IS PERFORMED. A <PF3> */
/* KEY-PRESS IS INTERCEPTED AND THE PARA_STACK VARIABLE IS CLEARED. */
/*__________________________________________________________________*/
CALL INITIALIZATION
IF PARM = 'IN' THEN DO
CALL MINE_IN
END
IF PARM = 'OUT' THEN DO
CALL MINE_OUT
END
EXIT
/*__________________________________________________________________*/
INITIALIZATION:
/*-------------- */
/* THE INITIALIZATION ROUTINE ASSIGNS TO DEFAULT VALUES TO VARIABLES*/
/* THAT ARE USED, EACH TIME THIS EXEC IS INVOKED. */
/*__________________________________________________________________*/
LINENUM = 0
LINEDATA = ''
RACFID = ''
EDIT_DATASET = ''
PARAGRAPH = ''
LINE_NUMBER = 00
PARA_NAME = ''
CALLSTK = ''
RETURN
/*__________________________________________________________________*/
VGET_CALL_STACK:
/*-------------- */
/* THIS ROUTINE VGETS THE CALLSTK VARIABLE FROM THE ISPF SHARED */
/* POOL. */
/*__________________________________________________________________*/
ADDRESS ISPEXEC "VGET (CALLSTK) SHARED"
SAY 'VGET : ' CALLSTK
RETURN
/*__________________________________________________________________*/
VPUT_CALL_STACK:
/*-------------- */
/* THIS ROUTINE VPUTS THE CALLSTK VARIABLE TO THE ISPF SHARED */
/* POOL. */
/*__________________________________________________________________*/
ADDRESS ISPEXEC
"VPUT CALLSTK SHARED";
SAY 'VPUT : ' CALLSTK
RETURN
/*__________________________________________________________________*/
MINE_IN:
/*------- */
/* THIS ROUTINE JUMPS FROM THE CALLING <PARA> TO THE CALLED <PARA>. */
/* IT FIRST ACQUIRES THE LINE-NO, THE PERFORM PARA-NAME, THE RACFID */
/* AND THE CURRENT DATASET NAME AND APPENDS THEM TO THE CALLSTK */
/* VARIABLE IN THE BASE ISR SHARED POOL. */
/* NEXT, IT EXECUTES THE FIND ALL <PARA-NAME> 08 COMMAND TO JUMP */
/* TO THE CALLED PARAGRAPH. */
/*__________________________________________________________________*/
/* GET THE CURRENT LINE NUMBER, WHERE THE CURSOR IS POSITIONED */
ADDRESS ISREDIT
"(LINENUM) = LINENUM .ZCSR"
/* GET THE CURRENT LINE DATA */
ADDRESS ISREDIT
"(LINEDATA) = LINE .ZCSR"
/* PARSE THE CURRENT LINE-OF-CODE, TO SEE IF THIS IS A PERFORM */
PARSE VAR LINEDATA TAG 8,
AREA_A 12,
AREA_B 72,
COMMENT
/* IF AREA-B STATEMENT CONTAINS THE COBOL KEYWORD PERFORM */
IF INDEX(AREA_B,'PERFORM') > 0
THEN DO
/* THE TSO-USER RACF-ID - 8 BYTES */
RACF_ID = USERID()
RACF_ID = RACF_ID || COPIES(' ',08 - LENGTH(RACF_ID))
/* THE STATEMENT NUMBER OF PERFORM <PARA> - 08 BYTES */
LINE_NUMBER = LINENUM
/* THE COBOL PARAGRAPH NAME - 30 BYTES */
PARSE VAR AREA_B VERB PARAGRAPH .
PARAGRAPH = PARAGRAPH || COPIES(' ',30 - LENGTH(PARAGRAPH))
/* THE CURRENT DATASET OPEN IN EDIT MODE - 54 BYTES */
ADDRESS ISREDIT "(CURDSN) = DATASET"
ADDRESS ISREDIT "(MEMBER) = MEMBER"
CURDSN = CURDSN || '(' || MEMBER || ')'
CURDSN = CURDSN || COPIES(' ',54 - LENGTH(CURDSN))
/* APPEND THE DATA TO END OF THE CALLSTK */
CALL VGET_CALL_STACK
CALLSTK = CALLSTK || RACFID || LINE_NUMBER,
|| PARAGRAPH || CURDSN || '|'
CALL VPUT_CALL_STACK
/* EXECUTE THE FIND ALL <PARA-NAME> 08 COMMAND */
ADDRESS ISREDIT "FIND ALL "PARAGRAPH" 08 "
END
RETURN
Error Output:
76 *-* ADDRESS ISPEXEC "VGET (CALLSTK) SHARED"
>>> "VGET (CALLSTK) SHARED"
+++ RC(8) +++
76 +++ ADDRESS ISPEXEC "VGET (CALLSTK) SHARED"
146 +++ CALL VGET_CALL_STACK
41 +++ CALL MINE_IN
+++ "ERROR"
IRX0016I Error running MINE, line 76: Label not found
>>> "VGET (CALLSTK) SHARED"
+++ RC(8) +++
76 +++ ADDRESS ISPEXEC "VGET (CALLSTK) SHARED"
146 +++ CALL VGET_CALL_STACK
41 +++ CALL MINE_IN
+++ "ERROR"
IRX0016I Error running MINE, line 76: Label not found
Thank you very much and appreciate any help you can provide.