DevTools

Cheatsheet COBOL

Linguagem empresarial clássica para sistemas mainframe e processamento batch

Voltar às linguagens
COBOL
60 cards encontrados
Categorias:
Versões:

Básico


8 cards
Estrutura do programa
       IDENTIFICATION DIVISION.
       PROGRAM-ID. HELLO-WORLD.
       AUTHOR. PROGRAMADOR.

       ENVIRONMENT DIVISION.
       CONFIGURATION SECTION.

       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01 WS-NOME PIC X(30).

       PROCEDURE DIVISION.
           DISPLAY "Ola Mundo".
           STOP RUN.

Um programa COBOL tem 4 divisões: IDENTIFICATION (nome), ENVIRONMENT (configuração), DATA (variáveis) e PROCEDURE (lógica). Cada instrução termina com ponto.

Formato e comentários
****** Col 1-6: número de sequência (opcional)
****** Col 7: indicador (* = comentário)
****** Col 8-11: Area A (divisions, sections)
****** Col 12-72: Area B (statements)

*      Comentário tradicional (coluna 7)

       *> Comentário moderno (inline)

       DISPLAY "Codigo".

* Cada instrução termina com ponto final
* Palavras-chave em MAIÚSCULAS (convenção)
* Nomes de variáveis com prefixo WS-

O COBOL usa formato fixo: coluna 7 para comentários, Área A (8-11) para divisões, Área B (12-72) para instruções. *> é o comentário moderno inline.

Hello World completo
       IDENTIFICATION DIVISION.
       PROGRAM-ID. HELLO.

       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01 WS-MENSAGEM PIC X(20)
          VALUE "Ola, Mundo!".

       PROCEDURE DIVISION.
           DISPLAY WS-MENSAGEM.
           DISPLAY "Adeus!".
           STOP RUN.

*> cobc -x hello.cob -o hello
*> ./hello

O programa mínimo: DISPLAY imprime no ecrã e STOP RUN termina. Compile com cobc -x (GnuCOBOL) para criar um executável.

As 4 divisões
* 1. IDENTIFICATION - quem é o programa
       IDENTIFICATION DIVISION.
       PROGRAM-ID. MEU-PROGRAMA.

* 2. ENVIRONMENT - configuração e ficheiros
       ENVIRONMENT DIVISION.
       INPUT-OUTPUT SECTION.

* 3. DATA - variáveis e estruturas
       DATA DIVISION.
       WORKING-STORAGE SECTION.

* 4. PROCEDURE - a lógica do programa
       PROCEDURE DIVISION.

As 4 divisões são obrigatórias e em ordem: IDENTIFICATION, ENVIRONMENT, DATA e PROCEDURE. Só IDENTIFICATION e PROCEDURE são sempre necessárias.

Compilar e executar
# GnuCOBOL:
cobc -x programa.cob -o programa
./programa

# Compilar como módulo (dinâmico):
cobc -m programa.cob

# Verificar só a sintaxe:
cobc -fsyntax-only programa.cob

# Com debug:
cobc -x -g -debug programa.cob

# Executar com runtime:
cobcrun programa

# Listar warnings:
cobc -x -Wall programa.cob

Use cobc -x para executável standalone e cobc -m para módulo. -fsyntax-only verifica sem compilar. cobcrun executa módulos.

STOP RUN e GOBACK
       PROCEDURE DIVISION.
           DISPLAY "A processar...".

* Terminar programa principal:
           STOP RUN.

* Terminar subprograma (retorna ao caller):
           GOBACK.

* STOP RUN com código de retorno:
           MOVE 0 TO RETURN-CODE.
           STOP RUN.

STOP RUN termina um programa principal. GOBACK devolve o controlo ao programa chamador (em subprogramas). RETURN-CODE indica o estado (0 = OK).

DISPLAY e ACCEPT
       PROCEDURE DIVISION.
           DISPLAY "Ola Mundo".
           DISPLAY "Nome: " WS-NOME.
           DISPLAY "Valor: " WS-VAL
               WITH NO ADVANCING.

           ACCEPT WS-NOME.
           ACCEPT WS-DATA FROM DATE.
           ACCEPT WS-HORA FROM TIME.
           ACCEPT WS-TECLA FROM CONSOLE.

DISPLAY escreve no ecrã (pode concatenar vários itens). ACCEPT lê do teclado. WITH NO ADVANCING não muda de linha. FROM DATE/TIME lê do sistema.

Parágrafos e secções
       PROCEDURE DIVISION.
       MAIN-PARAGRAPH.
           PERFORM INICIAR.
           PERFORM PROCESSAR.
           PERFORM TERMINAR.
           STOP RUN.

       INICIAR.
           DISPLAY "A iniciar...".

       PROCESSAR.
           DISPLAY "A processar...".

       TERMINAR.
           DISPLAY "A terminar...".

Parágrafos são blocos de código nomeados (Área A). Chamam-se com PERFORM nome. Organizam o programa em rotinas reutilizáveis.

Dados


8 cards
PIC clauses
       01 WS-CAMPOS.
           05 WS-NOME      PIC X(30).
           05 WS-IDADE     PIC 9(3).
           05 WS-SALARIO   PIC 9(5)V99.
           05 WS-CODIGO    PIC A(5).
           05 WS-FLAG      PIC X.
           05 WS-NEGATIVO  PIC S9(4).
           05 WS-EDITADO   PIC Z(4)9.99.

* X = alfanumérico, 9 = numérico
* A = alfabético, V = decimal implícito
* S = com sinal, Z = zero suprimido

