Está en la página 1de 46

1

INTRODUCCIÓN A PROGRAMAR EN COBOL


La orientación del curso / manual la enfocaré a mi entorno de trabajo, es decir RM bajo UNIX,
pero como os he dicho antes, no hay muchas diferencias.

Al pensar en Cobol como lenguaje de programación debemos de tener presente que nos
referimos a un lenguaje dedicado a gestión de datos con una magnífica transportabilidad entre
los distintos sistemas, yo he ejecutado el mismo programa en MS-DOS y UNIX sin modificar ni
una linea de código y copiando solo el objeto.

Si se le llaman lenguajes de programación, es porque realmente se consideran como cualquier


idioma, es decir tiene su gramática, sus verbos, sus frases, sus párrafos y el cobol además tiene
una gran similitud con el inglés, ya que todo su entorno está sacado de éste idioma. Cobol
además es un lenguaje estructurado y sus partes se diferencias claramente en Divisiones.
Estas son 4, son obligatorias y cada una de ellas tiene una misión diferente dentro de cada
programa como veremos a continuación.

El programa cobol se escribe secuencialmente en líneas de 80 caracteres o menos con la


siguiente división:

La parte (1) comprende las columnas de la 1 a la 6 ambas inclusive y se utiliza


para numerar las líneas, aunque hoy en día prácticamente no se utilizan.

La parte (2) comprende la columna 7 y en ella podemos encontrar, un guión (-)


que nos indica que esta línea es continuación de la anterior pero que por su
tamaño ocupa mas de una línea, un asteristo (*) que nos indica que el texto que
viene a continuación es un comentario y por lo tanto que el compilador lo ignore, o
bien puede servir dependiendo de los compiladores para indicaciones del debug.

La parte (3) se le llama Area A comprende las columnas 8 a 11 ambas inclusive y


aquí es donde se escriben los nombre de las divisiones, de las secciones, de los
párrafos, los indicadores de FD (File Description) y los niveles de variables 01 y 77.

La parte (4) llamada Area B comprende desde la columna 12 a la 72 y en ellas se


incluirán todas las instrucciones del programa, las lineas de las secciones y los
niveles de variables mayores a 01.

La parte (5) de la columna 73 a la 80 no se utiliza y por lo tanto es ignorada por el


compilador.
El punto es un signo de vital importancia en cobol ya que nos indica el final de una linea, en el
han de terminar todas las secciones, divisiones y párrafos. Si al final de una linea el compilador
no encuentra el punto, interpretará que la instrucción continúa hasta que aparezca el punto de
fin de linea.
Al igual que en otros lenguajes, el cobol dispone de palabras reservadas que no debemos de
utilizar como nombres de variables o de párrafos, además éstos no deben de exceder de 30
caracteres (depende del compilador).
Las variables y constantes que se pueden utilizar son numéricas, alfabéticas o alfanuméricas. Las
numéricas al contrario de la mayoría de los lenguajes actuales o las bases de datos no miden su
tamaño por bytes sino por dígitos, es decir, que una variable de 6 dígitos podrá contener
números desde 0 hasta 999999 si es de valor absoluto o incluyendo los negativos si lleva signo.
Para las alfanuméricas en cambio no hay cambio alguna y su tamaño viene indicado por el
número de caracteres que ocupa.
Existen además en cobol unas variables que vienen con un valor propio y que se pueden utilizar
libremente, como ZERO, SPACE, LOW-VALUES, HIGH-VALUES, etc...
Quisiera respetar para todo el manual las mismas pautas, color Rojo para las palabras
reservadas cobol, subrayado para las obligatorias, en cursiva los comentarios y en normal el
resto.
2
Nota final:
Es obvio que cada manual estará orientado a la manera de trabajar de quien lo
escribe, con ello quiero decir que habrá cosas que no explicaré mucho o incluso
otras que omitiré porque yo no las haya utilizado nunca.
Una explicación perfectamente detallada deberá venir en los manuales de cada uno
de los compiladores que del lenguaje Cobol existen hoy en dia.
Espero que podais comprender ésto, eso si, os puedo asegurar que todos mis
programas utilizan solo lo que aqui voy a exponer y ninguno nunca me ha dado
ningún problema.

IDENTIFICATION DIVISION.
IDENTIFICATION DIVISION. Esta es la primera linea de todo programa Cobol e identifica a la
primera división donde se especifica el nombre del programa, el del autor y demás datos, su
sintaxis sería la siguiente:

IDENTIFICATION DIVISION.
PROGRAM-ID. Nombre del programa.
AUTHOR. Nombre del autor.
INSTALLATION. Lugar donde está instalado.
DATE-WRITTEN. Fecha de creación.
DATE-COMPILED. Fecha de compilación.
REMARKS. Comentarios.
Vemos que el único párrafo obligatorio además del nombre de división es el que hace referencia
al nombre del programa, los demás nombre de autor, lugar de instalación, fechas de creación y
compilación y comentarios son opcionales, eso si, si se incluyen se deben de poner cumpliendo
las normas.
Podemos incluir además todos los comentarios o explicaciones que creamos oportunas
incluyendo en la columna 7 un asterisco (*) que nos indica que el compilador hará caso omiso de
lo que venga a continuación, por ejemplo.
* /////// Este programa es para hacer algo ///////
* // atención a la sección de la fecha ////
Ejemplo:
IDENTIFICATION DIVISION.
PROGRAM-ID. MANCLI.
AUTHOR. ANDRES MONTES.
INSTALLATION. WWW.
REMARKS. Programa para mantenimiento de fichero de clientes.

 
Nota final:
Poco mas podemos decir de ésta division, obviamente las demás no son tan
pequeñas, sin embargo posee dos de las lineas mas importantes de cualquier
programa cobol.

ENVIRONMENT DIVISION.
ENVIRONMENT DIVISION. Es la segunda division por orden de aparición, y en ella se
especifican, el ordenador donde se escribió y se ejecutará el programa, asi como la relacion entre
los ficheros a utilizar con sus correspondencias externas, es decir con los dispositivos a los que
hará referencia el programa objeto cuando vaya a establecer comunicación con dicho fichero.

Diremos antes de continuar que en los primeros cobol había muchas partes que eran obligatorias
en cada programa, pero hoy en dia, por ejemplo, ésta división ya no es obligatoria, asi como
ninguna de sus partes. Su sintaxis sería la siguiente:

ENVIRONMENT DIVISION.
CONFIGURATION SECTION.
3
SOURCE-COMPUTER. Ordenador donde se escribió el fuente.
OBJECT-COMPUTER. Ordenador donde se ejecuta el objeto.
SPECIAL-NAMES. Cambiar valores para constantes del lenguaje, pueden variar
en cada compilador.
Como se aprecia en su sintaxis, ésta segunda division se divide a su vez en dos secciones, que
se describen a continuacion:
CONFIGURATION SECTION: Donde describimos los tipos de ordenadores en que
se escribio y se ejecutará el programa, o bien el nombre del compilador y
asignación de valores a ciertas constantes utilizadas por el compilador, estos
valores se introducen en sus respectivas lineas como se ve arriba.

Para la linea de SPECIAL-NAMES el uso mas habitual es el de cambiar el punto


decimal usado por los ingleses por la coma y asi poder especificar los puntos para
los miles, su formato sería el siguiente:

SPECIAL-NAMES.
DECIMAL-POINT IS COMMA.

También podriamos cambiar el valor del símbolo de la moneda con:

CURRENCY SIGN IS literal , suele ser un solo caracter y no puede coincidir con
ninguno de los que usamos para definir las variables, es decir ni A,ni Z,ni 9,ni -,ni
+,ni X, etc...

O hacer que todas las letras introducidas sean mayúsculas o minúsculas o que no
haya diferencias entre ambas con la clausula ALPHABET.

 
INPUT-OUTPUT SECION: Es la siguiente sección dentro de la Environment,
donde se especificarán todos los ficheros que vamos a utilizar, su tipo, su modo de
acceso asi como el medio en que estarán, esta sección solo será obligatoria cuando
vayamos a utilizar ficheros. Esta tiene dos párrafos FILE-CONTROL e I-O-
CONTROL.
123456789012
           A     B
INPUT-OUTPUT SECTION.
FILE-CONTROL.
      SELECT Nombre-de-archivo
      ASSIGN TO Tipo-de-dispositivo
      ORGANIZATION IS Tipo de organizacion
      ACCESS MODE IS Mode de acceso al fichero
      RECORD KEY IS Clave del registro
      ALTERNATE RECORD KEY IS Claves alternativas registro
WITH DUPLICATES
      FILE STATUS IS Variable de estado del fichero.
Vamos a explicar cada una de las cláusulas que encontramos dentro de la Input-Output Section.
Cláusula SELECT es aqui donde especificamos el nombre lógico que va a tener el
fichero dentro del programa, suele ser una palabra que identifique lo mas claro
posible el contenido del fichero, por ejemplo ARTICULOS, PROVEEDORES,
CLIENTES.

Cláusula ASSIGN aqui especificamos el tipo de dispositivo, si es una impresora


PRINTER, si es un fichero sobre el que vamos a grabar RANDOM o DISC, se
pueden utilizar otros como INPUT, INPUT-OUTPUT, CASSETTE, MAGNETIC-TAPE,
pero sin duda los mas utilizados son los dos primeros para identificar si el fichero
utilizará una salida impresa o se utilizará sobre disco. Para identificar ficheros
utilizados para clasificar utilizaremos SORT.
4
Cláusula ORGANIZATION aqui indicamos la organización de los registros de
nuestro fichero, podrá ser SEQUENTIAL, RELATIVE o INDEXED, si nuestro archivo
fuera secuencial se podrían emitir ésta clausula asi como las restantes.
De ésta organización se deriva el formato del fichero, SEQUENTIAL si los registros
se graban secuencialmente conforme se dan entrada sin importar si están o no
repetidos, un ejemplo claro son los archivos de impresora, todos los listados son
secuenciales.
RELATIVE, si cada registro es identificado por un valor entero con su posición
relativa (practicamente no se utiliza).
INDEXED es la mas utilizada e identifica a ficheros que sus registros son accesibles
mediante una clave unica e irrepetible o por varias que pueden estar duplicadas,
cualquier fichero de mantenimiento, por ejemplo de ARTICULOS, podría ser
INDEXED, y cada código será único para cada artículo y con el nos iremos a su
posición y podremos ver todos los demas datos que hagan referencia al registro.
Existe también para los archivos de texto, tipo AUTOEXEC.BAT la posibilidad de
asignarlos directamente especificando LINE SEQUENTIAL en ésta clausula.

Cláusula ACCESS MODE indica el modo de acceso al fichero, puede ser


SEQUENTIAL, RANDOM o DYNAMIC, si no se especifica ninguno o si el fichero es
SEQUENTIAL entiende que el modo será SEQUENTIAL. RANDOM indica que
accederemos a el aleatoriamente por su clave y DYNAMIC (la mas utilizada) con la
que podremos acceder al fichero en el modo que queramos dentro del programa,
unas veces secuencialmente, si nos interesa, otras veces por su clave.

Cláusula RECORD KEY se utiliza solo si el fichero es indexado y en el decimos cual


es el nombre de la clave por la cual accederemos a los registros. Esta deberá ser
alfanúmerica y tendrá que estar especificada en la FD del fichero. Si el archivo
fuera RELATIVE, esta clausula se sustituiría por RELATIVE KEY e indicará el
número de registro del fichero, deberá estar declarado en la Working-Storage
Section como una variable numérica sin signo.

Cláusula ALTERNATE RECORD KEY solo para ficheros indexados e identifican una
o mas claves alternadas para nuestros registros, por ejemplo en un fichero de
clientes cuya clave principal sería el código, podríamos assignar como clave
alternativa el NIF, y podríamos acceder a el por las dos claves, bien por código o
bien por NIF, será también alfanumérico y deberá también estar declarado en la
FD. Si aparece WITH DUPLICATES, indica que ésta clave alternativa pudiera estar
duplicada, por ejemplo si hubieramos escogido como clave alternada además del
NIF, el Nombre del cliente, podría darse el caso de que dos clientes tuvieran el
mismo nombre.

Cláusula FILE STATUS aqui damos un nombre de una variable que


especificaremos en la Working como un campo alfanumérico de dos caracteres
donde el programa depositará el código de error que ocurra en el fichero,
dependiendo del valor nosotros podremos operar o hacer alguna acción en
concreto.
El párrafo I-O CONTROL se utiliza par indicarle al programa cuantos archivos van a utilizar el
mismo area de memoria para trabajar, os puedo decir poco mas de éste párrafo porque yo no lo
he utilizado nunca (lo que no quiere decir que no sea útil).

Ejemplo:
ENVIRONMENT DIVISION.
CONFIGURATION SECTION.
SOURCE-COMPUTER. RMCOBOL.
OBJECT-COMPUTER. RMCOBOL.
SPECIAL-NAMES. DECIMAL-POINT IS COMMA.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT CLIENTES ASSIGN TO RANDOM "C:\DATOS\
5

CLIENTES.DAT" ORGANIZATION INDEXED


ACCESS DYNAMIC RECORD KEY KEY-CLIENTE
ALTERNATE RECORD KEY-CLIENTE1 FILE STATUS
STACLI.

SELECT IMPRESORA ASSIGN TO PRINT "PRINTER".

Hemos declarado el archivo CLIENTES como indexado con dos claves,


una principal KEY-CLIENTE y otra alternativa KEY-CLIENTE1 y hemos
asignado una variable para guardar los posibles códigos de error para
cuando operemos con éste fichero STACLI. Al indicarle el acceso
dinámico le decimos que una vez dentro del programa podremos
acceder al fichero secuencialmente o bien directacmente al registro
que queramos por cualquiera de las claves.
Como el fichero IMPRESORA es secuencial no es necesario ninguna
aclaración, al darle el nombre PRINTER cojerá la impresora que
tengamos por defecto, si le damos cualquier otro nombre que no
identificara a ninguna impresora, el resultado sería grabar todo lo que
debería salir por la impresora en un archivo con ese nombre.

Nota final:
Creo que es una de las partes mas interesantes de la programación cobol y que
cuando he utilizado alguno de éstos nuevos lenguajes orientados a objetos y que
utilizan bases de datos, siempre he echado en falta. Para mi siempre es grato
dirigirme a la Environment de cualquier programa y saber con exactitud todos los
ficheros que se van a utilizar en ese programa.

Apreciar que para cada especificación de fichero en la Select solo se pone el punto
al final de todas las clausulas del párrafo.

Al asignar la impresora, si asignamos el nombre PRINTER, éste hace referencia a la


impresora por defecto pero tambien podríamos utilizar un nombre para especificar
una impresora de red, por ejemplo, si en nuestra red existe una impresora que
esta en \\PENTIUM\HPLASER, podemos identificar un nombre en el Autoexec.bat
para asignar ese valor a una variable de entorno como: IMPRE="\\PENTIUM\
HPLASER" y luego en el programa especificar como nombre de dispositivo de la
impresora IMPRE,
SELECT IMPRESORA ASSIGN TO PRINT "IMPRE".

En realidad haciendo ésto último podemos asignar cualquier archivo que esté en
cualquier dirección de la red, ya que el nombre que damos es lógico y su
asignación la podemos definir con una variable de entorno donde queramos.

DATA DIVISION.
DATA DIVISION. Es la tercera division por orden de aparición, y es donde se declaran
absolutamente todos los nombres de campos, registros, variables, es decir donde nombramos
cada dato que vayamos a utilizar en nuestro programa. Para almacenar todos estos nombres de
datos, ésta DIVISION se divide en varias secciones, cada una de ellas orientada a un tipo de
datos diferente.

 FILE SECTION. Aqui describiremos todos los campos que componen los
registros de todos los archivos que vayamos a utilizar, que previamente
habremos declarado en la INPUT-OUTPUT SECTION dentro de la
ENVIRONMENT DIVISION.

 WORKING-STORAGE SECTION. En ella declararemos todas las variables


no referentes a archivos, pero que durante la ejecución del programa
vayamos a utilizar.
6
 LINKAGE SECTION. Esta es la sección donde se registrarán las variables
que nos servirán para enlazar el programa principal con el que llamemos
mediante la orden CALL.

 COMMUNICATION SECTION. (No la he utilizado nunca).

 SCREEN SECTION. En ésta sección podremos describir los atributos y


