Translate

Mostrar mensagens com a etiqueta compilação. Mostrar todas as mensagens
Mostrar mensagens com a etiqueta compilação. Mostrar todas as mensagens

quarta-feira, 8 de julho de 2026

PERFORM Recursivo em COBOL: O Warning que Todo Padawan Ignora (Até o Job Estourar o TIME e o REGION)

 

Bellacosa e o perigo do perform recursivo

☕ Um Café no Bellacosa Mainframe

PERFORM Recursivo em COBOL: O Warning que Todo Padawan Ignora (Até o Job Estourar o TIME e o REGION)

"Recursão é uma ferramenta fantástica... exceto quando você tenta usá-la como estrutura de repetição dentro de um programa COBOL Batch."

Quem vem de Java, C#, Python ou C costuma achar natural escrever funções recursivas.

Quem cresceu no COBOL aprende rapidamente uma regra quase sagrada:

Nunca faça um PERFORM recursivo em um parágrafo ou seção.

Mas por quê?

Vamos abrir o capô do compilador.


Primeiro: o que é um PERFORM recursivo?

Imagine algo assim:

0000-PRINCIPAL.

    PERFORM 1000-PROCESSA

    STOP RUN.

1000-PROCESSA.

    DISPLAY "PROCESSANDO"

    PERFORM 1000-PROCESSA.

O programa chama...

...que chama...

...que chama...

...que chama novamente...

Nunca termina.


O warning da compilação

O Enterprise COBOL consegue detectar algumas formas óbvias de recursão.

Durante a compilação pode surgir mensagens semelhantes a:

IGYPSxxxx-W

Recursive PERFORM detected.

ou

Possible recursive PERFORM.

O compilador está dizendo:

"Existe um caminho onde este PERFORM pode executar novamente antes do anterior terminar."

Nem sempre é erro.

Mas quase sempre indica problema de projeto.


Por que isso é perigoso?

Porque PERFORM não foi criado para funcionar como chamada infinita de procedimentos.

Cada PERFORM precisa guardar informações como:

  • endereço de retorno

  • contexto de execução

  • pilha de controle

  • informações internas do runtime

A cada nova chamada tudo isso cresce.

PERFORM A
    ↓
PERFORM A
    ↓
PERFORM A
    ↓
PERFORM A
    ↓
PERFORM A

A pilha nunca é liberada.


O que acontece durante a execução?

Enquanto houver memória:

Stack

+----------------+
| retorno        |
+----------------+
| retorno        |
+----------------+
| retorno        |
+----------------+
| retorno        |
+----------------+
| retorno        |
+----------------+

Cada PERFORM adiciona um novo frame.

Quando acaba a pilha...

Boom.


O programa pode terminar com

Dependendo do ambiente:

  • S0C1

  • S0C4

  • S0CB

  • S878

  • S80A

Ou simplesmente:

ABEND

Tudo depende de onde ocorreu a falha.


O erro de TIME no JCL

Muito antes da memória acabar...

o Job pode morrer por tempo.

Exemplo:

//STEP1 EXEC PGM=MEUPROG,TIME=1

ou

TIME=1440

Mesmo com TIME=1440...

o programa nunca termina.

O JES percebe que o tempo máximo foi atingido.

Resultado:

S322

Ou mensagens semelhantes indicando limite de CPU excedido.

Não foi o COBOL.

Foi o JCL protegendo o sistema.


O erro de REGION

Outro clássico.

Cada PERFORM recursivo consome mais memória.

Em algum momento:

REGION=0M

não resolve.

Porque memória infinita não existe.

O resultado costuma ser:

S878

ou

S80A

Falta de armazenamento.


"Mas REGION=0M não é infinito?"

Não.

É apenas o máximo permitido pela instalação.

Existe limite de:

  • memória virtual

  • stack

  • storage abaixo da linha

  • storage acima da linha

  • política do sistema

Nada disso é infinito.


O maior problema: lógica

Suponha:

1000-ROTINA.

    IF WS-FIM = 'N'
       PERFORM 1000-ROTINA
    END-IF.

Quem altera:

WS-FIM

Se ninguém alterar...

Nunca haverá saída.

É um loop infinito disfarçado.