A PIC clause define o tipo e tamanho. X = texto, 9 = número, V = casa decimal implícita, S = sinal, Z = zero suprimido (formatação).

VALUE (valores iniciais)
       01 WS-CONTADOR PIC 9(4) VALUE 0.
       01 WS-NOME PIC X(20) VALUE "Anónimo".
       01 WS-PI PIC 9V9(6) VALUE 3.141593.
       01 WS-FLAG PIC X VALUE "N".
       01 WS-MAX PIC 9(3) VALUE 999.

* Constantes (nível 01 com VALUE):
       01 WS-TAXA-IVA PIC 9V99 VALUE 0.23.

* Sem VALUE, campos iniciam com espaços/zeros

VALUE define o valor inicial da variável. Sem VALUE, campos alfanuméricos iniciam com espaços e numéricos com zeros. Útil para constantes e defaults.

MOVE e SET
       MOVE "Ana" TO WS-NOME.
       MOVE 42 TO WS-IDADE.
       MOVE 1500.50 TO WS-SALARIO.
       MOVE ZERO TO WS-CONTADOR.
       MOVE SPACES TO WS-NOME.
       MOVE ALL "X" TO WS-LINHA.
       MOVE HIGH-VALUE TO WS-CAMPO.

       SET WS-INDICE TO 1.
       SET WS-INDICE UP BY 1.
       SET WS-INDICE DOWN BY 1.

MOVE atribui valores (destino por último). Figuras especiais: ZERO, SPACES, ALL "x", HIGH-VALUE. SET é usado para índices de tabelas.

REDEFINES
       01 WS-DADOS.
           05 WS-DATA-COMPLETA PIC X(8).
           05 WS-DATA-PARTES
              REDEFINES WS-DATA-COMPLETA.
               10 WS-ANO  PIC 9(4).
               10 WS-MES  PIC 9(2).
               10 WS-DIA  PIC 9(2).

       PROCEDURE DIVISION.
           MOVE "20240315" TO WS-DATA-COMPLETA.
           DISPLAY WS-ANO "/" WS-MES "/" WS-DIA.
           *> Mostra: 2024/03/15

REDEFINES permite ver a mesma memória com outra estrutura. Aqui uma string de 8 chars é reinterpretada como ano/mês/dia. Não ocupa espaço extra.

Níveis e grupos
       01 WS-CLIENTE.
           05 WS-NOME      PIC X(30).
           05 WS-ENDERECO.
               10 WS-RUA    PIC X(40).
               10 WS-CIDADE PIC X(20).
               10 WS-CP     PIC X(8).
           05 WS-TELEFONE  PIC X(15).

* Nível 01 = registo principal
* Nível 05-49 = subcampos (hierarquia)
* Nível 77 = variável independente
* Nível 88 = condição (booleano)

Os níveis criam hierarquia: 01 é o grupo principal, 05-49 são subcampos aninhados. 77 declara variáveis soltas. 88 define condições nomeadas.

Campos editados
       01 WS-VALOR PIC 9(6)V99 VALUE 1234.56.
       01 WS-EDITADO PIC Z(5)9.99.
       01 WS-MOEDA PIC ZZZ.ZZ9,99.
       01 WS-SINAL PIC +Z(5)9.

       PROCEDURE DIVISION.
           MOVE WS-VALOR TO WS-EDITADO.
           DISPLAY WS-EDITADO.  *> " 1234.56"
           MOVE WS-VALOR TO WS-MOEDA.
           DISPLAY WS-MOEDA.    *> "  1.234,56"

Campos editados formatam a saída: Z suprime zeros à esquerda, . e , inserem separadores, + mostra o sinal. Só para DISPLAY, não para cálculos.

Nível 88 (condições)
       01 WS-ESTADO PIC X.
           88 WS-ATIVO     VALUE "A".
           88 WS-INATIVO   VALUE "I".
           88 WS-PENDENTE  VALUE "P".

       01 WS-DIA PIC 9(2).
           88 WS-FIM-SEMANA VALUES 6, 7.
           88 WS-DIA-UTIL VALUES 1 THRU 5.

       PROCEDURE DIVISION.
           IF WS-ATIVO
               DISPLAY "Cliente ativo".
           SET WS-ATIVO TO TRUE.

O nível 88 cria condições nomeadas ligadas a valores. IF WS-ATIVO testa se WS-ESTADO = "A". Pode usar VALUES múltiplos e THRU (intervalo). SET ... TO TRUE ativa.

Nível 77 e RENAMES
* Nível 77 - variável independente:
       77 WS-CONTADOR PIC 9(4) VALUE 0.
       77 WS-FLAG PIC X VALUE "N".

* RENAMES - renomear um grupo:
       01 WS-PESSOA.
           05 WS-NOME PIC X(30).
           05 WS-IDADE PIC 9(3).
       66 WS-INFO RENAMES WS-NOME
           THRU WS-IDADE.

* 66 agrupa campos existentes sob novo nome

Nível 77 declara variáveis independentes (sem grupo). RENAMES (nível 66) dá um nome alternativo a um conjunto de campos existentes.

Controlo de Fluxo


8 cards
IF/ELSE
       IF WS-IDADE >= 18
           DISPLAY "Adulto"
       ELSE
           DISPLAY "Menor"
       END-IF.

       IF WS-NOTA >= 14
           DISPLAY "Aprovado"
       ELSE IF WS-NOTA >= 10
           DISPLAY "Recuperacao"
       ELSE
           DISPLAY "Reprovado"
       END-IF.