campos a utilizar en las pantallas.
Al igual que en la anterior DIVISION ninguna de sus partes es obligatoria, pero si vamos a
utilizar alguna variable, aunque solo sea una, tendremos que incluirla en la WORKING-STORAGE
SECTION y esto nos obligará tambien a definir la DATA DIVISION. Pasemos a continuación a
explicar mas a fondo cada una de ellas.
FILE SECTION.
En esta sección describiremos los campos que van a componer el registro de cada
uno de los archivos con los que vamos a trabajar, ésta sería su sintaxis:
123456789012
           A     B
FD Nombre del fichero.
       BLOCK CONTAINS Numero de registros por bloque RECORDS
       BRECORD CONTAINS Numero de caracteres por registro       
CHARACTERS
       LABEL RECORD Etiqueta de registro
       DATA RECORD Nombre del registro.
Vamos a explicar un poco mas detalladamente cada cláusula de la FILE SECTION. Quiero dejar
claro que ésta es mas amplia, pero que como en el resto del manual voy a explicar lo que creo
que es mas importante y en definitiva lo que mas se utiliza.
Cláusula FD nombre del fichero que previamente habiamos descrito
en la cláusula SELECT de la INPUT-OUTPUT SECTION en la
ENVIRONMENT DIVISION.

Cláusula BLOCK CONTAINS cuando queremos que por cada bloque


en disco se graben mas de un registro, aqui especificamos el número
de ellos que va a contener cada bloque, (512, 1024), si no se
especifica se supone que cada registro va a ocupar un bloque de
memoria, o bien será el propio compilador el que haga el cálculo
mas apropiado.

Cláusula RECORD CONTAINS el número de caracteres que tiene el


registro sumando todos sus campos, puede ser fija o variable. Si es
fija utilizamos un valor y si es variable un rango desde hasta, si no
se espicifica será el propio compilador quien la determine.

Cláusula LABEL RECORD puede tener dos valores STANDARD u


OMITTED, el primer caso indica que cada vez que se accede a un
registro el compilador hará las comprobaciones estandares descritas
por el propio compilador y en el segundo éstas serán omitidas. Para
el caso de los ficheros de datos en disco se suele poner STANDARD y
cuando el fichero es de impresora se indica OMITTED.

Cláusula DATA RECORD debido a que un mismo fichero puede


tener varias descripciones de registro, aqui indicamos los nombre de
éstas que deberán estar descritas a nivel 01. Normalmente no se
utiliza y casi siempre se suele utilizar una sola descripción por
fichero, por lo que no suele aparecer en casi ningún programa.
A continuación vendría la descripción de todos los campos que comprenden el
registro, pero antes de ver ésto es aconsejable tener claro como se define una
variable con todas sus opciones ya que a fin de cuentas, los campos de un registro
no son mas que eso, variables, con la única condición de que al formar parte de un
7
registro la información que contiene nos identifica los datos que se guardarán en el
medio en que esté el fichero (disco, impresora).
Antes de seguir adelante quisiera decir que siendo el cobol un lenguaje orientado casi
exclusivamente al manejo de ficheros de datos, es sin duda, ésta parte que hemos visto la mas
importante. Un buen análisis de los ficheros a utilizar antes de empezar es fundamental y nos
evitará  muchos calentamientos de cabeza, tener claro cuales van a ser sus claves tanto la
principal como las alternativas, definir bien todos sus campos y dejar espacio libre para un
posible aumento de datos. Esto lo digo porque si creamos un fichero con 80 caracteres por
registro y al cabo de un tiempo debemos de introducir un nuevo campo que no habiamos
preveido, tendremos que modificar toda su estructura rehaciendo el fichero y recompilando todos
los programas a los que afecte, si en cambio dejamos un poco de espacio nos evitaremos la
reestructuración del archivo, ésto se consigue utilizando el nombre de variable FILLER como
veremos un poco mas abajo.
123456789012
           A     B
WORKING-STORAGE SECTION.
LINKAGE SECTION.
COMMUNICATION SECTION
SCREEN SECTION
Para la WORKING y la LINKAGE las normas son las mismas, asi que las veremos
conjuntamente. Las otras dos secciones, COMMUNICATION y SCREEN no las
veremos en el manual.

Número de Nivel ...... Nombre de campo ...... PIC, VALUE, REDEFINES, OCCURS,
JUST, SIGN, SYNC.

Cada campo declarado debe de llevar un número de nivel que le informe al


compilador del tipo de campo que es:

El nivel 01, identifica la primera entrada de un registro o la primera entrada de un


campo que se va a subdividir.
El nivel 77, identifica a una variable que no se va a subdividir y que no forma parte
de ningún registro.
El nivel 88, identifica los posibles valores condicionales de una variable
previamente definida.
Los niveles 02 al 49 indicarán las distintas subdivisiones de un campo cuya
primera entrada ha sido definida a nivel 01. Los niveles 01 y 77 deberán de ir
siempre en el Area A (Col 8) el resto es independiente.

A continuación pondremos el nombre del campo, que no podrá ser ninguna palabra
cobol ni llevar ningún carácter extraño, principalmente se utilizarán letras y
números o guiones. Es posible que algún campo que definamos nunca vaya a ser
usado por el programa pero si en cambio es necesario que exista para que nos
reserve el espacio, le llamaremos FILLER.

Y finalmente podrán venir una serie de cláusulas como:

PICTURE / PIC esta palabra es la que utilizamos para identificar el tipo de datos
que va a contener la variable. Los posible valores son:

DE CAMPOS.
9 - Para campos numéricos.
A - Para campos alfabéticos.
X - Para campos alfanuméricos.
S - Indica variable con signo.
V - Indica punto decimal.

DE EDICIÓN.
$ - Representa la aparición del signo $ delante del campo numérico.
. - Indica separación de miles.
8
, - indica punto decimal. (estas dos pueden variar según hayamos
especificado en SPECIAL-NAMES DECIMAL-POINT IS COMMA).
Z - Representa un espacio para el 0 a la izquierda en campos
numéricos.
* - Igual pero se cambia el 0 por *.
B - Indica un espacio en blanco.
- ó + Indican la aparición del signo correspondiente.
Puede haber mas pero los mas utilizados son los que se han comentado.
Para indicar la longitud del campo se puede repetir el símbolo tantas veces como
longitud tenga o expresarla entre paréntesis, es decir para definir una variable
alfanumérica de 10 caracteres se pondría:
PIC X(10) o PIC XXXXXXXXXX. Los valores S y V solo pueden aparecer una vez por
cada variable.
A continuacion vamos a ver un ejemplo de todo lo que hemos explicado para que
se vaya quedando claro.
123456789012
           A     B
WORKING-STORAGE SECTION.
01  DOMICILIO.
    02  TIPO PIC XX.
    02  NOMBRE PIC X(20).
    02  NUMERO PIC 9(4).

Fijaros que hemos definido 4 variables, la primera no tiene PIC, por que indica que
está subdividida en las 3 restantes. La segunda "TIPO" nos dice que es una
variable alfanúmerica y que puede contener 2 caracteres como máximo, la
utilizariamos para guardar el tipo de calle, avenida, paseo, plaza, etc.. Para la
tercera "NOMBRE" va a ser también alfanumérica pero con una longitud máxima
de 20 caracteres y nos servirá para guardar el nombre de la calle, plaza, avenida,
etc y la última "NUMERO" indica una variable numérica de 4 dígitos, que quiere
decir que puede contener valores entre 0 y 9999.

Observad que en Cobol no se guardan las varables numéricas por bytes como
ocurre con todos los lenguajes actuales sino por número de dígitos, con ello quizás
desaprovechamos mas la memoria pero en cambio tenemos un control mejor del
dato que puede contener nuestra variable.

Si TIPO fuera "AV", NOMBRE "DE LOS DESAMPARADOS " y NUMERO "15", si nos
refiriéramos a la variable DOMICILIO ésta tendría el siguiente valor:"AVDE LOS
DESAMPARADOS 0015".

Vamos a ver algunos ejemplos mas de variables posibles:


123456789012
           A     B
WORKING-STORAGE SECTION.
77  FECHA PIC 9(8).
77  FECHA-EDIT PIC ZZ/ZZ/ZZZZ.
77  IMPORTE PIC S9(8)V99.
77  IMPORTE-EDIT PIC ZZ.ZZZ.ZZZ,ZZ-.
01  ESTADO PIC 9.
      88   SOLTERO VALUE 1.
      88   CASADO VALUE 2.
      88   DIVORCIADO VALUE 3.
Suponiendo que el valor de FECHA es 01111998 (1 Nov de 1998) y FECHA-EDIT es
el mismo, éste último se representaría: 01/11/1998.
Si IMPORTE es 12815V37 en negativo e IMPORTE-EDIT el mismo, éste se
representaría: 12.815,37-.
9

VALUE esta palabra a continuación del PIC indica el valor inicial que contendrá la
variable hasta que éste sea modificado. Por ejemplo podemos definir una variable:
123456789012
           A     B
WORKING-STORAGE SECTION.
01  RAYA PIC X(10) VALUE "----------".
01 MINOMBRE PIC X(30) VALUE "ANDRES MONTES".

Asi tendremos una variable llamada RAYA que contiene 10 guiones y otra llamada
MINOMBRE que contiene eso, mi nombre, si os fijais con ésta cláusula convertimos
cualquier variable en una constante. En cualquier momento del programa
podremos cambiar ese valor. Para las variables numéricas es conveniente ponerlas
siempre con VALUE 0 para que al empezar cada programa estemos seguros de que
no nos arrastra ningún valor. Normalmente al ejecutar un programa se ponen
todas las variables a 0, pero si ese programa ha sido llamado desde otro no pasará
eso, por eso no viene mal inicializarlas todas a 0.

REDEFINES esta cláusula se utiliza para dar mas de un nombre y formato a un


mismo campo. Este debe de ir a continuación del nombre de campo y antes del
nombre del campo a que hace referencia, deben de estar en el mismo nivel y uno
a continuación del otro en el orden de declaraciones.
123456789012
           A     B
WORKING-STORAGE SECTION.
01  DIAS PIC X(21) VALUE "LUNMARMIEJUEVIESABDOM".
01  TADIA REDEFINES DIAS.
     02 DIA PIC XXX OCCURS 7 TIMES.
He incluido la cláusula OCCURS para que sea vea un ejemplo práctico, aunque
todavía no lo he explicado, pero como veis a partir de éste momento DIAS y TADIA
tendrán siempre el mismo valor pero con diferente nombre y formato de datos.

OCCURS esta cláusula es la que se utiliza para declarar tablas. Una tabla es un
conjunto de elementos con un mismo tipo y longitud que se denominan con el
mismo nombre y se diferencian por un subíndice. No se puede especificar en
niveles 01, 77 88. Puede tener varios formatos:
123456789012
           A     B
WORKING-STORAGE SECTION.
01  NUMERO-DIAS PIC 99.
01  TABLA.
     02 DIA PIC XXX OCCURS 7 TIMES.
     02 MES PIC 99 OCCURS 28 TO 31 DEPENDING NUMERO-DIAS.
     02 OTRA PIC X(5) OCCURS 5 INDEXED BY IN-OTRA.
En la primera "DIA" indico que esa tabla va a tener 7 elementos que llamaremos
DIA (nn) y entre paréntesis el orden dentro de la tabla. Si hubiéramos guardado
en ésta tabla las 3 primeras letras de cada dia de la semana, para obtener el valor
del lunes pediriamos DIA (1), para el del Jueves DIA (4) y para el del domingo DIA
(7).
10
En la segunda "MES" le indicamos que los elementos de la tabla pueden variar
dependiendo del valor de la variable "NUMERO-DIAS" que ha de estar definida
antes de la tabla y siempre dentro de los márgenes de 28 y 31.

En la tercera le indicamos además que la variable IN-OTRA va a ser la encargada


de dirigirnos por los elementos de la tabla, ésta variable no puede estar definida
antes.

JUST la justificación de los valores de los campos suele ser a la izda. para los
alfanuméricos y a la derecha para los numéricos, si en cambio queremos cambiar
este orden tendremos que incluir ésta cláusula.
123456789012
           A     B
WORKING-STORAGE SECTION.
01  NOMBRE PIC X(10).
01  NOMBRE1 PIC X(10) JUST RIGHT.

Si le diéramos el mismo valor a las dos variables "ANDRES", la primera nos daría
"ANDRES      " y la segunda "      ANDRES", la diferencia, su justificación.

USAGE con ésta cláusula determinamos el formato en que se guarda el contenido


de las variables (numéricas, ya que las alfanuméricas siempre ocuparán un byte
por cada caracter). Con todos los campos se puede operar (obviamente) pero solo
los que se definan como DISPLAY serán editables directamente. Tiene varias
posibilidades:

 DISPLAY, es la forma por defecto e indica que cada dígito ocupará un byte,
es la que se toma por defecto y la que memoria ocupa.

 BINARY, COMP-1, COMP-3, COMP-6, son diferentes formas de


compactación de los datos. COMP-6 (la mas usual) guarda dos dígitos en
cada byte, COMP-3 es igual pero admite signo el cual iría en los cuatro
últimos bites del último byte. Las restantes formas se utilizan menos.
123456789012
           A     B
WORKING-STORAGE SECTION.
01  IMPORTE PIC 9(8). Ocupa 8 bytes uno por cada dígito.
01  FECHA PIC 9(8) COMP-6. Ocupa 4 bytes, uno cada 2 dígitos.
01  PRECIO PIC S9(8)V99 COMP-3. Ocupa 6 bytes, uno para los dos decimales,
cuatro para la parte entera y uno para el signo.

Cuando el tamaño es impar el signo no ocupa ya que comparte byte con el último
dígito, el punto decimal tampoco ocupa espacio, ya que solo indica su posición.
Estas tres formas que he utilizado son las mas comunes, yo por ejemplo como las
capacidades de los ordenadores son tan grandes ahora, cuando defino las variables
en la WORKING nunca utilizo ninguna compactación es decir no utilizo la cláusula
USAGE (que por cierto y como habreis visto se puede omitir) y por defecto toma
DISPLAY (un byte por caracter), en cambio cuando trabajo con campos de registro
de ficheros si me gusta compactar lo máximo para que el tamaño de los archivos
no se dispare.
11
LINKAGE SECTION. En ésta sección se declaran las variables de igual forma solo
que las que aqui declaremos nos van a servir de enlace para pasar información a
otro programa que será llamado por el principal.
Ejemplo:
DATA DIVISION.
FILE SECTION.
FD   CLIENTES BLOCK CONTAINS 4 RECORDS
       RECORD CONTAINS 128 CHARACTERS
       LABEL RECORD STANDARD.
01   REG-CLIENTE.
       02   KEY-CLIENTE.
       r      03   CLICOD        rPIC 9(4) COMP-6.
       02   CLINOM   PIC X(30).  
       02   CLIDIR     PIC X(30). 
       02   CLIPOB    PIC X(20).
       02   CLIPRO    PIC X(20).  
       02   CLINIF     PIC X(9).
       02   FILLER     PIC X(17).  

FD   IMPRESORA    LABEL RECORD OMITTED.


01   LINEA PIC X(132).
WORKING-STORAGE SECTION.
01  TABLA.
      02 FILLER PIC X(12) VALUE "LUNMARMIEJUE" .
      02 FILLER PIC X(9) VALUE "VIESABDOM" .
01  TABLAIDA REDEFINES TABLA.
      02 ELEDIA PIC XXX OCCURS 7 TIMES.
01   FECHA PIC 9(8).
01   IMPORTE PIC S9(8)V99.
01   VALORES.
      02 UNO PIC 99 VALUE 0.
      02 DOS PIC 9(6)
      02 TRES PIC 9(4)V99.
01 LINPA.
      02 LIMPOR PIC ZZ.ZZZ.ZZZ,ZZ-.

Como veis he diseñado el fichero CLIENTES para que cada bloque de 512
Kb, ocupe 4 registros, dejando 17 caracteres (FILLER), para una posible
ampliación del registro.
En la descripción del archivo IMPRESORA se declara una variable a nivel
01 que hace referencia al total del registro para luego ir moviendo a éste
campo el valor de lo que queramos imprimir.

En la WORKING se han declarado algunos campos con distintos


formatos, fijaros en la tabla que gracias al REDEFINES hemos llenado
con las tres primeras iniciales de cada dia, asi al referirnos a la variable
ELDIA (2) su contenido será "MAR".