Por que não usar recursão em parágrafos e seções?

Porque COBOL foi projetado para outro paradigma.

A linguagem nasceu para processamento sequencial.

Ela possui comandos próprios para repetição.

Como:

PERFORM UNTIL
PERFORM VARYING
SEARCH
SEARCH ALL

Essas estruturas:

  • são previsíveis

  • ocupam pouca memória

  • facilitam depuração

  • têm melhor desempenho


"Mas COBOL suporta recursão."

Sim.

Desde o Enterprise COBOL moderno existe:

RECURSIVE PROGRAM-ID.

ou

PROGRAM-ID. MEUPROG RECURSIVE.

Isso significa que o programa pode chamar a si próprio.

Exemplo clássico:

  • árvore binária

  • parsing

  • algoritmos matemáticos

  • estruturas hierárquicas

Mesmo assim...

Não significa que seja recomendado para processamento batch tradicional.


A diferença importante

Errado

Parágrafo
↓

PERFORM

↓

Mesmo parágrafo

Recursão interna.

Difícil de manter.


Correto

Programa A

CALL Programa A

Novo contexto

Retorna

Quando realmente houver necessidade de recursão.


Curiosidade

Os compiladores antigos praticamente desencorajavam qualquer tipo de recursão.

O foco sempre foi:

  • velocidade

  • previsibilidade

  • baixo consumo de memória

A maioria dos sistemas bancários jamais precisou de recursão.


Como um sênior resolveria?

Em vez disso:

PERFORM UNTIL WS-FIM = 'S'

    ...

END-PERFORM

ou

PERFORM VARYING IDX FROM 1 BY 1
        UNTIL IDX > TOTAL

Muito mais claro.

Muito mais rápido.

Muito mais seguro.


Boas práticas

✅ Prefira PERFORM UNTIL para laços controlados.

✅ Use PERFORM VARYING para contadores.

✅ Evite PERFORM chamando o próprio parágrafo.

✅ Revise IFs que nunca alteram a condição de saída.

✅ Analise os warnings do compilador; eles frequentemente apontam defeitos reais de lógica.

✅ Monitore consumo de CPU e storage no SDSF durante testes.

✅ Se precisar de recursão, utilize programas declarados RECURSIVE e valide cuidadosamente profundidade máxima e condição de parada.

✅ Sempre tenha uma condição de saída claramente identificável.


Dicas de depuração

Se um Job "não termina":

  1. Verifique se a CPU continua aumentando no SDSF.

  2. Procure PERFORMs que retornam ao mesmo parágrafo.

  3. Confirme se a variável de controle realmente muda.

  4. Ative SSRANGE em ambiente de teste para detectar erros relacionados a índices e referências inválidas.

  5. Gere um compile listing (LIST, MAP, XREF) para acompanhar o fluxo de chamadas.

  6. Revise mensagens do compilador; um warning ignorado hoje pode virar um ABEND amanhã.


Caminho para o Padawan COBOL

Antes de pensar em recursão, domine completamente:

  1. PERFORM

  2. PERFORM THRU

  3. PERFORM UNTIL

  4. PERFORM VARYING

  5. Estrutura de parágrafos e seções

  6. Escopo explícito (END-IF, END-PERFORM)

  7. Fluxo estruturado sem GO TO

  8. Subprogramas com CALL

  9. Programas RECURSIVE apenas quando o problema realmente exigir

Quando você entender por que o COBOL prefere estruturas iterativas, começará a enxergar o sistema como os arquitetos do IBM Z enxergam: programas previsíveis, eficientes e fáceis de manter. Em ambientes que processam milhões de transações por dia, previsibilidade vale muito mais do que elegância acadêmica.


terça-feira, 30 de dezembro de 2025

🧨 ABEND em Mainframe não é azar

 


🧨 ABEND em Mainframe não é azar

Como usar PARMs de compilação COBOL para caçar bugs no IBM Mainframe

Se você trabalha com COBOL em mainframe há mais de cinco minutos, já entendeu uma verdade universal:

❝ Programa não “cai”. Ele denuncia. ❞

E essa denúncia atende pelo nome de ABEND.