* Operadores: =  <>  <  >  <=  >=
* Lógicos: AND, OR, NOT

IF/ELSE/END-IF é a condicional básica. Aninhe com ELSE IF. Operadores: = (igual), <> (diferente), <, >, <=, >=. Combine com AND, OR, NOT.

EVALUATE (case)
       EVALUATE WS-DIA
           WHEN 1
               DISPLAY "Segunda"
           WHEN 2 THRU 5
               DISPLAY "Dia util"
           WHEN 6 7
               DISPLAY "Fim de semana"
           WHEN OTHER
               DISPLAY "Invalido"
       END-EVALUATE.

* WHEN 6 7 = múltiplos valores (OR)
* WHEN 2 THRU 5 = intervalo
* WHEN OTHER = default

EVALUATE é o "switch/case". WHEN testa cada caso, THRU define intervalos, valores separados por espaço são OR. WHEN OTHER é o default.

PERFORM VARYING (for)
* for (i = 1; i <= 10; i++):
       PERFORM VARYING WS-I FROM 1 BY 1
           UNTIL WS-I > 10
           DISPLAY WS-I
       END-PERFORM.

* Decrescente:
       PERFORM VARYING WS-I FROM 10 BY -1
           UNTIL WS-I < 1
           DISPLAY WS-I
       END-PERFORM.

* Passo 2:
       PERFORM VARYING WS-I FROM 0 BY 2
           UNTIL WS-I > 20
           DISPLAY WS-I
       END-PERFORM.

PERFORM VARYING é o loop "for": FROM (início), BY (passo), UNTIL (condição de paragem). O passo pode ser negativo ou maior que 1.

EVALUATE TRUE (if/elseif)
       EVALUATE TRUE
           WHEN WS-IDADE >= 65
               DISPLAY "Idoso"
           WHEN WS-IDADE >= 18
               DISPLAY "Adulto"
           WHEN WS-IDADE >= 12
               DISPLAY "Adolescente"
           WHEN OTHER
               DISPLAY "Crianca"
       END-EVALUATE.

* Equivalente a uma cadeia IF/ELSE-IF
* Mais legível para múltiplas condições

EVALUATE TRUE avalia expressões booleanas em cada WHEN. É a alternativa limpa a longas cadeias de IF/ELSE-IF. O primeiro WHEN verdadeiro executa.

PERFORM UNTIL (while)
* while (resposta <> "S"):
       PERFORM UNTIL WS-RESPOSTA = "S"
           DISPLAY "Continuar? (S/N)"
           ACCEPT WS-RESPOSTA
       END-PERFORM.

* Teste no fim (do-while):
       PERFORM WITH TEST AFTER
           UNTIL WS-CONTADOR > 5
           ADD 1 TO WS-CONTADOR
           DISPLAY WS-CONTADOR
       END-PERFORM.

PERFORM UNTIL é o loop "while" (teste no início). WITH TEST AFTER move o teste para o fim (executa pelo menos uma vez, como do-while).

PERFORM parágrafos
       PROCEDURE DIVISION.
           PERFORM INICIAR-PROGRAMA.
           PERFORM PROCESSAR-DADOS.
           PERFORM FINALIZAR-PROGRAMA.
           STOP RUN.

       INICIAR-PROGRAMA.
           DISPLAY "A iniciar...".
           OPEN INPUT FICHEIRO-CLIENTES.

       PROCESSAR-DADOS.
           PERFORM LER-REGISTO
               UNTIL WS-EOF = "S".

       FINALIZAR-PROGRAMA.
           CLOSE FICHEIRO-CLIENTES.

PERFORM nome-parágrafo executa uma rotina e retorna automaticamente. É a forma clássica de organizar o COBOL em subrotinas (antes dos subprogramas CALL).

PERFORM TIMES
* Repetir 5 vezes:
       PERFORM 5 TIMES
           DISPLAY "Ola"
       END-PERFORM.

* Com variável:
       PERFORM WS-VEZES TIMES
           ADD WS-VALOR TO WS-TOTAL
       END-PERFORM.

* Chamar parágrafo N vezes:
       PERFORM MOSTRAR-LINHA 3 TIMES.

PERFORM n TIMES repete um bloco um número fixo de vezes. Aceita uma variável numérica como contador. Forma mais simples de loop.

IF aninhado e condições
       IF WS-TEM-STOCK
           IF WS-PRECO <= WS-LIMITE
               PERFORM COMPRAR-ARTIGO
           ELSE
               DISPLAY "Muito caro"
           END-IF
       ELSE
           DISPLAY "Sem stock"
       END-IF.

* Condições compostas:
       IF WS-IDADE >= 18 AND WS-TEM-CARTA
           PERFORM ALUGAR-CARRO.

       IF WS-VIP OR WS-ANTIGUIDADE > 10
           PERFORM DAR-DESCONTO.

Aninhe IF com indentação clara e feche cada um com END-IF. Combine condições com AND/OR. Use parênteses implícitos pela ordem (AND antes de OR).

Operações


7 cards
Aritmética
       ADD 10 TO WS-TOTAL.
       ADD A B GIVING WS-SOMA.
       SUBTRACT 5 FROM WS-SALDO.
       MULTIPLY WS-PRECO BY WS-QTD
           GIVING WS-TOTAL.
       DIVIDE WS-TOTAL BY WS-QTD
           GIVING WS-MEDIA
           REMAINDER WS-RESTO.

