The rexx exec, I have created is called MINE. MINE refers to software mining and helps in the analysis of Cobol Programs. It runs as an Edit-Macro. The <Pf2> key is used to traverse down from Calling paragraph to the called paragraph. The <Pf4> key is used to back up. On pressing the <Pf1> key within a Cobol paragraph, it prepares a structure chart and displays all the caller and called routines. Take a look below.
Example 01 of the generated structure chart
Example 02 of the generated structure chart
I am displaying the structure chart in a dynamic-area. For the sake of readability and ease of understanding, I am not putting the entire Rexx script here, instead I have pasted only a section of the code, that is responsible for generating the structure chart. The next level of functionality, I intend to add to the above structure chart is, the paragraph-name fields should be unprotected and the if the user places his cursor on any other paragraph e.g. on 2000-MAINLINE-PROCESSING and presses <enter>, its calling and called routines should be displayed. I am not sure, how to go about this.
How do I make a part of the Dynamic Area, unprotected? How do I detect the cursor position?
GEN_FLOW_GRAPH:
/* UNDER WHICH PARAGRAPH WAS THE PF1 KEY PRESSED */
ADDRESS ISREDIT "FIND PREV P' #' 07"
ADDRESS ISREDIT "(LINEDATA) = LINE .ZCSR"
PARSE VAR LINEDATA TAG 08 GRAPH_PARA '.' .
/* COLLECT THE LIST OF ALL THE PARAGRAPHS IN AN ARRAY. */
LBL = 'PD'
ADDRESS ISREDIT "X ALL 07 '*'"
ADDRESS ISREDIT "F ALL 'PROCEDURE' 08"
ADDRESS ISREDIT "X ALL .ZF .ZCSR"
ADDRESS ISREDIT "UP MAX"
DO FOREVER
ADDRESS ISREDIT "F 08 P'^' NX"
IF RC > 0 THEN DO
PARA_LIST.0 = PARA_IDX
ADDRESS ISREDIT "RESET"
LEAVE
END
ELSE DO
/* 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 '.'
IF INDEX(AREA_A,'EXIT') = 0
THEN DO
PARA_IDX = PARA_IDX + 1
PARA_LIST.PARA_IDX = AREA_A
END
END
END
N = PARA_IDX
/* BUILD THE FLOW GRAPH - IT WILL BE A N X N MATRIX */
/* FIRST WE SHALL INITIALIZE THE MATRIX */
DO X = 1 TO N
DO Y = 1 TO N
GRAPH.X.Y = 0
END
END
DO PARA_IDX = 1 TO N
/* POSITION THE CURSOR AT THE PARA */
ADDRESS ISREDIT "F ALL "PARA_LIST.PARA_IDX" 08"
ADDRESS ISREDIT "(LINENUM) = LINENUM .ZCSR"
ADDRESS ISREDIT "(LASTLIN) = LINENUM .ZLAST"
SAY 'PARA:' PARA_LIST.PARA_IDX
/* READ ALL THE LINES IN THIS PARAGRAPH TILL THE END-OF-PARA */
DO FOREVER
/* QUERY THE LINE-NUMBER */
LINENUM = LINENUM + 1
ADDRESS ISREDIT "(LINEDATA) = LINE "LINENUM""
PARSE VAR LINEDATA TAG 8,
AREA_A 12,
AREA_B 72,
COMMENT
IF (AREA_A > '') | (LINENUM > LASTLIN) THEN DO
LEAVE
END
SAY 'AREA_B : ' AREA_B
/* IF A PERFORM STATEMENT IS FOUND ON THIS LINE */
IF INDEX(AREA_B,'PERFORM') > 0 DO
THEN DO
PARSE VAR AREA_B VERB PARAGRAPH
IF PARAGRAPH = 'VARYING' | PARAGRAPH = 'UNTIL' THEN DO
ITERATE
END
ELSE DO
SAY 'PARA-FOUND : ' PARAGRAPH
X = PARA_IDX
/* SEARCH THIS PARAGRAPH NAME IN THE PARA_LIST */
DO Y = 1 TO N
IF PARA_LIST.Y = PARAGRAPH THEN DO
SAY 'X:' X ' Y:' Y
/* THERE SHOULD BE AN EDGE FROM X TO Y */
GRAPH.X.Y = 1
END
END
END
END
END
END
DO X = 1 TO N
DO Y = 1 TO N
SAY 'GRAPH(' X ',' Y ')' GRAPH.X.Y
END
END
/* FIND OUT ALL EDGES LEADING INTO THE GRAPH_PARA - CALLER_LIST */
DO Y = 1 TO N
IF PARA_LIST.Y = GRAPH_PARA THEN DO
LEAVE
END
END
I = 0
DO X = 1 TO N
IF GRAPH.X.Y = 1 THEN DO
I = I + 1
CALLER_LIST.I = PARA_LIST.X
SAY 'CALLER_LIST.' I ' = ' CALLER_LIST.I
END
END
X = Y
/* FIND OUT ALL EDGES GOING OUT OF THE GRAPH_PARA - CALLED_LIST */
I = 0
DO Y = 1 TO N
IF GRAPH.X.Y = 1 THEN DO
I = I + 1
CALLED_LIST.I = PARA_LIST.Y
SAY 'CALLED_LIST.' I ' = ' CALLED_LIST.I
END
END
/* BUILD THE CONNECTOR ARRAY */
IF CALLER_LIST.1 > '' THEN DO
CALLER_CONNECTOR.1 = '-----'
END
ELSE DO
CALLER_CONNECTOR.1 = COPIES(' ',05)
END
J = 1
DO J = 02 TO 05
I = (J - 1)*2
IF CALLER_LIST.J > '' THEN DO
CALLER_CONNECTOR.I = ' | '
I = I + 1
CALLER_CONNECTOR.I = '--+ '
END
ELSE DO
CALLER_CONNECTOR.I = ' '
I = I + 1
CALLER_CONNECTOR.I = ' '
END
END
IF CALLED_LIST.1 > '' THEN DO
CALLED_CONNECTOR.1 = '-----'
END
ELSE DO
CALLED_CONNECTOR.1 = COPIES(' ',05)
END
J = 1
DO J = 02 TO 05
I = (J - 1)*2
IF CALLED_LIST.J > '' THEN DO
CALLED_CONNECTOR.I = ' | '
I = I + 1
CALLED_CONNECTOR.I = ' +--'
END
ELSE DO
CALLED_CONNECTOR.I = COPIES(' ',05)
I = I + 1
CALLED_CONNECTOR.I = COPIES(' ',05)
END
END
/* BUILD THE DYNAMIC AREA */
DO I = 1 TO 05
CALLER_LIST.I = SUBSTR(CALLER_LIST.I,1,20)
CALLED_LIST.I = SUBSTR(CALLED_LIST.I,1,20)
CALLER_LIST.I = LEFT(CALLER_LIST.I,20)
CALLED_LIST.I = LEFT(CALLED_LIST.I,20)
IF CALLER_LIST.I > '' THEN DO
SHAD_CALLER_LIST.I = COPIES('Y',20)
END
ELSE DO
SHAD_CALLER_LIST.I = COPIES(' ',20)
END
IF CALLED_LIST.I > '' THEN DO
SHAD_CALLED_LIST.I = COPIES('Y',20)
END
ELSE DO
SHAD_CALLED_LIST.I = COPIES(' ',20)
END
END
GRAPH_PARA = SUBSTR(GRAPH_PARA,1,20)
GRAPH_PARA = LEFT(GRAPH_PARA,20)
SAY 'CALLED_CONNECTOR 2= ' CALLED_CONNECTOR.2
SAY 'CALLED_CONNECTOR 3= ' CALLED_CONNECTOR.3
DYNVAR = ''
SHADVAR = ''
DYNVAR = DYNVAR ||,
CALLER_LIST.1 || CALLER_CONNECTOR.1 || GRAPH_PARA ||,
CALLED_CONNECTOR.1 || CALLED_LIST.1 ||,
COPIES(' ',05) ||,
COPIES(' ',20)|| CALLER_CONNECTOR.2 || COPIES(' ',20) ||,
CALLED_CONNECTOR.2 || COPIES(' ',25),
||CALLER_LIST.2 || CALLER_CONNECTOR.3 || COPIES(' ',20) ||,
CALLED_CONNECTOR.3 || CALLED_LIST.2 ||,
COPIES(' ',05) || ,
COPIES(' ',20)|| CALLER_CONNECTOR.4 || COPIES(' ',20) ||,
CALLED_CONNECTOR.4 || COPIES(' ',25),
||CALLER_LIST.3 || CALLER_CONNECTOR.5 || COPIES(' ',20) ||,
CALLED_CONNECTOR.5 || CALLED_LIST.3 ||,
COPIES(' ',05) || ,
COPIES(' ',20)|| CALLER_CONNECTOR.6 || COPIES(' ',20) ||,
CALLED_CONNECTOR.6 || COPIES(' ',25),
||CALLER_LIST.4 || CALLER_CONNECTOR.7 || COPIES(' ',20) ||,
CALLED_CONNECTOR.7 || CALLED_LIST.4 ||,
COPIES(' ',05) || ,
COPIES(' ',20)|| CALLER_CONNECTOR.8 || COPIES(' ',20) ||,
CALLED_CONNECTOR.8 || COPIES(' ',25),
||CALLER_LIST.5 || CALLER_CONNECTOR.9 || COPIES(' ',20) ||,
CALLED_CONNECTOR.9 || CALLED_LIST.5 ||,
COPIES(' ',05)
SHADVAR = SHADVAR,
|| SHAD_CALLER_LIST.1 || COPIES(' ',05) || COPIES('Y',20),
|| COPIES(' ',05) || SHAD_CALLED_LIST.1,
|| COPIES(' ',05) || COPIES(' ',75),
||SHAD_CALLER_LIST.2 || COPIES(' ',05) || COPIES(' ',20),
|| COPIES(' ',05) || SHAD_CALLED_LIST.2,
|| COPIES(' ',05) || COPIES(' ',75),
||SHAD_CALLER_LIST.3 || COPIES(' ',05) || COPIES(' ',20),
|| COPIES(' ',05) || SHAD_CALLED_LIST.3,
|| COPIES(' ',05) || COPIES(' ',75),
||SHAD_CALLER_LIST.4 || COPIES(' ',05) || COPIES(' ',20),
|| COPIES(' ',05) || SHAD_CALLED_LIST.4,
|| COPIES(' ',05) || COPIES(' ',75),
||SHAD_CALLER_LIST.5 || COPIES(' ',05) || COPIES(' ',20),
|| COPIES(' ',05) || SHAD_CALLED_LIST.5,
|| COPIES(' ',05)
ADDRESS ISPEXEC "ADDPOP"
ADDRESS ISPEXEC "DISPLAY PANEL(DYNAREA)"
ADDRESS ISPEXEC "REMPOP"
RETURN
/* UNDER WHICH PARAGRAPH WAS THE PF1 KEY PRESSED */
ADDRESS ISREDIT "FIND PREV P' #' 07"
ADDRESS ISREDIT "(LINEDATA) = LINE .ZCSR"
PARSE VAR LINEDATA TAG 08 GRAPH_PARA '.' .
/* COLLECT THE LIST OF ALL THE PARAGRAPHS IN AN ARRAY. */
LBL = 'PD'
ADDRESS ISREDIT "X ALL 07 '*'"
ADDRESS ISREDIT "F ALL 'PROCEDURE' 08"
ADDRESS ISREDIT "X ALL .ZF .ZCSR"
ADDRESS ISREDIT "UP MAX"
DO FOREVER
ADDRESS ISREDIT "F 08 P'^' NX"
IF RC > 0 THEN DO
PARA_LIST.0 = PARA_IDX
ADDRESS ISREDIT "RESET"
LEAVE
END
ELSE DO
/* 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 '.'
IF INDEX(AREA_A,'EXIT') = 0
THEN DO
PARA_IDX = PARA_IDX + 1
PARA_LIST.PARA_IDX = AREA_A
END
END
END
N = PARA_IDX
/* BUILD THE FLOW GRAPH - IT WILL BE A N X N MATRIX */
/* FIRST WE SHALL INITIALIZE THE MATRIX */
DO X = 1 TO N
DO Y = 1 TO N
GRAPH.X.Y = 0
END
END
DO PARA_IDX = 1 TO N
/* POSITION THE CURSOR AT THE PARA */
ADDRESS ISREDIT "F ALL "PARA_LIST.PARA_IDX" 08"
ADDRESS ISREDIT "(LINENUM) = LINENUM .ZCSR"
ADDRESS ISREDIT "(LASTLIN) = LINENUM .ZLAST"
SAY 'PARA:' PARA_LIST.PARA_IDX
/* READ ALL THE LINES IN THIS PARAGRAPH TILL THE END-OF-PARA */
DO FOREVER
/* QUERY THE LINE-NUMBER */
LINENUM = LINENUM + 1
ADDRESS ISREDIT "(LINEDATA) = LINE "LINENUM""
PARSE VAR LINEDATA TAG 8,
AREA_A 12,
AREA_B 72,
COMMENT
IF (AREA_A > '') | (LINENUM > LASTLIN) THEN DO
LEAVE
END
SAY 'AREA_B : ' AREA_B
/* IF A PERFORM STATEMENT IS FOUND ON THIS LINE */
IF INDEX(AREA_B,'PERFORM') > 0 DO
THEN DO
PARSE VAR AREA_B VERB PARAGRAPH
IF PARAGRAPH = 'VARYING' | PARAGRAPH = 'UNTIL' THEN DO
ITERATE
END
ELSE DO
SAY 'PARA-FOUND : ' PARAGRAPH
X = PARA_IDX
/* SEARCH THIS PARAGRAPH NAME IN THE PARA_LIST */
DO Y = 1 TO N
IF PARA_LIST.Y = PARAGRAPH THEN DO
SAY 'X:' X ' Y:' Y
/* THERE SHOULD BE AN EDGE FROM X TO Y */
GRAPH.X.Y = 1
END
END
END
END
END
END
DO X = 1 TO N
DO Y = 1 TO N
SAY 'GRAPH(' X ',' Y ')' GRAPH.X.Y
END
END
/* FIND OUT ALL EDGES LEADING INTO THE GRAPH_PARA - CALLER_LIST */
DO Y = 1 TO N
IF PARA_LIST.Y = GRAPH_PARA THEN DO
LEAVE
END
END
I = 0
DO X = 1 TO N
IF GRAPH.X.Y = 1 THEN DO
I = I + 1
CALLER_LIST.I = PARA_LIST.X
SAY 'CALLER_LIST.' I ' = ' CALLER_LIST.I
END
END
X = Y
/* FIND OUT ALL EDGES GOING OUT OF THE GRAPH_PARA - CALLED_LIST */
I = 0
DO Y = 1 TO N
IF GRAPH.X.Y = 1 THEN DO
I = I + 1
CALLED_LIST.I = PARA_LIST.Y
SAY 'CALLED_LIST.' I ' = ' CALLED_LIST.I
END
END
/* BUILD THE CONNECTOR ARRAY */
IF CALLER_LIST.1 > '' THEN DO
CALLER_CONNECTOR.1 = '-----'
END
ELSE DO
CALLER_CONNECTOR.1 = COPIES(' ',05)
END
J = 1
DO J = 02 TO 05
I = (J - 1)*2
IF CALLER_LIST.J > '' THEN DO
CALLER_CONNECTOR.I = ' | '
I = I + 1
CALLER_CONNECTOR.I = '--+ '
END
ELSE DO
CALLER_CONNECTOR.I = ' '
I = I + 1
CALLER_CONNECTOR.I = ' '
END
END
IF CALLED_LIST.1 > '' THEN DO
CALLED_CONNECTOR.1 = '-----'
END
ELSE DO
CALLED_CONNECTOR.1 = COPIES(' ',05)
END
J = 1
DO J = 02 TO 05
I = (J - 1)*2
IF CALLED_LIST.J > '' THEN DO
CALLED_CONNECTOR.I = ' | '
I = I + 1
CALLED_CONNECTOR.I = ' +--'
END
ELSE DO
CALLED_CONNECTOR.I = COPIES(' ',05)
I = I + 1
CALLED_CONNECTOR.I = COPIES(' ',05)
END
END
/* BUILD THE DYNAMIC AREA */
DO I = 1 TO 05
CALLER_LIST.I = SUBSTR(CALLER_LIST.I,1,20)
CALLED_LIST.I = SUBSTR(CALLED_LIST.I,1,20)
CALLER_LIST.I = LEFT(CALLER_LIST.I,20)
CALLED_LIST.I = LEFT(CALLED_LIST.I,20)
IF CALLER_LIST.I > '' THEN DO
SHAD_CALLER_LIST.I = COPIES('Y',20)
END
ELSE DO
SHAD_CALLER_LIST.I = COPIES(' ',20)
END
IF CALLED_LIST.I > '' THEN DO
SHAD_CALLED_LIST.I = COPIES('Y',20)
END
ELSE DO
SHAD_CALLED_LIST.I = COPIES(' ',20)
END
END
GRAPH_PARA = SUBSTR(GRAPH_PARA,1,20)
GRAPH_PARA = LEFT(GRAPH_PARA,20)
SAY 'CALLED_CONNECTOR 2= ' CALLED_CONNECTOR.2
SAY 'CALLED_CONNECTOR 3= ' CALLED_CONNECTOR.3
DYNVAR = ''
SHADVAR = ''
DYNVAR = DYNVAR ||,
CALLER_LIST.1 || CALLER_CONNECTOR.1 || GRAPH_PARA ||,
CALLED_CONNECTOR.1 || CALLED_LIST.1 ||,
COPIES(' ',05) ||,
COPIES(' ',20)|| CALLER_CONNECTOR.2 || COPIES(' ',20) ||,
CALLED_CONNECTOR.2 || COPIES(' ',25),
||CALLER_LIST.2 || CALLER_CONNECTOR.3 || COPIES(' ',20) ||,
CALLED_CONNECTOR.3 || CALLED_LIST.2 ||,
COPIES(' ',05) || ,
COPIES(' ',20)|| CALLER_CONNECTOR.4 || COPIES(' ',20) ||,
CALLED_CONNECTOR.4 || COPIES(' ',25),
||CALLER_LIST.3 || CALLER_CONNECTOR.5 || COPIES(' ',20) ||,
CALLED_CONNECTOR.5 || CALLED_LIST.3 ||,
COPIES(' ',05) || ,
COPIES(' ',20)|| CALLER_CONNECTOR.6 || COPIES(' ',20) ||,
CALLED_CONNECTOR.6 || COPIES(' ',25),
||CALLER_LIST.4 || CALLER_CONNECTOR.7 || COPIES(' ',20) ||,
CALLED_CONNECTOR.7 || CALLED_LIST.4 ||,
COPIES(' ',05) || ,
COPIES(' ',20)|| CALLER_CONNECTOR.8 || COPIES(' ',20) ||,
CALLED_CONNECTOR.8 || COPIES(' ',25),
||CALLER_LIST.5 || CALLER_CONNECTOR.9 || COPIES(' ',20) ||,
CALLED_CONNECTOR.9 || CALLED_LIST.5 ||,
COPIES(' ',05)
SHADVAR = SHADVAR,
|| SHAD_CALLER_LIST.1 || COPIES(' ',05) || COPIES('Y',20),
|| COPIES(' ',05) || SHAD_CALLED_LIST.1,
|| COPIES(' ',05) || COPIES(' ',75),
||SHAD_CALLER_LIST.2 || COPIES(' ',05) || COPIES(' ',20),
|| COPIES(' ',05) || SHAD_CALLED_LIST.2,
|| COPIES(' ',05) || COPIES(' ',75),
||SHAD_CALLER_LIST.3 || COPIES(' ',05) || COPIES(' ',20),
|| COPIES(' ',05) || SHAD_CALLED_LIST.3,
|| COPIES(' ',05) || COPIES(' ',75),
||SHAD_CALLER_LIST.4 || COPIES(' ',05) || COPIES(' ',20),
|| COPIES(' ',05) || SHAD_CALLED_LIST.4,
|| COPIES(' ',05) || COPIES(' ',75),
||SHAD_CALLER_LIST.5 || COPIES(' ',05) || COPIES(' ',20),
|| COPIES(' ',05) || SHAD_CALLED_LIST.5,
|| COPIES(' ',05)
ADDRESS ISPEXEC "ADDPOP"
ADDRESS ISPEXEC "DISPLAY PANEL(DYNAREA)"
ADDRESS ISPEXEC "REMPOP"
RETURN
Any help or pointers to other articles would be highly appreciated.