Nota final:
La DATA DIVISION nos sirve para tener todas nuestras variables bien definidas, ya
sean independientes o que formen parte de algún fichero para poder operar con
ellas en la PROCEDURE DIVISION. Me acuerdo de cuando empezamos a estudiar
que para otros lenguajes no era necesaria la declaración de variables previamente
y en cambio ahora en la mayoría de los lenguajes se exige que se declaren, eso
significa que el Cobol no iba mal encaminado.

Tenemos que tener siempre muy claro que con cualquier campo podemos hacer lo
que queramos, por ejemplo si en un registro de 120 caracteres nosotros en un
12
programa solo vamos a utilizar los 40 primeros podemos definir todo lo restante
como un campo FILLER y listo o viceversa si un campo de un registro lo tenemos
definido como alfanumérico de 30 en un programa necesitamos los 10 primeros
caracteres por un lado y los veinte restantes por otro, puese nada se subdivide
para ese programa y no pasa nada.

Espero que haya quedado por lo menos medio clara la explicación de ésta tercera
DIVISION, evidentemente con la práctica es con lo que mas vamos a aprender
siempre claro está que tengamos al menos unas nociones mínimas.

Tenemos que tener en cuenta que como en todos los lenguajes, ya sean de
programación o de habla (español, inglés, frances) son muchas las opciones que
nos ofrecen pero al final siempre utilizamos las que mas nos gustan o las que
consideramos mas útiles.

Una cosa que considero importante es dar a las variables un nombre un poco
lógico que nos recuerde su contenido, por ejemplo si queremos guardar la fecha,
pues llamarla FECHA, si queremos guardar el N.I.F. del gerente, NIFGEREN, etc ...

PROCEDURE DIVISION.
PROCEDURE DIVISION. Bien, hemos llegado a la última división que existe un los programas
Cobol, en ella encontramos todos los procesos necesarios para que el programa funcione, que
haga para la que fue concebido.
Todo ésto se realiza con instrucciones (ordenes, verbos, comandos, etc..), como explicaremos a
continuación. Cada uno de ellos con un formato y una solución que resolver.

Como son muchos los verbos de que se compone el lenguaje, vamos a ver éstos divididos por
grupos: De cálculo, De archivos, De pantalla, Resto.

A continuación vamos a explicar su formato y algunas consideraciones generales aparte de las


propias instrucciones:

PROCEDURE DIVISION (USING Variable Variable ...).


DECLARATIVES.
Nombre-seccion SECTION.
USE AFTER ERROR PROCEDURE ON tipo.
Nombre-parrafo.
Sentencias.
.....
END DECLARATIVES.
Nombre-seccion SECTION.
Nombre-parrafo.
Sentencias.
.....
Este sería a groso modo el formato general de una Procedure, pero incluso se puede omitir si en
un programa no vamos a realizar ningún proceso (es obvio que siempre lo realizaremos, pero se
podría omitir). Vamos a explicar un poco su formato:
PROCEDURE DIVISION (USING Variable Variable ...).
Cuando especificamos USING en la linea de PROCEDURE DIVISION, después
deberemos de dar los nombres de variables que hayamos definido en la LINKAGE
SECTION, para compartir en el programa, lo que nos indicará que éste ha sido
llamado por otro programa y que esas variables traerán un valor procedente del
programa llamador, que a su vez utilizó la instrucción CALL con las mismas
variables.

DECLARATIVES, es una sección dentro de la PROCEDURE que nos va a servir


para controlar los posibles errores en cuanto al manejo de ficheros se refiere. La
linea de DECLARATIVES, (si se va a utilizar) deberá de ir siempre a continuación
de la linea de PROCEDURE DIVISION. Despues de subdiviría en tantas secciones
13
como opciones de error tengamos, éstas pueden ser definidas por archivo o bien
forma de apertura, es decir podremos controlar los errores que nos lleguen de un
fichero en concreto o de todos aquellos que hayan sido abiertos de de igual forma,
ésto se especifica en la linea USER AFTER ERROR PROCEDURE ON tipo, pudiendo
ser tipo, el nombre del archivo o su modo de apertura (INPUT, OUTPUT, I-O,
EXTEND). A continuación irían los párrafos con sus respectivas instrucciones a
realizar en caso de error.
Se pondrían tantos párrafos y secciones como quisieramos controlar, siempre
teniendo en cuenta que ésta se acaba cuando se indique END DECLARATIVES.
Si no quisieramos utilizar ésta sección, podriamos de igual manera controlar los
errores en nuestro programa preguntando siempre por la variable de error de cada
fichero que se definió como FILE STATUS en la FILE-CONTROL.

Nombre-seccion SECTION, a partir de aqui incluiremos todas las instucciones


necesarias para la correcta ejecución del programa.

Ya sabemos que Cobol es un lenguaje estructurado, pues bien no pensemos que la Procedure va
a ser un caos de instrucciones escritas secuencialmente, no, en ella podremos definir tantas
Secciones (SECTION) y Párrafos como queramos para organizar mejor las instrucciones y para
delimitar acciones concretas, eso si siempre se ejecutarán secuencialmente, excepto cuando
encuentre algún verbo de bifurcación como GO, PERFORM que haciendo referencia a esos
nombres de párrafo harán que se rompa la secuencia lógica de ejecución.

En las comparaciones que hagamos podremos utilizar los siguientes formatos:


MAYOR QUE
  [ (NOT) GREATER ]
  [ (NOT) > ]  
MENOR QUE
  [ (NOT) LESS ]  
  [ (NOT) < ]  
IGUAL QUE
Literal [ (NOT) EQUAL ] Literal
Variable [ (NOT) = ] Variable
MAYOR O IGUAL QUE
  [ GREATER OR EQUAL ]  
  [ >= ]  
MENOR O IGUAL QUE
  [ LESS OR EQUAL ]  
  [ <= ]  
Si se especifica (NOT) se da a entender lo contrario de la comparación, con lo que
no mayor que puede ser igual que menor o igual que.

Tambien podemos utilizar para las condiciones complejas los operandos lógicos, AND, OR y NOT
según se requieran, todas las condicionea que incluyan AND han de ser correctas para que pase
la condición, si se utiliza OR solo alguna de ellas ha de ser correcta, cuando se utilice NOT no
podrá ser correcta para que la condición sea válida.

PROCEDURE DIVISION
INSTRUCCIONES DE CALCULO. Debido a que el lenguaje Cobol fue concebido para la gestión
de grandes cantidades de datos y a resolver problemas de tipo comercial y de administración, no
se incluyeron dentro de sus especificaciones verbos que nos puedieran ayudar a resolver cálculos
complejos como integrales, trigonometría, raices cuadradas, etc..., sino simplemente las
orientadas a los cálculos básicos, suma, resta, multiplicación y división que son las que vamos a
ver a continuación:
14
add, subtract, multiply, divide, compute.

ADD, ésta es la instrucción que utilizaremos para realizar sumas y tiene los siguientes formatos:

1.- ADD variable ó literal variable ó literal ... TO variable (ROUNDED) (ON SIZE
ERROR) instrucción

2.- ADD variable ó literal variable ó literal ... GIVING variable (ROUNDED) (ON
SIZE ERROR) instrucción

3.- ADD CORR variable TO variable (ROUNDED) (ON SIZE ERROR) instrucción
Para ver las explicaciones de cada uno de los formatos partiremos de la misma WORKING, y a
continuación pondremos un ejemplo y su explicación.
...
WORKING-STORAGE SECTION.
01   VALORES.
      02 UNO PIC 99 VALUE 10.
      02 DOS PIC 9(6) VALUE 280.
      02 TRES PIC 9(4) VALUE 540.
01   OTROS
      02 OTRO1 PIC 9.
      02 DOS PIC 9(6) VALUE 110.
01 RESULTADO PIC S9(8) VALUE 10.
01 RESTO PIC 99.
PROCEDURE DIVISION.
INICIO.

Formato 1:
ADD UNO TRES 5 TO RESULTADO.
Se sumarán todas las variables o literales numéricos (cifras) al valor de la
variable que se de a continuación del TO, guardandose el resultado también
en ésta última.
Por tanto al realizar ésta operación el valor de la variable RESULTADO, será
de: 10 (de la variable UNO) + 540 (de la variable TRES) + 5 + 10 (de
Resultado) = 565.
Como veis UNO + TRES + 5 suman 555 pero ésto se suma al valor que ya
tenía la variable RESULTADO, con lo que la suma total es de 565.

Este formato se usa mucho para hacer de contador y hacer que una varable
aumente en uno su valor poniendo:
ADD 1 TO RESULTADO.

Formato 2:
ADD UNO TRES 5 GIVING RESULTADO.

En éste caso la variable RESULTADO tendrá el valor de la suma de las


variables anteriores, sin tener en cuenta su valor inicial, es decir, será de:
10 (de la variable UNO) + 540 (de la variable TRES) + 5 = 555.

Formato 3:
ADD CORR VALORES TO OTROS.

Con éste formato conseguimos que las variables del campo compuesto
VALORES se sumen al valor de las variables con el mismo nombre del
campo compuesto OTROS, obteniendo como resultado: 280 (de la variable
DOS del campo VALORES) + 110 (de la variable DOS del campo OTROS) =
15
390.
Si hubiera coincidido alguna variable mas con el mismo nombre en ambos
campos también se hubiese sumado.

Nota: Como habreis podido apreciar pueden coexistir variables con el


mismo nombre pero nunca al nivel 01 o 77, es decir nunca como variables
independientes, pero si que formen parte de otra, aunque yo personalmente
nunca lo uso porque solo puede dar lugar a confusiones. Si de todas formas
lo utilizais, hay que tener en cuenta que para referirse a éstas variables no
solo bastará con poner su nombre, sino que además habrá que especificar a
que campo pertenece con la palabra IN u OF. Esto se explicará con mas
detalle cuando veamos los verbos para manipular variables como MOVE.

SUBTRACT, ésta es la instrucción que utilizaremos para realizar restas y tiene los siguientes
formatos:
1.- SUBTRACT variable ó literal variable ó literal ... FROM variable (ROUNDED)
(ON SIZE ERROR) instrucción

2.- SUBTRACT variable ó literal variable ó literal ... FROM variable ó literal
GIVING variable (ROUNDED) (ON SIZE ERROR) instrucción

3.- SUBTRACT CORR variable FROM variable (ROUNDED) (ON SIZE ERROR)
instrucción
Para ver las explicaciones de cada uno de los formatos partiremos de la misma WORKING que
hemos utilizado con la instrucción ADD, poniendo a continuación un ejemplo y su explicación.

Formato 1:
SUBTRACT UNO TRES 5 FROM RESULTADO.

Se restarán todas las variables o literales numéricos (cifras) del valor de la


variable que se de a continuación del FROM, guardandose el resultado
también en ésta última.
Por tanto al realizar ésta operación el valor de la variable RESULTADO, será
de: -10 (de la variable UNO) - 540 (de la variable TRES) - 5 + 10 (de
Resultado) = -545.
Como veis se le han restado los valores de UNO, TRES y 5 que suman -555
pero como RESULTADO valía +10, éste se suma y da un valor de -545.

Este formato lo podemos utilizar para hacer contadores en retroceso,


poniendo:
SUBTRACT 1 FROM RESULTADO.

Formato 2:
SUBTRACT UNO 5 FROM TRES GIVING RESULTADO.

Aquí lo que conseguiremos será restar el valor de la variable UNO y 5 del


valor de la variable TRES y el resultado guardarlo en la variable
RESULTADO, sin tener en cuenta su valor inicial, es decir, será de: 540 (de
la variable TRES) - 10 (de la variable UNO) - 5 = 525.

Formato 3:
SUBTRACT CORR VALORES FROM OTROS.

Al igual que con la instrucción ADD, con éste formato conseguimos que las
variables del campo compuesto VALORES se resten al valor de las variables
16
con el mismo nombre del campo compuesto OTROS, obteniendo como
resultado: 280 (de la variable DOS del campo VALORES) - 110 (de la
variable DOS del campo OTROS) = 170.
Si hubiera coincidido alguna variable mas con el mismo nombre en ambos
campos también se hubiese restado.

Nota: Tened en cuenta que al utilizar restas el signo puede ser negativo y si
no tenemos bien declarada la variable que va a contener el resultado, ésta
cojerá su valor absoluto.

MULTIPLY, ésta es la instrucción que utilizaremos para realizar multiplicaciones y tiene los
siguientes formatos:
1.- MULTIPLY variable ó literal BY variable (ROUNDED) (ON SIZE ERROR)
instrucción

2.- MULTIPLY variable ó literal BY variable ó literal GIVING variable


(ROUNDED) (ON SIZE ERROR) instrucción
Utilizando la misma WORKING que hemos utilizado con las instrucciones ADD y SUBTRACT,
veremos a continuación unos ejemplos y su explicación.

Formato 1:
MULTIPLY 5 FROM RESULTADO.

Multiplica el número 5 por el valor de la variable RESULTADO, guardando en


ésta misma el resultado de la operación que será: 5 x 10 (de la variable
RESULTADO) = 50.

Formato 2:
MULTIPLY 5 BY TRES GIVING RESULTADO.

Aquí multiplicaremos el número 5 por el valor de la variable TRES


guardando el resultado en la variable RESULTADO, sin tener en cuenta su
valor inicial, es decir, será de: 5 x 540 (de la variable TRES) = 2700.

DIVIDE, ésta es la instrucción que utilizaremos para realizar divisiones y tiene los siguientes
formatos:
1.- DIVIDE variable ó literal INTO variable (ROUNDED) (ON SIZE ERROR)
instrucción

2.- DIVIDE variable ó literal (BY ó INTO) variable ó literal GIVING variable
(ROUNDED) (REMAINDER) variable (ON SIZE ERROR) instrucción
Utilizando la misma WORKING que hemos utilizado con las instrucciones ADD y SUBTRACT,
veremos a continuación unos ejemplos y su explicación.

Formato 1:
DIVIDE 10 INTO TRES.

Divide el valor de la variable TRES entre el número 10, guardando el


resultado en la variable TRES: 540 (de la variable TRES) / 10 = 54.

Formato 2:
DIVIDE 7 INTO TRES GIVING RESULTADO REMAINDER RESTO.
17
Aquí dividiremos el valor del la variable TRES entre 7 guardando el
resultado en la variable RESULTADO, sin tener en cuenta su valor inicial, y
además el resto de la operación lo guardará en la variable RESTO,
quedando así: 540 / 7 = 77, pero como 7 x 77 son 539 el resto es 1 que
será el valor de RESTO.
Si en vez de utilizar INTO utilizamos BY cambia el orden de los operandos,
es decir en vez de dividir TRES entre 7 dividiríamos 7 entre TRES.

La opción REMAINDER no es obligatoria, todo dependerá del uso que


queramos hacer de la instrucción.

COMPUTE, con ésta orden podemos realizar todos los cálculos aritméticos posibles en una sola
instrucción, utilizando los operadores +(suma) -(resta) *(multiplicación) /(división)
**(potenciación), además de utilizar paréntesis para especificar mejor la operación a realizar.
1.- COMPUTE variable (ROUNDED) = expresión aritmética (ON SIZE ERROR)
instrucción
Utilizando la misma WORKING que hemos utilizado anteriormente vamos a ver un ejemplo:

Formato 1:
COMPUTE RESULTADO = DOS OF VALORES * 16 / 100.

El valor de la variable RESULTADO será de 44, obtenido después de


multiplicar 280 (de la variable DOS del grupo VALORES) x 16 y lo que de
dividido entre 100.
En realidad si hacemos el cálculo en una calculadora nos daremos cuenta
que el resultado exacto es 44,80 pero como la variable RESULTADO no la
hemos definido con decimales éstos son depreciados por el compilador.

Puesto que la variable DOS pertenece a dos grupos de variables deberemos


especificar a que grupo pertenece (OF VALORES).

Debemos de tener en cuenta que siempre tienen preferencia los operadores


que vayan entre paréntesis, a continuación los de multiplicación y división
(*) y (/) y por último los de suma y resta (+) y (-) y el orden en que va a ir
realizando las operaciones será de izquierda a derecha, por lo tanto:

COMPUTE RESULTADO = 2 + 3 * 5.

Esta operación daría como resultado 3*5=15+2=17.


