DevTools

Cheatsheet COBOL

Linguagem empresarial clássica para sistemas mainframe e processamento batch

Volver a los lenguajes
COBOL
60 tarjetas encontradas
Categorías:
Versiones:

Básico


8 cards
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
*> ./hello

El 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


8 cards
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 suprimido

La 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/ceros

VALUE 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/15

REDEFINES 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 nombre

Nivel 77 declara variables independientes (sin grupo). RENAMES (nivel 66) da un nombre alternativo a un conjunto de campos existentes.

Controlo de Fluxo


8 cards
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, NOT

IF/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 = default

EVALUATE 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 condiciones

EVALUATE 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


7 cards
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 operandos

Verbos 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 espacio

STRING 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-ERROR

Pruebas 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=2024

UNSTRING divide una string por delimitador en varios campos. Acepta múltiples delimitadores con OR. TALLYING IN cuenta cuántos segmentos se extrajeron.

Ficheiros


8 cards
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/relativos

DELETE 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


7 cards
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 basura

INITIALIZE limpia un grupo: alfanuméricos a espacios, numéricos a ceros. REPLACING permite especificar los valores. Evita "basura" de memoria en registros reutilizados.

Tabelas


7 cards
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 match

SEARCH 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 OCCURS

SEARCH 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


7 cards
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 nombre

Usa 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 2023

El 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 OCCURS

Errores frecuentes: falta del punto final, orden del MOVE invertido, PIC sin V para decimales (¡trunca!), comparar tipos diferentes, índice fuera de la tabla.