Neste artigo, vamos juntar tudo o que falamos até agora sobre bugs, ABENDs e parâmetros de compilação, para transformar você — humilde padawan — em alguém que olha um S0C7 e sorri, porque já sabe onde mexer.


🧠 A mentalidade correta: detectar → diagnosticar → eliminar

Antes de falar de PARM, ajuste o mindset.

No mundo IBM mainframe:

  • Detectar → perceber que algo deu errado
  • Diagnosticar → entender onde e por quê
  • Eliminar → corrigir sem criar outro monstro

Os parâmetros de compilação COBOL existem exatamente para acelerar o diagnóstico. Sem eles, você está debugando no escuro.



🧰 O arsenal do compilador COBOL

Quando você compila um programa COBOL no JCL, você pode pedir ajuda ao compilador usando PARMs.

Exemplo clássico:

//COBOL   EXEC IGYCRCTL,
 // PARM='LIST,MAP,OFFSET,SSRANGE,ARITH(EXTEND)' 

Isso não é excesso. Isso é sobrevivência profissional.


🗺️ MAP — o raio-X da memória COBOL

Vamos falar do MAP, porque ele é campeão de prova e de vida real.

O que o MAP faz?

  • Mostra o layout real da WORKING-STORAGE
  • Exibe offsets, tamanhos e alinhamento
  • Revela quem está sobrescrevendo quem

Quando usar MAP?

  • S0C7 (campo não numérico)
  • S0C4 (acesso indevido à memória)
  • Valores “malucos” após MOVE
  • Campos COMP / COMP-3 se comportando estranho

🧙♂️ Regra Jedi:

Se o valor não faz sentido, MAP revela o crime.

🧨 SSRANGE — o salva-vidas das tabelas

Se o seu programa usa:

  • OCCURS
  • Índices
  • Subscritos
  • Arrays

👉 SSRANGE não é opcional.

O que o SSRANGE faz?

  • Interrompe o programa no exato momento
  • Detecta acesso fora dos limites da tabela
  • Evita corrupção silenciosa de memória

Sem SSRANGE:

  • O erro acontece
  • O programa continua
  • O ABEND aparece 300 linhas depois
  • Você sofre


🧮 ARITH(EXTEND) — contra o overflow silencioso

O COBOL antigo adorava truncar valores sem avisar.

Com ARITH(EXTEND):

  • O compilador respeita precisão
  • Evita S0CB (overflow)
  • Resultados financeiros ficam corretos

📌 Essencial para:

  • COMPUTE
  • Cálculos financeiros
  • COMP e COMP-3


📜 LIST e OFFSET — o mapa do tesouro

LIST

  • Gera o listing completo
  • Mostra warnings, erros, mensagens
  • Fundamental para erros de arquivo (U4038, U4094)

OFFSET

  • Mostra deslocamento de cada instrução
  • Permite cruzar:

🧠 Dica de veterano:

Dump sem OFFSET é igual mapa sem legenda.

🐞 TEST — o modo “cirurgia aberta”

O parâmetro TEST habilita:

  • IBM z/OS Debugger
  • Breakpoints
  • Step by step
  • Inspeção de variáveis em tempo real

⚠️ Regra sagrada:

TEST nunca vai para produção.

Mas em desenvolvimento? 👉 É simplesmente o melhor amigo do padawan.


📊 Tabela definitiva — ABEND → PARM ideal

(sim, isso cai em prova)

Article content

ABEND / SintomaUse este PARMS0C7MAPS0C4SSRANGE + MAPOverflowARITH(EXTEND)Problema de arquivoLISTTabela / OCCURSSSRANGEDebug interativoTEST


🧪 Combo campeão (decora isso)

LIST, MAP, OFFSET, SSRANGE, ARITH(EXTEND)

Esse combo:

  • Resolve 80% dos ABENDs comuns
  • É aceito em ambientes de desenvolvimento
  • Te transforma em alguém respeitado na squad


🎓 Estilo prova IBM — frase mágica

❝ Qual parâmetro ajuda a identificar campos sobrepostos na memória? ❞

Resposta automática: 👉 MAP


🧠 Combo campeão de PROVA (decorar)