COMPUTE RESULTADO = (2 + 3) * 5.

En cambio ésta otra daría: 2+3=5*5=25.


Espero que hayais notado la diferencia y la podais aplicar a vuestros casos
en concreto.

Para todas éstas instrucciones de cálculo que hemos visto la opcion ROUNDED significa lo mismo
y quiere decir que fuerza al redondeo del resultado para cada operación y siempre teniendo en
cuenta la definición de la variable que va a guardar ese resultado, por ejemplo si tras una
operación resulta 18,76 éste podría quedar como sigue:
 77 RESULTADO PIC 99V99. (valor = 18,76)

 77 RESULTADO PIC 99V9. (valor sin redondeo = 18,7 - valor con redondeo
= 18,8)

 77 RESULTADO PIC 99. (Valor sin redondeo = 18 - valor con redondeo =


19).
18
Igual ocurre con la frase ON SIZE ERROR instrucción, que propiciará que se ejecute la instrucción
que pongamos a continuación cuando se produzca un desbordamiento del campo que va a
acoger el resultado, por ejemplo si el resultado de una operación es 8.976.400 y la variable la
hemos definido con PIC 9(6) y hemos especificado dicha opción se ejecutará la instrucción
especificada.

PROCEDURE DIVISION
INSTRUCCIONES DE ARCHIVOS. Sin duda son las instrucciones mas importantes con las que
cuenta el lenguaje Cobol, con ellas tendremos la oportunidad de manipular toda la información
contenida en nuestros archivos, es decir, podremos abrir archivos, cerrarlos, leerlos, guardar
información nueva o modificar datos existentes. Todo ésto lo haremos con las instrucciones que
voy a explicar a continuación:

open, close, read, write, rewrite, delete, start.

Antes de empezar a explicar éstas instrucciones me gustaría que entendiéseis bien algunos
conceptos como fichero, registro y campo, para que podais comprender mas claramente, la
explicación de todas las instrucciones que se verán en ésta sección.

 ¿Que es un fichero? Podríamos definir un fichero como un conjunto de registros, pero


estaríamos mas o menos igual. Si comparásemos un fichero de cobol con nuestra vieja
agenda de teléfonos, para cada amigo tendríamos los mismos datos, es decir, nombre,
teléfono, dirección, etc ... cada uno de esos datos es lo que llamamos campo y el
conjunto de todos esos campos para cada amigo sería un registro. Ahora podemos
comprender mejor que un fichero o archivo es un conjunto de registros, como una agenda
es un conjunto de datos de amigos.

 ¿Que es una clave? Una clave, es un campo de nuestra agenda que nos sirve para
identificar a cada amigo, en la agenda normal la clave podría ser la lengüeta con la letra
del abecedario correspondiente a los apellidos del amigo. Informáticamente es mas
completa y con ella podremos identificar a cada uno de ellos, por ejemplo con su nombre
o su teléfono o un código que le asignemos nosotros personalmente.
Ahora quizás entendais mejor el resto, si veo alguna aclaración necesaria, ampliaré este párrafo.

OPEN, ésta es la instrucción que utilizaremos para abrir un archivo, o lo que es lo mismo hacerlo
disponible para operar sobre el, obviamente éste archivo debe de haberse descrito en la
Environment y la Data según se explicó, su formato es el siguiente:
OPEN (EXCLUSIVE) modo nombre de archivo (WITH LOCK) (WITH NO
REWIND)
Donde modo, indica como se abrirá el archivo y puede tener los siguientes valores según su
utilización:
 INPUT, el archivo se abrirá solo para lectura, es decir no podremos grabar
ni modificar datos del mismo.

 I-O, el archivo se abrirá como lectura y escritura, con lo cual tendremos


acceso a toda la información de dicho archivo para leerla, escirbirla,
reescribirla o borrarla.

 OUTPUT, el archico se abre solo para escritura, es el formato que se utiliza


en los achivos de impresión y secuenciales. Tiene la particularidad que crea
el fichero nuevo cada vez que se utiliza, por lo tanto hay que tener cuidado
con archivos Indexados.

 EXTEND, igual que el anterior pero no crea el archivo, sino que la


información se va añadiendo a la ya existente. Se utiliza para archivos
secuenciales.
Las opciones EXCLUSIVE y WITH LOCK, nos indica cuando trabajamos en
multipuesto que éste archivo estará bloqueado, es decir que no estará disponible
19
para otros usuarios. El hecho de que existan dos opciones para lo mismo es por
compatibilidad con versiones anteriores.
La opción WITH NO REWIND, se utiliza cuando utilizamos archivos de cinta, para
que no la rebobine al abrirla.
 
...
PROCEDURE DIVISION.
INICIO.
       OPEN INPUT ARTICULOS.
       OPEN I-O CLIENTES
       OPEN EXTEND IMPRE.
CREAR-ARCHIVO.
       OPEN OUTPUT TRABAJO CLOSE TRABAJO.
...

Nota: Con éstas tres instrucciones estamos abriendo tres archivos, cada
uno de una forma diferente. Tambien podriamos haberlos puesto en una
sola linea de la siguiente forma:
     OPEN INPUT ARTICULOS I-O CLIENTES EXTEND IMPRE.

En el caso del archivo TRABAJO, se consigue crearlo como nuevo, exista


antes o no.

CLOSE, ésta es la instrucción contraria a OPEN, es decir termina la conexión establecida con el
archivo, a partir del momento que aparezca ésta instrucción el archivo no estará disponible para
operar con él, hasta la próxima vez que se abra. Obviamente antes de cerrarlo debe de estar
abierto.
CLOSE nombre de archivo (WITH LOCK) (WITH NO REWIND)
El nombre de archivo corresponderá a algún archivo abierto anteriormente.
Las opciones WITH LOCK y WITH NO REWIND, tienen la misma explicación que la vista en la
orden OPEN.
 
...
PROCEDURE DIVISION.
INICIO.
       OPEN INPUT ARTICULOS.
       OPEN I-O CLIENTES
       OPEN EXTEND IMPRE.
...
...
...
CERRAR.
       CLOSE ARTICULOS CLIENTES IMPRE.
...

Nota: Apuntaré que si finalizamos el programa con la sentencia STOP RUN,


que luego veremos, los archivos que esttuvieran abiertos se cierran
automáticamente aunque no se haya especificado la orden CLOSE. Anque
siempre es preferible utilizarla, ya que puede haber algunos compiladores
mas antiguos que no los cierren.
Me gustraría destacar de éstas dos instrucciones vistas que lo mas normal
es no utilizar ninguna de las opciones, es decir solo abrir de una manera el
archivo para su uso y una vez hayamos acabado con él, cerrarlo.

READ, es la instrucción que utilizamos para leer registros de un archivo, debe de estar abierto.
Con ella conseguimos que los datos referentes al registro accedido queden en la descripción de
20
dicho fichero, es decir, conseguimos que los campos declarados en la FD, tengan el valor
correspondiente al registro leido.
La sentencia READ, se utiliza para leer ficheros secuanciales o indexados, o para leer indexados
de manera secuencial, por lo que su sintaxis tiene dos formatos principales.
Formato para leer ficheros de manera secuncial. (Indexados o secuenciales)
READ nombre de archivo (NEXT/PREVIOUS RECORD) (INTO descripción) (AT
END / NO AT END sentencia) END-READ

nombre de archivo corresponderá a algún archivo abierto anteriormente.

La opción NEXT RECORD, indica que se va a leer el siguiente registro y es la que


se toma por defecto, ya que, cuando estamos leyendo un archivo de forma
secuencial, éste leerá registros uno tras otro, hasta llegar al final.

La opción PREVIOUS RECORD leería el registro anterior. Esta opción es la única


que no es válida para ficheros secuenciales de éste formato.

La opción INTO, indica cual de las descripciones de registro que hayamos podido
declarar será la que almacene los datos del registro leido. Tenemos que tener en
cuenta que Cobol nos permite mantener mas de una descripción de registro para
un mismo archivo. Si tuvieramos mas de una, ésta sería la opción para indicarle
cual es la que queremos utilizar en ésta lectura.

La sentencia que va después de AT END, indica que debe de hacer el programa al


llegar al final del fichero. Puede ser cualquier orden de cobol, pero es evidente que
si volvemos a leer una vez llegado al final, producirá un error.
...
PROCEDURE DIVISION.
INICIO.
       OPEN INPUT ARTICULOS.
LECTURA.
      READ ARTICULOS NEXT RECORD AT END GO CERRAR.
...
...
...
      GO LECTURA.
CERRAR.
       CLOSE ARTICULOS.
...

Nota: Si bien este formato nos sirve para leer cualquier tipo de archivo de
manera secuencial, en el caso de que el archivo fuera secuencial, éste solo
se podría leer así.
Existen muchas ocasiones en que un archivo indexado nos interesa leerlo de
manera secuencial. Si lo hicieramos éste sería su formato, además en éste
caso podriamos leerlo tanto del principio al final con la opción NEXT, como
del final al principio con la opción PREVIOUS.

Para poder leer un fichero indexado de manera secuencial, deberemos de


haber especificado en la SELECT, que su acceso va a ser DYNAMIC o
SEQUENTIAL.

Formato para leer ficheros indexados con acceso aleatorio.


READ nombre de archivo (INTO descripción) (KEY nombre de clave) (INVALID
KEY / NOT INVALID KEY sentencia) END-READ

Las opciones que se repiten con con el formato anterior tienen el mismo formtato y
producen el mismo resultado.
21
La opción KEY, indica por que clave se va a leer el fichero, siempre que éste tenga
mas de una.

La sentencia después de INVALID KEY se utiliza para ejecutar una acción cuando
se intenta acceder a un registro que no existe. En el caso de utilizar NOT INVALID
KEY sería al contrario, es decir cuando el registro existe.
...
PROCEDURE DIVISION.
INICIO.
       OPEN INPUT ARTICULOS.
LECTURA.
      MOVE 100 TO CLAVE-ARTICULO.
      READ ARTICULOS INVALID KEY GO ERROR.
...
...
...
      GO LECTURA.
ERROR.
...
...
CERRAR.
       CLOSE ARTICULOS.
...

Nota: Sin duda la forma mas usual de acceder a un registro será por su
clave. Asi por ejemplo para acceder a un fichero de poblaciones cuya clave
fuera su código postal, dando cualquier código accederiamos a ese registro
en concreto.
La acción que hagamos después de un INVALID KEY, dependerá del
contexto en que se encuentre, podremos volver a solicitar otra clave,
permitir crear un registro, etc ..

WRITE, con ésta instrucción se consigue grabar la información contenida en ese momento en los
campos del registro de un fichero. Es decir, si introducimos una ficha nueva en la agenda con los
datos de un nuevo amigo, ésta instrucción será la que nos sirva para almacenar en el fichero los
datos. A partir de ese momento estarán disponibles tantas veces como queramos para leerla. Y
por supuesto el fichero debe de estar abierto como OUTPUT o I-O.
WRITE nombre de registro (FROM descripción) (INVALID KEY / NOT INVALID
KEY sentencia)
END-WRITE

La opción FROM, indica con cual de las descripciones de registro que hayamos
podido declarar se graben los datos en el fichero. Hay que señalar que ésta
descripción puede estar definida en la WORKING, y lo que nos ahorra en realidad
es mover los datos de esa descripción que hemos usado como "temporal" a la
auténtica descripción del registro.

Las cláusulas de INVALID KEY y NOT INVALID KEY, tienen la misma función dada
en la instrucción READ. Solo que aqui, INVALID KEY, se produciría cuando al
grabar el registro, éste ya existiese o hubiera algún error por el cual no se
pudieran grabar los datos.
...
PROCEDURE DIVISION.
INICIO.
       OPEN I-O ARTICULOS.
LECTURA.
      MOVE 100 TO CLAVE-ARTICULO.
      MOVE "ANDRES MONTES" TO NOMBRE.
22
      WRITE REGISTRO-ARTICULO INVALID KEY GO ERROR.
...
...
      GO CERRAR.
ERROR.
...
...
CERRAR.
       CLOSE ARTICULOS.
...

Nota: Aunque se puedan utilizar varias descripciones, lo mas lógico es


utilizar siempre la misma para cada fichero.
El error mas probable siempre que sea una INVALID KEY, suele ser que
existe un registro ya con esa clave, a parte de ese, falta de espacio en
disco, archivo mal abierto o sin abrir.

Además de éste formato, existe para ésta instrucción otro muy común. Y es el que utilizamos
para enviar datos a la impresora, es decir para listar, para imprimir.
Es en éste caso, donde se hace indispensable el uso de mas de una descripción por registro.
¿Porque? Sencillo, definiremos nuestro fichero con un registro de tamaño igual al ancho de
nuestro listado, y luego en la WORKING, describiremos el formato de cada una de las lineas que
utilizaremos en la impresión. Quiero hacer un ejemplo mas extenso para éste caso, que será
muy utilizado y distinto en su filosofía al resto.
WRITE nombre de registro (FROM descripción) (AFTER número de lineas)(PAGE)
END-WRITE

Además para éste formato tendremos la cláusula AFTER, en la cual indicamos el


número de lineas que debe de avanzar la impresora antes de escribir, o bien que
lo haga directamente al principio de la siguiente página, poniendo AFTER PAGE.
Existen algunas otras cláusulas, pero no las vamos a ver aquí por ser poco usadas.
IDENTIFICATION DIVISION.
PROGRAM-ID. LISTADO.
ENVIRONMENT DIVISION.
CONFIGURATION SECTION.
        DECIMAL-POINT IS COMMA.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
        SELECT IMPRESORA ASSIGN TO PRINT "LPT1".
DATA DIVISION.
FILE SECTION.
FD  IMPRESORA  LABEL RECORD OMITTED.
01  REG-IMPRE   PIC X(80).
WORKING-STORAGE SECTION.
01   LINEA1.
       02  FILLER PIC X(30) VALUE SPACES.
       02  FILLER PIC X(20) VALUE "ESTA ES LA LINEA 1".
01  LINEA2.
       02  FILLER PIC X(30) VALUE SPACES.
       02  FILLER PIC X(20) VALUE "ESTA ES LA LINEA 2".
...
...
PROCEDURE DIVISION.
INICIO.
       OPEN OUTPUT IMPRESORA
ESCRIBIR.
      WRITE REG-IMPRE FROM LINEA1 AFTER PAGE.
      WRITE REG-IMPRE FROM LINEA2 AFTER 2.
23
...
...
CERRAR.
       CLOSE IMPRESORA.
...

Nota: Como podeis ver, hemos definido el registro como REG-IMPRE, pero
al escribir sobre el fichero impresora utilizamos las descripciones de LINEA1
y LINEA2, de ésta manera conseguimos que se impriman las dos lineas en
una impresora conectado al puerto LPT1 y que antes de escribir la primera
linea, salte a una página en blanco.

REWRITE, ésta instrucción se utiliza para regrabar datos de un registro ya existente. Toda la
sintaxis es exactamente igual que la explicada en WRITE.
REWRITE nombre de registro (FROM descripción) (INVALID KEY / NOT
INVALID KEY sentencia) END-REWRITE

Todas las opciones igual que en WRITE. Por lo que en el ejemplo vamos a ver
ambos casos juntos.
...
PROCEDURE DIVISION.
INICIO.
       OPEN I-O ARTICULOS.
LECTURA.
      MOVE 100 TO CLAVE-ARTICULO.
      MOVE "ANDRES MONTES" TO NOMBRE.
      WRITE REGISTRO-ARTICULO INVALID KEY GO ERROR.
      MOVE "OTRO NOMBRE" TO NOMBRE.
      REWRITE REGISTRO-ARTICULO INVALID KEY GO ERROR.
...
...
      GO CERRAR.
ERROR.
...
...
CERRAR.
       CLOSE ARTICULOS.
...

Nota: Podemos decir que ésta sentencia es la que utilizaremos para


modificar el contenido de cualquier registro, pero eso si, nunca podremos
alterar la clave, solo los campos que no formen parte de la clave principal.
Si quisieramos modificar cualquiera de los campos clave de un registro,
deberíamos crear uno nuevo con el mismo contenido pero con la clave que
ahora queramos y luego borrar el que teníamos.

DELETE, instrucción para borrar un registro de un fichero. La explicación es corta, pero tiene
pocos mas matices, lo que conseguimos es borrar todos los datos de un registro. Su sintaxix es
la siguiente:
DELETE nombre de fichero (INVALID KEY / NOT INVALID KEY sentencia)
END-DELETE

