Search code examples
variablesscopeproceduregnucobol

in gnucobol, sub programs of one parent can't invoke each other


I'm currently trying to achieve a pattern to write modest these days' programs in cobol.

By these days' programs I mean a source file with a few variables and procedures visible to each other.

The closest to my aim is a list of programs, each able to call each other, while the operating system is calling the first one.

To share the same variables, I had to mark them external. The drawback is, they are probably accessible in other sources eventually linked together.

IDENTIFICATION DIVISION.
    PROGRAM-ID. MAIN.
DATA DIVISION.
    WORKING-STORAGE SECTION.
        01 MY-NAME PIC X(10) VALUE 'MAIN'.
        01 CALLS PIC 9(3) EXTERNAL.
PROCEDURE DIVISION.
    MOVE 0 TO CALLS.
    CALL 'CALL-SHOW' USING MY-NAME, 'CALL-SHOW'.
    CALL 'ROUTINE1' USING MY-NAME.
    CALL 'ROUTINE2' USING MY-NAME.
END PROGRAM MAIN.

IDENTIFICATION DIVISION.
    PROGRAM-ID. CALL-SHOW.
DATA DIVISION.
    WORKING-STORAGE SECTION.
        01 CALLS PIC 9(3) EXTERNAL.
    LINKAGE SECTION.
        01 CALLER PIC X(10).
        01 CALLED PIC X(10).
PROCEDURE DIVISION
    USING CALLER, CALLED.
    ADD 1 TO CALLS.
    DISPLAY CALLS ' CALLS' END-DISPLAY.
    DISPLAY CALLER ' CALLED ' CALLED END-DISPLAY.
    GOBACK.
END PROGRAM CALL-SHOW.

IDENTIFICATION DIVISION.
    PROGRAM-ID. ROUTINE1.
DATA DIVISION.
    WORKING-STORAGE SECTION.
        01 MY-NAME PIC X(10) VALUE 'ROUTINE1'.
        01 CALLS PIC 9(3) EXTERNAL.
    LINKAGE SECTION.
        01 CALLER PIC X(10).
PROCEDURE DIVISION USING CALLER.
    CALL 'CALL-SHOW' USING CALLER, MY-NAME.
    CALL 'CALL-SHOW' USING MY-NAME, 'CALL-SHOW'.
    CALL 'ROUTINE2' USING MY-NAME.
    GOBACK.
END PROGRAM ROUTINE1.

IDENTIFICATION DIVISION.
    PROGRAM-ID. ROUTINE2.
DATA DIVISION.
    WORKING-STORAGE SECTION.
        01 MY-NAME PIC X(10) VALUE 'ROUTINE2'.
        01 CALLS PIC 9(3) EXTERNAL.
    LINKAGE SECTION.
        01 CALLER PIC X(10).
PROCEDURE DIVISION USING CALLER.
    CALL 'CALL-SHOW' USING CALLER, MY-NAME.
    CALL 'CALL-SHOW' USING MY-NAME, 'CALL-SHOW'.
    GOBACK.
END PROGRAM ROUTINE2.

Another approach I tried is a program with global variables and a few other programs embedded within it's procedure division. Here the global variables are happily visible within that program, but the subprograms seem to be visible in the parent program only.

IDENTIFICATION DIVISION.
PROGRAM-ID. DemoGLOBAL.
ENVIRONMENT DIVISION.
DATA DIVISION.
WORKING-STORAGE SECTION.
01  Arg GLOBAL                     PIC X(10).
PROCEDURE DIVISION.
000-Main.
    MOVE ALL "X" TO Arg
    CALL "DemoSub" END-CALL
    DISPLAY "DemoGLOBAL: " Arg END-DISPLAY
    CALL "DemoSub2" END-CALL
    DISPLAY "DemoGLOBAL: " Arg END-DISPLAY
    CALL "DemoSub3" END-CALL
    GOBACK
    .
IDENTIFICATION DIVISION.
PROGRAM-ID. DemoSub.
PROCEDURE DIVISION.
000-Main.
    MOVE ALL "*" TO Arg.
    GOBACK
    .
END PROGRAM DemoSub.
IDENTIFICATION DIVISION.
PROGRAM-ID. DemoSub2.
PROCEDURE DIVISION.
000-Main.
    MOVE ALL "?" TO Arg.
    GOBACK
    .
END PROGRAM DemoSub2.
IDENTIFICATION DIVISION.
PROGRAM-ID. DemoSub3.
PROCEDURE DIVISION.
000-Main.
*>    CALL "DemoSub" END-CALL
    GOBACK
    .
END PROGRAM DemoSub3.
END PROGRAM DemoGLOBAL.

Is there a better approach have data and procedures source-wide?


Solution

  • EXTERNAL variables are visible to the whole runtime unit (= the process / pid) and can be accessed by any program. It is "stored" in the runtime and its size must be identical in all programs (otherwise the first with a different size will either abort or cannot be CALLed, depending on the implementation).

    GLOBAL is nicely described by the standard - just the way you found it working:

    A global name is available to every program contained within the program that declares it.

    It is not 100% clear what you want to achieve; but it seems you want a common data used in all programs. The standard option would be that the "main" program (started from the operating system) has the data (defined in a copybook) in its WORKING-STORAGE (providing definition and data) while the other programs have it in LINKAGE (providing definition only) and reference it in PROCEDURE DIVISION USING (using the data passed by the program on CALL ... USING).

    If you ever need to share the data between independent processes, you'd have LINKAGE only and share the data via operating system (or COBOL implementation) specific functions (like shmget on posix environments), with the first program allocating the memory dynamically.