* ADD WS-A TO WS-B  =>  WS-B += WS-A
* GIVING guarda o resultado sem alterar operandos

Verbos aritméticos: ADD, SUBTRACT, MULTIPLY, DIVIDE. TO/FROM modificam o operando; GIVING guarda num campo à parte. REMAINDER dá o resto.

INSPECT e referência
* Substituir caracteres:
       INSPECT WS-TEXTO
           REPLACING ALL "a" BY "o".

* Contar caracteres:
       INSPECT WS-TEXTO
           TALLYING WS-CONT FOR ALL "e".

* Referência parcial (substring):
       MOVE WS-NOME(1:5) TO WS-PARTE.
       MOVE "2024" TO WS-DATA(1:4).

* WS-NOME(1:5) = 5 chars a partir da pos 1
* Referência com variável:
       MOVE WS-NOME(WS-POS:3) TO WS-TMP.

INSPECT substitui (REPLACING) ou conta (TALLYING) caracteres. A referência parcial campo(pos:tam) extrai ou escreve substrings. Muito útil para parsing.

COMPUTE (expressões)
       COMPUTE WS-AREA = 3.14 * WS-R ** 2.

       COMPUTE WS-JUROS ROUNDED =
           WS-CAPITAL * WS-TAXA / 100.

       COMPUTE WS-MEDIA =
           (WS-NOTA1 + WS-NOTA2) / 2.

       COMPUTE WS-RESULTADO = WS-A * WS-B
           + WS-C - WS-D / WS-E.

* ** = potência, ROUNDED = arredondar
* ON SIZE ERROR trata overflow
       COMPUTE WS-X = WS-Y * WS-Z
           ON SIZE ERROR DISPLAY "Overflow".

COMPUTE aceita expressões completas com + - * / ** e parênteses. ROUNDED arredonda o resultado. ON SIZE ERROR trata overflow.

Funções intrínsecas
* Matemáticas:
       COMPUTE WS-R = FUNCTION SQRT(16).
       COMPUTE WS-R = FUNCTION ABS(-5).
       COMPUTE WS-R = FUNCTION MAX(A B C).
       COMPUTE WS-R = FUNCTION MIN(A B C).

* Strings:
       MOVE FUNCTION UPPER-CASE(WS-S) TO WS-R.
       MOVE FUNCTION LOWER-CASE(WS-S) TO WS-R.
       MOVE FUNCTION TRIM(WS-S) TO WS-R.
       MOVE FUNCTION REVERSE(WS-S) TO WS-R.
       MOVE FUNCTION LENGTH(WS-S) TO WS-N.

FUNCTION dá acesso a funções built-in: SQRT, ABS, MAX, MIN (matemática) e UPPER-CASE, LOWER-CASE, TRIM, REVERSE, LENGTH (strings). Prefixe sempre com FUNCTION.

STRING (concatenar)
       STRING WS-NOME DELIMITED BY SPACE
           " - " DELIMITED BY SIZE
           WS-CIDADE DELIMITED BY SPACE
           INTO WS-RESULTADO.

* DELIMITED BY SPACE - até ao 1º espaço
* DELIMITED BY SIZE - campo inteiro

* Com ponteiro (posição de escrita):
       STRING WS-A DELIMITED BY SIZE
           INTO WS-B
           WITH POINTER WS-POS.

* ON OVERFLOW trata falta de espaço

STRING concatena vários campos num destino. DELIMITED BY SPACE corta nos espaços finais, BY SIZE usa o campo todo. WITH POINTER controla a posição.

Comparação e classes
* Condições numéricas:
       IF WS-VALOR IS NUMERIC
       IF WS-VALOR IS ZERO
       IF WS-VALOR IS POSITIVE
       IF WS-VALOR IS NEGATIVE

* Condições de classe:
       IF WS-CAMPO IS ALPHABETIC
       IF WS-CAMPO IS ALPHANUMERIC

* Condições de sinal (nível 88):
       IF WS-FLAG IS TRUE
       IF WS-FLAG IS FALSE

* Combinadas:
       IF WS-A > 0 AND WS-B < 100
       IF NOT WS-ERRO

Testes de classe: IS NUMERIC, IS ALPHABETIC, IS ALPHANUMERIC. Testes de valor: IS ZERO, IS POSITIVE, IS NEGATIVE. Testes de condição 88: IS TRUE/FALSE.

UNSTRING (dividir)
* Dividir por delimitador:
       UNSTRING WS-DATA DELIMITED BY "/"
           INTO WS-DIA WS-MES WS-ANO.

* Múltiplos delimitadores:
       UNSTRING WS-LINHA DELIMITED BY ","
           OR ";" INTO WS-C1 WS-C2 WS-C3.

* Com contadores:
       UNSTRING WS-FRASE DELIMITED BY " "
           INTO WS-P1 WS-P2 WS-P3
           TALLYING IN WS-NUM-PALAVRAS.

* WS-DATA = "15/03/2024"
* => WS-DIA=15, WS-MES=03, WS-ANO=2024

UNSTRING divide uma string por delimitador em vários campos. Aceita múltiplos delimitadores com OR. TALLYING IN conta quantos segmentos foram extraídos.

Ficheiros


8 cards
Definir ficheiros
       ENVIRONMENT DIVISION.
       INPUT-OUTPUT SECTION.
       FILE-CONTROL.
           SELECT CLIENTES
               ASSIGN TO "clientes.dat"
               ORGANIZATION IS LINE SEQUENTIAL
               FILE STATUS IS WS-STATUS.

       DATA DIVISION.
       FILE SECTION.
       FD CLIENTES.
       01 REG-CLIENTE.
           05 REG-NOME   PIC X(30).
           05 REG-IDADE  PIC 9(3).
           05 REG-SALDO  PIC 9(6)V99.

