Nested programs and END PROGRAM
On a mainframe, a subprogram is normally its own source member, compiled
into its own load module. COBOL also lets you put a called program
inside its caller's source. That is a nested program, and it is how
you will write both sides of a CALL in one editor.
The shape
A nested program is a complete program (its own IDENTIFICATION,
DATA and PROCEDURE divisions) placed after the containing program's
procedure code and before the containing program's END PROGRAM:
IDENTIFICATION DIVISION.
PROGRAM-ID. OUTER.
... OUTER's data and procedure code ...
IDENTIFICATION DIVISION.
PROGRAM-ID. INNER.
... INNER's data and procedure code ...
END PROGRAM INNER.
END PROGRAM OUTER.
END PROGRAM name. is required as soon as a source holds more than one
program; it tells the compiler where each one stops. Leave one out and
GnuCOBOL reports multiple PROGRAM-ID's without matching END PROGRAM.
END PROGRAM is not a statement that runs. It's a boundary marker, and it
starts in Area A.
Each program has its own data
A nested program cannot see its parent's WORKING-STORAGE, and the parent
cannot see the nested program's. Data moves between them through the
CALL ... USING parameter list, exactly as with a separately compiled
subprogram. (A parent item declared GLOBAL is visible to nested
programs, but shops avoid it for the same reason other languages avoid
global variables.)
WORKING-STORAGE survives between calls
A called program's WORKING-STORAGE is set up once, from its VALUE
clauses, the first time it is called. On later calls it still holds
whatever the previous call left there. If you want a fresh copy on every
call, declare the program IS INITIAL:
IDENTIFICATION DIVISION.
PROGRAM-ID. NESTDEMO.
PROCEDURE DIVISION.
CALL "TALLY"
CALL "TALLY"
CALL "FRESH"
CALL "FRESH"
STOP RUN.
IDENTIFICATION DIVISION.
PROGRAM-ID. TALLY.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-CALLS PIC 9(3) VALUE 0.
PROCEDURE DIVISION.
ADD 1 TO WS-CALLS
DISPLAY "TALLY CALL " WS-CALLS
GOBACK.
END PROGRAM TALLY.
IDENTIFICATION DIVISION.
PROGRAM-ID. FRESH IS INITIAL.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-CALLS PIC 9(3) VALUE 0.
PROCEDURE DIVISION.
ADD 1 TO WS-CALLS
DISPLAY "FRESH CALL " WS-CALLS
GOBACK.
END PROGRAM FRESH.
END PROGRAM NESTDEMO.
TALLY CALL 001
TALLY CALL 002
FRESH CALL 001
FRESH CALL 001
Both nested programs declare a field called WS-CALLS. That's fine: each
program's names are private to it.
Persistent storage is useful (a routine can load a rate table on its first call and reuse it) and dangerous (a flag set on one call is still set on the next). If a subprogram's results depend on the previous call, check what it initialises and when.
Who can call a nested program?
Only the program that directly contains it. In the demo above, TALLY
could not call FRESH: they are siblings, and the call fails at run time
with module 'FRESH' not found. Adding IS COMMON to a nested program's
PROGRAM-ID lets its siblings call it too.
On the job
Nested programs are uncommon in production code; most shops keep one program per member so each can be compiled, promoted and reused on its own. You will still meet them in older systems, and they are handy for private helper routines that nothing else should call.
Your task
The starter's main program LOANINT reads loan accounts and calls
CALCINT for each one, but CALCINT doesn't exist yet. Write it as a
nested program inside LOANINT, before END PROGRAM LOANINT.
LOANINT calls it like this:
CALL "CALCINT" USING WS-BALANCE WS-RATE
WS-INTEREST WS-CUM-INT
| Parameter | Picture | Direction | Meaning |
|---|---|---|---|
| 1 | 9(7)V99 |
in | loan balance |
| 2 | 9V9(4) |
in | annual interest rate, e.g. 0.0450 for 4.5% |
| 3 | 9(7)V99 |
out | this month's interest: balance × rate ÷ 12, rounded |
| 4 | 9(9)V99 |
out | total interest calculated by all calls so far |
CALCINT must keep the running total in its own WORKING-STORAGE, not
rely on the caller. For the input
03
IE10000100050000000450
IE10000200012000000600
IE10000300000999900399
the program prints
IE100001 5000.00 18.75
IE100002 1200.00 6.00
IE100003 99.99 0.33
TOTAL INTEREST 25.08
Don't change LOANINT itself.