Las únicas cláusulas INVALID y NOT INVALID KEY, se usan exactamente igual que
en las demás relativas a ficheros, es decir ejecutará la sentencia que pongamos a
continuación cuando una de las condiciones se cumpla, que la clave exista o que
no exista.
24
Si nos fijamos vemos que la gran diferencia está en que aquí la orden hace
referencia al nombre del fichero y no al del registro, como en las instrucciones
anteriores.
...
PROCEDURE DIVISION.
INICIO.
       OPEN I-O ARTICULOS.
LECTURA.
      MOVE 100 TO CLAVE-ARTICULO.
      READ ARTICULOS INVALID KEY GO ERROR.
      DELETE ARTICULOS INVALID KEY GO ERROR.
...
...
      GO CERRAR.
ERROR.
...
...
CERRAR.
       CLOSE ARTICULOS.
...
...
Nota: Obviamente para borrar un registro, primero hemos de tenerlo en
memoria, por eso en el ejemplo lo he leido primero.

START, ésta instrucción es de suma importancia en el tratamiento de ficheros, y nos sirve para
posicionarnos en cualquier parte del mismo, para una lectura mas rápida. Si imaginamos un
fichero con 10.000 clientes, clasificados por código, para ver todos los que cuyo código es mayor
a 9.000,  tendríamos que leernos el fichero secuencialmente hasta llegar al sitio correcto, en
cambio con ésta orden, podremos colocarnos en la posición del fichero que queramos dentro de
unas normas, que veremos a continuación.
START nombre de fichero KEY (expresión) nombre de clave (INVALID KEY /
NOT INVALID KEY sentencia) END-START

Las únicas cláusulas INVALID y NOT INVALID KEY, se usan exactamente igual que
en las demás relativas a ficheros, es decir ejecutará la sentencia que pongamos a
continuación cuando una de las condiciones se cumpla, que la clave exista o que
no exista.

Si nos fijamos vemos que la gran diferencia está en que aquí la orden hace
referencia al nombre del fichero y no al del registro, como en las instrucciones
anteriores.

La expresión a la que se hace referencia en la sintaxis, pueden ser las siguientes:

 LESS (<) menor que.

 NOT LESS (NOT <) no menor que.

 EQUAL (=) igual a.

 GREATER (>) mayor que.

 NOT GREATER (NOT >) no mayor que.

 GREATER OR EQUAL (>=) mayor o igual que.

 LESS OR EQUAL (<=) menor o igual que.

 FIRST principio de fichero (RM/COBOL).

 LAST final del fichero (RM/COBOL).


25
...
PROCEDURE DIVISION.
INICIO.
       OPEN I-O ARTICULOS.
COLOCAR.
      MOVE 100 TO CLAVE-ARTICULO.
      START ARTICULOS KEY NOT LESS KEY CLAVE-ARTICULOS
       INVALID KEY GO ERROR.
LECTURA.
      READ ARTICULOS NEXT RECORD AT END GO CERRAR.
      ...
      GO LECTURA.
ERROR.
...
...
      GO CERRAR.
ERROR.
...
...
CERRAR.
       CLOSE ARTICULOS.
...
...
Nota: Aqui empezariamos a leer el ficher artículos desde la clave que no
sea menor que 100, es decir de 100 en adelante. Fijaros como luego la
lectura se hace en otro párrafo diferente, ya que sino, siempre estariamos
haciendo el START. Recordad que con ésta instrucción SOLO nos situamos
en un sitio determinado del fichero, a partir de ahí podremos operar como
queramos.

RESUMIENDO
En la programación estructurada es conveniente sustituir el punto como final de una instrucción
por la cláusula END-....... para cada instrucción. De esta manera conservamos la estructura y no
obligamos con el punto a finalizar ninguna instrucción o bucle en el que estemos metidos.
Una vez vistas todas las intrucciones relativas a ficheros, quiero dejar bien claro su utilización.
Tendremos siempre en cuenta que cuando leemos, realmente le damos el valor del registro que
hemos leido a los campos o variables que lo componen. Que cuando grabamos o regrabamos, le
estamos dando el valor de las variables en ese momento al registro para que se grabe en disco y
cuando borramos, estamos quitando fisicamente del disco esa información.

PROCEDURE DIVISION
INSTRUCCIONES DE PANTALLA Y MOVIMIENTO. Sin duda alguna e independientemente del
lenguaje de programación escogido, las instrucciones que mas se suelen utilizar, serán las que
hagan uso de la pantalla, ya sea como salida o entrada de información.

Para la programación en Windows, pondré la información en la sección Programando en


Windows, en cuanto tenga todo preparado, la podréis consultar.

Vamos a utilizar ésta sección para hacer un análisis profundo de dichas instrucciones.

accept, display.

ACCEPT, es la instrucción que usaremos para la entrada de datos. Aunque su sintaxis principal
nunca ha variado, ésta ha sido una de las instrucciones que mas cláusulas se le han ido
añadiendo, incluso diferentes según el compilador, aquí vamos a explicar las comunes y
principales.
26
Aunque la forma mas usual de utilizarla, es para aceptar datos por el teclado, también es posible
utilizarla para "cogerlos" también del sistema, para aceptar valores de variables de entorno
definidas previamente a nivel de sistema o para aceptar pantallas completas definidas en la
SCREEN-SECTION. Además siguen aumentando sus posibilidades. Veamos sus formatos
principales:

Formato para aceptar datos del sistema o variables de entorno.

ACCEPT variable FROM (DATE, DAY, DAY-OF-WEEK, TIME, CENTURY-DATE,


CENTURY-DAY, ESCAPE-KEY, ENVIRONMENT variable de entorno)
Según la opción escogida, así será el valor que contendrá la variable usada, una vez completada
la sentencia. Veamos cada una de las opciones: 
 DATE, devuelve la fecha en formato AAMMDD, por lo que la variable debe
de estar definida con PIC 9(6).

 CENTUY-DATE, igual que DATE, pero acepta la fecha con 8 dígitos en


formato SSAAMMDD. Definir con PIC 9(8).

 DAY, devuelve el año y el día del año en que estamos con el formato
AADDD, siendo el valor 1, para el 1 de Enero y así sucesivamente. Debe de
estar definida con PIC 9(5).

 CENTURY-DAY, igual que DAY, pero acepta 4 dígitos para el año, quedando
el formato AAAADDD. Definir con PIC 9(7).

 DAY-OF-WEEK, devuelve un dígito que indica el día de la semana, siendo 1


el Lunes, 2 el Martes, ... Aquí, la variable debe de estar definida como PIC
9.

 TIME, devuelve la hora con formato HHMMSSMM, la variable debe de estar


como PIC 9(8).

 ESCAPE-KEY, devuelve el código de la tecla de excepción pulsada, debe de


estar definida con PIC 99 y según el compilador los valores pueden ser
distintos, pero los básicos suelen ser los mismos, por ejemplo: ENTER=13,
FLECHA ARRIBA=52, FLECHA-ABAJO=53 y las teclas de función desde F01
hasta F10 tomarían los valores del 1 al 10.

 ENVIRONMENT "Variable de entorno", nos devuelve el valor que dicha


variable tenga asignado, normalmente éstas variables se asignan en el
fichero de configuración del compilador o desde una variable del sistema.
Puede ser muy útil para darle capacidades a usuarios diferentes por
ejemplo. Tener en cuenta que la variable de entorno debe de ir entre
comillas para que sea reconocida.
La definición de la variable que he dado, no es fija, pero si la mas conveniente, es
decir para guardar el dia de la semana, he indicado una variable con PIC 9, pero
podíamos haber escogido PIC 9(8), lo que pasa, es que no tendría mucho sentido
malgastar espacio, cuando sabemos con seguridad, que el dato posible es de 1 a
7, y por lo tanto de PIC 9.
Además de todas éstas opciones, cada compilador ha ido incorporando las que ha
creido conveniente y por ejemplo con algunas de las nuevas es posible saber
información sobre el sistema sobre el que trabajamos, el terminal, la línea, etc ....
...
WORKING-STORAGE SECTION.
77  DIA  PIC 9.
77  FECHA PIC 9(6).
77  FECHA8 PIC 9(8).
...
PROCEDURE DIVISION.
INICIO.
27
       ACCEPT DIA FROM DAY-OF-WEEK.
       ACCEPT FECHA FROM DATE.
       ACCEPT FECHA8 FROM CENTURY-DATE.
...

Nota: Si usarames éste programa el día 1 de Julio de 1.999, el valor de las


variables sería:
     FECHA=990701.
     FECHA8=19990701
     DIA=4.

El 4 nos indicaría que el día de la semana sería Jueves.


Formato para aceptar datos por el teclado.
ACCEPT variable CLAUSULAS ... ON EXCEPTION variable instrucción. 
La lista de cláusulas es muy larga, y por desgracia algunos compiladores pueden
tener mas que otros, así que voy a explicar las mas comunes a continuación:
Recordad que lo que se explica aquí puede ser válido tanto para ACCEPT como
para DISPLAY.

 LINE variable, constante numérica,(ACCEPT Y DISPLAY) le indicamos la


línea donde se aceptará el campo, puede ser una variable o un número,
tendremos siempre en cuenta que la línea 1 será la primera de arriba de la
pantalla, normalmente podremos trabajar con 24 líneas. Si no se específica
tomará la referencia de la siguiente línea en la que estemos.

 COLUMN, COL, POSITION variable, constante numérica,(ACCEPT Y


DISPLAY)  aquí le indicamos la columna dentro de la línea y sus valores
pueden ser desde 1 (izquierda) hasta 80 (derecha) de la pantalla. En
algunos terminales es posible capturar 132 columnas. Si no se especifica
tomará el valor 1.

 BEEP, NO BEEP, (ACCEPT Y DISPLAY) con ésta opción le indicamos si


queremos o no que emita un pitido al llegar al comando. Por defecto
sonará.

 BLINK, (ACCEPT Y DISPLAY) si aparece ésta cláusula, el campo que


aceptemos parpadeará.

 HIGH, LOW, OFF, (ACCEPT Y DISPLAY) le indicamos el nivel de


luminosidad con que se acepta el campo, solo puede ir especificado uno:
HIGH con brillo, LOW sin brillo, OFF hace que los datos que introducimos no
se vean, se utiliza cuando queremos aceptar una contraseña o alguna
clave, en la pantalla no salen los datos que vamos introduciendo. Si no
indicamos ninguna el sistema coge HIGH por defecto.

 TAB, (ACCEPT) la presencia de ésta cláusula hace que no salte al siguiente


campo hasta que no pulsemos ENTER. Por defecto al introducir el número
de caracteres o dígitos del campo salta automáticamente.

 TIME variable, constante numérica, (ACCEPT) conseguiremos que la espera


para introducir el campo sea limitada y vendrá dada por el valor que le
asignemos. El valor se indica en centésimas de segundo.

 CURSOR variable, (ACCEPT) si especificamos ésta cláusula, el sistema


guardará en la variable la posición donde se ha terminado la introducción
de los datos. Por ejemplo si aceptamos un campo de PIC X(40) y solo
rellenamos 9 caracteres, el valor de la variable asociada a CURSOR será de
10. 

 ERASE, haremos que se borra toda la pantalla.


28
 ERASE EOL, (ACCEPT Y DISPLAY) le indicamos que borre la línea sobre la
que estamos desde la posición del ACCEPT.

 ERASE EOS, (ACCEPT Y DISPLAY) le indicamos que borre toda la página


desde la posición de la línea en la que estamos.

 PROMPT carácter, (ACCEPT) conseguimos que rellene con algún carácter


específico o por defecto el cursor bajo (_) la longitud del campo que vamos
a aceptar. Es bastante útil ya que el usuario puede ver claramente la
longitud del campo.

 ECHO, (ACCEPT) con ésta cláusula hacemos que vuelva a "pintar" el


contenido del campo después de aceptado. Es decir si le hemos puesto
PROMPT ECHO, mientras se acepta saldrán los guiones bajos para indicar el
tamaño pero al salir del campo se volverá a displayar y éstos guiones
desaparecerán.

 REVERSE, (ACCEPT Y DISPLAY) conseguimos que el campo que aceptamos


se vea en video inverso, si normalmente es blanco sobre negro, se hará
negro sobre blanco, y si tenemos otros colores, pues en su color inverso.

 SIZE variable, constante numérica, (ACCEPT) variamos el tamaño de la


variable que teníamos declarado. Por ejemplo si definimos una variable con
PIC X(40) y le indicamos al aceptarla SIZE 10, solo aceptará 10 caracteres
para esa variable.

 CONVERT, (ACCEPT Y DISPLAY) con ésta cláusula conseguimos que si


estamos aceptando un campo numérico o alfabético, e introducimos un
valor no aplicable, lo ignore. Por ejemplo si introducimos una letra en un
campo numérico será ignorada si CONVERT aparece.

 UPDATE, (ACCEPT) hace que el valor actual del campo aparezca y al


aceptar podamos modificar sobre su contenido actual. Es muy aconsejable
cuando estamos modificando datos.

 CONTROL tipo de control, (ACCEPT Y DISPLAY) ésta cláusula es bastante


amplia y en ella podemos atribuir otras opciones como caracteres gráficos,
colores, etc.. Su uso puede variar según los compiladores. Mas abajo
encontrareis mas información.

 ON EXCEPTION variable instrucción (ACCEPT) si al aceptar el campo


introducimos una de las teclas que causa excepción, es decir que no es
reconocida dentro de la tabla de caracteres admitida, el valor de la tecla se
guardará en la variable que definamos y a continuación podremos realizar
una instrucción. Por ejemplo si estamos aceptando un campo con PIC X(40)
y cuando estamos metiendo su valor pulsamos la tecla escape, si tenemos
ésta cláusula puesta la variable tomará el valor 27 (correspondiente a la
tecla escape) y a continuación se ejecutaría la instrucción que hubiéramos
puesto. Pero todo esto se ve mejor con los ejemplos que a continuación voy
a indicar. Decir que la variable debe de estar definida con PIC 9 COMP-1.

 UPPER, LOWER, (ACCEPT) con éstas opciones obligamos a que el valor del
campo aceptado esté en Mayúsculas (UPPER) o Minúsculas (LOWER).

 COLOR, (ACCEPT y DISPLAY) cláusula propia de Acucobol conla que


conseguimos aceptar el campo con un determinado color dependiendo de
una tabla para asignación de colores.

 REQUIRED, (ACCEPT) con ésta opción obligamos al usuario a que no deje


el campo en blanco e introduzca cualquier dato.
29
 FULL, (ACCEPT) obligamos a que una vez empecemos a introducir un
campo, este no se acepte hasta que esté completo, es decir si aceptamos
una variable con PIC X(30), mientras no introduzcamos los 30 caracteres
no nos dejará seguir.

Color Letra Fondo Observaciones

Negro 1 32 Para conseguir los colores, debemos


de sumar las dos cantidades
Azul 2 64
correspondientes a la letra y al
Verde 3 96 fondo, por ejemplo si queremos el
Celeste 4 128 fondo blanco y la letra azul, el valor
que se le debería de asigna a la
Rojo 5 160 cláusula COLOR será de 258 (256
Morado 6 192 fondo blanco + 2 letra azul).
Marrón 7 224
Blanco 8 256
TIPOS DE CONTROL. Voy a explicar algunos de los atributos que se pueden
utilizar cuando la frase CONTROL se especifica en ACCEPT o DISPLAY. El formato
es el siguiente:
CONTROL "FCOLOR=color, .............".
 FCOLOR, color de primer plano, utilizaremos los nombres de los colores
(white, black, red, blue, green, magenta, brown y cyan).

 BCOLOR, color de fondo y la gama de colores igual que la anterior.


Formatos Windows (100&100) de ACCEPT en Acucobol:
Con Acucobol (y hablo de él, por ser el que utilizo en la actualidad) se permite aceptar cualquier
control gráfico típico de windows, como un ENTRY-FIELD, directamente desde la PROCEDURE
DIVISION y con el comando ACCEPT propio de Cobol. Evidentemente cambia un poco sobre todo
porque las cláusulas o propiedades son mucho mas amplias. Todo ésto quisiera mostrarlo en la
sección para su propósito COBOL-WINDOWS, cuando tenga material disponible.
...
WORKING-STORAGE SECTION.
77  NOMBRE  PIC X(30).
77  CODIGO   PIC 9(5).
77  ESCA        PIC 9 COMP-1.
77  QW           PIC 9.
...
PROCEDURE DIVISION.
INICIO.
       ACCEPT NOMBRE LINE 10 COL 20 PROMPT LOW REVERSE ECHO CONTROL