Declare em FILE-CONTROL (SELECT/ASSIGN) e defina o registo em FD (FILE SECTION). FILE STATUS guarda o código de resultado de cada operação.

Ficheiro indexado
       SELECT CLIENTES
           ASSIGN TO "clientes.idx"
           ORGANIZATION IS INDEXED
           ACCESS MODE IS DYNAMIC
           RECORD KEY IS REG-CODIGO
           ALTERNATE KEY IS REG-NOME
               WITH DUPLICATES.

* Leitura por chave:
       MOVE 123 TO REG-CODIGO.
       READ CLIENTES
           KEY IS REG-CODIGO
           INVALID KEY DISPLAY "Nao encontrado"
       END-READ.

ORGANIZATION INDEXED permite acesso direto por chave. RECORD KEY é a chave primária, ALTERNATE KEY são chaves secundárias. ACCESS MODE DYNAMIC permite sequencial + direto.

Leitura sequencial
       PROCEDURE DIVISION.
           OPEN INPUT CLIENTES.
           IF WS-STATUS NOT = "00"
               DISPLAY "Erro: " WS-STATUS
               STOP RUN
           END-IF.

           PERFORM UNTIL WS-EOF = "S"
               READ CLIENTES
                   AT END
                       MOVE "S" TO WS-EOF
                   NOT AT END
                       DISPLAY REG-NOME
               END-READ
           END-PERFORM.
           CLOSE CLIENTES.

OPEN INPUT abre para leitura. O loop READ ... AT END processa registo a registo até ao fim. CLOSE liberta o ficheiro. Padrão clássico de processamento batch.

START e leitura sequencial
* Posicionar no início (chave >= 100):
       MOVE 100 TO REG-CODIGO.
       START CLIENTES
           KEY IS >= REG-CODIGO
           INVALID KEY DISPLAY "Sem registos".

* Ler sequencialmente a partir daí:
       PERFORM UNTIL WS-EOF = "S"
           READ CLIENTES NEXT
               AT END MOVE "S" TO WS-EOF
               NOT AT END DISPLAY REG-CODIGO
           END-READ
       END-PERFORM.

START posiciona o ficheiro indexado numa chave (com =, >, >=, <). Depois READ NEXT percorre sequencialmente a partir daí. Ideal para relatórios por intervalo.

Escrita
* Criar/reescrever:
       OPEN OUTPUT CLIENTES.
       MOVE "Ana" TO REG-NOME.
       MOVE 30 TO REG-IDADE.
       WRITE REG-CLIENTE.
       CLOSE CLIENTES.

* Acrescentar ao fim:
       OPEN EXTEND CLIENTES.
       WRITE REG-CLIENTE.
       CLOSE CLIENTES.

* WRITE com verificação:
       WRITE REG-CLIENTE
           INVALID KEY DISPLAY "Erro escrita".

OPEN OUTPUT cria/reescreve. OPEN EXTEND acrescenta ao fim. WRITE grava o registo do FD. INVALID KEY deteta erros de escrita.

DELETE
       OPEN I-O CLIENTES.

* Posicionar no registo:
       MOVE 123 TO REG-CODIGO.
       READ CLIENTES
           KEY IS REG-CODIGO
           INVALID KEY DISPLAY "Nao existe"
       END-READ.

* Apagar:
       DELETE CLIENTES RECORD
           INVALID KEY DISPLAY "Erro delete".

       CLOSE CLIENTES.

* Só funciona em ficheiros indexados/relativos

DELETE ficheiro RECORD remove o registo atual. Requer ficheiro aberto em I-O e registo previamente lido. Só funciona em organizações indexada ou relativa.

Atualização (I-O)
       OPEN I-O CLIENTES.

* Ler o registo a modificar:
       MOVE 123 TO REG-CODIGO.
       READ CLIENTES
           KEY IS REG-CODIGO
           INVALID KEY DISPLAY "Nao existe"
       END-READ.

* Modificar e reescrever:
       MOVE 999.99 TO REG-SALDO.
       REWRITE REG-CLIENTE
           INVALID KEY DISPLAY "Erro".

       CLOSE CLIENTES.

OPEN I-O abre para leitura e escrita. Leia o registo, modifique os campos e use REWRITE para gravar as alterações no mesmo lugar. Requer ficheiro indexado ou relativo.

FILE STATUS
       01 WS-STATUS PIC XX.

* Códigos comuns:
* "00" - Sucesso
* "02" - Sucesso (duplicado em alternate key)
* "10" - Fim de ficheiro
* "23" - Registo não encontrado
* "35" - Ficheiro não existe
* "46" - Leitura inválida (sequencial)
* "9x" - Erro de sistema

       IF WS-STATUS = "00"
           DISPLAY "OK"
       ELSE
           DISPLAY "Erro: " WS-STATUS
       END-IF.

O FILE STATUS (2 chars) guarda o resultado de cada operação de ficheiro. "00" = sucesso, "10" = EOF, "23" = não encontrado, "35" = ficheiro inexistente. Verifique sempre após OPEN/READ/WRITE.

Avançado


7 cards
COPY e COPYBOOK
* Ficheiro COPYBOOK (comum.cpy):
       01 WS-DADOS-COMUNS.
           05 WS-USUARIO   PIC X(20).
           05 WS-DATA-SIS  PIC 9(8).
           05 WS-HORA-SIS  PIC 9(6).

