Conocimientos mínimos que debe tener antes de leer código fuente COBOL

· Actualizado el: · · COBOL, Tecnología heredada, Sistemas empresariales, Mantenimiento, Mainframe

Traspasos de responsabilidad, atención de incidencias, mantenimiento de paquetes de proveedores. En situaciones así, puede ocurrir que un día, de repente, le llegue código fuente COBOL.

  • El nombre de archivo es .cbl o .cpy
  • Los nombres de variable están todos en mayúsculas
  • Aparecen en fila 01, 05, 77, 88
  • Aparecen expresiones como PIC S9(7)V99 COMP-3, a medio camino entre un conjuro y un programa de contabilidad
  • Y, para colmo, está lleno de COPY, así que con solo el archivo abierto no se ve el conjunto completo

En este punto, la mayoría de las personas se detiene un momento.

Sin embargo, el mapa necesario para leerlo no es tan grande. COBOL tiene diferencias según el compilador o el producto, pero el esqueleto que conviene dominar primero para leer un sistema empresarial existente es bastante común entre ellos. Este artículo, pensando sobre todo en los entornos de tipo IBM y en el COBOL empresarial típico, organiza el conjunto mínimo para quienes de repente deben leer código fuente.

1. Conclusión primero (en pocas palabras)

Dicho de forma bastante directa pero útil en la práctica, es así:

  • COBOL es, antes que un lenguaje de lógica, muy marcadamente un lenguaje de definición de registros
  • Leer solo el PROCEDURE DIVISION le dará únicamente la mitad del panorama. Primero hay que mirar el DATA DIVISION
  • PIC es la forma del campo y USAGE es en qué representación se guarda
  • COMP-3 es packed decimal. Aparece con frecuencia en el mundo de los importes y las cantidades
  • 88 no es tanto una variable aparte como un nombre de condición asociado al valor del campo inmediatamente anterior
  • REDEFINES es un mecanismo para ver la misma memoria con otra forma. No es una copia
  • Si hay un COPY, el código fuente que tiene abierto todavía está incompleto. Sin consultar el copybook no se ve el conjunto completo
  • Si puede seguir PERFORM, IF, EVALUATE, READ, WRITE y CALL, ya captará el flujo general
  • El código fuente antiguo está en formato fijo, donde la posición de columna tiene significado. Los espacios en blanco que se ven no son solo decoración1

En resumen: DIVISION, PIC, USAGE, COMP-3, REDEFINES, OCCURS, 88, COPY, PERFORM. Si puede leer estos elementos, la probabilidad de perderse baja considerablemente.

2. Piense primero en COBOL como el lenguaje de «la forma de los datos»

Si lo lee con la mentalidad de C# o Java, al principio querrá seguir los if, los for y las llamadas a funciones. Pero en COBOL, antes de llegar ahí, resulta más rápido tener claro «qué registros recibe este programa, qué registros produce y qué búferes maneja».

Un COBOL empresarial típico sigue, a grandes rasgos, este flujo.

  1. Lee un registro de un archivo o de una base de datos
  2. Lo coloca en un campo de WORKING-STORAGE
  3. Realiza una bifurcación condicional
  4. Lo reorganiza en otro registro
  5. Lo escribe

Es decir, el diseño (layout) suele imponerse antes que el algoritmo.

Por ejemplo, este es el esqueleto típico:

       IDENTIFICATION DIVISION.
       PROGRAM-ID. SAMPLE01.

       ENVIRONMENT DIVISION.
       INPUT-OUTPUT SECTION.
       FILE-CONTROL.
           SELECT SALES-FILE ASSIGN TO ...

       DATA DIVISION.
       FILE SECTION.
       FD  SALES-FILE.
       01  SALES-REC.
           05  SALE-ID       PIC 9(8).
           05  SALE-AMOUNT   PIC S9(7)V99 COMP-3.

       WORKING-STORAGE SECTION.
       01  WS-EOF            PIC X VALUE 'N'.
           88  EOF           VALUE 'Y'.

       PROCEDURE DIVISION.
           PERFORM UNTIL EOF
               READ SALES-FILE
                   AT END
                       SET EOF TO TRUE
                   NOT AT END
                       PERFORM PROCESS-SALE
               END-READ
           END-PERFORM
           STOP RUN.

Al leer este código, lo primero que conviene mirar, antes que el PERFORM, es el tipo de SALE-AMOUNT y el significado de EOF. Si se lee en ese orden, COBOL de repente se vuelve mucho más tranquilo de leer.

3. Mire primero los cuatro DIVISION

El código fuente COBOL se divide, a grandes rasgos, en cuatro DIVISION.

DIVISION Qué mirar primero
IDENTIFICATION DIVISION Nombre del programa, comentarios antiguos, origen
ENVIRONMENT DIVISION Archivos, recursos externos, condiciones de entrada y salida
DATA DIVISION Definición de registros, área de trabajo, argumentos
PROCEDURE DIVISION El procedimiento de procesamiento real