S0C7  → MAP
S0C4  → SSRANGE
Overflow → ARITH(EXTEND)
Arquivo → LIST
Tabela → SSRANGE + MAP

📊 Tabela “ABEND → PARM ideal”

Guia de sobrevivência COBOL Mainframe (estilo prova IBM)

Regra de ouro de prova: 👉 ABEND ≠ erro aleatório 👉 Sempre existe um PARM que entrega o criminoso

🧨 ABENDs de DADOS (os mais comuns)

ABENDO que aconteceuPARM IDEALPor quêS0C7Campo não numérico em operação aritméticaMAP, NUMPROC(MIG), LISTMAP mostra o campo corrompidoS0CBOverflow aritméticoARITH(EXTEND), LISTEvita truncamento silenciosoS0C1Instrução inválidaOFFSET, LISTOFFSET cruza dump × código


🧠 ABENDs de MEMÓRIA / ENDEREÇO

ABENDO que aconteceuPARM IDEALPor quêS0C4Acesso fora de área válidaSSRANGE, MAP, OFFSETSSRANGE pega o erro na horaS0C2Endereço inválidoOFFSET, MAPOffset aponta instrução culpada

🧠 Dica de prova:

Se envolver tabela, OCCURS ou índice, pense primeiro em SSRANGE.

📂 ABENDs de ARQUIVO / I-O

ABENDO que aconteceuPARM IDEALPor quêU4038OPEN/CLOSE erradoLISTMensagens aparecem no listingU4094READ inválidoLIST, MAPErro lógico, não de memóriaS013 / S213DCB / espaçoLISTDiagnóstico está no compile/list


🔄 ABENDs de LOOP / LÓGICA

SintomaCausaPARM IDEALPor quêLoop infinitoContador corrompidoTRUNC(BIN), MAPCOMP mal definidoValor estranho em COMPTruncamentoTRUNC(BIN)Controle binário correto


🧪 ABENDs “NÃO REPRODUZÍVEIS” (os traiçoeiros)

SintomaSuspeitoPARM IDEALPor quêErro intermitenteDados sobrepostosSSRANGE, MAPDetecta overwriteFunciona às vezesMOVE erradoMAP, FLAG(I)FLAG denuncia práticas ruins


🐞 ABENDs para DEBUG INTERATIVO

SituaçãoPARM IDEALUsoAnálise passo a passoTESTIBM z/OS DebuggerBreakpointsTESTDebug onlineCódigo grandeXREFLocalizar variáveis

⚠️ Prova e vida real:

TEST nunca entra em produção.

🧠 Checklist Bellacosa antes de debugar

✅ Compilou com LIST?

✅ MAP está ativo?

✅ SSRANGE ligado?

✅ Sabes qual ABEND estás caçando?

✅ Não levou TEST para PROD?

☠️ ABENDs clássicos e o parâmetro certo

Article content

ABENDCausa comumParâmetro salvadorS0C7Campo não numéricoMAP, NUMPROCS0C4Acesso inválidoSSRANGES0CBOverflowARITHU4038OPEN/CLOSELISTU4094Arquivo erradoLIST, MAP

🧙♂️ Conclusão El Jefe

ABEND não é castigo. É feedback brutalmente honesto.

Quem domina PARMs de compilação COBOL:

  • Debuga mais rápido
  • Sofre menos
  • Aprende mais
  • E vira referência no time

E lembre-se, padawan:

❝ O compilador sempre tentou te avisar. Você é que não pediu ajuda. ❞
Vagner Renato Bellacosa, IBM Champion e especialista em IBM Mainframe
IBM Z17 SYSTEM ONLINE
Sobre o autor

Vagner Renato Bellacosa

IBM Champion 2026 • Especialista em IBM Mainframe

Vagner Renato Bellacosa trabalha com IBM Mainframe desde 1988 , é IBM Champion e especialista em COBOL, CICS, Db2, z/OS e IBM Z. Compartilha experiências profissionais, conhecimento técnico, história da computação e práticas do universo mainframe para aproximar novas gerações das tecnologias que sustentam empresas, bancos e governos ao redor do mundo.

IBM Champion IBM Z COBOL CICS Db2 z/OS Mainframe desde 1988
GitHub LinkedIn
Inicializando conteúdo...