* No programa:
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       COPY "comum.cpy".

* Com REPLACING (renomear prefixo):
       COPY "comum.cpy"
           REPLACING WS- BY CLI-.

COPY insere um copybook (código partilhado). REPLACING renomeia prefixos para evitar conflitos. Essencial para partilhar estruturas entre programas.

SORT e MERGE
* Ordenar um ficheiro:
       SORT FICH-TRABALHO
           ON ASCENDING KEY REG-CODIGO
           USING FICH-ENTRADA
           GIVING FICH-SAIDA.

* Com INPUT/OUTPUT procedures:
       SORT FICH-TRABALHO
           ON DESCENDING KEY REG-SALDO
           INPUT PROCEDURE É LER-DADOS
           OUTPUT PROCEDURE É GRAVAR-DADOS.

* MERGE junta ficheiros ordenados:
       MERGE FICH-TRABALHO
           ON ASCENDING KEY REG-CODIGO
           USING FICH-A FICH-B
           GIVING FICH-C.

SORT ordena um ficheiro por chave (ASCENDING/DESCENDING). MERGE junta ficheiros já ordenados. USING/GIVING definem entrada e saída. Ordenação nativa do COBOL.

Subprogramas (CALL)
* Programa chamador:
       CALL "SUBPROG" USING
           WS-PARAM1
           WS-PARAM2
           WS-RESULTADO.

* Subprograma (SUBPROG.COB):
       IDENTIFICATION DIVISION.
       PROGRAM-ID. SUBPROG.
       DATA DIVISION.
       LINKAGE SECTION.
       01 LS-PARAM1  PIC X(10).
       01 LS-PARAM2  PIC 9(5).
       01 LS-RESULT  PIC 9(8).
       PROCEDURE DIVISION USING
           LS-PARAM1 LS-PARAM2 LS-RESULT.
           COMPUTE LS-RESULT = LS-PARAM2 * 2.
           GOBACK.

CALL "nome" USING chama um subprograma passando parâmetros. O subprograma declara-os na LINKAGE SECTION e recebe em PROCEDURE DIVISION USING. Termina com GOBACK.

Tratamento de erros
* FILE STATUS:
       IF WS-STATUS = "00"
           DISPLAY "Sucesso"
       ELSE IF WS-STATUS = "10"
           DISPLAY "Fim de ficheiro"
       ELSE IF WS-STATUS = "23"
           DISPLAY "Registo nao existe"
       ELSE
           DISPLAY "Erro: " WS-STATUS
       END-IF.

* USE declaratives (handler global):
       DECLARATIVES.
       TRATAMENTO-ERRO SECTION.
           USE AFTER STANDARD ERROR
               PROCEDURE ON CLIENTES.
           DISPLAY "Erro no ficheiro".
       END DECLARATIVES.

Verifique o FILE STATUS após cada operação. DECLARATIVES define handlers globais de erro que executam automaticamente quando ocorre um erro no ficheiro.

Parâmetros BY VALUE/REFERENCE
* Por referência (padrão - pode modificar):
       CALL "SUB" USING WS-DADO.

* Por valor (cópia - não modifica):
       CALL "SUB" USING BY VALUE WS-NUM.

* No subprograma (BY VALUE):
       PROCEDURE DIVISION USING
           BY VALUE LS-NUM.

* BY CONTENT (cópia só de leitura):
       CALL "SUB" USING BY CONTENT WS-TEXTO.

* Devolver valor:
       CALL "SUB" USING WS-X
           RETURNING WS-RESULTADO.

Por padrão os parâmetros são BY REFERENCE (o subprograma pode modificá-los). BY VALUE passa uma cópia. RETURNING devolve um valor como função.

Ponteiros e ADDRESS
       01 WS-PONTEIRO USAGE POINTER.
       01 WS-DADOS PIC X(100).

* Obter endereço:
       SET WS-PONTEIRO TO ADDRESS OF WS-DADOS.

* Alocar memória dinâmica:
       ALLOCATE 100 CHARACTERS
           RETURNING WS-PONTEIRO.

* Libertar:
       FREE WS-PONTEIRO.

* SET POINTER para posição:
       SET WS-PONTEIRO UP BY 10.

* Comparar ponteiros:
       IF WS-PONTEIRO = NULL
           DISPLAY "Sem memoria".

USAGE POINTER declara ponteiros. ADDRESS OF obtém o endereço de um campo. ALLOCATE/FREE gerem memória dinâmica. Útil para estruturas de tamanho variável.

INITIALIZE
       01 WS-REGISTO.
           05 WS-NOME   PIC X(20).
           05 WS-IDADE  PIC 9(3).
           05 WS-SALDO  PIC 9(6)V99.

* Limpar tudo (espaços + zeros):
       INITIALIZE WS-REGISTO.

* Só campos alfanuméricos:
       INITIALIZE WS-REGISTO
           REPLACING ALPHANUMERIC BY SPACES.

* Com valor específico:
       INITIALIZE WS-REGISTO
           REPLACING NUMERIC DATA BY ZERO.

* Sem INITIALIZE, campos mantêm lixo

INITIALIZE limpa um grupo: alfanuméricos para espaços, numéricos para zeros. REPLACING permite especificar os valores. Evita "lixo" de memória em registos reutilizados.

Tabelas