Lo que resulta especialmente importante es lo siguiente.

  • FILE SECTION Contiene la definición de registro de los archivos de entrada y salida
  • WORKING-STORAGE SECTION Contiene las variables, banderas, contadores y búferes de trabajo de uso habitual
  • LOCAL-STORAGE SECTION Puede contener áreas que se inicializan en cada llamada
  • LINKAGE SECTION Puede contener los argumentos que se pasan desde fuera, o el punto de entrada de un subprograma

Si ve LINKAGE SECTION junto con PROCEDURE DIVISION USING ..., es muy probable que ese programa no sea autónomo, sino que funcione recibiendo datos desde fuera.

4. No se asuste con el aspecto del formato fijo

En el COBOL antiguo, la propia posición de columna de cada línea del código fuente tiene significado. Si lo mira sin saber esto, nunca llegará a entender «por qué hay ese margen raro a la izquierda».1

En el formato fijo, a grandes rasgos, es así:

  • Columnas 1-6: número de secuencia
  • Columna 7: indicador (indicator)
  • Columnas 8-11: Área A (Area A)
  • Columnas 12-72: Área B (Area B)

La columna 7 es especialmente importante.

  • * o /: línea de comentario
  • -: línea de continuación
  • D: línea de depuración (debugging line)
  • *>: comentario que también puede escribirse en medio de la línea

Si se representa la correspondencia entre columna y contenido con una regla graduada, queda así. La primera línea marca las decenas y la segunda línea marca las unidades.

         1         2         3         4         5         6         7         8
12345678901234567890123456789012345678901234567890123456789012345678901234567890
SSSSSSIAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB........
  • S = número de secuencia (columnas 1-6)
  • I = indicador (columna 7)
  • A = Área A (columnas 8-11)
  • B = Área B (columnas 12-72)
  • . = a partir de la columna 73. Según el compilador, puede usarse como campo de identificación, pero no afecta al significado del programa

Aplicado a un código fuente real, queda así:

000100* Esta línea es un comentario porque la columna 7 es *
000200 IDENTIFICATION DIVISION.
000300 PROGRAM-ID. SAMPLE01.
000400 DATA DIVISION.
000500 WORKING-STORAGE SECTION.
000600 01  WS-ORDER.
000700     05  WS-ORDER-ID    PIC 9(8).
000800     05  WS-LONG-NAME   PIC X(30) VALUE 'ABCDEFGHIJKLMNOPQRST
000900-    'UVWXYZ0123'.

Hay cuatro puntos clave para leerlo.

  • Las columnas 1-6 son el número de secuencia. En el ejemplo anterior es lo que aparece numerado como 000100, y no afecta al funcionamiento del programa. A veces está en blanco.
  • La columna 7 es el indicador. * significa comentario y - significa línea de continuación. La línea 000900 del ejemplo anterior es justamente eso: la continuación del literal de cadena de la línea previa.
  • Las columnas 8-11 son el Área A. DIVISION, SECTION, los nombres de párrafo, FD, y los números de nivel 01 y 77 empiezan aquí. En el ejemplo anterior, IDENTIFICATION DIVISION. y 01 WS-ORDER. comienzan en el Área A.
  • Las columnas 12-72 son el Área B. Ahí se escriben las sentencias normales y los niveles inferiores como 05. En el ejemplo anterior, 05 WS-ORDER-ID comienza en el Área B.

Los espacios en blanco aquí no son un «formateo» en el sentido moderno, sino parte de la sintaxis. Si el editor convierte tabulaciones, alinea todo a la izquierda o se copia y pega sin cuidado, el código se rompe con facilidad. Al ver código fuente antiguo, sospeche primero si el archivo está en formato fijo (fixed format) o en formato libre (free format). Si se aplica un autoformateo moderno a un código fuente en formato fijo, el límite entre el Área A y el Área B se rompe y deja de compilar.

5. Lo mínimo del DATA DIVISION

5.1 Números de nivel

La definición de datos en COBOL construye la jerarquía mediante números de nivel, no mediante la sangría.2

       01  WS-ORDER.
           05  WS-ORDER-ID    PIC 9(8).
           05  WS-AMOUNT      PIC S9(7)V99 COMP-3.
           05  WS-STATUS      PIC X.
               88  WS-OK      VALUE '0'.
               88  WS-ERROR   VALUE '9'.

       77  WS-COUNT           PIC 9(4).

Basta con recordar, como mínimo, lo siguiente.

  • 01: el registro o grupo de nivel superior que forma una unidad
  • 02-49: los niveles jerárquicos por debajo de ese
  • 77: un elemento único e independiente
  • 88: condition-name (nombre de condición). Da nombre al valor del campo inmediatamente anterior3
  • 66: para RENAMES. No es muy frecuente encontrarlo, pero existe

