miércoles, 9 de febrero de 2011

Ejemplo 1: Leer de SYSIN y escribir en SYSOUT.

En cobol hay que diferenciar entre los programas que acceden a DB2 y los que no, pues se compilarán de maneras diferentes y se ejecutarán de forma diferente.
Enpezaremos por ver el programa sin DB2 más sencillo:

El programa más sencillo es aquel que recibe datos por SYSIN del JCL y los muestra por SYSOUT.

JCL:

//PROG1 EXEC PGM=PRUEBA1
//SYSOUT DD SYSOUT=*
//SYSIN DD *
JOSE LOPEZ VAZQUEZ HUGO CASILLAS DIAZ JAVIER CARBONERO PACO GONZALEZ
/*


donde EXEC PGM= indica el programa SIN DB2 que vamos a ejecutar
SYSOUT DD SYSOUT=* indica que la información "displayada" se quedará en la cola del SYSOUT (no lo vamos a guardar en un fichero)
en SYSIN DD * metemos la información que va a recibir el programa

Fijaos en las posiciones de los nombres de la SYSIN, para entender bien el programa:

----+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8
JOSE LOPEZ VAZQUEZ  HUGO CASILLAS DIAZ  JAVIER CARBONERO    PACO GONZALEZ


Como veis, la longitud máxima que se puede pasar a un programa a través de la SYSIN es de 80. En nuestro caso la hemos dividido en 4 trozos de 20 posiciones, cada uno con un nombre.

PROGRAMA:

 IDENTIFICATION DIVISION.
 PROGRAM-ID. PRUEBA1.
*==========================================================*
*     PROGRAMA QUE LEE DE SYSIN Y ESCRIBE EN SYSOUT
*==========================================================*
*
 ENVIRONMENT DIVISION.
*
 CONFIGURATION SECTION.
*
 SPECIAL-NAMES.
     DECIMAL-POINT IS COMMA.
*
 DATA DIVISION.
*
 WORKING-STORAGE SECTION.
*
 01 WI-INDICE PIC 9(4) COMP.
 01 WX-SYSIN PIC X(80).
 01 WX-TABLA-NOMBRES.
    05 WX-NOMBRE PIC X(20) OCCURS 4 TIMES.
*
************************************************************
 PROCEDURE DIVISION.
************************************************************
*  |     0000 - PRINCIPAL
*--|------------------+----------><----------+-------------*
* 1| EJECUTA EL INICIO DEL PROGRAMA
* 2| EJECUTA EL PROCESO DEL PROGRAMA
* 3| EJECUTA EL FINAL DEL PROGRAMA
************************************************************
 00000-PRINCIPAL.
*
     PERFORM 10000-INICIO
*
     PERFORM 20000-PROCESO
*
     PERFORM 30000-FINAL
     .
************************************************************
*  |     10000 - INICIO
*--|------------+----------><----------+-------------------*
*  | SE REALIZA EL TRATAMIENTO DE INICIO:
* 1| Inicialización de Áreas de Trabajo
* 2| Primera lectura de SYSIN
************************************************************
 10000-INICIO.
*
     INITIALIZE WX-SYSIN

     ACCEPT WX-SYSIN FROM SYSIN

     .
************************************************************
*  |     20000 - PROCESO
*--|------------------+----------><------------------------*
*  | SE REALIZA EL TRATAMIENTO DE LOS DATOS:
* 1| Realiza el tratamiento de cada registro leido
************************************************************
 20000-PROCESO.
*
     MOVE WX-SYSIN TO WX-TABLA-NOMBRES
     MOVE 1        TO WI-INDICE

     PERFORM UNTIL WI-INDICE GREATER 4
        DISPLAY 'WX-NOMBRE:'WX-NOMBRE(WI-INDICE)

        ADD 1 TO WI-INDICE
     END-PERFORM

     .
************************************************************
*  |     30000 - FINAL
*--|------------------+----------><----------+-------------*
*  | FINALIZA LA EJECUCION DEL PROGRAMA
************************************************************
 30000-FINAL.
*
     STOP RUN
     .



En el programa podemos ver las siguientes divisiones/secciones:
IDENTIFICATION DIVISION: existirá siempre.
ENVIRONMENT DIVISION: existirá siempre.
  CONFIGURATION SECTION: existirá siempre.
  En este caso no existirá la INPUT-OUTPUT SECTION, pues nuestro programa no utiliza ficheros.
DATA DIVISION: existirá siempre.
  En este caso no existirá la FILE SECTION, pues nuestro programa no utiliza ficheros.
  WORKING-STORAGE SECTION: exisitirá siempre.
  En este caso no exisistirá la LINKAGE SECTION pues el programa no se comunica con otros programas.
PROCEDURE DIVISION: exisitirá siempre.


En el programa podemos ver las siguientes sentencias:
PERFORM: llamada a párrafo
INITIALIZE: para inicializar variable
ACCEPT: esta sentencia recoge la información del campo indicado en el "FROM". En este caso recoge la información almacenada en "SYSIN"; la que nosotros hemos introducido en el JCL.
MOVE/TO: movemos la información de un campo a otro
PERFORM UNTIL: bucle
DISPLAY: escribe el contenido del campo indicado en la SYSOUT del JCL.
ADD:Operador de adición (suma)
STOP RUN: sentencia de finalización de ejecución.


Descripción del programa:
En el párrafo de inicio, inicializamos WX-SYSIN para guardar posteriormente mediante un ACCEPT la información que hemos escrito en la SYSIN del JCL.

En el párrafo de proceso, informamos la tabla interna WX-TABLA-NOMBRES, donde el campo WX-NOMBRES se repetirá 4 veces (occurs 4 times).

Informamos el campo WI-INDICE con un 1, pues vamos a utilizar los campos de la tabla interna:
Para utilizar un campo que pertenezca a una tabla interna (tiene occurs), debemos acompañar el campo de un "índice" entre paréntesis. De tal forma que indiquemos a que "ocurrencia" de la tabla nos estamos refiriendo. Por ejemplo, WX-NOMBRE(1) sería el primer nombre guardado (JOSE LOPEZ VAZQUEZ).
Como queremos displayar todas las ocurrencias de la tabla, haremos que el índice sea una variable que va aumentando.

A continuación montamos un bucle (perform until) con la condición WI-INDICE mayor (greater) de 4, pues la primera vez WI-INDICE valdrá 1, y necesitamos que el bucle se repita 4 veces:
WI-INDICE = 1: WX-NOMBRE(1) = JOSE LOPEZ VAZQUEZ
WI-INDICE = 2: WX-NOMBRE(2) = HUGO CASILLAS DIAZ
WI-INDICE = 3: WX-NOMBRE(3) = JAVIER CARBONERO
WI-INDICE = 4: WX-NOMBRE(4) = PACO GONZALEZ
WI-INDICE = 5: salimos del bucle porque se cumple WI-INDICE GREATER 4


NOTA: el índice de una tabla interna NUNCA puede ser cero, pues no existe la ocurrencia cero. Si no informásemos WI-INDICE con 1, el DISPLAY de WX-NOMBRE(0) nos daría un estupendo casque, de este estilo:

IGZ0006S The reference to table WX-NOMBRE by verb number 01 on line 001099 addressed an area outside the region of the table.
From compile unit R2BCTAN1 at entry point R2BCTAN1 at compile unit offset +00001122 at entry offset +00001122 at address 1965BBAA.

Aunque ahora ya sabemos cómo encontrar la línea que nos da el OFFSET :D

RESULTADO:
WX-NOMBRE: JOSE LOPEZ VAZQUEZ
WX-NOMBRE: HUGO CASILLAS DIAZ
WX-NOMBRE: JAVIER CARBONERO
WX-NOMBRE: PACO GONZALEZ

15 comentarios:

Andy dijo...

tengo una duda respecto al JCL, de que manera se determina en el codigo donde empieza y donde termina un nombre completo?

Es decir como lograron dividir la cadena de 80 caracteres con todos los nombres en subcadenas de longitud variable?? (paco gonzalez no tiene la misma longitud que jose lopez vazquez)

agradeceria una respuesta, muy bueno el blog!

Saludos

Tallian dijo...

Hola Andy,
lo que hice fue que cada nombre ocupase 20 posiciones, rellenando con espacios al final los más cortos.
Si te fijas, el primer nombre empieza en la posición 1, el segundo nombre en la 21, el tercer nombre en la 41, y el cuarto nombre en la 61.
Por eso se puede guardar en 4 variables de longitud 20.
Son los espacios al final los que completan las 20 posiciones.

Si necesitas cualquier otra cosa me dices : )

Andy dijo...

es verdad era bastante obvia la respuesta pero aun asi te la agradezco talian! jejeje

Excelente el blog, sigan enseñandonos el arte de programar en COBOL

Tallian dijo...

Para eso estamos Andy!
: )

Anónimo dijo...

Felicidades!! estupendo el blog

Tallian dijo...

Muchas gracias^^

santiago dijo...

tengo una duda al ver el programa creí que los nombres aparecerían en una sola linea, pero aparecieron en lineas distintas, con que instrucción le dices al programa que divida los nombre? o cada ocurrencia se hace en una linea?.. gracia por la info es un exelente blog... estoy iniciando en la programación Cobol llevo 1 semana de curso. gracias por la respuesta...

Tallian dijo...

Hola Santiago.
Los nombres aparecen en lineas distintas porque hacemos un display por cada ocurrencia (lo que displayamos es WX-NOMBRE).
Para que saliesen en una sola linea tendrias q displayar WX-TABLA-NOMBRES, que es la variable de nivel superior que los contiene a todos.

Saludos!

Juan José Cerezo Mata dijo...

Utilizo Cobol MicroFocus for visual studio 2010, he plantado este programa de ejemplo y bueno decir que falta un punto despues del END-PERFORM si no el 30000-FINAL da error, (hacia tiempo que no utilizaba cobol y esta pagina me viene que ni pintado para recordar), de todos modos no entiendo porque cuando ejecuto el programa no me aparece nada en pantalla se queda a la espera de una pulsacion e inmediatamente despues la ejecución termina, no se si sera porque no haya escogido correctamente el tipo de proyecto

Uso windows 8.1 64 bits el visual studio 2010 ultimate de 32 bits y por supuesto el visual cobol 2.2 for visual studio 2010,

el tipo de proyecto utilizado es COBOL Managed, console application, quizas el problema sea que no debe de ser un COBOL Managed si no un COBOL Native, lo pruebo y comento.

Juan José Cerezo Mata dijo...

Me corrigo el problema es el JCL, se me olvido, pero de todos modos la version free de visual cobol no permite JCL ni CICS, onggg

Anónimo dijo...

Hola, tengo una consulta para hacerles, bastante parecida al ejemplo anterior.
Mi programa recibe un parametro por SYSIN de 60 caracteres maximo, los cuales dividos de a 4 posiciones representan sucursales, las cuales las tengo que mostrar por pantalla, una al lado de la otra separadas por un espacio y ademas solo entran 5 sucursales por linea.

La unica manera que encontre para hacerlo es de la siguiente manera:

PRIMERA LINEA DEL DISPLAY
05 WSV-SUCURS1 PIC X(25) VALUE SPACES.
05 WST-SAL-PAR1 REDEFINES WSV-SUCURS1 OCCURS 5 TIMES.
10 WST-SAL-SUC1 PIC X(04).
10 FILLER PIC X(01).

SEGUNDA LINEA DEL DISPLAY
05 WSV-SUCURS2 PIC X(25) VALUE SPACES.
05 WST-SAL-PAR2 REDEFINES WSV-SUCURS2 OCCURS 5 TIMES.
10 WST-SAL-SUC2 PIC X(04).
10 FILLER PIC X(01).

TERCERA LINEA DEL DISPLAY
05 WSV-SUCURS3 PIC X(25) VALUE SPACES.
05 WST-SAL-PAR3 REDEFINES WSV-SUCURS3 OCCURS 5 TIMES.
10 WST-SAL-SUC3 PIC X(04).
10 FILLER PIC X(01).

310000-ARMAR-PAR-INGRESADO.

MOVE WSC-1 TO WSI-I
WSI-J
WSI-K
PERFORM VARYING WSI-I FROM WSC-1 BY WSC-1 UNTIL
WSI-I > WSA-TOPE-VECT
EVALUATE TRUE
WHEN WSI-I <= WSC-5
MOVE WST-SUC(WSI-I) TO WST-SAL-SUC1(WSI-I)
WHEN WSI-I > WSC-5 AND WSI-I <= WSC-10
COMPUTE WSI-J = WSI-I - WSC-5
MOVE WST-SUC(WSI-I) TO WST-SAL-SUC2(WSI-J)
WHEN WSI-I > WSC-10
COMPUTE WSI-K = WSI-J - WSC-5
MOVE WST-SUC(WSI-I) TO WST-SAL-SUC3(WSI-K)
END-EVALUATE

END-PERFORM.
(el tope es 15 occurs, 60 / 4 = 15 )

Ojala puedan darme una mano, saludos !!

Mauricio Vega dijo...

Hola, Un comentario.
Tengo esta situación: Un archivo que tiene una lista de archivos(datos).
Con qué comandete leo cada linea de ese archivo.?
gracias.

ACN dijo...

Buenas, Pregunta facilita, como hago para crear un ejecutable que no me de error. La compilacion me va cien pero al ejecutar casca. El JCL de compilacion me crea el PDS (OBJ) con formato FB no U, si intento ejecutar el archivo que me genera, se me produce un abend S806. Podría facilitarme un JCL de ejemplo para compilación y para ejecución. Tengo el ADCD 1.9

ACN dijo...

Buenas, me respondo yo mismo, logre solucionar el problema. Cuento lo que hice por si ayuda a alguien. El problema estaba en el PROC que llamaba mi JCL de compilación, éste no tenia los PDS correctos (lo pude comprobar cuando ví el JCL expandido en el spool) y el programa de linkage (HEWL) no encontraba los miembros que necesitaba, éstos se encontraban en CEE.SCEELKED.

Gracias y Saludos

David dijo...

HOLA TENGO UNA DUDA COMO SERIA EL JCL COMPLETO PARA ESTE PROGRAMA?