"FCOLOR=BLUE, BCOLOR=WHITE" ON EXCEPTION  ESCA MOVE 1 TO QW.
       ACCEPT CODIGO LINE 12 COL 20 CONVERT.

...

Nota: Con el primer ACCEPT conseguiriamos introducir un valor en la variable


NOMBRE, lo aceptaremos en brillo suave con video reverso y una vez
introducido el campo, este se volverá a mostrar tal y como va a quedar,
gracias a ECHO. Además se aceptará en color azul con fondo blanco y si
pulsamos una de las teclas que causan excepcion según los valores permitidos,
esta se guardaría en la variable ESCA y luego podríamos preguntar por su
valor. Por ejemplo si pulsamos F1, F2, F3 tomará el valor 1, 2, 3. Si pulsamos
ENTER (13) ESCAPE (27), Tabular (9), etc ...
La siguiente orden nos permitirá aceptar la variable CODIGO en la cual los
carácteres no numéricos no se admitirán al llevar la clásusula CONVERT.
Os aconsejo que hagáis todo tipo de pruebas con las opciones disponibles hasta
que el resultado sea el que deseáis.
30
Muchas veces cuando se muestra un mensaje, se acepta una
variable a continuación solo para dar tiempo al usuario. Algunos
compiladores como Acucobol han implementado la siguiente
opción:
ACCEPT OMITTED, y así no tenemos que definir ninguna variable.

Teneis que tener en cuenta que algunas de las cláusulas que


explico es posible que no funcionen en todos los compiladores,
así como es posible que existan otras que yo desconozca debido
a que son usadas por otros compiladores.

DISPLAY, es la instrucción que usaremos como salida de datos en pantalla. Con ella
mostraremos cualquier texto, cualquier variable, cualquier constante o cualquier valor, en
resumidas es la instrucción para que aparezca lo que sea en pantalla. Las cláusulas asociadas a
esta instrucción son practicamente las mismas que hemos visto para ACCEPT, con lo que solo las
indicaré, su explicación la obtendréis arriba. De todas maneras ésta instrucción está siendo
implementada en muchos mas campos, por determinados compiladores y no sería justo pensar
que su única función es la que voy a explicar aquí, lo que si es cierto es que ésta es la común a
todos los compiladores. Mas abajo hablaré un poco de todo esto que os digo y de su futuro.
DISPLAY variable, literal CLAUSULAS ...

 LINE, COL, SIZE, HIGH, LOW, REVERSE, BEEP, BLINK, ERASE. Todos
funcionana igual que con la sentencia ACCEPT.
TIPOS DE CONTROL. Además de los vistos en ACCEPT, en DISPLAY podemos
utilizar otros:
CONTROL "FCOLOR=color, .............".
 FCOLOR, igual que en ACCEPT.

 BCOLOR, igual que en ACCEPT.

 GRAPHICS, según una tabla es posible utilizar caracteres semigráficos en


cualquier sistema. Cuando programamos en MS-DOS, estos caracteres se
pueden asignar muy facilmente pero al trabajar con sistemas UNIX-LINUX,
gracias a ésta cláusula podemos conseguir esos carácteres. Existe una tabla
para asignar los valores, por ejemplo la "q" nos da la linea horizontal
(Alt+196 (-)) con la que se forman los cuadros, la "m" nos da la vertical
(Alt+179 (¦)) Aqui no se ven bien.

 WINDOW-CREATE, WINDOW-REMOVE, En RM/Cobol, también se utiliza


para crear y borrar las pantallas virtuales con las que Cobol puede trabajar,
pero para ver su uso, os podeis ir a la sección que existe específica para
ello aquí.
...
WORKING-STORAGE SECTION.
77  NOMBRE  PIC X(30).
...
PROCEDURE DIVISION.
INICIO.
     DISPLAY " " LINE 1 ERASE CONTROL "FCOLOR=BLUE,
BCOLOR=WHITE". 
       DISPLAY "INTRODUZCA EL NOMBRE" LINE 10 COL 10 REVERSE.
       ACCEPT NOMBRE LINE 10 COL 34 PROMPT LOW ECHO.

...

Nota: Una cosa a tener en cuenta tanto con FCOLOR, como con BCOLOR,
es que los colores que tomen seguirán activos hasta encontrar otra orden
que los cambie, por eso al comenzar con esa primera linea conseguimos
31
que toda la pantalla se muestre blanca y el texto en azul para todo el
programa, hasta que se encuentre el compilador con otra linea que lo
cambie. O sea que no será necesario seguir incluyendo la cláusula
CONTROL, en todos los ACCEPT y DISPLAY que vayamos a utilizar mientras
queramos mantener éste formato.
Otros formatos de DISPLAY:
DISPLAY nombre de pantalla CLAUSULAS ..., podemos mostrar una pantalla
completa que previamente hayamos definido en la SCREEN SECTION.

DISPLAY WINDOW CLAUSULAS ..., en Acucobol se utiliza para crear las


ventanas virtuales con las que Cobol puede trabajar, pero para ver su uso, os
podeis ir a la sección que existe específica para ello aquí.

DISPLAY LINE CLAUSULAS ..., conseguimos dibujar una línea vertical u


horizontal donde le indiquemos con las cláusulas correspondientes. (No todos los
compiladores), se incorporan además éstas cláusulas:

 SIZE variable, constante numérica, longitud de la línea (horizontal).

 LINES variable, constante numérica, altura de la línea (vertical).


DISPLAY BOX CLAUSULAS ..., igual a la anterior per conseguimos dibujar un
cuadro, muy útil, pero no todos los compiladores lo tienen implementado. Se
incorporan además éstas cláusulas:
 SIZE variable, constante numérica, anchura del cuadro (horizontal).

 LINES variable, constante numérica, altura del cuadro (vertical).

 TITLE variable, constante alfanumérica, título del cuadro.

 TOP, BUTTON, CENTERED, RIGHT, LEFT posición que ocupará el título


dentro del cuadro.
Formatos Windows (100&100) de DISPLAY en Acucobol:
Acucobol en su afán por conseguir una programación totalmente integrada con los sistemas
gráficos, ha conseguido implementar a la orden DISPLAY la potencia necesaria para displayar
ventanas Windows (100%100) así como cualquier tipo de control. Hoy podemos con una linea de
código displayar un COMBOBOX, LABEL, FRAME, BITMAP, STANDARD WINDOW, FLOATING
WINDOW, PUSH-BUTTON, ENTRY-LABEL, etc... y asignarle cualquiera de sus propiedades. Pero
es un tema demasiado amplio para tratarlo desde aquí. Necesitaría una sección unica y
exclusivamente para la programación gráfica, pero todo se andará.
Os aseguro que es muy grato obtener resultados Windows, programando directamente con el
editor de MS-DOS (ese azul con muy pocas opciones) sin necesidad de ninguna herramienta
externa que también existe.

PROCEDURE DIVISION
INSTRUCCIONES DE MOVIMIENTO DE VARIABLES.

Daré cabida en esta sección a la explicación de todas las instrucciones que hacen referencia a las
variables y sus valores. Como todas, este grupo de instrucciones tiene su vital importancia en la
programación y son usadas habitualmente.

Instrucciones incluidas en esta sección:

move, initialize, inspect, string, unstring

MOVE, es la instrucción que usaremos para enviar datos de una variable a otra u otras.
Lo que en realidad hace es que la una variable adquiera un valor determinado, ya sea procedente
de otra variable o bien desde un valor fijo o constante.

Estos son los dos formatos que posee:


32
Formato 1:

MOVE variable, valor TO variable, variable, variable, ....


Con el primer formato las variables que siguen al TO tomarán el dato de la variable o del
valor que le preceden. De todo se verá al final una serie de ejemplos bien detallados.
Siempre tendremos una serie de normas o restricciones para asegurarnos de que los
valores han pasado correctamente.
 Los campos numéricos siempre se van a alinear a la derecha, respetando la
posición del punto decimal si lo hubiera. Si la variable que recibe el campo
es mas pequeña, evidentemente se perderán los que no quepan y si es mas
grande el resto se pondrá a ceros.

 Si además el campo al que se mueven los datos es de edición, al hacer el paso


del valor, este a su vez se formateará con la edición declarada en la Working.

 Si son alfanuméricos la alineación se efectuará a la izquierda a menos que se


haya especificado en la Working, al definirla, una justificación a la derecha (JUST
RIGHT). Al igual que en los numéricos si es mas pequeño se perderán los
caracteres que no quepan y si es mas grande el resto irá relleno de espacios en
blanco.
...
WORKING-STORAGE SECTION.
77  NUMERO1   PIC 9(6).
77  NUMERO2   PIC 9(8)V99.
77  NUMERO3   PIC ZZZ.ZZZ,ZZ.
77  TEXTO1     PIC X(15)  VALUE "LENGUAJE COBOL".
77  TEXTO2     PIC X(10).
77  TEXTO3     PIC X(20) JUST RIGHT.
...
PROCEDURE DIVISION.
INICIO.
       MOVE 1536 TO NUMERO1.
       MOVE NUMERO1 TO NUMERO2 NUMERO3.
       MOVE TEXTO1 TO TEXTO2 TEXTO3.
...

Nota: Después de aplicar estas sentencias, éste sería el resultado:


     NUMERO1=001536
     NUMERO2=0000153600 (La coma decimal es virtual)
     NUMERO3=  1.536,00

     TEXTO1=LENGUAJE COBOL
     TEXTO2=LENGUAJE C
     TEXTO3=      LENGUAJE COBOL

Formato 2:
MOVE CORR Identificador1 TO Identificador2

Agregando CORR a la instrucción conseguimos mover de una sola vez un valor


entre identificadores siempre que los campos que contengan tengan el mismo
nombre. Estos identificadores no pueden ir en niveles 66, 77 ni 88. El efecto es el
mismo que si hicieramos tantos MOVE normales como campos iguales tuviera el
identificador. No es muy usual, pero si hay casos en los que puede ser razonable
su uso.

No es necesario que tengan el mismo PIC, ni que estén en el mismo orden, solo
que coincidan en su nombre.
...
33
WORKING-STORAGE SECTION.
01  DATOS1.
     02  NOMBRE   PIC X(30).
     02  REGION   PIC X(20).
     02  PAIS       PIC X(15).
01  DATOS2.
     02  PAIS       PIC X(10).
     02  REGION    PIC X(10).
     02  NOMBRE   PIC X(10).
...
PROCEDURE DIVISION.
INICIO.
       MOVE "ANDRES MONTES" TO NOMBRE IN DATOS1.
       MOVE "ANDALUCIA" TO REGION IN DATOS1.
       MOVE "ESPAÑA" TO PAIS IN DATOS1.
       MOVE CORR DATOS1 TO DATOS2.
...

Nota: Para partir con unos valores, primero los he movido a las variables del
primer grupo (DATOS1). Después de aplicar el MOVE CORR, el valor de las
variables de DATOS2 sería:
     DATOS2:
        PAIS=ESPAÑA
        REGION=ANDALUCIA
        NOMBRE=ANDRES MON

Fijaros que aunque el orden ni el tamaño era el mismo, el resultado es el que


queríamos.

INITIALIZE, se utiliza para inicializar variables según su descripción, es decir pondrá a ceros
todas las variables numéricas o de edición y a espacios en blanco las alfabéticas y alfanuméricas.
No funciona con campos definidos como FILLER, (evidente). Y puede ser muy útil para inicializar
tablas completamente cuando nos referimos al nivel mas alto de la misma.
...
WORKING-STORAGE SECTION.
77  TEXTO PIC X(10) VALUE "HOLA MUNDO".
77  NUMERO PIC 9(8) VALUE "12345678".
...
PROCEDURE DIVISION.
INICIO.
     INITIALIZE TEXTO NUMERO.
...

Nota: Después de hacer INITIALIZE el valor de TEXTO será igual a


espacios y el de NUMERO igual a ceros.
Es el mismo resultado que utilizar MOVE haciendo uso de las CONSTANTES
FIGURATIVAS que vimos en la Introducción de los manuales:

       MOVE SPACES TO TEXTO.


       MOVE ZEROS TO NUMERO.

El resultado es el mismo en ambos casos, pero en el segundo teníamos que


saber de que tipo eran las variables para moverles SPACES o ZEROS,
mientras que en el primer caso, es el compilador quien se encarga se saber
el tipo de la variable.

INSPECT, esta sentencia se utiliza para contar, reemplazar o contar y reemplazar caracteres o
grupos de caracteres dentro de un campo. Se puede contar las veces que aparece un caracter, o
cambiar todos esos caracteres por otros, etc ...
34
Esta instrucción tiene formatos diferentes según lo que se desee hacer, así que vamos a ver cada
uno de ellos por separado.
Formato 1:
INSPECT campo1
        TALLYING variable1 FOR (CHARACTERS)
          ((BEFORE/AFTER) INITIAL) Cadena1
                  (ALL)(LEADING) Cadena2 ...
          (Se puede repetir de nuevo)

Este formato es el utilizado para contar el número de veces que aparece


Identificador1 en el campo1 y guardará el valor en la variable1 que previamente
hayamos definido en la Working.

 CHARACTERS indica que cuente todos los caracteres del campo incluso los
espacios en blanco.

 ALL indica que tiene que buscar en todos los caracteres del campo, la
cadena especificada en Cadena2.

 LEADING indica que tiene que buscar la cadena especificada en Cadena2,


pero solo hasta que encontremos uno diferente, si nada mas empezar es
diferente el resultado sera directamente 0.

 BEFORE INITIAL, busca solo hasta que aparezca la cadena especificada


como Cadena1.

 AFTER INITIAL, empieza a buscar justo después de la cadena especificada


en Cadena1.
Veamos unos ejemplos para salir de dudas. Primero vamos a definir una
WORKING-STORAGE.
...
WORKING-STORAGE SECTION.
77  TEXTO PIC X(15) VALUE "PAGINA DE COBOL".
77  CONTA PIC 9(8).
...
PROCEDURE DIVISION.
INICIO.
     INSPECT TEXTO TALLYING CONTA FOR CHARACTERS.
...
El valor de conta será de 15 que son los caracteres que tiene la variable
TEXTO.
     INSPECT TEXTO TALLYING CONTA FOR ALL "A".
...
El valor de conta será de 2 que son las veces que aparece la letra A en la
variable TEXTO.

     INSPECT TEXTO TALLYING CONTA FOR LEADING "A".


...
El valor de conta será de 0 porque no aparece ninguna A en el primer
carácter de la variable TEXTO.

      INSPECT TEXTO TALLYING CONTA FOR ALL "A"


                   BEFORE INITIAL "N".
...
El valor de conta será de 1 que son las veces que aparece la letra A en la
variable TEXTO hasta la aparición del caracter N.

     INSPECT TEXTO TALLYING CONTA FOR ALL "A"


                  AFTER INITIAL "G".
...
35
El valor de conta será de 1 que son las veces que aparece la letra A en la
variable TEXTO, empezando a contar desde el caracter G.

Formato 2:
INSPECT campo1
       REPLACING variable1 CHARACTERS BY Cambio1
         ((BEFORE/AFTER) INITIAL) Cadena1
                 (ALL)(LEADING)(FIRST) Cadena2 ...
        (Se puede repetir de nuevo)

Con este formato podemos cambiar caracteres de Campo1, su funcionamiento es


igual que el anterior formato solo que en vez de contar reemplaza. Se ha incluido
solo FIRST, que indicaría que solo se reemplazaría la primera vez que coincidieran
las condiciones. El tamaño de la sustitución debe de ser igual al tamaño sustituido,
ya que la variable campo1 no puede cambiar su tamaño.
...
WORKING-STORAGE SECTION.
77  TEXTO PIC X(15) VALUE "PAGINA DE COBOL".
77  CONTA PIC 9(8).
...
PROCEDURE DIVISION.
INICIO.
     INSPECT TEXTO REPLACING CHARACTERS BY "H".