Lo importante es no pensar que 88 es una variable booleana aparte. No existe una zona separada llamada WS-OK; más bien, cuando WS-STATUS vale '0', se puede leer con el nombre WS-OK.

Otro punto importante es que lo que determina la jerarquía es el número de nivel, no los espacios en blanco. La sangría visual sirve de referencia, pero en última instancia hay que confiar en 01 / 05 / 10 / 88.2

5.2 PICTURE

PIC representa la forma de ese campo. Lo que más se ve es lo siguiente.

Notación Significado aproximado
X Carácter
9 Dígito numérico
S Con signo
V Punto decimal solo lógico
X(10) 10 caracteres
9(5) Número de 5 dígitos
S9(7)V99 Con signo, 7 dígitos enteros + 2 dígitos decimales

Por ejemplo:

  • PIC X(10) → 10 caracteres
  • PIC 9(5)V99 → 5 dígitos enteros + 2 dígitos decimales
  • PIC S9(7)V99 → con signo, 7 dígitos enteros + 2 dígitos decimales

eso es todo.

Aquí lo especialmente importante es la V. La V no tiene un carácter . real. PIC 9(5)V99 se trata como «un número con 2 dígitos decimales», pero no hay ningún carácter de punto en los datos. Por eso, interpretar el archivo o el volcado como «una cadena de texto tal cual» casi siempre lleva al error.

5.3 USAGE / DISPLAY / COMP / COMP-3

Si PIC es la forma, USAGE es en qué representación se guarda. Con dominar solo lo siguiente, ya se puede leer bastante bien.45

Notación Significado aproximado Precaución al leer
DISPLAY Decimal externo visible como carácter En mainframe a veces se asume EBCDIC6
COMP / BINARY Número binario El número de dígitos visible y la representación interna son cosas distintas
COMP-3 / PACKED-DECIMAL packed decimal Al leerlo como texto se ve como datos corruptos

Por ejemplo:

       01  WS-AMOUNT-DISP   PIC S9(7)V99.
       01  WS-AMOUNT-BIN    PIC S9(7) COMP.
       01  WS-AMOUNT-PACK   PIC S9(7)V99 COMP-3.

Estos tres son todos «numéricos», pero la forma en que guardan el contenido es distinta.

Lo que más rinde en la práctica es la reacción inmediata al ver COMP-3.

  • Es packed decimal
  • Probablemente se trate de un importe, un impuesto, una cantidad o una tasa
  • Es normal que se vea como datos corruptos si se lee como texto
  • Mirarlo con la mentalidad de un CSV o de UTF-8 lleva al error

Tener esto claro evita que se alarme innecesariamente al ver el aspecto de un volcado o de un archivo binario.

Qué bytes produce realmente COMP-3

Si sigue este cálculo a mano una sola vez, su forma de ver esto cambiará a partir de entonces.

Las reglas del packed decimal son solo dos.45

  1. Cada byte guarda dos dígitos decimales
  2. Salvo que el byte más a la derecha usa 1 dígito bajo más el signo en ese único byte

El signo se representa con un valor de 4 bits: C es positivo, D es negativo y F es sin signo.

Vamos a comprobarlo con los ejemplos que aparecen en el manual de IBM.4

Definición Valor Secuencia de bytes
PIC S9(4) PACKED-DECIMAL +1234 01 23 4C
PIC S9(4) PACKED-DECIMAL -1234 01 23 4D
PIC 9(4) PACKED-DECIMAL 1234 01 23 4F

Como 1234 tiene 4 dígitos, la regla 2 deja un hueco de 1 dígito al principio. Ese es el 0 inicial.

Siguiendo el mismo procedimiento, vamos a seguir PIC S9(7)V99 COMP-3, que ha aparecido varias veces en este artículo.

  • S9(7)V99 son 7 dígitos enteros + 2 dígitos decimales = 9 dígitos
  • La V solo indica la posición del punto decimal, así que no consume ni un solo byte
  • Al empaquetar los 9 dígitos de 2 en 2 se obtienen 4 bytes, y el dígito restante junto con el signo ocupan 1 byte más. En total, 5 bytes

Si el valor es +12345.67, al ajustarlo a 9 dígitos queda 001234567, así que resulta lo siguiente:

Valor          : +12345.67
9 dígitos      : 0 0 1 2 3 4 5 6 7  y signo
Bytes          : 00 12 34 56 7C
                                ^ signo C = positivo

Si el valor fuera negativo, -12345.67, lo único que cambia es que el final es 7D.

Bytes : 00 12 34 56 7D

Lo importante es cómo se ve esto si se abre como texto. Si se fuerza 00 12 34 56 7C a corresponder con ASCII, un byte por carácter:

  • 00 es NUL y 12 es un carácter de control; ninguno de los dos se puede mostrar como carácter
  • 34 es 4, 56 es V y 7C es |