7 cards
OCCURS (arrays)
       01 WS-TABELA.
           05 WS-ITEM OCCURS 10 TIMES
               INDEXED BY WS-IDX.
               10 WS-CODIGO PIC 9(4).
               10 WS-NOME   PIC X(20).

* Percorrer:
       PERFORM VARYING WS-IDX FROM 1 BY 1
           UNTIL WS-IDX > 10
           DISPLAY WS-NOME(WS-IDX)
       END-PERFORM.

* Aceder por índice:
       MOVE 5 TO WS-IDX.
       DISPLAY WS-CODIGO(WS-IDX).

OCCURS n TIMES cria um array com n elementos. INDEXED BY declara um índice. Aceda com campo(índice). Índices começam em 1.

SET UP / DOWN
       01 WS-TAB.
           05 WS-ELEM OCCURS 10 TIMES
               INDEXED BY WS-IDX
               PIC X(10).

* Incrementar/decrementar índice:
       SET WS-IDX TO 1.
       SET WS-IDX UP BY 1.      *> WS-IDX = 2
       SET WS-IDX DOWN BY 1.    *> WS-IDX = 1

* Percorrer ao contrário:
       SET WS-IDX TO 10.
       PERFORM VARYING WS-IDX FROM 10 BY -1
           UNTIL WS-IDX < 1
           DISPLAY WS-ELEM(WS-IDX)
       END-PERFORM.

SET índice UP BY n incrementa, DOWN BY n decrementa. Índices (INDEXED BY) só se modificam com SET, não com MOVE/COMPUTE.

SEARCH (busca linear)
       SET WS-IDX TO 1.
       SEARCH WS-ITEM
           AT END
               DISPLAY "Nao encontrado"
           WHEN WS-CODIGO(WS-IDX) = WS-ALVO
               DISPLAY "Achado: " WS-NOME(WS-IDX)
       END-SEARCH.

* SEARCH percorre do índice atual
* Para no primeiro WHEN verdadeiro
* AT END executa se nenhum match

SEARCH faz busca linear na tabela. Defina o índice antes (SET ... TO 1). WHEN testa cada elemento, AT END executa se não encontrar.

OCCURS DEPENDING ON
       01 WS-TABELA.
           05 WS-CONT PIC 9(3).
           05 WS-ITEM OCCURS 1 TO 100 TIMES
               DEPENDING ON WS-CONT
               PIC X(20).

* Definir quantos elementos usar:
       MOVE 50 TO WS-CONT.

* Agora WS-ITEM tem 50 elementos válidos
       PERFORM VARYING WS-I FROM 1 BY 1
           UNTIL WS-I > WS-CONT
           DISPLAY WS-ITEM(WS-I)
       END-PERFORM.

OCCURS DEPENDING ON cria tabelas de tamanho variável. O campo contador (WS-CONT) define quantos elementos estão ativos. Poupa memória em tempo de execução.

SEARCH ALL (binária)
* Tabela DEVE estar ordenada pela chave:
       SEARCH ALL WS-ITEM
           AT END
               DISPLAY "Nao encontrado"
           WHEN WS-CODIGO(WS-IDX) = WS-ALVO
               DISPLAY "Achado: " WS-NOME(WS-IDX)
       END-SEARCH.

* SEARCH ALL = busca binária (O(log n))
* Mais rápido que SEARCH para tabelas grandes
* Requer ASCENDING/DESCENDING KEY no OCCURS

SEARCH ALL usa busca binária (muito mais rápida). A tabela deve estar ordenada. Declare ASCENDING KEY no OCCURS. Ideal para tabelas grandes.

Preencher tabela
       PERFORM VARYING WS-I FROM 1 BY 1
           UNTIL WS-I > 10
           DISPLAY "Valor " WS-I ":"
           ACCEPT WS-VALOR(WS-I)
       END-PERFORM.

* Ou ler de ficheiro:
       MOVE 0 TO WS-CONT.
       PERFORM UNTIL WS-EOF = "S" OR
           WS-CONT >= 100
           READ DADOS AT END MOVE "S" TO WS-EOF
               NOT AT END
                   ADD 1 TO WS-CONT
                   MOVE REG-CAMPO TO
                       WS-ITEM(WS-CONT)
           END-READ
       END-PERFORM.

Preencha tabelas com PERFORM VARYING + ACCEPT ou lendo de um ficheiro registo a registo. Controle sempre o limite máximo para não exceder o OCCURS.

Tabela multidimensional
       01 WS-MATRIZ.
           05 WS-LINHA OCCURS 3 TIMES.
               10 WS-COLUNA OCCURS 4 TIMES
                   PIC 9(4).

* Aceder [linha][coluna]:
       MOVE 100 TO WS-MATRIZ(2, 3).
       DISPLAY WS-MATRIZ(1, 1).

* Percorrer tudo:
       PERFORM VARYING WS-L FROM 1 BY 1
           UNTIL WS-L > 3
           PERFORM VARYING WS-C FROM 1 BY 1
               UNTIL WS-C > 4
               DISPLAY WS-MATRIZ(WS-L, WS-C)
           END-PERFORM
       END-PERFORM.

Aninhe OCCURS para criar matrizes. Aceda com (linha, coluna). Percorra com PERFORM VARYING aninhados (um por dimensão).

Dicas e Boas Práticas


7 cards
Convenções de nomes
* Prefixos por tipo:
       01 WS-CONTADOR PIC 9(4).      *> Working Storage
       01 REG-CLIENTE PIC X(30).     *> Registo de FD
       01 LS-PARAM PIC 9(5).         *> Linkage Section
       01 FD-DADOS PIC X(10).        *> File Description

