2

I want to create a builder in scons works with COBOL.

Here is a start:

import re

Import('env')

# Source:
# src/cpy/COPYBK1.cpy
# src/cpy/COPYBK2.cpy
# src/cpy/COPYBK3.cpy
# src/bat/PROG1.cbl
# src/bat/PROG2.cbl
# These commands would run:
# cobc -o lib/PROG1.so -Isrc/cpy src/cbl/PROG1.cbl
# cobc -o lib/PROG2.so -Isrc/cpy src/cbl/PROG2.cbl
#     +-.
#       +-SConstruct
#       +-PROG1.cbl
#       +-PROG1.so
#       | +-PROG1.cbl
#       | +-COPYBK1.cpy
#       | +-COPYBK2.cpy
#       +-PROG2.cbl
#       +-PROG2.so
#       | +-PROG2.cbl
#       | +-COPYBK1.cpy
#       | +-COPYBK3.cpy
#
# Also, PROG2 is called from PROG1 so lib/PROG2.so target should be automatically generated.
# PROG2 is dynamically loaded so it does not need to linked into PROG1 target.

"""
def getCalls(fullprogrampath):
    # This needs to be modified to support multiple lines.
    # This needs to be modified to support nested COPY.
    theregex = r'^......]\s*CALL\s*([A-Z0-9]*)\.$'
    calllist = []

    with open(fullprogrampath, 'r') as f:
        linenum = 0
        for line in f.readlines():
            linenum += 1
            line = line.rstrip()
            m = re.match(theregex, line, re.I)
            if m:
                calllist.append(m.group(1))

    return(calllist)
"""

def getCopyBooks(fullprogrampath):
    # This needs to be modified to support multiple lines.
    # This needs to be modified to support nested COPY.
    theregex = r'^...... \s*COPY\s*([A-Z0-9]*)\.$'
    copybooklist = []

    with open(fullprogrampath, 'r') as f:
        linenum = 0
        for line in f.readlines():
            linenum += 1
            line = line.rstrip()
            m = re.match(theregex, line, re.I)
            if m:
                copybooklist.append(m.group(1))

    return(copybooklist)

bld = Builder(action = 'cobc -o $TARGET -Icpy $SOURCE')
env.Append(BUILDERS = {'CobolProgram': bld})

env.CobolProgram('lib/PROG1.so', 'bat/PROG1.cbl')
env.Depends(target = 'lib/PROG1.so', dependency = getCopyBooks('bat/PROG1.cbl'))

env.CobolProgram('lib/PROG2.so', 'cbl/PROG2.cbl')
env.Depends(target = 'lib/PROG2.so', dependency = getCopyBooks('cbl/PROG2.cbl'))

That actually runs

here is what needs to be added:

  1. Cache the scan for copybooks so that we only scan for copybooks if the files have changed. Scons seems to do that for C files so it must be possible.
  2. Detect call statements and add targets. There is no analogy to this in C.

A. How do I do that?

B. Is there some sample builders I can look at that I can model off of?

I acknowledge that COBOL is difficult to scan and that it will be limited to how crazy the COBOL is formatted. it will be up to the developer of the COBOL to add Depends calls for their copybooks and call statements that are not detected.

Be Kind To New Users
  • 9,672
  • 13
  • 78
  • 125
  • FYI: When dealing with "nested" (or contained) programs (COBOL 85 and later), `CALL literal` statements will occur. Some of those `CALL` statements will be references to contained programs. Furthermore, whether a `CALL` statement refers to such a contained program, depends on the scope of the containing program. All `program-names` must be unique with respect to the outermost containing program, but need not be unique with respect to other programs. There may be cases where identically coded `CALL literal`s may refer to two different programs. – Rick Smith Oct 04 '21 at 19:22

1 Answers1

1

You cannot reliably find the target of a COBOL call in the general case with a regex. There are COBOL grammars you could use to generate a parser to aid you in writing an application to figure out the CALLs and COPYs but it's a non-trivial exercise.

Consider...

01  Work-Areas.
    05  Program1     PIC X(008) Value Low-Values.
        88  Name-Validate       Value 'N8675309'.
        88  Addr-Validate       Value 'A2718281'.
        88  Date-Validate       Value 'D3141592'.

[...]

    Set Addr-Validate To True
    Call Program1 Using [...]
    Set Date-Validate To True
    Call Program1 Using [...]
    Move 'X' To Program1(1:1)
    Call Program1 Using [...]

...and note that the code isn't even pathological, like this...

    Identification Division.
    Program-ID. CRAIS.
    Data Division.
    Working-Storage Section.

    01                                                              C
   -                                                                O
   -                                                                N
   -                                                                S
   -                                                                T
   -                                                                A
   -                                                                N
   -                                                                T
   -                                                               S.
        05                                                          P
   -                                                                G
   -                                                                M
                                                                    P
   -                                                                I
   -                                                                C
                                                                    X
   -                                                                (
   -                                                                8
   -                                                                )
                                                                    V
   -                                                                A
   -                                                                L
   -                                                                U
   -                                                                E
                                                                   'B
   -                                                               'R
   -                                                               'A
   -                                                               'C
   -                                                              'A'
        .
    Procedure Division.
                                                                    C
   -                                                                A
   -                                                                L
   -                                                                L
                                                                    P
   -                                                                G
   -                                                                M
                                                                    G
   -                                                                O
   -                                                                B
   -                                                                A
   -                                                                C
   -                                                                K
        .

COBOL COPY statements can also be continued like the nasty CALL above.

cschneid
  • 10,237
  • 1
  • 28
  • 39
  • This comment is very much appreciated but my solution does not need to cover all cases. Just my case where I know the code is "clean". if this works well then I might keep handling more edge cases but as you pointed out it is pretty much hopeless of when the programmer codes a dynamic call. – Be Kind To New Users Oct 03 '21 at 01:53
  • If I need a rigorous parse I will look into adding an option to the GnuCOBOL compiler that will do the rigorous parse and output the CALL programs and COPYBOOKs. – Be Kind To New Users Oct 03 '21 at 02:49
  • Two things to add to the consideration: you can also `CALL` program-pointers and have user-defined functions (both "named" and again with a function-pointer). Concerning the addition to GnuCOBOL: There was a dependency generation (`-MT` and friends) in GnuCOBOL 1.1 - they got removed in 2.x. I have no idea if they ever worked but it would be very nice to have them working again (even when those are `make` related they could be easily be re-parsed for using with scons). Side-note: one could use the generated listing + xref to find CALLs and SET/MOVE of constants when calling variables. – Simon Sobisch Oct 03 '21 at 11:05