Es decir, en pantalla se ve algo así como «varios caracteres no representables seguidos de 4V|». La secuencia 12345.67 no aparece por ninguna parte.

Esto es lo que hay detrás de «parece corrupto pero no lo está». Si al abrir un volcado se encuentra con una secuencia sin sentido, sospeche primero si el USAGE de ese campo no será COMP-3.

De paso, aquí tiene una tabla de referencia rápida para calcular el número de bytes a partir del número de dígitos. El número de bytes se obtiene «dividiendo entre 2 la cantidad de nueves, redondeando hacia abajo, y sumando 1».

Cantidad de nueves en el PICTURE Bytes de COMP-3
1 1
2 - 3 2
4 - 5 3
6 - 7 4
8 - 9 5
10 - 11 6
12 - 13 7

Que dos cantidades de dígitos compartan el mismo número de bytes se debe a que solo cuando la cantidad de nueves es par se genera un hueco de 1 dígito al principio. Por eso S9(4) ocupa 3 bytes como 01 23 4C, y S9(5) también cabe en los mismos 3 bytes.

Al cotejar el diseño con un archivo externo, sin esta tabla el desfase avanza byte a byte.

Una última aclaración: que un campo sea DISPLAY no garantiza que sea una cadena ASCII. En los entornos z/OS se asume EBCDIC, así que aunque los dígitos se vean como caracteres, el valor de byte puede ser distinto de '0'-'9' en ASCII.6

5.4 REDEFINES / OCCURS / COPY / FILLER

Estos cuatro elementos son los puntos donde más se atasca la lectura.

REDEFINES

REDEFINES es un mecanismo para ver la misma zona con otra forma. No es una copia.7

       01  REC-BUF.
           05  REC-TYPE      PIC X.
           05  REC-DATA      PIC X(99).

       01  HEADER-REC REDEFINES REC-BUF.
           05  HDR-TYPE      PIC X.
           05  HDR-DATE      PIC 9(8).
           05  FILLER        PIC X(91).

Esto se parece a la sensación de un union en lenguajes de la familia C. Aparece con frecuencia en escrituras del tipo «distinguir un mismo bloque de 100 bytes como distintos tipos de registro».

OCCURS

OCCURS es un arreglo (array). En COBOL suele llamarse table.

       05  WS-ITEM OCCURS 12 TIMES.
           10  WS-PRICE    PIC 9(5).

Además, si aparece OCCURS DEPENDING ON, se trata de una tabla de longitud variable. En ese caso, puede afectar incluso a la posición de los campos posteriores, así que si se sigue con la mentalidad de longitud fija se pierde el paso.8

COPY

COPY es un include que se resuelve en tiempo de compilación. Es decir, el código fuente que tiene abierto puede no ser todavía la forma completa.9

       COPY CUSTOMER-REC.
       COPY ERROR-MAP.

Es bastante habitual que las definiciones de registro, las banderas comunes, las host variables para SQL y las interfaces externas estén metidas dentro de los copybooks.

Cuando hay tantos COPY que resulta difícil de leer, lo más rápido es comprobar si puede consultar el código fuente ya expandido o el compiler listing. IBM Enterprise COBOL cuenta además con una opción llamada MDECK para volcar el código fuente de entrada después del procesamiento de biblioteca.10

FILLER

FILLER es un campo sin nombre. Sin embargo, eso no significa que sea «irrelevante porque no se referencia».

  • Área reservada
  • Un hueco para compatibilidad con una especificación anterior
  • Ajuste de la longitud del registro
  • Margen para REDEFINES

y cumple estas funciones con normalidad.

FILLER solo carece de nombre, pero existe como cantidad de bytes. Si se olvida esto, la correspondencia con un archivo externo se va desalineando byte a byte.

6. Lo mínimo del PROCEDURE DIVISION

Si el DATA DIVISION es el mapa, el PROCEDURE DIVISION es la ruta de desplazamiento.

6.1 PERFORM

PERFORM es la transferencia de control básica de COBOL. Dicho de forma sencilla, es llamar a un proceso y volver.11

La forma más habitual es la siguiente.

       PERFORM INIT-PROC
       PERFORM UNTIL EOF
           PERFORM READ-PROC
           IF NOT EOF
               PERFORM EDIT-PROC
               PERFORM WRITE-PROC
           END-IF
       END-PERFORM

PERFORM tiene, a grandes rasgos, dos variantes.

  • El PERFORM out-of-line, que indica un párrafo o una sección
  • El PERFORM ... END-PERFORM inline, que escribe el bloque en el propio lugar

En código todavía más antiguo, también aparece con normalidad la indicación de un rango, como PERFORM A-100 THRU A-199. Esto es cómodo, pero si se añade un párrafo en medio es fácil provocar un incidente por arrastre, así que al leer conviene fijarse bien en dónde termina el rango.