...
El valor de TEXTO será "HHHHHHHHHHHHHHH", es decir cambia todos los
caracteres por el caracter H.
     INSPECT TEXTO REPLACING ALL "A" BY "I".
...
El valor de TEXTO será "PIGINI DE COBOL", es decir ha cambiado todas las
A por I.

     INSPECT TEXTO REPLACING FIRST "A" BY "O".


...
El valor de TEXTO será "POGINA DE COBOL", solo cambia la primera A por
una O.
 

     MOVE "PAGIPATOPETOPA" TO TEXTO.


     INSPECT TEXTO REPLACING ALL "PA" BY "--"
             AFTER INITIAL "G"  BEFORE INITIAL "T".
...
Complicando un poco mas, el valor de TEXTO despueés de la sentencia
INSPECT será PAGI--TOPETOPA, es decir se cambia todas las PA por -- pero
empezando a buscar a partir de la primera letra G y justo hasta la letra T.

       MOVE "PAGIPATOPETOPA" TO TEXTO.     


       INSPECT TEXTO TALLYING CONTA FOR ALL "PA"
                  REPLACING ALL "TO" BY "PO" AFTER INITIAL "OP".
...
Aquí hemos mezclado ambos formatos y el resultado es el siguiente. El
valor de CONTA es 3 que son las veces que aparece la cadena PA en TEXTO
y después se ejecuta el REPLACING y el resultado da que TEXTO vale
PAGIPATOPEPOPA, ya que ha cambiado todos los TO por PO pero después
de la cadena OP.

Formato 3:
INSPECT campo1
        CONVERTING Identificador1 TO Identificador2
36
          ((BEFORE/AFTER) INITIAL) Cadena1 ...
          (Se puede repetir de nuevo)

Con este formato convertimos los caracteres que se especifiquen en identificador1


por los que pongamos en identificador2, respetando el orden.

Veamos algunos ejemplos, se suele utilizar mucho para que al aceptar un campo
nos de igual se ha sido introducido en mayúsculas o en minúsculas ya que lo
convertiriamos a alguno de los formatos.
...
WORKING-STORAGE SECTION.
77  TEXTO PIC X(15) VALUE "PAGINA DE COBOL".
...
PROCEDURE DIVISION.
INICIO.
     INSPECT TEXTO CONVERTING "AO" TO "12".
...
El valor de TEXTO será "P1GIN1 DE C2B2L", convertirá todas las A por 1 y
todas las O por 2.
     INSPECT TEXTO CONVERTING
"ABCDEFGHIJKLMNÑOPQRSTUVWXYZ" TO
               "abcdefghijklmnñopqrstuvwxyz".
...
El valor de TEXTO será "pagina de cobol" ya que ha convertido todas las
letras mayúsculas por minúsculas.
Para finalizar con el comando INSPECT, decir que es un comando muy particular y cada uno
deberá decidir en cada momento y con que situaciones utilizarlo.

STRING, se utiliza para unir o concatenar campos o partes de estos y el resultado almacenarlo
en otro campo. En la unión se pueden incluir tanto variables como literales o constantes de
texto.
STRING campo1, literal1
         DELIMITED BY (campo2, literal2)(SIZE)
           INTO Campo3
         (WITH POINTER Identificador1)  
           (ON OVERFLOW Sentencia1)
           (NOT ON OVERFLOW Sentencia2)

 DELIMITED BY, indica hasta donde vamos a "coger" del campo para concatenar sin contar
ese caracter o cadena que se especifique en campo2 o literal2, es decir si tenemos un
campo con un valor = "HOLA" y especificamos DELIMITED BY "L" a la hora de la
concatenación nos hubiera cogido solo el HO, ya que al encontrarse la primera L hubiera
parado.

 SIZE, indica que se pasará todo el contenido del campo1 o literal1 sin limitaciones.

 INTO, con esto indicamos en que variable se guardará el resultado, campo3.

 WITH POINTER, si incluimos esta cláusula el valor de identificador1 será en la posición en


que empezará a contener datos la variable que recibe el STRING. Ese identificador1 debe
estar definido como binario. Por defecto el valor es 1.

 ON OVERFLOW, se ejecutaría Sentencia1 si hubiera habido un error al hacer la


concatenación, por ejemplo si se especifica Identificador1 con un valor superior al tamaño
del Campo3.

 NOT ON OVERFLOW, se ejecutará Sentencia2 si no existe error en la operación.


Vamos a ver unos ejemplos y además vamos a comparar como se hubiera hecho utilizando la
Working si no existiera el STRING.
37
...
WORKING-STORAGE SECTION.
01  LAFECHA.
     02  FILLER PIC X(7) VALUE "HOY ES ".
     02  LDIA    PIC Z9.
     02  FILLER PIC X(4) VALUE " DE ".
     02  LMES   PIC X(10).
     02  FILLER PIC X(4)  VALUE " DE ".
     02  LANIO  PIC 9999.
01  FECHA.
     02  DIA    PIC 99 VALUE 22.
     02  MES   PIC 99 VALUE 06.
     02  ANIO  PIC 9999 VALUE 2001.
01  CONSTRING PIC X(40).
01  TABLAMES.
     02  FILLER PIC X(30) VALUE "ENERO     FEBRERO   MARZO      ".
     02  FILLER PIC X(30) VALUE "ABRIL      MAYO       JUNIO        ".
     02  FILLER PIC X(30) VALUE "JULIO      AGOSTO  SEPTIEMBRE".
     02  FILLER PIC X(30) VALUE "OCTUBRE NOVIEMBREDICIEMBRE ".
01  LATABLA REDEFINES TABLAMES.
     02  TMES PIC X(10) OCCURS 12 TIMES.
01  PUNTO PIC 9(4) BINARY.
...
PROCEDURE DIVISION.
INICIO.
      MOVE DIA TO LDIA.
      MOVE TMES (MES) TO LMES.
      MOVE ANIO TO LANIO.
      STRING "HOY ES " DIA " DE " TMES (MES) " DE " ANIO
                 DELIMITED BY SIZE INTO CONSTRING.
...
El valor de LAFECHA sería: HOY ES 22 DE JUNIO       DE 2001.
El valor de CONSTRING sería: HOY ES 22 DE JUNIO       DE 2001.
Fijaros que el resultado es el mismo pero en cambio gracias a STRING no hemos tenido
que definir ninguna linea en la WORKING ni tampoco tener que mover campos de unas
variables a otras.
La cláusula DELIMITED BY se ha puesto al final porque dicha cláusula se aplica a todos los
campos que la preceden, si hubieramos querido coger otra limitación para un campo en
concreto habría que haberlo especificado, por ejemplo vamos a afinar mas el ejemplo y
conseguir que entre el mes JUNIO y el DE no exista mas que un espacio. En el ejemplo
anterior a unido los 10 caracteres que tiene la variable TMES.
STRING "HOY ES " DIA " DE " DELIMITED BY SIZE
        TMES (MES) DELIMITED BY " "
      " DE " ANIO  DELIMITED BY SIZE INTO CONSTRING.
El valor que tendrá ahora CONSTRING será el siguiente:
HOY ES 22 DE JUNIO DE 2001.
Como veis la diferencia está en los espacios que le sobran al mes, que al poner
DELIMITED BY " " los ha evitado porque solo ha concatenado hasta que ha encontrado el
primer caracter en blanco.
MOVE 4 TO PUNTO.
STRING "HOY ES " DIA " DE " DELIMITED BY SIZE
        TMES (MES) DELIMITED BY " "
      " DE " ANIO  DELIMITED BY SIZE INTO CONSTRING
      WITH POINTER PUNTO.
El valor que tendrá ahora CONSTRING será el siguiente:
    HOY ES 22 DE JUNIO DE 2001.
38
Es decir habrá empezado a concatenar a partir de la posición 4 del campo CONSTRING. Si
el valor de CONSTRING previamente era espacios habría dejado 3 espacios en blanco y si
hubiera sido cualquier otro hubiera respetado los 3 primeros caracteres que tuviera.       

UNSTRING, hace exactamente lo contrario de que hemos visto que hacía STRING, es decir
divide el contenido de un campo en otros.
UNSTRING campo1, literal1
       DELIMITED BY (campo2, literal2)(ALL)  
         OR (campo2, literal2)(ALL)
          (Se puede repetir de nuevo)
         INTO Campo3, Campo4, ....
              (DELIMITER Identificador1)
                  (COUNT Identificador2)
         (Se puede repetir de nuevo)
       (WITH POINTER Identificador3)
       (TALLYING Identificador4)
         (ON OVERFLOW Sentencia1)
         (NOT ON OVERFLOW Sentencia2)

 DELIMITED BY, indica el límite hasta donde vamos cogiendo el campo1 para partirlo. Igual
que en STRING, solo que con la función a la inversa.

 OR es igual que DELIMITED y se utiliza si hay varios delimitadores sobre los que buscar.

 INTO indica en que campo o campos se guardará la información que vaya fragmentando.

 DELIMITER va a contener en cada caso el elemento separador, si hemos incluido en


DELIMITED varios, Identificador1 guardará el carácter que de los elegidos ha sido el
causante de la fragmentación.

 COUNT cuenta el número de caracteres incluidos en la fragmentación.

 DELIMITER y COUNT se podrán usar si se ha especificado DELIMITED. Podemos usar


tantos DELIMITER y COUNT como campos se vayan a crear en la fragmentación.

 TALLYING si especificamos esta opción la instrucción nos guardará en Identificador4 el


número de campos que se han utilizado en la fragmentación.

 POINTER indica desde que posición va a ser examinado el campo que desea
desfragmentar, por defecto su valor es 1, es decir desde el primer caracter.

 ON OVERFLOW, se ejecutaría Sentencia1 si hubiera habido un error al hacer la operación.

 NOT ON OVERFLOW, se ejecutará Sentencia2 si no existe error en la operación.


Vamos a hacer lo contrario de antes y conseguir una fecha numérica de una frase con la fecha:
...
WORKING-STORAGE SECTION.
01  LAFECHA PIC X(30) VALUE "HOY ES 22 DE JUNIO DE 2001".
01  FECHA.
     02  DIA    PIC 99.
     02  MES   PIC 99.
     02  ANIO  PIC 9999.
01  CONSTRING PIC X(40).
01  TABLAMES.
     02  FILLER PIC X(30) VALUE "ENERO     FEBRERO   MARZO      ".
     02  FILLER PIC X(30) VALUE "ABRIL      MAYO       JUNIO        ".
     02  FILLER PIC X(30) VALUE "JULIO      AGOSTO  SEPTIEMBRE".
     02  FILLER PIC X(30) VALUE "OCTUBRE NOVIEMBREDICIEMBRE ".
01  LATABLA REDEFINES TABLAMES.
     02  TMES PIC X(10) OCCURS 12 TIMES.
01  CONTA PIC 99.
39
01  PALABRAS PIC 99.
01  LETRAS PIC 99.
01  TEXTOS.
     02  TEXTO1 PIC X(20).
     02  TEXTO2 PIC X(20).
     02  TEXTO3 PIC X(20).
     02  TEXTO4 PIC X(20).
     02  ELMES   PIC X(10).
...
PROCEDURE DIVISION.
INICIO.
      UNSTRING LAFECHA DELIMITED BY " "
          INTO TEXTO1 TEXTO2 DIA TEXTO3
                 ELMES COUNT LETRAS TEXTO4 ANIO.
      PERFORM VARYING CONTA FROM 1 BY 1
        UNTIL ELMES = TMES (CONTA) OR CONTA = 12
        TALLYING PALABRAS
        END-PERFORM    
...
El valor de LAFECHA era: HOY ES 22 DE JUNIO DE 2001.
Después de aplicar las instrucciones siguientes el contenido de los campos sería el
siguiente:
 TEXTO1 = HOY

 TEXTO2 = ES

 TEXTO3 = DE

 TEXTO4 = DE

 ELMES = JUNIO

 DIA = 22

 ANIO = 2001

 FECHA = 22062001

 LETRAS = 5

 PALABRAS = 7
La variable PALABRAS nos ha guardado el número de variables utilizadas en la
fragmentación, en este caso 7. La variable LETRAS ha guardado el número de caracteres
que ha cogido en la separación que ha guardado en ELMES, que han sido 5 (JUNIO).
Podiamos haber puesto un COUNT para cada una.
El PERFORM de después lo hemos hecho para encontrar en la tabla la posición que
ocupaba el nombre del mes y así poder construir la variable FECHA completa en
númerico.
Vamos a hacer un ejemplo de como podríamos separar un nombre completo, por ejemplo para el
nuevo modelo de la Seguridad Social (en España) y el sistema R.E.D.:
...
WORKING-STORAGE SECTION.
01  TEXTO PIC X(30) VALUE "MONTES ROBLES, ANDRES".
01  APELLI1   PIC X(20).
01  APELLI2   PIC X(20).
01  NOMBRE PIC X(20).
01  SEPARA   PIC X.
01  SEGURIDAD.
     02  AP1 PIC XX.
     02  AP2 PIC XX.
40
     02  NOM PIC X.
...
PROCEDURE DIVISION.
INICIO.
      UNSTRING TEXTO DELIMITED BY " " OR ", "
          INTO APELLI1 APELLI2 NOMBRE.
Aquí conseguimos separar cada apellido y el nombre en campos diferentes.
(APELLI1, APELLI2, NOMBRE)

      MOVE APELLI1 TO AP1 MOVE APELLI2 TO AP2


      MOVE NOMBRE TO NOM.
...

Aquí la variable SEGURIDAD tendría el valor: MOROA. Válido para el


sistema RED.

PROCEDURE DIVISION
PERFORM. Creo que por méritos propios esta instrucción se merece un apartado para ella sola.
Es una instrucción que nos permite tranferir el control a otro u otros procedimientos o bien
realizar una serie de sentencias dentro de ella misma mientras se cumplan las condiciones que le
hayamos indicado. Es la instrucción mas importante tanto por su variedad de formatos, como por
el número de veces que se suele usar dentro de un programa, además nos puede hacer mucho
mas sencillo el realizar una programación estructurada.

Cuando decimos que un programa está estructurado, no cabe duda que es debido al uso de ésta
instrucción. Pero creo que lo importante no es tanto hablar de ella, sino comenzar a explicarla.

Empecemos a ver sus formatos desde el mas simple al mas complicado: Siempre debéis de tener
en cuenta que los ejemplos son solo para aclarar la explicación, nunca los toméis como
programas completos y con una lógica aplastante.

Formato 1: Con este formato transferimos el control del programa a un párrafo, cuando éste
termine vuelve el control a la instrucción que sigue al PERFORM.

PERFORM nombre_parrafo 
...
WORKING-STORAGE SECTION.
01  NOMBRE PIC X(30).
01  OP PIC X.
PROCEDURE DIVISION.
INICIO.
       DISPLAY 'PROGRAMA DE SALUDO' LINE 1 ERASE.
       PERFORM PIDENOMBRE.
       DISPLAY 'HOLA ' LINE 10.
       DISPLAY NOMBRE LINE 10 COL 6.
       ACCEPT OP LINE 20.
       STOP RUN.
PIDENOMBRE.
       DISPLAY 'INTRODUZCA EL NOMBRE ..' LINE 20.
       ACCEPT NOMBRE LINE 20 COL 30 PROMPT.
       DISPLAY SPACES LINE 20 SIZE 70.
...

Nota: Simplemente hemos hecho que el programa salte a un párrafo que lo


ejecute y que vuelva el control a la secuencia.
41
Formato 2: Una extensión del anterior es indicarle que ejecute mas de un párrafo, especificando
el inicio y el fin.
PERFORM nombre_parrafo THRU nombre_parrafo
...
WORKING-STORAGE SECTION.
01  NOMBRE PIC X(12).
01  APELLIDO PIC X(12).
01  OP PIC X.
PROCEDURE DIVISION.
INICIO.
       DISPLAY 'PROGRAMA DE SALUDO' LINE 1 ERASE.
       PERFORM PIDENOMBRE THRU PIDEAPELLIDO.
       DISPLAY 'HOLA ' LINE 10.
       DISPLAY NOMBRE LINE 10 COL 6.
       DISPLAY APELLIDO LINE 10 COL 20.
       ACCEPT OP LINE 20.
       STOP RUN.
PIDENOMBRE.
       DISPLAY 'INTRODUZCA EL NOMBRE ..' LINE 20.
       ACCEPT NOMBRE LINE 20 COL 30 PROMPT.
