Menu

Problem with calling a subroutine with returning

2023-12-15
2025-01-17
1 2 > >> (Page 1 of 2)
  • Bill Komanetsky

    Bill Komanetsky - 2023-12-15

    Hello everyone!

    I have a program (below) which calls a couple of subroutines in gnucobol. The first one, functionABC works fine using the linkage section to send and receive back values from the main function to the subroutine.

    The second subroutine, functionABC2 (which uses the returning keyword) does not work. I get this strange error:

    libcob: subProgram.cbl:44: error: BASED/LINKAGE item 'avalue2' has NULL address

    It doesn't matter if I pass returnValue or returnValue2 to the subroutine, I get the same error. The error occurs on either of these lines:
    move 0 to avalue2
    compute avalue2 = aValue2 + 2

    I have done exactly what the programmer's guide says to do, but I keep getting this error.

    See this on GNU Cobol 4.x. GNU Cobol 3.2 also shows this behavior, but warns me that RETURNING is not implemented yet, same error though.

    Any ideas? And thanks!

       Identification Division.
           Program-ID.  TestSubProgram.
           Environment Division.
           Data Division.
       Working-Storage Section.
           01 ctr1         pic 999         value 0.
           77 returnvalue  pic 9(8)        value 0.
           77 returnvalue2 usage binary-long signed.
       Linkage Section.
       Procedure Division.
       Begin.
           Display "Hello World!"
           move 10 to ctr1.
           call 'functionABC' USING ctr1 returnvalue.  
           Display returnvalue.  
           move 0 to returnvalue2.
           call 'functionABC2' RETURNING returnvalue2.
           Display returnvalue2.
           stop run.
    
       identification division.
           program-id. functionABC.
       data division.
       working-storage section.
           77 localvar     pic     999.
       linkage section.
           01 countervar   pic     999.
           01 avalue       pic     9(8)     value 0.
       procedure division USING countervar avalue.
           perform countervar times
               Display "hello from sub-program"
           end-perform
           move 999 to avalue.
       exit.
       END PROGRAM functionABC.
    
       identification division.
           program-id. functionABC2.
       data division.
       working-storage section.
       linkage section.
           77 avalue2      USAGE BINARY-LONG signed.
       procedure division RETURNING avalue2.
           move 0 to avalue2
           compute avalue2 = aValue2 + 2
           Display avalue2
       GoBack.
       END PROGRAM functionABC2.
    
     

    Last edit: Bill Komanetsky 2023-12-15
  • Chuck Haatvedt

    Chuck Haatvedt - 2023-12-15

    Bill,

    I noticed that when you call functionABC2, you do not pass any parameters to it.

    call 'functionABC2' RETURNING returnvalue2.

    In the called program functionABC2, in order to have addressability to the avalue2 field in the linkage section, it either has to be passed with a USING clause on the CALL statement in the calling program OR you can use a SET ADDRESS OF avalue2 to a POINTER variable.

    Since neither of those conditions are true, the field avalue2 is NOT addressable.

    try this change

    in TestSubProgram

    77 fld-1 usage binary-long signed.

    call 'functionABC2' USING fld-1 RETURNING returnvalue2.

    Chuck Haatvedt

     

    Last edit: Chuck Haatvedt 2023-12-15
    • Bill Komanetsky

      Bill Komanetsky - 2023-12-15

      Thank you Mr. Chuck H, much appreciated!

      I did try something like that in my previous attempts, and still have the problem after putting your code suggestion in. I had to add a using in the procedure division of functionABC2. Dies on the first line of code in functionABC2 that tries and update avalue2

         Identification Division.
             Program-ID.  TestSubProgram.
             Environment Division.
             Data Division.
         Working-Storage Section.
             01 ctr1         pic 999         value 0.
             77 returnvalue  pic 9(8)        value 0.
             77 returnvalue2 usage binary-long signed.
             77 fld-1 usage binary-long signed.
         Linkage Section.
         Procedure Division.
         Begin.
             Display "Hello World!"
             move 10 to ctr1.
             call 'functionABC' USING ctr1 returnvalue.  
             Display returnvalue.  
             move 0 to returnvalue2.
             call 'functionABC2' USING fld-1 RETURNING returnvalue2.
             Display returnvalue2.
             stop run.
      
         identification division.
             program-id. functionABC.
         data division.
         working-storage section.
             77 localvar     pic     999.
         linkage section.
             01 countervar   pic     999.
             01 avalue       pic     9(8)     value 0.
         procedure division USING countervar avalue.
             perform countervar times
                 Display "hello from sub-program"
             end-perform
             move 999 to avalue.
         exit.
         END PROGRAM functionABC.
      
         identification division.
             program-id. functionABC2.
         data division.
         working-storage section.
         linkage section.
             77 value1       usage binary-long signed.
             77 avalue2      USAGE BINARY-LONG signed.
         procedure division USING value1 RETURNING avalue2.
             move 0 to avalue2
             compute avalue2 = aValue2 + 2
             Display avalue2
         GoBack.
         END PROGRAM functionABC2.
      
       
      • Simon Sobisch

        Simon Sobisch - 2023-12-18

        This program doesn't abide to the rules outlined in IBM's doc:

        Do not use the PROCEDURE DIVISION RETURNING phrase in: [...] Nested programs.

        :-)

        That aside:somedayTM we should support that as IBM does (with a dialect option as that does not work this way everywhere).

         
        • Bill Komanetsky

          Bill Komanetsky - 2023-12-18

          So I could try putting the functionis in their own cbl source file and call it from the main program to see if that makes a difference. I see that in the IBM doc it says nested programs, and I assume that is what you are referring to. I never used those throughout my career anyway, it was just a prototype program to see how returning is implemented in GNUCobol. (I miss this back and forth - me being retired and all :-)

           
          • Simon Sobisch

            Simon Sobisch - 2023-12-18

            Same source is also fine, it only gets nested if before an END PROGRAM you have another one.
            But that doesn't make a difference with GnuCOBOL. As noted above GnuCOBOL will support GOBACK RETURNING num-var-or-literal fine for programs. As noted below if you want to pass something more complex in a program the common way is to pass another parameter on the CALL and just update there - as you did in the first program which works fine.
            As noted below you can use PROCEDURE DIVISION ... RETURNING in GnuCOBOL and as showed that works fine - but only for user-defined functions where that actually makes sense, too.

             
            • Bill Komanetsky

              Bill Komanetsky - 2023-12-18

              Using Function-ID instead of Program-ID, correct?

               
              • Simon Sobisch

                Simon Sobisch - 2023-12-18

                yes, but that also leads to a different invocation - just have a look at my example rewrite (currently the last post in this discussion, on page 2)

                 
            • Bill Komanetsky

              Bill Komanetsky - 2023-12-18

              If I put the returning variable into the linkage section of the sub-program, it still dies if I use program-ID. If I use Function-ID, I need to change the environment division to include the function, as well as changing data types to USAGE BINARY-LONG SIGNED and it seems to work. Code below

                 Identification Division.
                     Program-ID.  TestSubProgram.
                     Environment Division.
                     Configuration section.
                     Repository.
                     function functionABC2.
                     Data Division.
                 Working-Storage Section.
                     01 ctr1         pic 999         value 0.
                     77 returnvalue  USAGE BINARY-LONG SIGNED.
                     77 someValue    USAGE BINARY-LONG SIGNED.
                 Linkage Section.
                 Procedure Division.
                 Begin.
                     Display "Hello World!"
                     move 10 to ctr1.
                     call 'functionABC' USING ctr1 returnvalue.  
                     Display "returnvalue from functionABC sub-program: ", returnvalue.  
                     move 100 to someValue.
                     compute returnvalue = functionABC2(someValue).
                     Display "returnvalue from functionABC2 function: ", returnvalue.
                     stop run.
                 END PROGRAM TestSubProgram.
              
                 Identification Division.
                     FUNCTION-ID. functionABC2.
                 data division.
                 working-storage section.
                 linkage section.
                     77 avalue2      USAGE BINARY-LONG SIGNED.
                     77 value1       USAGE BINARY-LONG SIGNED.
                 procedure division USING value1 returning avalue2.
                     move 0 to avalue2
                     compute avalue2 = value1 * 2
                     Display "avalue2 inside of functioniABC2: ", avalue2
                 GoBack returning avalue2.
                 END FUNCTION functionABC2.
              
                 identification division.
                     program-id. functionABC.
                 data division.
                 working-storage section.
                     77 localvar     pic     999.
                 linkage section.
                     01 countervar   pic     999.
                     01 avalue       USAGE BINARY-LONG SIGNED.
                 procedure division USING countervar avalue.
                     perform countervar times
                         Display "hello from sub-program"
                     end-perform
                     move 999 to avalue.
                 exit.
                 END PROGRAM functionABC.
              

              Program Output:
              Hello World!
              hello from sub-program
              hello from sub-program
              hello from sub-program
              hello from sub-program
              hello from sub-program
              hello from sub-program
              hello from sub-program
              hello from sub-program
              hello from sub-program
              hello from sub-program
              returnvalue from functionABC sub-program: +0000000999
              avalue2 inside of functioniABC2: +0000000200
              returnvalue from functionABC2 function: +0000000200

               
  • Chuck Haatvedt

    Chuck Haatvedt - 2023-12-16

    Bill,

    in my 40+ years as a COBOL programmer, I've never seen the RETURNING clause on the PROCEDURE DIVISION statement.

    after a number of attempts I received this message when doing a compile.

    F:\AA-minGW32-static>cobc -x testsub.cbl
    testsub.cbl:1: note: free format detected
    1 > IDENTIFICATION DIVISION.
    2 | PROGRAM-ID. TESTSUB.
    3 | ENVIRONMENT DIVISION.
    testsub.cbl:47: warning: program RETURNING is not implemented [-Wpending]
    45 | 77 AVALUE2 USAGE BINARY-LONG SIGNED.
    46 | PROCEDURE DIVISION USING VALUE1, AVALUE2
    47 > RETURNING AVALUE2.
    48 | MOVE 0 TO AVALUE2
    49 | COMPUTE AVALUE2 = AVALUE2 + 2

    So I've attached a working version of the source code (I renamed the main program to TESTSUB)

    here is the result of a compile and execution....

    F:\AA-minGW32-static>cobc -x testsub.cbl
    testsub.cbl:1: note: free format detected
    1 > IDENTIFICATION DIVISION.
    2 | PROGRAM-ID. TESTSUB.
    3 | ENVIRONMENT DIVISION.

    F:\AA-minGW32-static>TESTSUB
    HELLO WORLD!
    HELLO FROM SUB-PROGRAM
    HELLO FROM SUB-PROGRAM
    HELLO FROM SUB-PROGRAM
    HELLO FROM SUB-PROGRAM
    HELLO FROM SUB-PROGRAM
    HELLO FROM SUB-PROGRAM
    HELLO FROM SUB-PROGRAM
    HELLO FROM SUB-PROGRAM
    HELLO FROM SUB-PROGRAM
    HELLO FROM SUB-PROGRAM
    00000999
    IN FUNCTIONABC2 --> AVALUE2 IS -> +0000000002
    IN FUNCTIONABC2 --> VALUE1 IS -> +0000000029
    +0000000002

    If you have any questions, perhaps I could help you via a chat on SKYPE, my user name is chuck.haatvedt

    Chuck Haatvedt

     

    Last edit: Chuck Haatvedt 2023-12-16
    • Bill Komanetsky

      Bill Komanetsky - 2023-12-16

      Yea, I've been coding in Cobol since 1978, and have never used returning in the procedure division statement either, but the gnucobol programmers guide says it is supported. Thanks so much and I'll take a look at your code.

       
    • Bill Komanetsky

      Bill Komanetsky - 2023-12-16

      I see what you did, you removed the returning clause and it looks like you are simply returning the value within the RETURN-CODE register instead of returning a value like one would from a C/C++/Java application. I was trying to implement the procedure division returning clause as described in the 3.2 programmer's guide on page 256.

      https://sourceforge.net/p/gnucobol/code/HEAD/tree/external-doc/guide/PDFs/gnucobpg-letter.pdf?format=raw

      If it's not working, maybe they need to know this since they document it's valid syntax? I was getting the same messages as it seemed you did, but it is documented as a valid clause in the Procedure Division statement.

       
    • Bill Komanetsky

      Bill Komanetsky - 2023-12-16

      BTW, the Procedure division returning clause is also implemented in the IBM (v 1.2) and Microfocus cobol compilers. Which is why, I'm sure, the GNUCobol authors implemented it.
      :-)

       
      • Simon Sobisch

        Simon Sobisch - 2023-12-16

        Note: this is mostly used for user defined functions, where it does work "in general" (still not completely). I guess we have test examples in our testsuite (a simple grep should show that).

        If it is an integer then you can:

        • use the RETURN-CODE register directly (not for all STDs as this is common, but non-standard)
        • use GOBACK / EXIT PROGRAM RETURNING in the called program and use the CALL ... RETURNING clause in the calling program

        If the chosen STD supports that, then you have the value there in the RETURN-CODE register also in the second case, when you leave the RETURNING away.

        Please double-check if the PG mentions the RETURNING clause for PROCEDURE DIVISION in general or only for user-defined functions. If this first is the case drop a note @ vcoen to explicit document that this isn't implemented for programs and has some issues depending on the system used (= you need to check if it works for you as expected, no guarantee made).

         
        • Bill Komanetsky

          Bill Komanetsky - 2023-12-17

          Hi. The programmer's guide says this about exit program (page 332):
          1. The EXIT PROGRAM statement is not legal anywhere within a user-defined function.
          2. The EXIT FUNCTION statement cannot be used anywhere within a subroutine.
          So if that is correct, then Exit Program Returning isn't an option

          Return-code register will work, yes. I mentioned that somewhere in this thread already :-)

          I'll try GoBack Returning and see if that works. Thanks for the suggestion.

           
          • Simon Sobisch

            Simon Sobisch - 2023-12-17

            It is good that you do learning videos on COBOL. Especially in this case I'd suggest to also look at what the standard says - EXIT is deprecated (in favor of GOBACK). The only real use it had left was in programs that may be CALLed (subprograms) or be main programs where EXIT PROGRAM would have effectively been a CONTINUE statement in the second case.
            The PG likely mentions that deprecation (in its COBOL variant).

             
        • Bill Komanetsky

          Bill Komanetsky - 2023-12-17

          Goback returning works! Code shown below. The returning variable cannot be defined in the linkage section, otherwise, un-allocated memory area error is shown. So, in the subroutine, put it in the working storage section, and it works. Also needs to be defined as USAGE BINARY-LONG SIGNED

             Identification Division.
                 Program-ID.  TestSubProgram.
                 Environment Division.
                 Data Division.
             Working-Storage Section.
                 01 ctr1         pic 999         value 0.
                 77 returnvalue  pic 9999        value 0.
                 77 someValue    USAGE BINARY-LONG SIGNED.
             Linkage Section.
             Procedure Division.
             Begin.
                 Display "Hello World!"
                 move 10 to ctr1.
                 call 'functionABC' USING ctr1 returnvalue.  
                 Display returnvalue.  
                 move 100 to someValue.
                 call 'functionABC2' USING someValue RETURNING returnvalue.
                 Display returnvalue.
                 stop run.
          
             identification division.
                 program-id. functionABC2.
             data division.
             working-storage section.
                 77 avalue2      USAGE BINARY-LONG SIGNED.
             linkage section.
                 77 value1       USAGE BINARY-LONG SIGNED.
             procedure division USING value1.
                 move 0 to avalue2
                 compute avalue2 = value1 * 2
                 Display avalue2
             GoBack returning avalue2.
             END PROGRAM functionABC2.
          
             identification division.
                 program-id. functionABC.
             data division.
             working-storage section.
                 77 localvar     pic     999.
             linkage section.
                 01 countervar   pic     999.
                 01 avalue       pic     9(8)     value 0.
             procedure division USING countervar avalue.
                 perform countervar times
                     Display "hello from sub-program"
                 end-perform
                 move 999 to avalue.
             exit.
             END PROGRAM functionABC.
             END PROGRAM TestSubProgram.
          
           
  • Chuck Haatvedt

    Chuck Haatvedt - 2023-12-16

    Bill,

    I spent my career working in an IBM mainframe environment using IBM Enterprise COBOL compiler. So just take this as a gentle reminder that the use of the RETURN-CODE to return a numeric value to the calling program is not implemented the same by all compiler vendors...

    In that environment the RETURN-CODE in a COBOL program was treated as a 2 byte binary variable. So we had some occasions to use the RETURNING clause on a CALL statement. This was due to calling some IBM utilities written in ASSEMBLER which passed a 4 byte error code when they failed. In this case the COBOL RETURN-CODE did not contain the entire 4 byte error code... Hence the need to use the RETURNING clause on the CALL statement.

    So if you really want a portable means of returning data to the calling program, it is better to pass a "return-area" variable as part of the USING phrase in the CALL statement.

    If you are not concerned with the portability of your code, then just test that it is working in your environment.

        Chuck Haatvedt
    
     
    • Bill Komanetsky

      Bill Komanetsky - 2023-12-16

      I understand all of that Mr. Haatvedt, but that isn't what I'm having trouble with. I was wondering why the returning clause isn't working in GNUCobol when it is documented as working, and it also works on the IBM/Microfocus compilers.

      Nice to hear you worked on IBM mainframes. I retired from IBM back in 2013. Just isn't the company today it was back in the 80's.

       
  • Bill Komanetsky

    Bill Komanetsky - 2023-12-16

    This code, using the IBM 1.2 Cobol Compiler, works great with returning in the procedure division. Just compiled/linked/ran it. The IBM compiler doesn't allow you to have free-form code, you need to use Area A, B, C, etc... But, it was worth it to show that returning is suppose to work.

    Source Code:

       Identification Division.
       Program-ID.  TestSubProgram.
       Environment Division.
       Data Division.
       Working-Storage Section.
       01 ctr1               pic 9999   value 0.
       77 returnvalue        pic 9999   value 0.
       77 avalue2            pic 9999   value 0.
       Linkage Section.
       Procedure Division.
       Begin.
           Display "Hello World!"
           move 10 to ctr1.
           call 'functionABC' USING ctr1 returnvalue.  
           Display "First function return: ", returnvalue.  
           move 2 to avalue2.
           Display "Return value before calling functionABC2:", avalue2.
           call 'functionABC2' USING ctr1 RETURNING avalue2.
           Display "Return value from functionABC2:", avalue2.
           stop run.
    
       identification division.
       program-id. functionABC.
       data division.
       working-storage section.
       77 localvar           pic 999.
       linkage section.
       01 countervar         pic 9999.
       01 avalue             pic 9999   value 0.
       procedure division USING countervar avalue.
           perform countervar times
               Display "hello from sub-program"
           end-perform
           move 999 to avalue.
           exit.
       END PROGRAM functionABC.
    
       identification division.
       program-id. functionABC2.
       data division.
       working-storage section.
       linkage section.
       77 value1             pic 9999.
       77 someValue          pic 9999.
       procedure division USING value1 returning someValue.
           compute someValue = value1 * 2
           Display "Inside functionABC2: ", someValue
           GoBack.
       END PROGRAM functionABC2.
       END PROGRAM TestSubProgram.
    

    Program Output:
    Hello World!
    hello from sub-program
    hello from sub-program
    hello from sub-program
    hello from sub-program
    hello from sub-program
    hello from sub-program
    hello from sub-program
    hello from sub-program
    hello from sub-program
    hello from sub-program
    First function return: 0999
    Return value before calling functionABC2:0002
    Inside functionABC2: 0020
    Return value from functionABC2:0020
    linuxuser@linuxuser-None:~/Documents/

     

    Last edit: Bill Komanetsky 2023-12-16
    • Simon Sobisch

      Simon Sobisch - 2023-12-16

      Just to recheck: this is IBM COBOL for x86, right? Now that all IBM compilers are similar but different (Enterprise COBOL, AIX, ILE MVS) and that the x86 one is the one most far away from all the others, including support of a bunch of "new" COBOL features not available with the others.

       
      • Bill Komanetsky

        Bill Komanetsky - 2023-12-17

        Yes, this is the x86 Linux Cobol from IBM. But, their AIX and MVS cobol work this way as well (returning)

         
    • Simon Sobisch

      Simon Sobisch - 2023-12-18

      Run with GnuCOBOL 2.2:

      Hello World!
      hello from sub-program
      hello from sub-program
      hello from sub-program
      hello from sub-program
      hello from sub-program
      hello from sub-program
      hello from sub-program
      hello from sub-program
      hello from sub-program
      hello from sub-program
      First function return: 0999
      Return value before calling functionABC2:0002
      
      attempt to reference unallocated memory (signal SIGSEGV)
      abnormal termination - file contents may be incorrect
      

      Similar result with 3.2, but the last two lines are replaced by:

      attempt to reference invalid memory address (signal)
      
      
       Last statement of "functionABC2" unknown
       Last statement of "TestSubProgram" unknown
       Started by ./TestSubProgram
      Segmentation fault
      

      adding -fsource-location changes those to:

      TestSubProgram.cob:46: attempt to reference invalid memory address (signal)
      
      
       Last statement of "functionABC2" was COMPUTE at line 46 of TestSubProgram.cob
       Last statement of "TestSubProgram" was CALL
              Begin at TestSubProgram.cob:18
       Started by ./TestSubProgram
      Segmentation fault
      

      adding all runtime checks and full stack information by --debug, there is no crash any more but

      libcob: TestSubProgram.cob:46: error: BASED/LINKAGE item 'someValue' has NULL address
      
       Last statement of "functionABC2" was COMPUTE at line 46 of TestSubProgram.cob
              ENTRY functionABC2 at TestSubProgram.cob:46
       Last statement of "TestSubProgram" was CALL
              Begin at TestSubProgram.cob:18
              ENTRY TestSubProgram at TestSubProgram.cob:11
       Started by ./TestSubProgram
      

      ... and for the result not being lost: I'm posting a warning-free, working version below.

       
  • Chuck Haatvedt

    Chuck Haatvedt - 2023-12-16

    Sorry about the late response Bill,

    it appears that as of the current release of GNUCOBOL, even though it is documented in the programmers guide, that it has not been implemented in the actual compiler.

    I would suggest that we wait for a response from Simon as he is the chief architect / developer on the GNUCOBOL compiler project.

    Simon is currently traveling away from his home and should be back by Monday or Tuesday of next week. He is located in Germany so if you are located in the US there may be some delay for him to catch up on the activity here.

        Thanks,    Chuck Haatvedt
    
     
    • Bill Komanetsky

      Bill Komanetsky - 2023-12-16

      Makes sense. Hope he's enjoying his travels!

       
1 2 > >> (Page 1 of 2)

Anonymous
Anonymous

Add attachments
Cancel





Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.