6.2 IF / EVALUATE / el alcance (scope)

La bifurcación condicional básica es IF. Pensar en EVALUATE como algo similar a un switch/case es, en general, correcto.

Lo que hay que vigilar es cómo termina el alcance (scope).12

  • END-IF
  • END-PERFORM
  • END-READ

el código que tiene un cierre explícito como estos todavía es fácil de leer.

El problema es el código antiguo. En COBOL, el . funciona como un terminador de alcance implícito y cierra de golpe todas las sentencias que aún no se habían cerrado.12

Es decir, con un único punto,

  • hasta dónde llega el IF
  • hasta dónde llega el PERFORM
  • dónde se pasa a la siguiente sentence

puede cambiar.

Además, NEXT SENTENCE no es lo mismo que CONTINUE. NEXT SENTENCE avanza hasta después del siguiente punto, así que el destino del salto cambia según dónde esté ese . posterior.12

Al leer COBOL antiguo, conviene tener presente que hay que fijarse en el punto, no en el final de línea.

6.3 READ / WRITE / CALL

En el COBOL empresarial, lo que aparece con más frecuencia es lo siguiente.

  • READ
  • WRITE
  • REWRITE
  • START
  • CALL

En particular, READ ... AT END ... es el patrón clásico por excelencia.

       READ IN-FILE
           AT END
               SET EOF TO TRUE
           NOT AT END
               PERFORM PROCESS-REC
       END-READ

Si hay CALL 'SUBPGM' USING ..., el control salta a otro programa. En ese caso, mirar el LINKAGE SECTION y el PROCEDURE DIVISION USING del programa llamado deja bastante claro cómo se realiza el paso de datos.

7. Lo que queda fuera de COBOL

En COBOL, es bastante frecuente que el mundo no se complete solo con el código fuente.

  • La definición de archivos
  • El entorno de ejecución
  • La conexión a la base de datos
  • El entorno transaccional
  • El control de jobs

quedan separados fuera del código fuente.

Como mínimo, dominar lo siguiente facilita la lectura.

Los archivos y FILE STATUS

El FILE-CONTROL del ENVIRONMENT DIVISION y el FILE SECTION / FD del DATA DIVISION se leen como un conjunto.13

       SELECT IN-FILE ASSIGN TO ...
           FILE STATUS IS WS-FS.

       FD  IN-FILE.
       01  IN-REC.
           05 ...

Si hay FILE STATUS, en él se guarda el código de resultado tras cada operación de E/S. Al leer fallos relacionados con archivos o la determinación del EOF, no se puede empezar sin consultarlo.14

EXEC SQL

Cuando aparece esto, se trata de SQL embebido.

       EXEC SQL
           SELECT ...
       END-EXEC.

En este caso, COBOL actúa como «el contenedor de las host variables», mientras que las condiciones de obtención reales o el objetivo de la actualización están del lado del SQL. Por eso, el camino más corto es leer el contenido de EXEC SQL como SQL normal.

EXEC CICS

Cuando aparece esto, se trata del contexto transaccional de CICS.15

       EXEC CICS
           RECEIVE MAP(...)
       END-EXEC.

En ese momento, deja de ser una simple lectura de proceso por lotes. Hay que leerlo incluyendo el contexto externo: pantallas, transacciones, códigos de respuesta, COMMAREA, etc.

JCL y las definiciones de ejecución

En los procesos por lotes de mainframe, no es raro que qué dataset se asigna realmente o en qué orden se ejecutan los jobs queden fuera del código fuente COBOL. Cuando, mirando solo el código, no se entiende «dónde está este archivo», lo habitual no es que el código esté mal, sino simplemente que el alcance que se está mirando todavía es insuficiente.

Diferencias entre compiladores (procesadores del lenguaje)

Este artículo está escrito pensando sobre todo en el entorno IBM, pero en la práctica también puede encontrarse con Micro Focus o con COBOL sobre Linux / Windows. Como el esqueleto es común, la forma de leer no cambia, pero los puntos donde «la misma forma de escribir da resultados distintos» están bien delimitados, así que conocerlos de antemano evita sorpresas.

Aspecto a revisar Entorno z/OS (IBM Enterprise COBOL) Entornos abiertos (Micro Focus, versiones para Linux / Windows, etc.)
Codificación de caracteres Se asume EBCDIC6 Se asume ASCII6
Formato de referencia El formato fijo (fixed) es la opción predeterminada tradicional. También puede elegirse el formato libre (free)1 Admite tanto fixed como free, y cuál es el predeterminado depende de la configuración de compilación1
Cómo se localizan los copybooks Mediante la indicación de una biblioteca Mediante la indicación de una ruta de búsqueda en las opciones del compilador
Dialecto Existe una opción para cambiar «a qué compilador se ajusta»

