GnuCOBOL: Trying to create a recursive user defined function

236 views Asked by At

I'm trying to create a recursive user defined function with GnuCOBOL 2.0.0 but when I try to run the caller program it crashes with a "segmentation failure" error.

This is the function:

identification division.
function-id.   FATORIAL.
author.        Paulo Andre Dias.
date-written.  15/02/2017.
remarks.       Calcula o fatorial do numero N informado via argumento.     

environment division.
configuration section.

data division.
working-storage section.
77 ws-fatorial-n-menos-1    pic 9(006) value zeros.

linkage section.
01 lk-n                     pic 9(006).
01 lk-fatorial              pic 9(006). 

procedure division using lk-n returning lk-fatorial.
principal.

    if lk-n = zeros
        move 1 to lk-fatorial
    else
        move FATORIAL(lk-n - 1) to ws-fatorial-n-menos-1
        compute lk-fatorial = lk-n * ws-fatorial-n-menos-1
    end-if

    goback.

end function FATORIAL.

This is the caller program:

identification division.
program-id. gtc002.

environment division.
configuration section.
repository.
    function FATORIAL.

data division.
working-storage section.
77 ws-n pic 9(006) value zeros.

procedure division.
main.
    display "Entre com um numero inteiro positivo (ou zero para encerrar):"
    accept ws-n from console
    if ws-n = zeros
        stop run
    else
        display "O fatorial de " ws-n " e' " FATORIAL(ws-n)
    end-if
    go to main.

And this is what happens:

[aeisxpad ~/cbl]$ ../bin/gtc002
Entre com um numero inteiro positivo (ou zero para encerrar)::
5
Falha de segmentação
[aeisxpad ~/cbl]$ 

Am I missing something? Any ideas?

Thank you all in advance.

1

There are 1 answers

0
Brian Tiffin On BEST ANSWER

Workaround for a bug with User Defined Functions and GnuCOBOL.

User defined FUNCTION calls are not properly marshaled in terms of BINARY and DISPLAY usage. Values are passed as usage DISPLAY with pic 9. Try changing ws-n to USAGE BINARY. That will force a native numeric in the call, (which then needs to match in the linkage section of lk-n in FATORIAL itself.

   identification division.
   program-id. gtc002.

   environment division.
   configuration section.
   repository.
       function FATORIAL.

   data division.
   working-storage section.
  *> 77 ws-n pic 9(006) value zeros.
   77 ws-n usage binary-long.

   procedure division.
   main.
       display "Entre com um numero inteiro positivo" &
               " (ou zero para encerrar):"
       accept ws-n from console
       if ws-n = zeros
           stop run
       else
           display "O fatorial de " ws-n " e' " FATORIAL(ws-n)
       end-if
       go to main.

and

   identification division.
   function-id.   FATORIAL.
   author.        Paulo Andre Dias.
   date-written.  15/02/2017.
   remarks. Calcula o fatorial do numero N informado via argumento.     
   
   environment division.
   configuration section.

   data division.
   working-storage section.
   77 ws-fatorial-n-menos-1    pic 9(006) value zeros.

   linkage section.
  *> 01 lk-n                     pic 9(006).
   01 lk-n                     usage binary-long.
   01 lk-fatorial              pic 9(006).

   procedure division using lk-n returning lk-fatorial.
   principal.

       if lk-n = zeros
           move 1 to lk-fatorial
       else
           move FATORIAL(lk-n - 1) to ws-fatorial-n-menos-1
           compute lk-fatorial = lk-n * ws-fatorial-n-menos-1
       end-if

       goback.

   end function FATORIAL.

Giving here,

prompt$ cobc -g -xj gtc002.cob FACTORIAL.cob
Entre com um numero inteiro positivo (ou zero para encerrar):
3
O fatorial de +0000000003 e' 000006
Entre com um numero inteiro positivo (ou zero para encerrar):
5
O fatorial de +0000000005 e' 000120
Entre com um numero inteiro positivo (ou zero para encerrar):
7
O fatorial de +0000000007 e' 005040
Entre com um numero inteiro positivo (ou zero para encerrar):
0

Excuse the slight reformatting, the version above should work as FIXED or FREE format COBOL compiles

The original is passing an ASCII "00005" to the function, attempting to recurse a huge number of times when improperly marshaling as USAGE BINARY (it's a bug in GnuCOBOL). As @Simon Sobisch noted, this will be fixed someday, but a sound workaround for now is coding user defined functions with actual USAGE BINARY arguments for numerics instead of PIC 9 COBOL fields.

That work around will hold for recursive or non recursive functions.

With literals in source, use FUNCTION NUMVAL(123) for 123. The source text literal defaults to "123" PIC 9 (usage DISPLAY) form in GnuCOBOL cobc, and you need to force a USAGE BINARY numeric when calling User Defined Functions in current releases.