PIDEAPELLIDO.
       DISPLAY 'INTRODUZCA EL APELLIDO ..' LINE 21.
       ACCEPT APELLIDO LINE 21 COL 30 PROMPT.
       DISPLAY SPACES LINE 20 SIZE 70.
       DISPLAY SPACES LINE 21 SIZE 70. 
...

Nota: En este caso PIDENOMBRE y PIDEAPELLIDO van seguidos, pero al


poner el THRU lo que conseguimos es que el control no se devuelva hasta
llegar al párrafo indicado después del THRU. Es decir que entre
PIDENOMBRE y PIDEAPELLIDO podrá haber cinco párrados mas y todos
ellos se hubieran ejecutado.

Formato 3: Seguimos ampliando las capacidades, ahora conseguimos que el PERFORM se


realice tantas veces como se indique en el número o variable que va delante de TIMES.
PERFORM nombre_parrafo THRU nombre_parrafo número-variable TIMES
...
WORKING-STORAGE SECTION.
01  NOMBRE   PIC X(12).
01  APELLIDO PIC X(12).
01  OP           PIC X.
01  LI            PIC 99 VALUE 10.
PROCEDURE DIVISION.
INICIO.
       DISPLAY 'PROGRAMA DE SALUDO' LINE 1 ERASE.
       PERFORM PIDENOMBRE THRU PIDEAPELLIDO.
       PERFORM SALUDAR 3 TIMES.
       STOP RUN.
PIDENOMBRE.
       DISPLAY 'INTRODUZCA EL NOMBRE ..' LINE 20.
       ACCEPT NOMBRE LINE 20 COL 30 PROMPT.
PIDEAPELLIDO.
       DISPLAY 'INTRODUZCA EL APELLIDO ..' LINE 21.
       ACCEPT APELLIDO LINE 21 COL 30 PROMPT.
       DISPLAY SPACES LINE 20 SIZE 70.
       DISPLAY SPACES LINE 21 SIZE 70.
SALUDAR.
       ADD 1 TO LI.
42
       DISPLAY 'HOLA ' LINE LI.
       DISPLAY NOMBRE LINE LI COL 6.
       DISPLAY APELLIDO LINE LI COL 20.
       ACCEPT OP LINE 20.
...

Nota: Ahora hemos conseguido que el saludo nos lo muestre 3 veces. Por
supuesto THRU y TIMES pueden ir perfectamente juntos. Ya os he dicho al
principio que los ejemplos pueden no ser muy lógicos, pero si hacen la
función de explicación.

Formato 4: Igual que el antrior formato solo que el número de veces que se ejecute dependerá
de una condición y no de un número fijo.
PERFORM nombre_parrafo THRU nombre_parrafo UNTIL  condición
...
WORKING-STORAGE SECTION.
01  NOMBRE   PIC X(12).
01  APELLIDO PIC X(12).
01  OP           PIC X.
01  LI            PIC 99 VALUE 10.
PROCEDURE DIVISION.
INICIO.
       DISPLAY 'PROGRAMA DE SALUDO' LINE 1 ERASE.
       PERFORM PIDENOMBRE THRU PIDEAPELLIDO.
       PERFORM SALUDAR UNTIL LI = 15.
       STOP RUN.
PIDENOMBRE.
       DISPLAY 'INTRODUZCA EL NOMBRE ..' LINE 20.
       ACCEPT NOMBRE LINE 20 COL 30 PROMPT.
PIDEAPELLIDO.
       DISPLAY 'INTRODUZCA EL APELLIDO ..' LINE 21.
       ACCEPT APELLIDO LINE 21 COL 30 PROMPT.
       DISPLAY SPACES LINE 20 SIZE 70.
       DISPLAY SPACES LINE 21 SIZE 70.
SALUDAR.
       ADD 1 TO LI.
       DISPLAY 'HOLA ' LINE LI.
       DISPLAY NOMBRE LINE LI COL 6.
       DISPLAY APELLIDO LINE LI COL 20.
       ACCEPT OP LINE 20.
...

Nota: En este caso el compilador comprueba antes de iniciar el PERFORM


que la condición no se cumple para ejecutarla, en el momento que se
cumpla salta a la siguiente instrucción. En el ejemplo ejecutará el PERFORM
hasta que la variable LI alcance el valor 15.

PRIMERA CONCLUSION
En los dos primeros formatos, como podréis comprobar a menos que sean instrucciones que se
vayan a llamar desde nuestro programa en mas de una ocasión, éstas podían haber ido en el
lugar del PERFORM, es decir las instrucciones una detrás de otra y evitar el PERFORM.
Hasta ahora se ha explicado una manera de utilizar la sentencia PERFORM en la que el control
pasa a otro lugar del programa. Como véis el STOP RUN está antes de los párrafos que han sido
llamados con los PERFORM lo cual indica que éstos no se ejecutarán sino es precisamente por los
PERFORM.
Si bien con esto conseguimos una estructuración para nuestro programa la instrucción PERFORM
nos permite un mayor grado de estructura incluyendo las sentencias de los párrafos llamados
dentro de la propia sentencia PERFORM.
43
Para ello hay que tener en cuenta que la utilización del punto en las instrucciones daría lugar al
fin de la instrucción y nos daría errores, por ello, para finalizar la instrucción nos basamos en
END-PERFORM. Veamos un ejemplo de ello con los dos últimos formatos explicados
anteriormente.
PERFORM número-variable TIMES
       sentencias 
END-PERFORM

PERFORM UNTIL  condición


     sentencias 
END-PERFORM
...
WORKING-STORAGE SECTION.
01  NOMBRE   PIC X(12).
01  APELLIDO PIC X(12).
01  OP           PIC X.
01  LI            PIC 99 VALUE 10.
PROCEDURE DIVISION.
INICIO.
       DISPLAY 'PROGRAMA DE SALUDO' LINE 1 ERASE.
       PERFORM PIDENOMBRE THRU PIDEAPELLIDO.
       PERFORM 3 TIMES
            ADD 1 TO LI
            DISPLAY 'HOLA ' LINE LI
            DISPLAY NOMBRE LINE LI COL 6
            DISPLAY APELLIDO LINE LI COL 20
            ACCEPT OP LINE 20
       END-PERFORM
       STOP RUN.
PIDENOMBRE.
       DISPLAY 'INTRODUZCA EL NOMBRE ..' LINE 20.
       ACCEPT NOMBRE LINE 20 COL 30 PROMPT.
PIDEAPELLIDO.
       DISPLAY 'INTRODUZCA EL APELLIDO ..' LINE 21.
       ACCEPT APELLIDO LINE 21 COL 30 PROMPT.
       DISPLAY SPACES LINE 20 SIZE 70.
       DISPLAY SPACES LINE 21 SIZE 70.
...
...
  WORKING-STORAGE SECTION.
01  NOMBRE   PIC X(12).
01  APELLIDO PIC X(12).
01  OP           PIC X.
01  LI            PIC 99 VALUE 10.
PROCEDURE DIVISION.
INICIO.
       DISPLAY 'PROGRAMA DE SALUDO' LINE 1 ERASE.
       PERFORM PIDENOMBRE THRU PIDEAPELLIDO.
       PERFORM UNTIL LI = 15
            ADD 1 TO LI
            DISPLAY 'HOLA ' LINE LI
            DISPLAY NOMBRE LINE LI COL 6
            DISPLAY APELLIDO LINE LI COL 20
            ACCEPT OP LINE 20
       END-PERFORM
       STOP RUN.
PIDENOMBRE.
       DISPLAY 'INTRODUZCA EL NOMBRE ..' LINE 20.
       ACCEPT NOMBRE LINE 20 COL 30 PROMPT.
44
PIDEAPELLIDO.
       DISPLAY 'INTRODUZCA EL APELLIDO ..' LINE 21.
       ACCEPT APELLIDO LINE 21 COL 30 PROMPT.
       DISPLAY SPACES LINE 20 SIZE 70.
       DISPLAY SPACES LINE 21 SIZE 70.
...

Nota: Esta es una manera mas lógica de utilizar el PERFORM en estos


formatos, como veís se consigue una visión muy clara de lo que estamos
haciendo y no hay saltos de secuencia innecesarios. Por supuesto el COBOL
permite cualquier modalidad de uso y siempre funcionaría igual. Como veis
no puede haber puntos entre el PERFORM y en END-PERFORM puesto que
eso haría terminar con error la sentencia.

Formato 5: En esta ocasión utilizaremos el PERFORM basándonos en un valor inicial el cual


podremos y aumentar o disminuir y terminar cuando se cumpla una condición. No se si me he
liado un poco con la explicación pero lo que conseguimos es ahorrarnos varias instrucciones y
resumirlas en una sola, para que lo comprendáis veamos su formato y un ejemplo. Como he
explicado anteriormente podemos hacer que el PERFORM invoque a uno o varios párrafos o bien
incluir el conjunto de sentencias entre PERFORM y END-PERFORM. En el ejemplo veremos este
último caso, porque creo que es mas aconsejable.
PERFORM  VARYING  variable FROM  número, variable  BY  número, valor
UNTIL  condición
     sentencias 
END-PERFORM
...
WORKING-STORAGE SECTION.
01  NOMBRE   PIC X(12).
01  APELLIDO PIC X(12).
01  OP           PIC X.
01  LI            PIC 99.
PROCEDURE DIVISION.
INICIO.
       DISPLAY 'PROGRAMA DE SALUDO' LINE 1 ERASE.
       PERFORM PIDENOMBRE THRU PIDEAPELLIDO.
       PERFORM VARYING LI FROM 10 BY 1 UNTIL LI = 15
            DISPLAY 'HOLA ' LINE LI
            DISPLAY NOMBRE LINE LI COL 6
            DISPLAY APELLIDO LINE LI COL 20
            ACCEPT OP LINE 20
       END-PERFORM
       STOP RUN.
PIDENOMBRE.
       DISPLAY 'INTRODUZCA EL NOMBRE ..' LINE 20.
       ACCEPT NOMBRE LINE 20 COL 30 PROMPT.
PIDEAPELLIDO.
       DISPLAY 'INTRODUZCA EL APELLIDO ..' LINE 21.
       ACCEPT APELLIDO LINE 21 COL 30 PROMPT.
       DISPLAY SPACES LINE 20 SIZE 70.
       DISPLAY SPACES LINE 21 SIZE 70.
...
La instrucción realiza los siguientes pasos:
Inicializa la variable LI con el valor que sigue al FROM, es decir 10, a continuación va
incrementado el valor de LI en 1 que es lo que va después del BY y ejecuta las sentencias que
van a continuación hasta que se cumple la condición de LI = 15.
Es decir las sentencias se ejecutarían para el valor 10, 11, 12, 13 y 14.
La instrucción PERFORM se puede anidar tantas veces como se quiera, teniendo en cuenta que el
PERFORM contenido debe de ejecutarse completamente interno o completamente externo al que
lo contiene.
45
Si necesitamos que por alguna circunstancia finalice la ejecución de un PERFORM aún cuando la
secuencia no corresponde, podemos utilizar la sentencia EXIT, que precisamente lo que propicia
es eso, que se interrumpa la sentencia PERFORM.
Para finalizar vamos a ver un ejemplo con varios PERFORM anidados:
...
WORKING-STORAGE SECTION.
01  NOMBRE   PIC X(12).
01  APELLIDO PIC X(12).
01  SALUDO   PIC X(30).
01  OP           PIC X.
01  LI            PIC 99.
01  CONTA1   PIC 99.
01  CONTA2   PIC 9(6).
PROCEDURE DIVISION.
INICIO.
       DISPLAY 'PROGRAMA DE SALUDO' LINE 1 ERASE
       PERFORM PIDENOMBRE THRU PIDEAPELLIDO
       STRING 'HOLA ' DELIMITED BY SIZE NOMBRE DELIMITED BY ' '
       ' ' DELIMITED BY SIZE APELLIDO DELIMITED BY ' ' INTO SALUDO
       PERFORM VARYING LI FROM 10 BY 1 UNTIL LI = 15
            PERFORM VARYING CONTA1 FROM 1 BY 1 UNTIL CONTA1 > 30
                 DISPLAY SALUDO(CONTA1:1) LINE LI COL CONTA1 LOW
                 PERFORM VARYING CONTA2 FROM 1 BY 1 UNTIL CONTA2 > 400000
                    MOVE ' ' TO OP
                 END-PERFORM
            END-PERFORM
       END-PERFORM
       DISPLAY 'FINALIZADO' LINE 22
       ACCEPT OP
       STOP RUN.
PIDENOMBRE.
       DISPLAY 'INTRODUZCA EL NOMBRE ..' LINE 20
       ACCEPT NOMBRE LINE 20 COL 30 PROMPT.
PIDEAPELLIDO.
       DISPLAY 'INTRODUZCA EL APELLIDO ..' LINE 21
       ACCEPT APELLIDO LINE 21 COL 30 PROMPT
       DISPLAY SPACES LINE 20 SIZE 70
       DISPLAY SPACES LINE 21 SIZE 70.
...

Nota: En el ejemplo como véis, después de aceptar el nombre y el apellido


construimos una frase y la guardamos en la variablen SALUDO utilizando el comando
STRING. A continuación y para mantener los mismos ejemplos de toda la sección
hacemos que aparezca en pantalla el SALUDO 5 veces, (dependiendo del valor de LI,
que como dijimos antes sería para 10, 11, 12, 13 y 14).
Pero ahora hemos intercalado dos PERFORM dentro de éste, el primero para que nos
muestre el mensaje letra a letra y el segundo para hacer de retardo y así conseguir
un efecto como si escribiéramos el SALUDO con una máquina de escribir.

Como pódeis observar el único punto de toda la secuencia se haya en el STOP RUN. El
hecho de mantener los márgenes izquierdos, es para dar mas claridad a la
programación y conseguir que ésta sea lo mas estructurada posible.

AUN HAY MAS


Pues sí, podemos desarrollar aún mas la instrucción incluyendo dos nuevos elementos.
EJECUTANDO ANTES O DESPUES
En primer lugar, por defecto el contenido del PERFORM se ejecuta después de hacer la
comprobación de la condición que precede a UNTIL, pero podemos hacer que ésta se realice
antes.
46
PERFORM  WITH TEST  [AFTER - BEFORE ] VARYING  variable FROM
número, variable  BY  número, valor  UNTIL  condición
     sentencias 
END-PERFORM
Con la opción TEST BEFORE, que es la opción por defecto se comprueba primero la condición y si
se cumple se ejcuta el resto, con lo cual es posible que las sentencias no se ejecuten ninguna
vez, si al comenzar ya está rota la condición.
Con la opción TEST AFTER,  se ejecutan las sentencias antes de comprobar la condición, con lo
cual las sentencias se van a ejecutar al menos en una ocasión, incluso aunque entremos en el
PERFORM con la condición rota.
AUMENTANDO LAS CONDICIONES
Efectivamente además de la primera condición podemos incrementar el número de condiciones
para que se cumplan los requisitos y así ejecutar las sentencias. Esto lo conseguimos incluyendo
mas cláusulas precedidas de AFTER.
PERFORM  WITH TEST  [AFTER - BEFORE ] VARYING  variable FROM
número, variable  BY  número, valor  UNTIL  condición
AFTER  variable FROM  número, variable  BY  número, valor  UNTIL  condición
     sentencias 
AFTER .......
END-PERFORM
Al aplicar este formato cuando se cumpla la primera condición pasará el control al AFTER y
comprobará de nuevo la condición que precede al siguiente UNTIL según los valores
especificados en la línea que contiene AFTER. Además podemos ir incrementando el número de
condiciones a nuestro antojo, consiguiendo de éste modo hacer unos anidamientos y un
desarrollo mas completo de la sentencia, obteniendo por consiguiente unos niveles de
perfeccionamiento muy altos.

RESUMIENDO
Una mayor utilización de PERFORM sin duda traerá un uso menor de la declaración GO y con ello
conseguimos una programación estructurada. Las ventajas de la programación estructurada las
quiero explicar en un apartado dentro de ésta misma sección de Manuales, una vez explique las
sentenicas GO e IF, que serán la siguiente aportación al manual.
En esa nueva sección se verá un caso mas práctico y real de utilización de PERFORM con uso de
lecturas de ficheros y demás experiencias cotidianas en el mundo de la programación en el
ámbito de la gestión.

También podría gustarte