Lo que más pesa en la práctica es la codificación de caracteres. Incluso con el mismo PIC X(10), si un archivo escrito en z/OS se lee tal cual en Windows, incluso los dígitos numéricos tienen valores de byte distintos. Muchos casos de «al transferirlo todo se corrompió» se deben a esto, y es un problema distinto del de COMP-3.

Hay otro punto donde suele haber diferencias: la representación interna de los valores numéricos. En IBM Enterprise COBOL, BINARY / COMP-4 trunca según la cantidad de dígitos escrita en el PICTURE, mientras que COMP-5 mantiene el valor hasta la capacidad nativa del binario, de 2, 4 u 8 bytes, y el truncamiento se produce según el tamaño del binario.16 Es decir, PIC S9(4) COMP y PIC S9(4) COMP-5 parecen iguales, pero el límite superior del valor que admiten es distinto. Si se encuentra con COMP-5 en código que intercambia valores en binario puro con otro sistema, interprételo como que está escrito así a propósito.

El procedimiento más corto para contrastarlo con su propio entorno es este.

  1. Abra primero la definición de compilación (makefile, JCL, configuración del proyecto). Antes que el código fuente, esto le dirá con qué compilador y con qué opciones se compila.
  2. Determine el formato de referencia (fixed / free). Si se equivoca aquí y formatea con el editor, el código se rompe.
  3. Determine la codificación de caracteres. La forma de leer un volcado cambia según sea EBCDIC o ASCII.
  4. Marque los campos de la familia COMP. Es prácticamente ahí donde aparecen las diferencias entre compiladores.

8. El orden mínimo de lectura

Cuando de repente le toque leer COBOL, el siguiente orden es el más seguro.

  1. Revise todos los COPY. Si puede abrir el copybook, ábralo. Si no puede, busque el listing o el código fuente ya expandido.
  2. Recoja las definiciones de registro de nivel 01. Elabore un listado de los niveles superiores de FILE SECTION, WORKING-STORAGE y LINKAGE SECTION.
  3. Lea PIC y USAGE. Identifique los importes, las fechas, las cantidades, los códigos y las banderas.
  4. Busque READ / WRITE / REWRITE / CALL / EXEC SQL / EXEC CICS. Capte primero la entrada, la salida y los límites externos.
  5. Siga solo la ruta principal, al principio. Recorra la cadena de PERFORM desde el inicio del PROCEDURE DIVISION.
  6. Mire el 88 y los campos de estado. Así resulta más fácil leer el significado del EOF, de normal/anormal y de los códigos de tipo.
  7. Marque REDEFINES / OCCURS DEPENDING ON / COMP-3. Como seguro que le afectarán más adelante, márquelos de antemano como elementos de riesgo.
  8. Si es un archivo, mire FILE STATUS. Esto reduce considerablemente los errores de interpretación en los fallos de E/S.

Con este orden, no hace falta leer todo el texto en detalle desde el principio. En COBOL, en lugar de intentar entenderlo todo al 100 % desde el inicio, es mucho más cómodo dominar primero los tres puntos —los registros, los límites externos y la ruta principal— y luego pasar a los detalles.

8.1 Ejercicio: lea esta definición de registro

Solo con la explicación de cómo leer no queda del todo asimilado, así que le dejamos un registro pequeño. Primero intente responder usted mismo y después mire las respuestas que aparecen abajo.

       01  CUST-REC.
           05  CUST-ID          PIC X(8).
           05  CUST-NAME        PIC X(20).
           05  CUST-KBN         PIC X.
               88  CUST-NORMAL  VALUE '0'.
               88  CUST-VIP     VALUE '1'.
           05  CUST-BALANCE     PIC S9(7)V99 COMP-3.
           05  CUST-HIST OCCURS 3 TIMES.
               10  HIST-DATE    PIC 9(8).
               10  HIST-AMOUNT  PIC S9(5)V99 COMP-3.
           05  FILLER           PIC X(4).

Preguntas

  1. ¿Cuántos bytes ocupa CUST-REC en total?
  2. ¿A partir de qué byte, contando desde el inicio del registro, empieza CUST-BALANCE?
  3. ¿A partir de qué byte, contando desde el inicio, empieza el segundo HIST-AMOUNT?
  4. Cuando CUST-KBN contiene '1', ¿qué nombre de condición se vuelve verdadero?
  5. Al abrir este archivo en un editor de texto, ¿qué campos se ven como datos corruptos?
  6. Mencione dos cosas que no se pueden saber solo con esta definición.

