Cheatsheet COBOL
Linguagem empresarial clássica para sistemas mainframe e processamento batch
COBOL
Básico
Estructura del programa
IDENTIFICATION DIVISION.
PROGRAM-ID. HELLO-WORLD.
AUTHOR. PROGRAMADOR.
ENVIRONMENT DIVISION.
CONFIGURATION SECTION.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-NOMBRE PIC X(30).
PROCEDURE DIVISION.
DISPLAY "Hola Mundo".
STOP RUN.Un programa COBOL tiene 4 divisiones: IDENTIFICATION (nombre), ENVIRONMENT (configuración), DATA (variables) y PROCEDURE (lógica). Cada instrucción termina con punto.
Formato y comentarios
****** Col 1-6: número de secuencia (opcional)
****** Col 7: indicador (* = comentario)
****** Col 8-11: Area A (divisions, sections)
****** Col 12-72: Area B (statements)
* Comentario tradicional (columna 7)
*> Comentario moderno (inline)
DISPLAY "Código".
* Cada instrucción termina con punto final
* Palabras clave en MAYÚSCULAS (convención)
* Nombres de variables con el prefijo WS-COBOL usa formato fijo: columna 7 para comentarios, Area A (8-11) para divisiones, Area B (12-72) para instrucciones. *> es el comentario moderno inline.
Hello World completo
IDENTIFICATION DIVISION.
PROGRAM-ID. HELLO.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-MENSAJE PIC X(20)
VALUE "Hola, Mundo!".
PROCEDURE DIVISION.
DISPLAY WS-MENSAJE.
DISPLAY "¡Adiós!".
STOP RUN.
*> cobc -x hello.cob -o hello
*> ./helloEl programa mínimo: DISPLAY imprime en pantalla y STOP RUN termina. Compila con cobc -x (GnuCOBOL) para crear un ejecutable.
Las 4 divisiones
* 1. IDENTIFICATION - quién es el programa
IDENTIFICATION DIVISION.
PROGRAM-ID. MI-PROGRAMA.
* 2. ENVIRONMENT - configuración y ficheros
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
* 3. DATA - variables y estructuras
DATA DIVISION.
WORKING-STORAGE SECTION.
* 4. PROCEDURE - la lógica del programa
PROCEDURE DIVISION.Las 4 divisiones son obligatorias y en orden: IDENTIFICATION, ENVIRONMENT, DATA y PROCEDURE. Solo IDENTIFICATION y PROCEDURE son siempre necesarias.
Compilar y ejecutar
# GnuCOBOL: cobc -x programa.cob -o programa ./programa # Compilar como módulo (dinámico): cobc -m programa.cob # Verificar solo la sintaxis: cobc -fsyntax-only programa.cob # Con debug: cobc -x -g -debug programa.cob # Ejecutar con runtime: cobcrun programa # Listar warnings: cobc -x -Wall programa.cob
Usa cobc -x para un ejecutable standalone y cobc -m para un módulo. -fsyntax-only verifica sin compilar. cobcrun ejecuta módulos.
STOP RUN y GOBACK
PROCEDURE DIVISION.
DISPLAY "Procesando...".
* Terminar programa principal:
STOP RUN.
* Terminar subprograma (retorna al llamador):
GOBACK.
* STOP RUN con código de retorno:
MOVE 0 TO RETURN-CODE.
STOP RUN.STOP RUN termina un programa principal. GOBACK devuelve el control al programa llamador (en subprogramas). RETURN-CODE indica el estado (0 = OK).
DISPLAY y ACCEPT
PROCEDURE DIVISION.
DISPLAY "Hola Mundo".
DISPLAY "Nombre: " WS-NOMBRE.
DISPLAY "Valor: " WS-VAL
WITH NO ADVANCING.
ACCEPT WS-NOMBRE.
ACCEPT WS-FECHA FROM DATE.
ACCEPT WS-HORA FROM TIME.
ACCEPT WS-TECLA FROM CONSOLE.DISPLAY escribe en pantalla (puede concatenar varios ítems). ACCEPT lee del teclado. WITH NO ADVANCING no cambia de línea. FROM DATE/TIME lee del sistema.
Párrafos y secciones
PROCEDURE DIVISION.
MAIN-PARAGRAPH.
PERFORM INICIAR.
PERFORM PROCESAR.
PERFORM TERMINAR.
STOP RUN.
INICIAR.
DISPLAY "Iniciando...".
PROCESAR.
DISPLAY "Procesando...".
TERMINAR.
DISPLAY "Terminando...".Los párrafos son bloques de código con nombre (Area A). Se llaman con PERFORM nombre. Organizan el programa en rutinas reutilizables.
Dados
Cláusulas PIC
01 WS-CAMPOS.
05 WS-NOMBRE PIC X(30).
05 WS-EDAD 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 = con signo, Z = cero suprimidoLa cláusula PIC define el tipo y tamaño. X = texto, 9 = número, V = decimal implícito, S = signo, Z = cero suprimido (formato).
VALUE (valores iniciales)
01 WS-CONTADOR PIC 9(4) VALUE 0.
01 WS-NOMBRE 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 (nivel 01 con VALUE):
01 WS-TASA-IVA PIC 9V99 VALUE 0.23.
* Sin VALUE, los campos inician con espacios/cerosVALUE define el valor inicial de la variable. Sin VALUE, los campos alfanuméricos inician con espacios y los numéricos con ceros. Útil para constantes y defaults.
MOVE y SET
MOVE "Ana" TO WS-NOMBRE.
MOVE 42 TO WS-EDAD.
MOVE 1500.50 TO WS-SALARIO.
MOVE ZERO TO WS-CONTADOR.
MOVE SPACES TO WS-NOMBRE.
MOVE ALL "X" TO WS-LINEA.
MOVE HIGH-VALUE TO WS-CAMPO.
SET WS-INDICE TO 1.
SET WS-INDICE UP BY 1.
SET WS-INDICE DOWN BY 1.MOVE asigna valores (destino al final). Figuras especiales: ZERO, SPACES, ALL "x", HIGH-VALUE. SET se usa para índices de tablas.
REDEFINES
01 WS-DATOS.
05 WS-FECHA-COMPLETA PIC X(8).
05 WS-FECHA-PARTES
REDEFINES WS-FECHA-COMPLETA.
10 WS-ANIO PIC 9(4).
10 WS-MES PIC 9(2).
10 WS-DIA PIC 9(2).
PROCEDURE DIVISION.
MOVE "20240315" TO WS-FECHA-COMPLETA.
DISPLAY WS-ANIO "/" WS-MES "/" WS-DIA.
*> Muestra: 2024/03/15REDEFINES permite ver la misma memoria con otra estructura. Aquí una string de 8 chars se reinterpreta como año/mes/día. No ocupa espacio extra.
Niveles y grupos
01 WS-CLIENTE.
05 WS-NOMBRE PIC X(30).
05 WS-DIRECCION.
10 WS-CALLE PIC X(40).
10 WS-CIUDAD PIC X(20).
10 WS-CP PIC X(8).
05 WS-TELEFONO PIC X(15).
* Nivel 01 = registro principal
* Nivel 05-49 = subcampos (jerarquía)
* Nivel 77 = variable independiente
* Nivel 88 = condición (booleano)Los niveles crean jerarquía: 01 es el grupo principal, 05-49 son subcampos anidados. 77 declara variables sueltas. 88 define condiciones con nombre.
Campos editados
01 WS-VALOR PIC 9(6)V99 VALUE 1234.56.
01 WS-EDITADO PIC Z(5)9.99.
01 WS-MONEDA PIC ZZZ.ZZ9,99.
01 WS-SIGNO PIC +Z(5)9.
PROCEDURE DIVISION.
MOVE WS-VALOR TO WS-EDITADO.
DISPLAY WS-EDITADO. *> " 1234.56"
MOVE WS-VALOR TO WS-MONEDA.
DISPLAY WS-MONEDA. *> " 1.234,56"Los campos editados formatean la salida: Z suprime ceros a la izquierda, . y , insertan separadores, + muestra el signo. Solo para DISPLAY, no para cálculos.
Nivel 88 (condiciones)
01 WS-ESTADO PIC X.
88 WS-ACTIVO VALUE "A".
88 WS-INACTIVO VALUE "I".
88 WS-PENDIENTE VALUE "P".
01 WS-DIA PIC 9(2).
88 WS-FIN-SEMANA VALUES 6, 7.
88 WS-DIA-HABIL VALUES 1 THRU 5.
PROCEDURE DIVISION.
IF WS-ACTIVO
DISPLAY "Cliente activo".
SET WS-ACTIVO TO TRUE.El nivel 88 crea condiciones con nombre ligadas a valores. IF WS-ACTIVO comprueba si WS-ESTADO = "A". Puedes usar VALUES múltiples y THRU (rango). SET ... TO TRUE activa.
Nivel 77 y RENAMES
* Nivel 77 - variable independiente:
77 WS-CONTADOR PIC 9(4) VALUE 0.
77 WS-FLAG PIC X VALUE "N".
* RENAMES - renombrar un grupo:
01 WS-PERSONA.
05 WS-NOMBRE PIC X(30).
05 WS-EDAD PIC 9(3).
66 WS-INFO RENAMES WS-NOMBRE
THRU WS-EDAD.
* 66 agrupa campos existentes bajo un nuevo nombreNivel 77 declara variables independientes (sin grupo). RENAMES (nivel 66) da un nombre alternativo a un conjunto de campos existentes.
Controlo de Fluxo
IF/ELSE
IF WS-EDAD >= 18
DISPLAY "Adulto"
ELSE
DISPLAY "Menor"
END-IF.
IF WS-NOTA >= 14
DISPLAY "Aprobado"
ELSE IF WS-NOTA >= 10
DISPLAY "Recuperación"
ELSE
DISPLAY "Suspendido"
END-IF.
* Operadores: = <> < > <= >=
* Lógicos: AND, OR, NOTIF/ELSE/END-IF es la condicional básica. Anida con ELSE IF. Operadores: = (igual), <> (distinto), <, >, <=, >=. Combina con AND, OR, NOT.
EVALUATE (case)
EVALUATE WS-DIA
WHEN 1
DISPLAY "Lunes"
WHEN 2 THRU 5
DISPLAY "Día hábil"
WHEN 6 7
DISPLAY "Fin de semana"
WHEN OTHER
DISPLAY "Inválido"
END-EVALUATE.
* WHEN 6 7 = múltiples valores (OR)
* WHEN 2 THRU 5 = rango
* WHEN OTHER = defaultEVALUATE es el "switch/case". WHEN comprueba cada caso, THRU define rangos, los valores separados por espacio son OR. WHEN OTHER es el 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.
* Decreciente:
PERFORM VARYING WS-I FROM 10 BY -1
UNTIL WS-I < 1
DISPLAY WS-I
END-PERFORM.
* Paso 2:
PERFORM VARYING WS-I FROM 0 BY 2
UNTIL WS-I > 20
DISPLAY WS-I
END-PERFORM.PERFORM VARYING es el bucle "for": FROM (inicio), BY (paso), UNTIL (condición de parada). El paso puede ser negativo o mayor que 1.
EVALUATE TRUE (if/elseif)
EVALUATE TRUE
WHEN WS-EDAD >= 65
DISPLAY "Anciano"
WHEN WS-EDAD >= 18
DISPLAY "Adulto"
WHEN WS-EDAD >= 12
DISPLAY "Adolescente"
WHEN OTHER
DISPLAY "Niño"
END-EVALUATE.
* Equivalente a una cadena IF/ELSE-IF
* Más legible para múltiples condicionesEVALUATE TRUE evalúa expresiones booleanas en cada WHEN. Es la alternativa limpia a largas cadenas de IF/ELSE-IF. El primer WHEN verdadero se ejecuta.
PERFORM UNTIL (while)
* while (respuesta <> "S"):
PERFORM UNTIL WS-RESPUESTA = "S"
DISPLAY "¿Continuar? (S/N)"
ACCEPT WS-RESPUESTA
END-PERFORM.
* Prueba al final (do-while):
PERFORM WITH TEST AFTER
UNTIL WS-CONTADOR > 5
ADD 1 TO WS-CONTADOR
DISPLAY WS-CONTADOR
END-PERFORM.PERFORM UNTIL es el bucle "while" (prueba al inicio). WITH TEST AFTER mueve la prueba al final (se ejecuta al menos una vez, como do-while).
PERFORM párrafos
PROCEDURE DIVISION.
PERFORM INICIAR-PROGRAMA.
PERFORM PROCESAR-DATOS.
PERFORM FINALIZAR-PROGRAMA.
STOP RUN.
INICIAR-PROGRAMA.
DISPLAY "Iniciando...".
OPEN INPUT FICHERO-CLIENTES.
PROCESAR-DATOS.
PERFORM LEER-REGISTRO
UNTIL WS-EOF = "S".
FINALIZAR-PROGRAMA.
CLOSE FICHERO-CLIENTES.PERFORM nombre-párrafo ejecuta una rutina y retorna automáticamente. Es la forma clásica de organizar COBOL en subrutinas (antes de los subprogramas CALL).
PERFORM TIMES
* Repetir 5 veces:
PERFORM 5 TIMES
DISPLAY "Hola"
END-PERFORM.
* Con variable:
PERFORM WS-VECES TIMES
ADD WS-VALOR TO WS-TOTAL
END-PERFORM.
* Llamar párrafo N veces:
PERFORM MOSTRAR-LINEA 3 TIMES.PERFORM n TIMES repite un bloque un número fijo de veces. Acepta una variable numérica como contador. La forma más simple de bucle.
IF anidado y condiciones
IF WS-TIENE-STOCK
IF WS-PRECIO <= WS-LIMITE
PERFORM COMPRAR-ARTICULO
ELSE
DISPLAY "Muy caro"
END-IF
ELSE
DISPLAY "Sin stock"
END-IF.
* Condiciones compuestas:
IF WS-EDAD >= 18 AND WS-TIENE-CARNET
PERFORM ALQUILAR-COCHE.
IF WS-VIP OR WS-ANTIGUEDAD > 10
PERFORM DAR-DESCUENTO.Anida IF con indentación clara y cierra cada uno con END-IF. Combina condiciones con AND/OR. Usa la precedencia implícita (AND antes de OR).
Operações
Aritmética
ADD 10 TO WS-TOTAL.
ADD A B GIVING WS-SUMA.
SUBTRACT 5 FROM WS-SALDO.
MULTIPLY WS-PRECIO BY WS-CANT
GIVING WS-TOTAL.
DIVIDE WS-TOTAL BY WS-CANT
GIVING WS-MEDIA
REMAINDER WS-RESTO.
* ADD WS-A TO WS-B => WS-B += WS-A
* GIVING guarda el resultado sin alterar operandosVerbos aritméticos: ADD, SUBTRACT, MULTIPLY, DIVIDE. TO/FROM modifican el operando; GIVING guarda en un campo aparte. REMAINDER da el resto.
INSPECT y referencia
* Sustituir caracteres:
INSPECT WS-TEXTO
REPLACING ALL "a" BY "o".
* Contar caracteres:
INSPECT WS-TEXTO
TALLYING WS-CONT FOR ALL "e".
* Referencia parcial (substring):
MOVE WS-NOMBRE(1:5) TO WS-PARTE.
MOVE "2024" TO WS-FECHA(1:4).
* WS-NOMBRE(1:5) = 5 chars desde la pos 1
* Referencia con variable:
MOVE WS-NOMBRE(WS-POS:3) TO WS-TMP.INSPECT sustituye (REPLACING) o cuenta (TALLYING) caracteres. La referencia parcial campo(pos:tam) extrae o escribe substrings. Muy útil para parsing.
COMPUTE (expresiones)
COMPUTE WS-AREA = 3.14 * WS-R ** 2.
COMPUTE WS-INTERES ROUNDED =
WS-CAPITAL * WS-TASA / 100.
COMPUTE WS-MEDIA =
(WS-NOTA1 + WS-NOTA2) / 2.
COMPUTE WS-RESULTADO = WS-A * WS-B
+ WS-C - WS-D / WS-E.
* ** = potencia, ROUNDED = redondear
* ON SIZE ERROR trata overflow
COMPUTE WS-X = WS-Y * WS-Z
ON SIZE ERROR DISPLAY "Overflow".COMPUTE acepta expresiones completas con + - * / ** y paréntesis. ROUNDED redondea el resultado. ON SIZE ERROR trata el overflow.
Funciones 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 da acceso a funciones built-in: SQRT, ABS, MAX, MIN (matemáticas) y UPPER-CASE, LOWER-CASE, TRIM, REVERSE, LENGTH (strings). Prefija siempre con FUNCTION.
STRING (concatenar)
STRING WS-NOMBRE DELIMITED BY SPACE
" - " DELIMITED BY SIZE
WS-CIUDAD DELIMITED BY SPACE
INTO WS-RESULTADO.
* DELIMITED BY SPACE - hasta el 1er espacio
* DELIMITED BY SIZE - campo entero
* Con puntero (posición de escritura):
STRING WS-A DELIMITED BY SIZE
INTO WS-B
WITH POINTER WS-POS.
* ON OVERFLOW trata la falta de espacioSTRING concatena varios campos en un destino. DELIMITED BY SPACE corta en los espacios finales, BY SIZE usa el campo entero. WITH POINTER controla la posición.
Comparación y clases
* Condiciones numéricas:
IF WS-VALOR IS NUMERIC
IF WS-VALOR IS ZERO
IF WS-VALOR IS POSITIVE
IF WS-VALOR IS NEGATIVE
* Condiciones de clase:
IF WS-CAMPO IS ALPHABETIC
IF WS-CAMPO IS ALPHANUMERIC
* Condiciones de nombre (nivel 88):
IF WS-FLAG IS TRUE
IF WS-FLAG IS FALSE
* Combinadas:
IF WS-A > 0 AND WS-B < 100
IF NOT WS-ERRORPruebas de clase: IS NUMERIC, IS ALPHABETIC, IS ALPHANUMERIC. Pruebas de valor: IS ZERO, IS POSITIVE, IS NEGATIVE. Pruebas de condición 88: IS TRUE/FALSE.
UNSTRING (dividir)
* Dividir por delimitador:
UNSTRING WS-FECHA DELIMITED BY "/"
INTO WS-DIA WS-MES WS-ANIO.
* Múltiples delimitadores:
UNSTRING WS-LINEA DELIMITED BY ","
OR ";" INTO WS-C1 WS-C2 WS-C3.
* Con contadores:
UNSTRING WS-FRASE DELIMITED BY " "
INTO WS-P1 WS-P2 WS-P3
TALLYING IN WS-NUM-PALABRAS.
* WS-FECHA = "15/03/2024"
* => WS-DIA=15, WS-MES=03, WS-ANIO=2024UNSTRING divide una string por delimitador en varios campos. Acepta múltiples delimitadores con OR. TALLYING IN cuenta cuántos segmentos se extrajeron.
Ficheiros
Definir ficheros
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-NOMBRE PIC X(30).
05 REG-EDAD PIC 9(3).
05 REG-SALDO PIC 9(6)V99.Declara en FILE-CONTROL (SELECT/ASSIGN) y define el registro en FD (FILE SECTION). FILE STATUS guarda el código de resultado de cada operación.
Fichero indexado
SELECT CLIENTES
ASSIGN TO "clientes.idx"
ORGANIZATION IS INDEXED
ACCESS MODE IS DYNAMIC
RECORD KEY IS REG-CODIGO
ALTERNATE KEY IS REG-NOMBRE
WITH DUPLICATES.
* Lectura por clave:
MOVE 123 TO REG-CODIGO.
READ CLIENTES
KEY IS REG-CODIGO
INVALID KEY DISPLAY "No encontrado"
END-READ.ORGANIZATION INDEXED permite acceso directo por clave. RECORD KEY es la clave primaria, ALTERNATE KEY son claves secundarias. ACCESS MODE DYNAMIC permite secuencial + directo.
Lectura secuencial
PROCEDURE DIVISION.
OPEN INPUT CLIENTES.
IF WS-STATUS NOT = "00"
DISPLAY "Error: " 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-NOMBRE
END-READ
END-PERFORM.
CLOSE CLIENTES.OPEN INPUT abre para lectura. El bucle READ ... AT END procesa registro a registro hasta el final. CLOSE libera el fichero. Patrón clásico de procesamiento batch.
START y lectura secuencial
* Posicionar al inicio (clave >= 100):
MOVE 100 TO REG-CODIGO.
START CLIENTES
KEY IS >= REG-CODIGO
INVALID KEY DISPLAY "Sin registros".
* Leer secuencialmente a partir de ahí:
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 el fichero indexado en una clave (con =, >, >=, <). Después READ NEXT recorre secuencialmente a partir de ahí. Ideal para informes por rango.
Escritura
* Crear/reescribir:
OPEN OUTPUT CLIENTES.
MOVE "Ana" TO REG-NOMBRE.
MOVE 30 TO REG-EDAD.
WRITE REG-CLIENTE.
CLOSE CLIENTES.
* Añadir al final:
OPEN EXTEND CLIENTES.
WRITE REG-CLIENTE.
CLOSE CLIENTES.
* WRITE con verificación:
WRITE REG-CLIENTE
INVALID KEY DISPLAY "Error escritura".OPEN OUTPUT crea/reescribe. OPEN EXTEND añade al final. WRITE graba el registro del FD. INVALID KEY detecta errores de escritura.
DELETE
OPEN I-O CLIENTES.
* Posicionar en el registro:
MOVE 123 TO REG-CODIGO.
READ CLIENTES
KEY IS REG-CODIGO
INVALID KEY DISPLAY "No existe"
END-READ.
* Borrar:
DELETE CLIENTES RECORD
INVALID KEY DISPLAY "Error delete".
CLOSE CLIENTES.
* Solo funciona en ficheros indexados/relativosDELETE fichero RECORD elimina el registro actual. Requiere el fichero abierto en I-O y un registro previamente leído. Solo funciona en organizaciones indexada o relativa.
Actualización (I-O)
OPEN I-O CLIENTES.
* Leer el registro a modificar:
MOVE 123 TO REG-CODIGO.
READ CLIENTES
KEY IS REG-CODIGO
INVALID KEY DISPLAY "No existe"
END-READ.
* Modificar y reescribir:
MOVE 999.99 TO REG-SALDO.
REWRITE REG-CLIENTE
INVALID KEY DISPLAY "Error".
CLOSE CLIENTES.OPEN I-O abre para lectura y escritura. Lee el registro, modifica los campos y usa REWRITE para grabar los cambios en el mismo lugar. Requiere fichero indexado o relativo.
FILE STATUS
01 WS-STATUS PIC XX.
* Códigos comunes:
* "00" - Éxito
* "02" - Éxito (duplicado en alternate key)
* "10" - Fin de fichero
* "23" - Registro no encontrado
* "35" - Fichero no existe
* "46" - Lectura inválida (secuencial)
* "9x" - Error de sistema
IF WS-STATUS = "00"
DISPLAY "OK"
ELSE
DISPLAY "Error: " WS-STATUS
END-IF.El FILE STATUS (2 chars) guarda el resultado de cada operación de fichero. "00" = éxito, "10" = EOF, "23" = no encontrado, "35" = fichero inexistente. Verifica siempre tras OPEN/READ/WRITE.
Avançado
COPY y COPYBOOK
* Fichero COPYBOOK (comun.cpy):
01 WS-DATOS-COMUNES.
05 WS-USUARIO PIC X(20).
05 WS-FECHA-SIS PIC 9(8).
05 WS-HORA-SIS PIC 9(6).
* En el programa:
DATA DIVISION.
WORKING-STORAGE SECTION.
COPY "comun.cpy".
* Con REPLACING (renombrar prefijo):
COPY "comun.cpy"
REPLACING WS- BY CLI-.COPY inserta un copybook (código compartido). REPLACING renombra prefijos para evitar conflictos. Esencial para compartir estructuras entre programas.
SORT y MERGE
* Ordenar un fichero:
SORT FICH-TRABAJO
ON ASCENDING KEY REG-CODIGO
USING FICH-ENTRADA
GIVING FICH-SALIDA.
* Con INPUT/OUTPUT procedures:
SORT FICH-TRABAJO
ON DESCENDING KEY REG-SALDO
INPUT PROCEDURE IS LEER-DATOS
OUTPUT PROCEDURE IS GRABAR-DATOS.
* MERGE junta ficheros ordenados:
MERGE FICH-TRABAJO
ON ASCENDING KEY REG-CODIGO
USING FICH-A FICH-B
GIVING FICH-C.SORT ordena un fichero por clave (ASCENDING/DESCENDING). MERGE junta ficheros ya ordenados. USING/GIVING definen entrada y salida. Ordenación nativa de COBOL.
Subprogramas (CALL)
* Programa llamador:
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 "nombre" USING llama a un subprograma pasando parámetros. El subprograma los declara en la LINKAGE SECTION y los recibe en PROCEDURE DIVISION USING. Termina con GOBACK.
Tratamiento de errores
* FILE STATUS:
IF WS-STATUS = "00"
DISPLAY "Éxito"
ELSE IF WS-STATUS = "10"
DISPLAY "Fin de fichero"
ELSE IF WS-STATUS = "23"
DISPLAY "Registro no existe"
ELSE
DISPLAY "Error: " WS-STATUS
END-IF.
* USE declaratives (handler global):
DECLARATIVES.
MANEJO-ERROR SECTION.
USE AFTER STANDARD ERROR
PROCEDURE ON CLIENTES.
DISPLAY "Error en el fichero".
END DECLARATIVES.Verifica el FILE STATUS tras cada operación. DECLARATIVES define handlers globales de error que se ejecutan automáticamente cuando ocurre un error de fichero.
Parámetros BY VALUE/REFERENCE
* Por referencia (por defecto - puede modificar):
CALL "SUB" USING WS-DATO.
* Por valor (copia - no modifica):
CALL "SUB" USING BY VALUE WS-NUM.
* En el subprograma (BY VALUE):
PROCEDURE DIVISION USING
BY VALUE LS-NUM.
* BY CONTENT (copia de solo lectura):
CALL "SUB" USING BY CONTENT WS-TEXTO.
* Devolver un valor:
CALL "SUB" USING WS-X
RETURNING WS-RESULTADO.Por defecto los parámetros son BY REFERENCE (el subprograma puede modificarlos). BY VALUE pasa una copia. RETURNING devuelve un valor como una función.
Punteros y ADDRESS
01 WS-PUNTERO USAGE POINTER.
01 WS-DATOS PIC X(100).
* Obtener la dirección:
SET WS-PUNTERO TO ADDRESS OF WS-DATOS.
* Asignar memoria dinámica:
ALLOCATE 100 CHARACTERS
RETURNING WS-PUNTERO.
* Liberar:
FREE WS-PUNTERO.
* SET POINTER a una posición:
SET WS-PUNTERO UP BY 10.
* Comparar punteros:
IF WS-PUNTERO = NULL
DISPLAY "Sin memoria".USAGE POINTER declara punteros. ADDRESS OF obtiene la dirección de un campo. ALLOCATE/FREE gestionan memoria dinámica. Útil para estructuras de tamaño variable.
INITIALIZE
01 WS-REGISTRO.
05 WS-NOMBRE PIC X(20).
05 WS-EDAD PIC 9(3).
05 WS-SALDO PIC 9(6)V99.
* Limpiar todo (espacios + ceros):
INITIALIZE WS-REGISTRO.
* Solo campos alfanuméricos:
INITIALIZE WS-REGISTRO
REPLACING ALPHANUMERIC BY SPACES.
* Con un valor específico:
INITIALIZE WS-REGISTRO
REPLACING NUMERIC DATA BY ZERO.
* Sin INITIALIZE, los campos mantienen basuraINITIALIZE limpia un grupo: alfanuméricos a espacios, numéricos a ceros. REPLACING permite especificar los valores. Evita "basura" de memoria en registros reutilizados.
Tabelas
OCCURS (arrays)
01 WS-TABLA.
05 WS-ITEM OCCURS 10 TIMES
INDEXED BY WS-IDX.
10 WS-CODIGO PIC 9(4).
10 WS-NOMBRE PIC X(20).
* Recorrer:
PERFORM VARYING WS-IDX FROM 1 BY 1
UNTIL WS-IDX > 10
DISPLAY WS-NOMBRE(WS-IDX)
END-PERFORM.
* Acceder por índice:
MOVE 5 TO WS-IDX.
DISPLAY WS-CODIGO(WS-IDX).OCCURS n TIMES crea un array con n elementos. INDEXED BY declara un índice. Accede con campo(índice). Los índices empiezan en 1.
SET UP / DOWN
01 WS-TAB.
05 WS-ELEM OCCURS 10 TIMES
INDEXED BY WS-IDX
PIC X(10).
* Incrementar/decrementar el índice:
SET WS-IDX TO 1.
SET WS-IDX UP BY 1. *> WS-IDX = 2
SET WS-IDX DOWN BY 1. *> WS-IDX = 1
* Recorrer al revés:
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. Los índices (INDEXED BY) solo se modifican con SET, no con MOVE/COMPUTE.
SEARCH (búsqueda lineal)
SET WS-IDX TO 1.
SEARCH WS-ITEM
AT END
DISPLAY "No encontrado"
WHEN WS-CODIGO(WS-IDX) = WS-OBJETIVO
DISPLAY "Encontrado: " WS-NOMBRE(WS-IDX)
END-SEARCH.
* SEARCH recorre desde el índice actual
* Para en el primer WHEN verdadero
* AT END se ejecuta si no hay matchSEARCH hace búsqueda lineal en la tabla. Define el índice antes (SET ... TO 1). WHEN comprueba cada elemento, AT END se ejecuta si no encuentra.
OCCURS DEPENDING ON
01 WS-TABLA.
05 WS-CONT PIC 9(3).
05 WS-ITEM OCCURS 1 TO 100 TIMES
DEPENDING ON WS-CONT
PIC X(20).
* Definir cuántos elementos usar:
MOVE 50 TO WS-CONT.
* Ahora WS-ITEM tiene 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 crea tablas de tamaño variable. El campo contador (WS-CONT) define cuántos elementos están activos. Ahorra memoria en tiempo de ejecución.
SEARCH ALL (binaria)
* La tabla DEBE estar ordenada por la clave:
SEARCH ALL WS-ITEM
AT END
DISPLAY "No encontrado"
WHEN WS-CODIGO(WS-IDX) = WS-OBJETIVO
DISPLAY "Encontrado: " WS-NOMBRE(WS-IDX)
END-SEARCH.
* SEARCH ALL = búsqueda binaria (O(log n))
* Más rápida que SEARCH para tablas grandes
* Requiere ASCENDING/DESCENDING KEY en OCCURSSEARCH ALL usa búsqueda binaria (mucho más rápida). La tabla debe estar ordenada. Declara ASCENDING KEY en el OCCURS. Ideal para tablas grandes.
Rellenar tabla
PERFORM VARYING WS-I FROM 1 BY 1
UNTIL WS-I > 10
DISPLAY "Valor " WS-I ":"
ACCEPT WS-VALOR(WS-I)
END-PERFORM.
* O leer de un fichero:
MOVE 0 TO WS-CONT.
PERFORM UNTIL WS-EOF = "S" OR
WS-CONT >= 100
READ FICH-DATOS 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.Rellena tablas con PERFORM VARYING + ACCEPT o leyendo de un fichero registro a registro. Controla siempre el límite máximo para no exceder el OCCURS.
Tabla multidimensional
01 WS-MATRIZ.
05 WS-FILA OCCURS 3 TIMES.
10 WS-COLUMNA OCCURS 4 TIMES
PIC 9(4).
* Acceder [fila][columna]:
MOVE 100 TO WS-MATRIZ(2, 3).
DISPLAY WS-MATRIZ(1, 1).
* Recorrer todo:
PERFORM VARYING WS-F FROM 1 BY 1
UNTIL WS-F > 3
PERFORM VARYING WS-C FROM 1 BY 1
UNTIL WS-C > 4
DISPLAY WS-MATRIZ(WS-F, WS-C)
END-PERFORM
END-PERFORM.Anida OCCURS para crear matrices. Accede con (fila, columna). Recorre con PERFORM VARYING anidados (uno por dimensión).
Dicas e Boas Práticas
Convenciones de nombres
* Prefijos por tipo:
01 WS-CONTADOR PIC 9(4). *> Working Storage
01 REG-CLIENTE PIC X(30). *> Registro de FD
01 LS-PARAM PIC 9(5). *> Linkage Section
01 FD-DATOS PIC X(10). *> File Description
* Nombres descriptivos con guiones:
01 WS-TOTAL-VENTAS PIC 9(8)V99.
01 WS-NOMBRE-CLIENTE PIC X(40).
* Niveles 88 con nombres de condición:
88 WS-REGISTRO-VALIDO VALUE "S".
* Máximo 30 caracteres por nombreUsa prefijos: WS- (working storage), REG- (registros), LS- (linkage). Nombres descriptivos con guiones. Niveles 88 con nombres que se lean como condiciones.
COBOL moderno (2002+)
* Comentarios inline:
*> Esto es un comentario moderno
* Booleanos reales:
01 WS-OK PIC 1 VALUE 0.
SET WS-OK TO TRUE.
* Funciones intrínsecas:
COMPUTE WS-R = FUNCTION SQRT(16).
* Referencia parcial:
MOVE WS-S(1:3) TO WS-T.
* SELF (programas con estado):
IDENTIFICATION DIVISION.
PROGRAM-ID. CONTADOR IS RECURSIVE.
* GnuCOBOL soporta la mayoría de estándares
* COBOL 85, 2002, 2014 y 2023El COBOL moderno (2002+) añadió comentarios *>, booleanos, funciones intrínsecas y referencia parcial. GnuCOBOL soporta los estándares 85, 2002, 2014 y 2023.
Estructura de programa limpia
PROCEDURE DIVISION.
0000-MAIN.
PERFORM 1000-INICIALIZAR.
PERFORM 2000-PROCESAR
UNTIL WS-EOF = "S".
PERFORM 9000-FINALIZAR.
STOP RUN.
1000-INICIALIZAR.
OPEN INPUT CLIENTES.
MOVE 0 TO WS-CONTADOR.
2000-PROCESAR.
READ CLIENTES
AT END MOVE "S" TO WS-EOF
END-READ.
9000-FINALIZAR.
CLOSE CLIENTES.
DISPLAY "Total: " WS-CONTADOR.Numera los párrafos (1000-, 2000-, 9000-) para organización e inserción fácil. MAIN llama a INICIALIZAR, PROCESAR y FINALIZAR. Patrón clásico de mantenimiento.
GnuCOBOL
# Instalar: # Ubuntu: sudo apt install gnucobol # Windows: vía MSYS2 o binarios # Compilar y ejecutar: cobc -x programa.cob -o programa ./programa # Herramientas: cobc --version *> versión cobc --list-intrinsics *> funciones disponibles cobcrun --runtime-conf *> configuración # Formato libre (sin columnas fijas): cobc -x -free programa.cbl # Optimización: cobc -x -O2 programa.cob
GnuCOBOL es el compilador open-source más usado. -free permite formato libre (sin columnas fijas). -O2 optimiza. --list-intrinsics muestra las funciones disponibles.
Debug con DISPLAY
* Mostrar valores durante la ejecución:
DISPLAY "WS-CONTADOR = " WS-CONTADOR.
DISPLAY "STATUS = " WS-STATUS.
DISPLAY "REGISTRO: " REG-CLIENTE.
* Con UPON para separar:
DISPLAY "DEBUG" UPON SYSERR.
* GnuCOBOL - trace de ejecución:
*> cobc -x -debug -ftraceall programa.cob
*> COB_SET_TRACE=1 ./programa
* ACCEPT para pausar:
DISPLAY "Pulsa ENTER para continuar".
ACCEPT WS-TECLA.DISPLAY es la herramienta de debug principal. Muestra variables en puntos clave. GnuCOBOL soporta -ftraceall para un trace completo. ACCEPT pausa la ejecución.
Plantilla de programa
IDENTIFICATION DIVISION.
PROGRAM-ID. TEMPLATE.
AUTHOR. SU-NOMBRE.
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-PROCESO.
PERFORM 9000-FIN.
STOP RUN.
1000-INICIO.
2000-PROCESO.
9000-FIN.Una plantilla estándar con cabecera (AUTHOR, DATE-WRITTEN), divisiones vacías y párrafos numerados. Cópiala y adáptala para nuevos programas — ahorra tiempo y mantiene consistencia.
Errores comunes
* 1. Olvidar el punto final:
DISPLAY "Hola" *> ¡ERROR!
DISPLAY "Hola". *> correcto
* 2. MOVE en orden equivocado:
MOVE WS-A TO WS-B. *> WS-B recibe WS-A
* 3. PIC 9 con valor decimal sin V:
01 WS-X PIC 99.
MOVE 3.14 TO WS-X. *> queda 31 (¡truncado!)
01 WS-Y PIC 9V99. *> correcto: 3.14
* 4. Comparar alfanumérico con numérico:
IF WS-NOMBRE = 100 *> ERROR de tipo
IF WS-NOMBRE = "100" *> correcto
* 5. Índice fuera del OCCURSErrores frecuentes: falta del punto final, orden del MOVE invertido, PIC sin V para decimales (¡trunca!), comparar tipos diferentes, índice fuera de la tabla.