* Nomes descritivos com hífens:
       01 WS-TOTAL-VENDAS PIC 9(8)V99.
       01 WS-NOME-CLIENTE PIC X(40).

* Níveis 88 com nomes de condição:
       88 WS-REGISTO-VALIDO VALUE "S".

* Máximo 30 caracteres por nome

Use prefixos: WS- (working storage), REG- (registos), LS- (linkage). Nomes descritivos com hífens. Níveis 88 com nomes que leiam como condições.

COBOL moderno (2002+)
* Comentários inline:
       *> Isto é um comentário moderno

* Booleanos reais:
       01 WS-OK PIC 1 VALUE 0.
       SET WS-OK TO TRUE.

* Funções intrínsecas:
       COMPUTE WS-R = FUNCTION SQRT(16).

* Referência parcial:
       MOVE WS-S(1:3) TO WS-T.

* SELF (programas com estado):
       IDENTIFICATION DIVISION.
       PROGRAM-ID. CONTADOR IS RECURSIVE.

* GnuCOBOL suporta a maioria dos padrões
* COBOL 85, 2002, 2014 e 2023

O COBOL moderno (2002+) adicionou comentários *>, booleanos, funções intrínsecas e referência parcial. O GnuCOBOL suporta os padrões 85, 2002, 2014 e 2023.

Estrutura de programa limpa
       PROCEDURE DIVISION.
       0000-MAIN.
           PERFORM 1000-INICIALIZAR.
           PERFORM 2000-PROCESSAR
               UNTIL WS-EOF = "S".
           PERFORM 9000-FINALIZAR.
           STOP RUN.

       1000-INICIALIZAR.
           OPEN INPUT CLIENTES.
           MOVE 0 TO WS-CONTADOR.

       2000-PROCESSAR.
           READ CLIENTES
               AT END MOVE "S" TO WS-EOF
           END-READ.

       9000-FINALIZAR.
           CLOSE CLIENTES.
           DISPLAY "Total: " WS-CONTADOR.

Numere os parágrafos (1000-, 2000-, 9000-) para organização e fácil inserção. MAIN chama INICIALIZAR, PROCESSAR e FINALIZAR. Padrão clássico de manutenção.

GnuCOBOL
# Instalar:
# Ubuntu: sudo apt install gnucobol
# Windows: via MSYS2 ou binários

# Compilar e executar:
cobc -x programa.cob -o programa
./programa

# Ferramentas:
cobc --version        *> versão
cobc --list-intrinsics *> funções disponíveis
cobcrun --runtime-conf *> configuração

# Formato livre (sem colunas fixas):
cobc -x -free programa.cbl

# Otimização:
cobc -x -O2 programa.cob

GnuCOBOL é o compilador open-source mais usado. -free permite formato livre (sem colunas fixas). -O2 otimiza. --list-intrinsics mostra as funções disponíveis.

Debug com DISPLAY
* Mostrar valores durante a execução:
       DISPLAY "WS-CONTADOR = " WS-CONTADOR.
       DISPLAY "STATUS = " WS-STATUS.
       DISPLAY "REGISTO: " REG-CLIENTE.

* Com UPON para separar:
       DISPLAY "DEBUG" UPON SYSERR.

* GnuCOBOL - trace de execução:
*> cobc -x -debug -ftraceall programa.cob
*> COB_SET_TRACE=1 ./programa

* ACCEPT para pausar:
       DISPLAY "Prima ENTER para continuar".
       ACCEPT WS-TECLA.

DISPLAY é a ferramenta de debug principal. Mostre variáveis em pontos-chave. GnuCOBOL suporta -ftraceall para trace completo. ACCEPT pausa a execução.

Template de programa
       IDENTIFICATION DIVISION.
       PROGRAM-ID. TEMPLATE.
       AUTHOR. SEU-NOME.
       DATE-WRITTEN. 2024-01-15.

       ENVIRONMENT DIVISION.
       INPUT-OUTPUT SECTION.
       FILE-CONTROL.

       DATA DIVISION.
       FILE SECTION.
       WORKING-STORAGE SECTION.
       01 WS-CONTADOR PIC 9(4) VALUE 0.

       PROCEDURE DIVISION.
       0000-MAIN.
           PERFORM 1000-INICIO.
           PERFORM 2000-PROCESSO.
           PERFORM 9000-FIM.
           STOP RUN.
       1000-INICIO.
       2000-PROCESSO.
       9000-FIM.

Um template padrão com cabeçalho (AUTHOR, DATE-WRITTEN), divisões vazias e parágrafos numerados. Copie e adapte para novos programas — poupa tempo e mantém consistência.

Erros comuns
* 1. Esquecer o ponto final:
       DISPLAY "Ola"      *> ERRO!
       DISPLAY "Ola".     *> correto

* 2. MOVE com ordem errada:
       MOVE WS-A TO WS-B.  *> WS-B recebe WS-A

* 3. PIC 9 com valor decimal sem V:
       01 WS-X PIC 99.
       MOVE 3.14 TO WS-X.  *> fica 31 (truncado!)
       01 WS-Y PIC 9V99.   *> correto: 3.14

* 4. Comparar alfanumérico com numérico:
       IF WS-NOME = 100   *> ERRO de tipo
       IF WS-NOME = "100" *> correto

* 5. Índice fora do OCCURS

Erros frequentes: falta do ponto final, ordem do MOVE invertida, PIC sem V para decimais (trunca!), comparar tipos diferentes, índice fora da tabela.