Respuestas

  1. 74 bytes. El desglose es el siguiente.

    Campo Cálculo Bytes
    CUST-ID X(8) 8
    CUST-NAME X(20) 20
    CUST-KBN X 1
    CUST-BALANCE COMP-3 de 9 dígitos 5
    CUST-HIST (8 + 4) × 3 veces 36
    FILLER X(4) 4
    Total   74

    El nivel 88 es un nombre de condición, así que no consume bytes. Contarlo es un error frecuente. FILLER solo carece de nombre; los 4 bytes existen de forma efectiva.

  2. A partir del byte 30. Antes hay 8 + 20 + 1 = 29 bytes, así que empieza justo después de esos.

  3. A partir del byte 55. CUST-HIST empieza en el byte 35, y como cada elemento ocupa 12 bytes, el primero va del byte 35 al 46 y el segundo del 47 al 58. De esos, los primeros 8 bytes son HIST-DATE, así que HIST-AMOUNT empieza en el byte 55.

  4. CUST-VIP. No existe una zona separada llamada CUST-VIP; simplemente, cuando CUST-KBN vale '1', se puede leer con ese nombre.

  5. CUST-BALANCE y HIST-AMOUNT. Como ambos son COMP-3, al leerlos como caracteres se convierten en secuencias sin sentido. HIST-DATE es DISPLAY con PIC 9(8), así que en un entorno ASCII se puede leer como un número, por ejemplo 20260317. Sin embargo, en un entorno EBCDIC, aunque parezca un número, el valor de byte es distinto del de ASCII.

  6. Por ejemplo, cosas como estas.

    • Si esta definición en sí se importa mediante COPY. Sin mirar el copybook no se sabe si es la versión realmente en uso.
    • Si la codificación de caracteres del archivo es EBCDIC o ASCII. El aspecto de PIC X y de PIC 9 DISPLAY cambia según eso.
    • Si en la operación real CUST-KBN puede recibir valores distintos de '0' y '1'. Solo hay dos nombres de condición definidos, pero eso no garantiza que no lleguen otros valores.
    • Los atributos del propio archivo (la longitud de registro, si es de longitud variable, FILE STATUS). Esto no se puede saber sin mirar el ENVIRONMENT DIVISION y el FD.

Si se equivocó en las preguntas 1 y 3, vuelva a la tabla de dígitos y bytes de la sección 5.3. Los errores de interpretación en COBOL casi siempre empiezan por aquí.

9. Puntos habituales donde se atasca la lectura

Por último, resumimos los puntos donde los principiantes suelen atascarse con bastante frecuencia.

Pensar que REDEFINES es «otra variable»

No es así. Se está leyendo la misma zona con otra forma. Si se modifica una de las dos, la forma en que se ve la otra también cambia.7

Pensar que 88 es «un bool independiente»

No es así. Solo se le ha dado un nombre al valor del campo inmediatamente anterior. SET WS-OK TO TRUE, por detrás, coloca el valor correspondiente en el campo base.3

Ignorar el COPY y leer solo el cuerpo

El archivo que tiene abierto todavía es, en el mejor de los casos, la mitad del conjunto. Es normal que las definiciones de campo, las banderas comunes y las host variables estén, en su mayor parte, fuera de él.9

Pensar que MOVE es una simple asignación

MOVE no es un simple memcpy. Según el tipo del campo de destino, puede implicar conversión, ajuste de dígitos, relleno con ceros, truncamiento, y edición o edición inversa.17

Subestimar el efecto del .

El . en COBOL pesa más de lo que uno imagina. En código antiguo sin cierre explícito, si se malinterpreta hasta dónde cierra ese punto, se lee mal el flujo de control.12

Pensar que packed decimal o EBCDIC son «datos corruptos»

No siempre están corruptos. Con bastante frecuencia, simplemente no son una cadena de caracteres desde el principio, o no están en ASCII.46

Pensar que lo que sigue a OCCURS DEPENDING ON está en una posición fija

Los campos que siguen a una tabla de longitud variable pueden cambiar de posición según el valor. Si se lee con la mentalidad de longitud fija, todos los cálculos de desplazamiento (offset) quedan desalineados.8

10. Tabla de referencia rápida

Palabra encontrada Qué pensar primero
01 El nivel superior de un registro o grupo. A partir de aquí se capta el panorama general
88 El nombre con significado de una bandera o código de estado. La clave para leer las bifurcaciones
PIC X(...) Campo de caracteres
PIC 9(...) / S9(...)V... Campo numérico. Verifique el número de dígitos y la posición del decimal
COMP binario
COMP-3 packed decimal. Es muy probable que sea un importe o una cantidad
REDEFINES Se está interpretando la misma zona de otra forma
OCCURS Arreglo / table
OCCURS DEPENDING ON Longitud variable. Tenga cuidado también con las posiciones posteriores
FILLER No tiene nombre, pero sí longitud
COPY Sin ver el copybook no se ve la forma completa
PERFORM El esqueleto de la ruta principal
READ / WRITE / REWRITE E/S de archivos
EXEC SQL Procesamiento de base de datos
EXEC CICS Procesamiento transaccional
FILE STATUS Código de resultado de la E/S

11. Resumen

COBOL no es difícil porque sea antiguo. Simplemente, la definición de datos, los archivos externos y el contexto de ejecución están estrechamente entrelazados, por lo que la puerta de entrada inicial cuesta más de ver.

