Cheatsheet COBOL
Linguagem empresarial clássica para sistemas mainframe e processamento batch
COBOL
Básico
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
*> ./helloO 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
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 suprimidoA 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/zerosVALUE 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/15REDEFINES 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 nomeNí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
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, NOTIF/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 = defaultEVALUATE é 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çõesEVALUATE 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
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 operandosVerbos 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çoSTRING 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-ERROTestes 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=2024UNSTRING divide uma string por delimitador em vários campos. Aceita múltiplos delimitadores com OR. TALLYING IN conta quantos segmentos foram extraídos.
Ficheiros
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/relativosDELETE 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
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 lixoINITIALIZE 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
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 matchSEARCH 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 OCCURSSEARCH 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
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 nomeUse 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 2023O 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 OCCURSErros frequentes: falta do ponto final, ordem do MOVE invertida, PIC sem V para decimais (trunca!), comparar tipos diferentes, índice fora da tabela.