Mostrar un mensaje, calcular un importe y leer un archivo son buenas formas de empezar con COBOL. Los diez programas siguientes se pueden guardar, compilar y ejecutar por separado; cada uno incluye su salida y una explicación de lo que conviene observar.
COBOL significa Common Business-Oriented Language, lenguaje común orientado a los negocios. Se utiliza en procesamiento de datos administrativos, como nóminas, contabilidad y sistemas financieros. Sus instrucciones se parecen a palabras del inglés, pero tienen una sintaxis precisa. [4]
Cómo ejecutar los ejemplos
Se han compilado y ejecutado con GnuCOBOL 3.2.0, dialecto predeterminado (-std=default) y formato libre (-free), en Windows. Usa una terminal donde el compilador esté configurado; cobc --version permite comprobarlo. El programa no exige un mainframe. [1][2]
Guarda el primer código como saludo.cob. En Windows, compila y ejecuta:
Para los demás, cambia saludo por el nombre que aparece en cada ejemplo. -x crea un ejecutable y -free evita interpretar el código con las columnas del formato fijo. Las salidas usan texto sin tildes para simplificar las diferencias de codificación entre consolas; el punto decimal se mantiene en todos los programas.
Descargar los diez programas y pedidos.txt. El archivo incluye instrucciones y resultados esperados; no incluye compilador ni ejecutables. La sección de CICS se explica aparte y no forma parte de este conjunto ejecutado.
10 ejemplos de COBOL para practicar
Los códigos son programas completos e independientes. Comienza por los primeros y avanza hasta la lectura de archivos: cada ejemplo incorpora una operación o un caso de error distinto. En móvil puedes desplazar el código horizontalmente; con teclado, enfoca el bloque y usa las flechas.
EJEMPLO 01 · DISPLAY y programa mínimo
Mostrar un mensaje
Archivo:saludo.cob
identification division.
program-id. saludo.
procedure division.
display "Programa de ejemplo de Cobol"
stop run.
DISPLAY escribe el texto entre comillas rectas. STOP RUN termina este programa principal. No hacen falta declaraciones de datos para mostrar un literal.
Las divisiones ENVIRONMENT y DATA pueden omitirse aquí porque no hay configuración externa ni datos que declarar.
EJEMPLO 02 · PIC X, PIC 9, MOVE y espacios
Declarar y mostrar datos
Archivo:ficha.cob
identification division.
program-id. ficha.
data division.
working-storage section.
01 nombre pic x(12) value "Ana".
01 unidades pic 9(3) value 7.
procedure division.
move "Luis" to nombre
display "Nombre: " function trim(nombre)
display "Unidades: " unidades
stop run.
El campo alfanumérico admite doce posiciones; MOVE cambia su contenido y lo completa con espacios. TRIM permite mostrar el nombre sin los espacios finales. El campo numérico tiene tres dígitos, por eso se ven los ceros iniciales.
EJEMPLO 03 · Decimales implícitos y formato de salida
V indica una posición decimal implícita: no es un carácter almacenado. Al reducir de tres a dos decimales, COMPUTE sin ROUNDED trunca; con ROUNDED redondea. La máscara editada 99.99 hace visible el punto. Estos programas usan punto decimal y datos positivos definidos en el código.
La capacidad del campo importa: un redondeo también puede producir un valor que ya no quepa. La regla de redondeo apropiada para un sistema real debe definirse en sus requisitos.
EJEMPLO 04 · ON SIZE ERROR y estado conservado
Detectar un resultado que no cabe
Archivo:limite.cob
identification division.
program-id. limite.
data division.
working-storage section.
01 contador pic 99 value 98.
procedure division.
perform 2 times
add 1 to contador
on size error display "No cabe"
not on size error display "Correcto"
end-add
display "Contador: " contador
end-perform
stop run.
El primer incremento cabe en dos dígitos. El segundo intentaría guardar 100 y ejecuta ON SIZE ERROR. En esa operación, el receptor conserva 99. La comprobación evita tratar un resultado recortado como si fuera correcto.
El tratamiento de errores de tamaño evita aceptar silenciosamente el resultado de una operación que no cabe. [5]
EJEMPLO 05 · EVALUATE y WHEN OTHER
Elegir entre varios estados
Archivo:estado.cob
Entrada de esta ejecución: escribe C y pulsa Intro. La salida de abajo muestra lo que escribe el programa, sin incluir el eco del teclado.
identification division.
program-id. estado.
data division.
working-storage section.
01 codigo pic x.
procedure division.
accept codigo
evaluate codigo
when "P" display "Pendiente"
when "C" display "Confirmado"
when "A" display "Anulado"
when other display "Codigo desconocido"
end-evaluate
stop run.
EVALUATE selecciona una rama según el código introducido. WHEN OTHER cubre los valores que no coinciden. Las comparaciones distinguen mayúsculas y minúsculas: c no equivale a C.
Escribe un solo carácter y pulsa Intro; el campo de este ejemplo tiene una posición.
EJEMPLO 06 · PERFORM VARYING
Sumar con un bucle
Archivo:suma.cob
identification division.
program-id. suma.
data division.
working-storage section.
01 indice pic 9.
01 total pic 99 value 0.
procedure division.
perform varying indice from 1 by 1
until indice > 5
add indice to total
end-perform
display "Total: " total
stop run.
El bucle suma 1 + 2 + 3 + 4 + 5. Comprueba la condición antes de cada vuelta; cuando el índice alcanza 6, termina. El receptor de dos dígitos basta para estos datos, pero no para cualquier suma.
EJEMPLO 07 · OCCURS, subíndices e IF
Recorrer una tabla de importes
Archivo:tabla.cob
identification division.
program-id. tabla.
data division.
working-storage section.
01 ventas.
05 importe pic 9(3) occurs 3 times.
01 indice pic 9.
01 total pic 9(4) value 0.
01 mayores pic 9 value 0.
procedure division.
move 120 to importe(1)
move 80 to importe(2)
move 150 to importe(3)
perform varying indice from 1 by 1
until indice > 3
add importe(indice) to total
if importe(indice) > 100
add 1 to mayores
end-if
end-perform
display "Total: " total
display "Mayores de 100: " mayores
stop run.
OCCURS reserva tres elementos con la misma descripción. Sus subíndices son 1, 2 y 3. El programa acumula todos los importes y cuenta solo los que superan 100; un importe igual a 100 no cumple la condición.
EJEMPLO 08 · STRING y ON OVERFLOW
Unir textos con un separador
Archivo:nombre.cob
identification division.
program-id. nombre.
data division.
working-storage section.
01 nombre pic x(10) value "Ana".
01 apellido pic x(10) value "Luna".
01 completo pic x(25) value spaces.
01 cabe pic 9 value 1.
procedure division.
string function trim(nombre) " "
function trim(apellido)
delimited by size into completo
on overflow move 0 to cabe
end-string
if cabe = 1
display function trim(completo)
else
display "Texto demasiado largo"
end-if
stop run.
STRING concatena nombre, un espacio y apellido. DELIMITED BY SIZE utiliza el tamaño de cada elemento enviado; TRIM quita el relleno de los campos. ON OVERFLOW detecta que el destino no basta, y el programa evita mostrar el resultado parcial.
ON OVERFLOW no promete deshacer lo ya copiado. Por eso este ejemplo usa una bandera y no presenta el campo como resultado completo cuando falla.
EJEMPLO 09 · ACCEPT, prueba NUMERIC y NUMVAL
Validar un entero antes de convertirlo
Archivo:entrada.cob
Entrada de esta ejecución: escribe 12 y pulsa Intro. La salida de abajo muestra lo que escribe el programa, sin incluir el eco del teclado.
identification division.
program-id. entrada.
data division.
working-storage section.
01 entrada pic x(80).
01 cantidad pic 99.
procedure division.
accept entrada
if function length(function trim(entrada)) = 2
if function trim(entrada) is numeric
compute cantidad = function numval(entrada)
display "Cantidad: " cantidad
else
display "Escribe exactamente dos digitos"
end-if
else
display "Escribe exactamente dos digitos"
end-if
stop run.
Se recibe texto y se comprueba que, tras quitar espacios exteriores, contiene exactamente dos dígitos. Solo entonces se convierte. Acepta 00 a 99; rechaza 7, -1, 1.5, letras y una entrada vacía. Una regla que exigiera una cantidad positiva tendría que comprobar además que el valor es mayor que cero.
La entrada se limita a 80 caracteres en este ejercicio de consola; ACCEPT no constituye por sí solo un validador general de entradas de longitud arbitraria.
identification division.
program-id. lectura.
environment division.
input-output section.
file-control.
select pedidos assign to "pedidos.txt"
organization is line sequential
file status is estado-archivo.
data division.
file section.
fd pedidos.
01 registro pic x(80).
working-storage section.
01 estado-archivo pic xx.
01 fin pic 9 value 0.
01 total pic 9(4) value 0.
procedure division.
open input pedidos
if estado-archivo not = "00"
display "No se pudo abrir: " estado-archivo
stop run
end-if
perform until fin = 1
read pedidos
evaluate estado-archivo
when "00"
display function trim(registro)
add 1 to total
on size error
display "Demasiados registros"
move 1 to fin
end-add
when "10" move 1 to fin
when other
display "Error de lectura: " estado-archivo
move 1 to fin
end-evaluate
end-perform
close pedidos
if estado-archivo not = "00"
display "Error de cierre: " estado-archivo
end-if
display "Registros contados: " total
stop run.
Pedido A
Pedido B
Pedido C
Registros contados: 0003
Guarda pedidos.txt en la carpeta desde la que ejecutas el programa. OPEN INPUT abre para lectura; el código 00 indica éxito y 10, fin de archivo. El bucle solo cuenta registros leídos correctamente. CLOSE libera el archivo. Si no se puede abrir, el programa informa del estado y termina.
Usa líneas de hasta 80 caracteres y un máximo de 9.999 registros en este ejercicio. Un archivo vacío produce 0000. Una línea vacía es un registro y también se cuenta. El total es el número contado, no una confirmación de que nunca hubo errores.
Divisiones y tipos de datos en COBOL
Dónde se describe cada parte del programa
División
Función
Ejemplo
IDENTIFICATION
Identifica el programa.
PROGRAM-ID. saludo.
ENVIRONMENT
Configura relaciones con el entorno, como archivos.
SELECT pedidos ASSIGN TO "pedidos.txt".
DATA
Declara registros y campos.
WORKING-STORAGE SECTION.
PROCEDURE
Contiene las instrucciones ejecutables.
DISPLAY, COMPUTE, IF y PERFORM.
PIC X(12) describe doce posiciones alfanuméricas; PIC 9(3), tres dígitos; PIC 99V99, dos enteros y dos decimales implícitos. Para valores negativos hace falta un formato con signo adecuado; los ejemplos numéricos de esta página trabajan con cantidades no negativas.
Usa cierres explícitos como END-IF y END-PERFORM. Un punto termina una sentencia COBOL y puede cerrar ámbitos aún abiertos: no lo añadas al final de cada línea por costumbre de otros lenguajes. La indentación ayuda a leer, pero no sustituye esos límites. [3]
COBOL con CICS: enviar una pantalla
CICS es un entorno de procesamiento de transacciones. Las instrucciones EXEC CICS … END-EXEC son servicios de ese entorno, no instrucciones de consola equivalentes a DISPLAY. Un mapa BMS describe una pantalla y pertenece a un conjunto de mapas o mapset. [6]
Fragmento contextual para IBM CICS TS; no ejecutado aquí. Supone un programa CICS ya configurado, con el mapa INICIO en el mapset DEMOMAP disponibles. No es un programa autónomo para compilar con los comandos anteriores.
*> Fragmento para un programa de IBM CICS TS.
*> Requiere el mapa INICIO en el mapset DEMOMAP.
exec cics send map('INICIO') mapset('DEMOMAP')
maponly erase
resp(ws-resp) resp2(ws-resp2)
end-exec
if ws-resp not = dfhresp(NORMAL)
perform tratar-error
end-if
exec cics return
end-exec
ws-resp y ws-resp2 deben declararse en WORKING-STORAGE como campos binarios de palabra completa, por ejemplo cada uno con PIC S9(8) COMP. tratar-error representa un párrafo que la aplicación debe implementar para atender una respuesta no normal; no está definido en este fragmento. Se necesita además el procesamiento de CICS para traducir sus comandos.
MAP y MAPSET: identifican recursos; el texto que quieres mostrar no se pone como nombre de mapa. Los nombres del ejemplo tienen siete caracteres o menos.
MAPONLY: envía datos constantes del mapa físico, sin añadir datos variables desde un área FROM. Para este envío sin datos variables no se necesita una estructura simbólica de datos.
ERASE: pide borrar la pantalla antes de mostrar el mapa.
RESP y RESP2: permiten comprobar la respuesta del servicio; omitir el manejo de errores no equivale a resolverlos.
RETURN: devuelve el control según el nivel lógico de ejecución de CICS; en el nivel superior termina la tarea y retorna a CICS. No debe sustituirse rutinariamente por STOP RUN.
El contenido visible de la pantalla lo determina el mapa definido en el entorno; sin ese recurso no se puede prometer una salida concreta. [7][8][9]
Usos, historia y compiladores
COBOL nació del trabajo de CODASYL iniciado en 1959 para facilitar el procesamiento de datos de negocio. Puede participar en procesos por lotes, como calcular una nómina, o en aplicaciones transaccionales. Conservar un sistema también depende de sus reglas de negocio, integraciones y requisitos; no se explica solo por el costo de cambiar de lenguaje. [4]
COBOL 85 reforzó la programación estructurada, por ejemplo con terminadores explícitos de ámbito. No hay que atribuirle en bloque todas las capacidades de compiladores posteriores: recursividad, almacenamiento local y gestión dinámica de memoria deben comprobarse en el estándar y el compilador concretos. [3]
El lenguaje y el compilador son cosas diferentes. GnuCOBOL permite practicar en equipos personales; IBM mantiene compiladores para sus plataformas. Los entornos mainframe son un ámbito de uso, no un requisito para ejecutar todo programa COBOL. [1][4]
Microsoft COBOL aparece en la historia de productos de Microsoft de 1980. RM/COBOL 11 también es una versión histórica, anterior a RM/COBOL 12 en la documentación de migración. Esas denominaciones no deben confundirse con un catálogo de versiones actuales. [10][11]
8 ejercicios para practicar
¿Por qué el ejemplo 2 muestra 007 y no 7?
¿Qué representa V en PIC 99V99?
¿Qué salidas da el ejemplo 3 con 19.994?
¿Por qué el contador del ejemplo 4 sigue en 99 al fallar?
¿Qué muestra el ejemplo 5 si introduces X o c?
Si el importe central de la tabla pasa de 80 a 100, ¿qué cambia?
¿Acepta el ejemplo 9 las entradas 00, 7 y AB?
¿Da lo mismo un archivo vacío que uno inexistente?
Ver respuestas razonadas
El receptor PIC 9(3) tiene tres posiciones numéricas; DISPLAY muestra sus ceros iniciales.
La posición decimal implícita. Para mostrar un punto se mueve el valor a una máscara editada, como 99.99.
Sin redondeo: 19.99. Con redondeo: 19.99. Con 19.995, en cambio, ROUNDED da 20.00.
La operación detecta SIZE ERROR y, al manejarlo con ON SIZE ERROR, conserva el receptor de esa operación.
Codigo desconocido en ambos casos: no coinciden con P, C ni A.
El total pasa de 0350 a 0370. El contador de mayores de 100 sigue en 2 porque 100 no es mayor que 100.
Acepta 00. Rechaza 7 porque tiene un solo dígito y AB porque no es numérico.
No. El vacío se abre y alcanza el fin sin registros; el inexistente falla al abrirse. En el entorno probado, el estado de archivo inexistente es 35.
Errores frecuentes
Compilar formato libre como fijo: Utiliza -free para estos programas; el formato fijo interpreta posiciones de columna.
Pegar comillas tipográficas: El código usa comillas rectas. Las comillas curvas de un procesador de texto pueden provocar errores.
Confundir V con un punto visible: V marca la escala decimal; una máscara editada presenta el separador.
No dimensionar los receptores: Comprueba cuántos dígitos admite el campo y maneja desbordamientos cuando corresponda.
Convertir texto sin validarlo: Una entrada puede ser vacía, alfabética o demasiado larga para el campo numérico.
Confundir subíndices: La tabla del ejemplo 7 tiene elementos 1 a 3; no se accede al 0 ni al 4.
Confundir fin de archivo con fallo de apertura: Son situaciones distintas. Revisa FILE STATUS en cada operación.
Tratar CICS como una biblioteca de consola: Necesita su entorno, sus recursos y su preparación del programa. DISPLAY no sustituye a SEND MAP.