Como criar um subprograma recursivo em Cobol?
Para criar um subprograma recursivo (um subprograma que chama a si mesmo) devemos utilizar a opção “IS RECURSIVE” no PROGRAM-ID e atentar para alguns detalhes.
O subprograma a seguir mostra o tradicional cálculo de fatorial, utilizado por dez em cada dez programadores que querem dar exemplos de recursividades.
Só para recordar…
5! = 5 x 4 x 3 x 2 x 1 = 120
…que é a mesma coisa que escrever…
5! = 5 x 4!
Ou seja, uma das propriedades do fatorial é que…
n! = n x (n - 1)!
…então vamos codificar um subprograma que subtrai 1 do argumento recebido e chama a si mesmo com esse novo argumento:
identification division. program-id. FATORIAL is recursive. data division. working-storage section. 01 wt-n-1 pic 9(009) value zeros. 01 wt-fatorial pic 9(009) value zeros. 01 wt-fatorial-1 pic 9(009) value zeros. linkage section. 01 lk-n pic 9(009) value zeros. procedure division using lk-n returning wt-fatorial. inicio.if lk-n = 1
move 1 to wt-fatorial
else
compute wt-n-1 = lk-n - 1
call "FATORIAL" using by content wt-n-1
returning wt-fatorial-1
compute wt-fatorial = lk-n * wt-fatorial-1
end-if
goback.
Repare que o subprograma chama a si mesmo passando o valor do argumento recebido (lk-n) menos 1 e em seguida multiplica o argumento original pelo resultado do CALL.
O programa chamador…
identification division.
program-id. gtc002.
data division.
working-storage section.
77 wt-n pic 9(009) value zeros.
77 wt-fatorial pic 9(009) value zeros.
procedure division.
main.
display "Entre com um numero inteiro positivo:"
accept wt-n from console
call "FATORIAL" using wt-n returning wt-fatorial
display wt-n "!=" wt-fatorial
stop run.
…mostra a seguinte mensagem quando é executado:
[aeisxpad ~/cbl]$ gtc002
Entre com um numero inteiro positivo:
5
000000005!=000000120
Alguns detalhes que reparei enquanto estava codificando os programas é que as variáveis de resultado não devem fazer parte da linkage (por isso a opção RETURNING tanto na PROCEDURE DIVISION do subprograma quanto no CALL.
Além disso, só deu certo depois que coloquei a cláusula BY CONTENT no CALL dentro do subprograma. Diferentemente da opção BY REFERENCE (default), a opção BY CONTENT faz com que o programa chamador passe para o programa chamado o endereço de memória de uma cópia do argumento (e não o endereço de memória do argumento em si). Com isso, na prática, estamos isolando as variáveis das diversas instâncias de FATORIAL que são criadas durante a execução do programa principal.