El conjunto mínimo para leerlo, resumido de nuevo, es este:

  • Captar el mapa mediante los DIVISION
  • Leer primero el DATA DIVISION
  • Leer la forma de los campos mediante PIC y USAGE
  • Marcar COMP-3, REDEFINES, OCCURS, 88 y COPY
  • Seguir PERFORM, READ, WRITE y CALL
  • Dominar los límites externos mediante FILE STATUS, EXEC SQL y EXEC CICS
  • No subestimar cómo actúa el .

Cuando esto se ve con claridad, COBOL deja de ser una «magia antigua y misteriosa» para convertirse en «un lenguaje de procesamiento de registros». Las tecnologías legadas no dan miedo porque su nombre sea antiguo; simplemente, si se equivoca la escala con la que se mira al principio, se vuelve de repente difícil de entender. Si la escala del mapa es la correcta, se lee sorprendentemente bien.

12. Referencias

Estas son las principales referencias citadas en el cuerpo del artículo. Los números en superíndice del texto son enlaces directos a esta lista, y la flecha al final de cada elemento permite volver a la posición original.

Artículos recientes con las mismas etiquetas para profundizar en temas cercanos.

Estas páginas sitúan el tema en un contexto más amplio de servicios y decisiones.

El artículo está directamente relacionado con los siguientes servicios.

Consultoría técnica y revisión de diseño

Un tema que encaja bien con la consultoría técnica y la revisión de diseño, ya que abarca desde cómo interpretar los activos COBOL existentes hasta el punto de entrada para las modificaciones, la comprensión de los límites externos y la organización del diagnóstico previo a una migración.

Investigación de fallos y causas

La atención de incidencias justo después de una transferencia de responsabilidad, así como el rastreo de dónde se producen las inconsistencias en los activos COBOL, son tareas que avanzan bien como investigación de fallos y análisis de causa raíz.

Preguntas frecuentes

Preguntas habituales en las consultas sobre el tema del artículo.

¿Por dónde debo empezar a leer el código fuente COBOL?
Leer solo el PROCEDURE DIVISION le dará únicamente la mitad del panorama. COBOL es, antes que un lenguaje de lógica, un lenguaje de definición de registros muy marcado, así que primero conviene mirar el DATA DIVISION. El orden de lectura seguro consiste en revisar todos los COPY y comprobar los copybooks, listar las definiciones de registro de nivel 01, leer la forma de cada campo mediante PIC y USAGE, buscar READ, WRITE, CALL, EXEC SQL y EXEC CICS para captar las entradas, salidas y los límites externos, y finalmente seguir solo la ruta principal a través de la cadena de PERFORM que arranca al inicio del PROCEDURE DIVISION.
¿Qué significa PIC S9(7)V99 COMP-3?
PIC indica la forma del campo y USAGE indica en qué representación se guarda. S9(7)V99 es un número con signo de 7 dígitos enteros más 2 dígitos decimales, pero la V es un punto decimal lógico: no hay ningún carácter de punto real en los datos. COMP-3 es packed decimal y aparece con frecuencia en campos de importes, impuestos, cantidades o tasas. Es normal que se vea como datos corruptos si se lee como texto, así que examinar un volcado con la mentalidad de un CSV o de UTF-8 lleva directo al error.
¿Cómo debo entender el nivel 88 y REDEFINES en COBOL?
El nivel 88 no es una variable booleana independiente, sino un nombre de condición (condition-name) que se le da al valor del campo inmediatamente anterior. SET WS-OK TO TRUE, por detrás, coloca el valor correspondiente en el campo base. REDEFINES es un mecanismo para ver la misma zona de memoria con otra forma; no es una copia, sino algo más cercano a un union del estilo de C. Como modificar una de las formas cambia también cómo se ve la otra, esta técnica aparece con frecuencia para distinguir el tipo de registro dentro de una misma zona.
¿Qué hacer cuando hay tantas instrucciones COPY que no se puede ver el conjunto completo?
COPY es un include que se resuelve en tiempo de compilación, así que el código fuente que tiene abierto puede no ser todavía la forma completa. Es bastante habitual que las definiciones de registro, las banderas comunes, las host variables para SQL y las interfaces externas estén metidas dentro de los copybooks. Cuando resulta difícil de leer, lo más rápido es comprobar si puede consultar el código fuente ya expandido o el compiler listing; IBM Enterprise COBOL cuenta además con una opción llamada MDECK que vuelca el código fuente de entrada después del procesamiento de biblioteca.

Perfil del autor

Página de presentación del autor del artículo.

Go Komura

Representante de KomuraSoft LLC

Especializado en desarrollo de software para Windows, consultoría técnica e investigación de fallos, sobre todo en proyectos con sistemas existentes y errores difíciles de reproducir.

Volver al blog