En PL/I 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 SYSPRINT.
JCL:
//PROG1 EXEC PGM=PRUEBA1
//SYSPRINT DD SYSOUT=*
//SYSIN DD *
JOSE LOPEZ VAZQUEZ HUGO CASILLAS DIAZ
JAVIER CARBONERO PACO GONZALEZ
JESUS IGLESIAS RICARDO MONTES
/*
donde EXEC PGM= indica el programa SIN DB2 que vamos a ejecutar
SYSPRINT DD SYSOUT=* indica que la información "displayada" se quedará en la cola del SYSPRINT (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
JESUS IGLESIAS RICARDO MONTES
Como veis, hemos dividido la información en 2 trozos de 20 posiciones, cada uno con un nombre. Además hemos escrito varias líneas de SYSIN, pues como vimos en el artículo de Ficheros en PL/I, podemos recuperar varias líneas (en COBOL esto no es posible).
PROGRAMA:
PLIPRU1: PROCEDURE OPTIONS (MAIN);
/* PROGRAMA QUE LEE DE SYSIN(GET EDIT)*/
/* Y ESCRIBE EN SYSPRINT (PUT EDIT) */
/*DEFINIMOS SYSIN*/
DCL SYSIN FILE STREAM INPUT;
/*DEFINIMOS SYSPRINT*/
DCL SYSPRINT FILE PRINT;
/*DECLARACION DE VARIABLES DEL PROGRAMA*/
DCL 1 TABLA_NOMBRES,
2 NOMBRE(6) CHAR(20);
DCL 1 LINEA_SYSIN,
2 NOMBRE_SYSIN1 CHAR(20),
2 NOMBRE_SYSIN2 CHAR(20);
DCL CONT_NOMBRE DEC FIXED (2);
DCL FIN CHAR(1) INIT ('0');
/*CONTROL FIN SYSIN*/
ON ENDFILE(SYSIN) BEGIN;
FIN = '1';
END;
/*PROCESO DEL PROGRAMA*/
GET FILE(SYSIN) EDIT(LINEA_SYSIN)(A(40));
CONT_NOMBRE = 1;
DO WHILE (FIN = '0');
CALL MOVER_A_TABLA;
GET FILE(SYSIN) EDIT(LINEA_SYSIN)(A(40));
END;
CALL PINTAR_NOMBRES;
/*PARRAFO QUE GUARDA LOS NOMBRES RECUPERADOS EN TABLA_NOMBRES*/
MOVER_A_TABLA: PROC;
NOMBRE(CONT_NOMBRE) = NOMBRE_SYSIN1;
CONT_NOMBRE = CONT_NOMBRE + 1;
NOMBRE(CONT_NOMBRE) = NOMBRE_SYSIN2;
CONT_NOMBRE = CONT_NOMBRE + 1;
END MOVER_A_TABLA;
/*PARRAFO QUE ESCRIBE EN EL SYSPRINT LOS NOMBRES DE LA SYSIN*/
PINTAR_NOMBRES: PROC;
CONT_NOMBRE = 1;
DO WHILE CONT_NOMBRE < 7
PUT EDIT('NOMBRE: ', NOMBRE(CONT_NOMBRE)) (SKIP,A,A);
CONT_NOMBRE = CONT_NOMBRE + 1;
END;
END PINTAR_NOMBRES;
END PLIPRU1;
En el programa podemos ver las siguientes sentencias:
ON ENDFILE(SYSIN): controla el final de la SYSIN (como el fin fichero pero para la SYSIN).
GET FILE: lee del fichero STREAM SYSIN.
DO WHILE: es un bucle. Las instrucciones de dentro del bucle se harán MIENTRAS se cumpla la condición indicada.
CALL: llamada a párrafo
PUT EDIT: escribe en el fichero STREAM SYSPRINT.
SKIP: indica salto de línea.
END PLIPRU1: indica fin del programa.
Descripción del programa:
Al inicio, declararemos los ficheros y las variables que utilizaremos a lo largo del programa.
En el proceso principal, leemos el primer registro de la SYSIN y ponemos a 1 el contador CONT_NOMBRE y montamos un bucle para recuperar todos los registros.
En el párrafo MOVER_A_TABLA guardamos los 2 nombres recuperados de la SYSIN en diferentes filas de la tabla TABLA_NOMBRES. Para ello indicamos entre paréntesis el número de la fila donde se va a guardar. El máximo de filas de la tabla es 6 (es el número indicado entre paréntesis al lado del campo NOMBRE).
En el párrafo PINTAR_NOMBRES escribiremos en el SYSPRINT todos los nombres guardados en nuestra TABLA_NOMBRES.
Informamos el campo CONT_NOMBRE con un 1, pues vamos a utilizar los campos de la tabla interna:
Para utilizar un campo que pertenezca a una tabla interna, debemos acompañar el campo de un "índice" entre paréntesis. De tal forma que indiquemos a que fila de la tabla nos estamos refiriendo. Por ejemplo, NOMBRE(1) sería el primer nombre guardado (JOSE LOPEZ VAZQUEZ).
Como queremos displayar todas las filas de la tabla, haremos que el índice sea una variable que va aumentando.
A continuación montamos un bucle (DO WHILE) con la condición CONT_NOMBRE menor de 7, pues el máximo es 6. La primera vez CONT_NOMBRE valdrá 1, y necesitamos que el bucle se repita 6 veces:
CONT_NOMBRE = 1: NOMBRE(1) = JOSE LOPEZ VAZQUEZ
CONT_NOMBRE = 2: NOMBRE(2) = HUGO CASILLAS DIAZ
CONT_NOMBRE = 3: NOMBRE(3) = JAVIER CARBONERO
CONT_NOMBRE = 4: NOMBRE(4) = PACO GONZALEZ
CONT_NOMBRE = 5: NOMBRE(5) = JESUS IGLESIAS
CONT_NOMBRE = 6: NOMBRE(6) = RICARDO MONTES
CONT_NOMBRE = 7: salimos del bucle porque ya no se cumple CONT_NOMBRE menor que 7
NOTA: el índice de una tabla interna NUNCA puede ser cero, pues no existe la fila cero. Si no informásemos CONT_NOMBRE con 1, el PUT de NOMBRE(0) nos daría un estupendo OFFSET.
RESULTADO:
NOMBRE: JOSE LOPEZ VAZQUEZ
NOMBRE: HUGO CASILLAS DIAZ
NOMBRE: JAVIER CARBONERO
NOMBRE: PACO GONZALEZ
NOMBRE: JESUS IGLESIAS
NOMBRE: RICARDO MONTES
He de decir que no me ha dado tiempo a ejecutar este ejemplo, en cuanto tenga un rato lo pruebo y corrijo si es necesario.
Mostrando entradas con la etiqueta pli. Mostrar todas las entradas
Mostrando entradas con la etiqueta pli. Mostrar todas las entradas
miércoles, 22 de junio de 2011
lunes, 13 de junio de 2011
Ficheros en PL/I
Seguimos adentrándonos en el mundo del PL/I. En este artículo veremos los tipos de ficheros con los que se puede trabajar y como defenirlos. Los usos los iremos viendo en futuros ejemplos.
FICHEROS RECORD
Como vimos en artículos anteriores, un programa PL/I no tiene divisiones como el COBOL, por lo que podremos definir el fichero en cualquier punto del programa. Para poner orden, lo definiremos al principio del procedimiento principal.
Los ficheros de tipo RECORD deben declararse explícitamente.
PRUEBA1: PROCEDURE OPTIONS(MAIN);
DCL FICHERO1 FILE INPUT;
Donde FICHERO1 será el nombre lógico del fichero, que se corresponderá con el nombre que se le haya dado en el JOB.
FILE nos indica que se trata de un fichero.
INPUT es el atributo, y nos indica que se trata de un fichero de entrada. Otros posibles atributos son:
OUTPUT: fichero de salida.
UPDATE: fichero de entrada y salida (para modificaciones; DISP=MOD).
SEQUENTIAL: fichero secuencial.
DIRECT: acceso directo.
INDEXED: fichero indexado.
KEYED: para acceder al fichero se utilizarán claves.
ENVIROMENT: describe el conjunto de datos externos asociados al fichero (ej: ENV(VSAM)).
EXTERNAL: el fichero es un elemento externo al programa.
RECORD: fichero tipo record.
Apertura/Cierre
Forma explícita:
OPEN FILE (FICHERO1); / CLOSE FILE (FICHERO1);
Podemos añadir atributos a continuación del nombre, siempre que no se contradigan con lo declarado en la definición.
Forma implícita:
Si se ejecuta una instrucción de entrada/salida sin haber abierto el fichero con la sentencia OPEN, el sistema abrirá el fichero de forma implícita y se le asignarán los atributos que tenga en la declaración.
Si no hacemoe el CLOSE del fichero, el sistema lo cerrará al final de la ejecución.
OJO! En los ficheros de salida, importante hacer OPEN. Si por casuística no se escribe sobre ellos, el sistema intentará cerrarlos al final de la ejecución, y al no haberlos abierto previamente dará un error.
Lectura
Dependerá del tipo de acceso:
SEQUENTIAL(secuencial)
READ FILE (FICHERO1) INTO (REG_ENTRADA);
Donde REG_ENTRADA es la variable donde se guardará la información del registro.
DIRECT(directo)
READ FILE (FICHERO1) INTO (REG_ENTRADA) KEY(CLAVE);
Donde KEY indica que se accederá por clave, y CLAVE es una variable donde estará el valor de la clave por la que vamos a acceder.
Escritura
Dependerá del tipo de acceso.
SEQUENTIAL(secuencial)
WRITE FILE (FICHERO2) FROM (REG_SALIDA);
Donde REG_SALIDA es la variable que contiene la información que escribiremos en el fichero.
DIRECT(directo)
WRITE FILE (FICHERO2) FROM (REG_SALIDA) KEYFROM (CLAVE);
Donde KEYFROM indica que se accederá por clave, y la varriable CLAVE llevará el valor de la clave.
Modificación/Sobreescritura
Dependerá del tipo de acceso.
SEQUENTIAL(secuencial)
REWRITE FILE (FICHERO3) FROM (REG_ENTSAL);
Donde REWRITE indica sobreescritura.
DIRECT(directo)
REWRITE FILE (FICHERO3) FROM (REG_ENTSAL) KEY(CLAVE);
Borrado
Dependerá del tipo de acceso.
SEQUENTIAL(secuencial)
Todo borrado debe estar precedido por una operación de lectura.
DELETE FILE (FICHERO4);
Donde DELETE indica que debe borrarse el último registro leído del fichero especificado.
DIRECT(directo)
DELETE FILE (FICHERO4) KEY (CLAVE);
Donde DELETE indica que debe borrarse el registro del fichero y clave especificados.
FICHEROS STREAM
El acceso siempre es de tipo SEQUENTIAL(secuencial). Los datos se guardan como una cadena de caracteres.
Existen 3 tipos de declaración para estos ficheros:
1. Explícita.
DCL SYSIN FILE STREAM INPUT;
DCL SYSPRINT FILE PRINT;
Donde STREAM indica que el fichero se procesará por flujo de caracteres.
PRINT indica que el fichero es de tipo impresora.
Estos dos ejemplos se refieren a la SYSIN de un JOB y a la cola del SYSPRINT. En la SYSIN escribiremos los datos que va a leer el programa, y en ek SYSPRINT escribiremos datos de salida.
El resto de posibles atributos son los mismos que para los ficheros RECORD.
2. Implícita.
Si omitimos el nombre del fichero en una operación de lectura (READ), el sistema supondrá que se trata de un fichero STREAM INPUT (SYSIN). En caso de la escritura (WRITE) se asumirá STREAM OUTPUT (SYSPRINT).
3. Por defecto.
Si se realiza una operación de entrada/salida contra un fichero que no tenga atributos se considerará STREAM por defecto.
Apertura/Cierre
Es el mismo caso que para los ficheros RECORD.
Lectura
GET FILE (SYSIN) LIST/DATA/EDIT;
Donde GET indica orden de lectura.
SYSIN indica que se trata del fichero del sistema. Si no se indica nombre asume SYSIN.
LIST/DATA/EDIT: son las opciones de lectura que se pueden indicar.
LIST: requiere que los datos de entrada estén en formato dato1,...,datoN. Entre cada dato debe haber una coma o un espacio en blanco. Cada dato se leerá sobre la variable indicada.
SYSIN DD *
datos1 datos2 datos3
/*
GET FILE LIST(variable_1, variable_2, variable_3);
DATA: requiere que la entrada esté en el formato var_1 = dato_1. Entre und ato y la variable siguiente debe haber una coma o un espacio en blanco. Cada dato se copiará sobre su variable correspondiente.
SYSIN DD *
var1=datos1 var2=datos2 var3=datos3
/*
GET FILE DATA (variable_1,variable_2,variable_3);
EDIT: los datos están dispuestos igual que en la opción LIST, pero podemos añadir el formato en que los leemos.
SYSIN DD *
campo1 campo2 campo3
/*
GET FILE EDIT (variable1,variable2,variable3) (A,A,A);
Los formatos que se pueden indicar son:
SKIP(n): salta n líneas antes de leer.
COL(n): se posiciona en la columna n antes de leer.
A: datos alfanuméricos.
P'formato PIC': datos numéricos. Ej P'999'.
X(n): salta n posiciones antes de leer.
Vamos a fijarnos en la opción SKIP.
Pensad que estamos leyendo de la SYSIN, y con SKIP le estamos indicando que salte a la siguiente línea de la SYSIN:
SYSIN DD *
campo1
campo2
campo3
/*
Esto en COBOL no sería posible, pues la SYSIN tiene una única línea que se recupera mediante un ACCEPT.
Sin embargo en PL/I podemos introducir mucha más información a través de la SYSIN.
Escritura
PUT FILE (SYSPRINT) LIST/DATA/EDIT;
Donde PUT indica orden de escritura.
Si no se indica nombre del fichero el sistema asume SYSPRINT.
LIST/DATA/EDIT son las mismas opciones que para el GET, pero referido a los datos que vamos a escribir. En EDIT se ñade la opción de "PAGE" para hacer salto de página al escribir.
"Los PUT" en PL/I son el equivalente a los DISPLAYs en COBOL. Cuando necesitemos "displayar" alguna variable para controles de errores, buscar un fallo en el programa, etc. lo haremos con un PUT y la información saldrá en el SYSPRINT en lugar de salir en la SYSOUT.
Tanto para programa ONLINE como BATCH, podremos ver los "PUTs" en el SYSPRINT.
En próximos artículos veremos ejemplos concretos del uso de estos ficheros. Hasta entonces, cualquier duda preguntad sin problema : )
FICHEROS RECORD
Como vimos en artículos anteriores, un programa PL/I no tiene divisiones como el COBOL, por lo que podremos definir el fichero en cualquier punto del programa. Para poner orden, lo definiremos al principio del procedimiento principal.
Los ficheros de tipo RECORD deben declararse explícitamente.
PRUEBA1: PROCEDURE OPTIONS(MAIN);
DCL FICHERO1 FILE INPUT;
Donde FICHERO1 será el nombre lógico del fichero, que se corresponderá con el nombre que se le haya dado en el JOB.
FILE nos indica que se trata de un fichero.
INPUT es el atributo, y nos indica que se trata de un fichero de entrada. Otros posibles atributos son:
OUTPUT: fichero de salida.
UPDATE: fichero de entrada y salida (para modificaciones; DISP=MOD).
SEQUENTIAL: fichero secuencial.
DIRECT: acceso directo.
INDEXED: fichero indexado.
KEYED: para acceder al fichero se utilizarán claves.
ENVIROMENT: describe el conjunto de datos externos asociados al fichero (ej: ENV(VSAM)).
EXTERNAL: el fichero es un elemento externo al programa.
RECORD: fichero tipo record.
Apertura/Cierre
Forma explícita:
OPEN FILE (FICHERO1); / CLOSE FILE (FICHERO1);
Podemos añadir atributos a continuación del nombre, siempre que no se contradigan con lo declarado en la definición.
Forma implícita:
Si se ejecuta una instrucción de entrada/salida sin haber abierto el fichero con la sentencia OPEN, el sistema abrirá el fichero de forma implícita y se le asignarán los atributos que tenga en la declaración.
Si no hacemoe el CLOSE del fichero, el sistema lo cerrará al final de la ejecución.
OJO! En los ficheros de salida, importante hacer OPEN. Si por casuística no se escribe sobre ellos, el sistema intentará cerrarlos al final de la ejecución, y al no haberlos abierto previamente dará un error.
Lectura
Dependerá del tipo de acceso:
SEQUENTIAL(secuencial)
READ FILE (FICHERO1) INTO (REG_ENTRADA);
Donde REG_ENTRADA es la variable donde se guardará la información del registro.
DIRECT(directo)
READ FILE (FICHERO1) INTO (REG_ENTRADA) KEY(CLAVE);
Donde KEY indica que se accederá por clave, y CLAVE es una variable donde estará el valor de la clave por la que vamos a acceder.
Escritura
Dependerá del tipo de acceso.
SEQUENTIAL(secuencial)
WRITE FILE (FICHERO2) FROM (REG_SALIDA);
Donde REG_SALIDA es la variable que contiene la información que escribiremos en el fichero.
DIRECT(directo)
WRITE FILE (FICHERO2) FROM (REG_SALIDA) KEYFROM (CLAVE);
Donde KEYFROM indica que se accederá por clave, y la varriable CLAVE llevará el valor de la clave.
Modificación/Sobreescritura
Dependerá del tipo de acceso.
SEQUENTIAL(secuencial)
REWRITE FILE (FICHERO3) FROM (REG_ENTSAL);
Donde REWRITE indica sobreescritura.
DIRECT(directo)
REWRITE FILE (FICHERO3) FROM (REG_ENTSAL) KEY(CLAVE);
Borrado
Dependerá del tipo de acceso.
SEQUENTIAL(secuencial)
Todo borrado debe estar precedido por una operación de lectura.
DELETE FILE (FICHERO4);
Donde DELETE indica que debe borrarse el último registro leído del fichero especificado.
DIRECT(directo)
DELETE FILE (FICHERO4) KEY (CLAVE);
Donde DELETE indica que debe borrarse el registro del fichero y clave especificados.
FICHEROS STREAM
El acceso siempre es de tipo SEQUENTIAL(secuencial). Los datos se guardan como una cadena de caracteres.
Existen 3 tipos de declaración para estos ficheros:
1. Explícita.
DCL SYSIN FILE STREAM INPUT;
DCL SYSPRINT FILE PRINT;
Donde STREAM indica que el fichero se procesará por flujo de caracteres.
PRINT indica que el fichero es de tipo impresora.
Estos dos ejemplos se refieren a la SYSIN de un JOB y a la cola del SYSPRINT. En la SYSIN escribiremos los datos que va a leer el programa, y en ek SYSPRINT escribiremos datos de salida.
El resto de posibles atributos son los mismos que para los ficheros RECORD.
2. Implícita.
Si omitimos el nombre del fichero en una operación de lectura (READ), el sistema supondrá que se trata de un fichero STREAM INPUT (SYSIN). En caso de la escritura (WRITE) se asumirá STREAM OUTPUT (SYSPRINT).
3. Por defecto.
Si se realiza una operación de entrada/salida contra un fichero que no tenga atributos se considerará STREAM por defecto.
Apertura/Cierre
Es el mismo caso que para los ficheros RECORD.
Lectura
GET FILE (SYSIN) LIST/DATA/EDIT;
Donde GET indica orden de lectura.
SYSIN indica que se trata del fichero del sistema. Si no se indica nombre asume SYSIN.
LIST/DATA/EDIT: son las opciones de lectura que se pueden indicar.
LIST: requiere que los datos de entrada estén en formato dato1,...,datoN. Entre cada dato debe haber una coma o un espacio en blanco. Cada dato se leerá sobre la variable indicada.
SYSIN DD *
datos1 datos2 datos3
/*
GET FILE LIST(variable_1, variable_2, variable_3);
DATA: requiere que la entrada esté en el formato var_1 = dato_1. Entre und ato y la variable siguiente debe haber una coma o un espacio en blanco. Cada dato se copiará sobre su variable correspondiente.
SYSIN DD *
var1=datos1 var2=datos2 var3=datos3
/*
GET FILE DATA (variable_1,variable_2,variable_3);
EDIT: los datos están dispuestos igual que en la opción LIST, pero podemos añadir el formato en que los leemos.
SYSIN DD *
campo1 campo2 campo3
/*
GET FILE EDIT (variable1,variable2,variable3) (A,A,A);
Los formatos que se pueden indicar son:
SKIP(n): salta n líneas antes de leer.
COL(n): se posiciona en la columna n antes de leer.
A: datos alfanuméricos.
P'formato PIC': datos numéricos. Ej P'999'.
X(n): salta n posiciones antes de leer.
Vamos a fijarnos en la opción SKIP.
Pensad que estamos leyendo de la SYSIN, y con SKIP le estamos indicando que salte a la siguiente línea de la SYSIN:
SYSIN DD *
campo1
campo2
campo3
/*
Esto en COBOL no sería posible, pues la SYSIN tiene una única línea que se recupera mediante un ACCEPT.
Sin embargo en PL/I podemos introducir mucha más información a través de la SYSIN.
Escritura
PUT FILE (SYSPRINT) LIST/DATA/EDIT;
Donde PUT indica orden de escritura.
Si no se indica nombre del fichero el sistema asume SYSPRINT.
LIST/DATA/EDIT son las mismas opciones que para el GET, pero referido a los datos que vamos a escribir. En EDIT se ñade la opción de "PAGE" para hacer salto de página al escribir.
"Los PUT" en PL/I son el equivalente a los DISPLAYs en COBOL. Cuando necesitemos "displayar" alguna variable para controles de errores, buscar un fallo en el programa, etc. lo haremos con un PUT y la información saldrá en el SYSPRINT en lugar de salir en la SYSOUT.
Tanto para programa ONLINE como BATCH, podremos ver los "PUTs" en el SYSPRINT.
En próximos artículos veremos ejemplos concretos del uso de estos ficheros. Hasta entonces, cualquier duda preguntad sin problema : )
miércoles, 6 de abril de 2011
Proceso de un programa PL/I
El proceso del programa comienza en donde nosotros queramos, aunque por poner un poco de orden, podemos decir que empazará después de que acabemos de definir todas las variables que vayamos a necesitar.
INFORMANDO VARIABLES
En PL/I la manera de informar variables es "asignándoles" un valor:
DCL CAMPO1 CHAR(3) INIT ('123');
DCL CAMPO2 CHAR(3);
CAMPO2 = CAMPO1;
Ahora CAMPO2 valdrá '123'.
Vamos a ver algunos ejemplos de asignaciones denominadas "simples", es decir, la asignación se hace entre variables del mismo tipo (numéricos con numéricos, alfanuméricos con alfanuméricos).
Ejemplo 1: Campos numéricos.
DCL CAMPO_NUM1 DEC FIXED (3,2) INIT (0);
DCL CAMPO_NUM2 DEC FIXED (6,3) INIT (0);
CAMPO_NUM1 = 1.23;
CAMPO_NUM2 = CAMPO_NUM1;
Ahora CAMPO_NUM2 valdrá 001.230.
CAMPO_NUM2 = 456.789;
CAMPO_NUM1 = CAMPO_NUM2;
Ahora CAMPO_NUM1 valdrá 6.78.
Como podéis ver, mantiene la posición del punto decimal.
En las asginaciones de campos numéricos también podremos guardar operaciones artiméticas:
CAMPO_NUM1 = CAMPO_NUM2/2 + CAMPO_NUM3 * (CAMPO_NUM4 - CAMPO_NUM5) ** 2;
Y se aplican las mismas reglas de prioridades que en matemáticas (el doble asterisco es la potencia).
Ejemplo 2: campos alfanuméricos.
DCL ALFANUM1 CHAR (5) INIT(' ');
DCL ALFANUM2 CHAR (11) INIT (' ');
ALFANUM1 = 'COBOL';
ALFANUM2 = ALFANUM1;
Ahora ALFANUM2 valdrá 'COBOL '.
ALFANUM2 = 'CONSULTORIO';
ALFANUM1 = ALFANUM2;
Ahora ALFANUM1 valdrá 'CONSU'.
Usando el operador de concatenación || podemos guardar varios campos en una variable:
DCL CAMPO1 CHAR(10) INIT ('COMO MOLA ');
DCL CAMPO2 CHAR(20) INIT ('EL CONSULTORIO COBOL');
DCL CAMPO3 CHAR(30);
CAMPO3 = CAMPO1||CAMPO2;
Ahora CAMPO3 contendrá 'COMO MOLA EL CONSULTORIO COBOL' :D
Ejemplo 3: matrices (tablas internas).
DCL TABLA(3) CHAR(1);
Para utilizar un elemento de una matriz tendremos que indicar el índice del elemento entre paréntesis.
TABLA(1) = 'A';
TABLA(2) = 'B';
TABLA(3) = 'C';
Ahora el elemento 1 de la tabla valdrá 'A', el elemento 2 valdrá 'B', y el elemento 3 valdrá 'C'.
Para tablas de 2 dimensiones se indicarán los dos índices entre paréntesis.
DCL TABLA_DOBLE(2,3) CHAR(1);
Y en las asignaciones también se indicarán los dos índices:
TABLA_DOBLE(1,1) = 'A';
INICIALIZANDO VARIABLES
La inicialización de variables en PL/I se hace en el momento de declararlas, con la sentencia INIT que vimos en el artículo del "Esquema de un programa pl/i".
Vamos a ver algunos ejemplos:
DCL CAMPO_ALFANUM CHAR(10) INIT(' '); Se rellena con espacios. Para campos alfanuméricos el valor se indica entre comillas simples ''.
DCL CAMPO_ALFANUM CHAR(100) INIT((100)'-'); Se rellena con 100 guiones.
DCL CAMPO_NUM PIC 10(9) INIT(0); Se rellena con ceros. Para campos numéricos, el valor se indica sin comillas.
DCL CAMPO_DEC DEC FIXED (10,3) INIT(0); Se rellena con ceros.
DCL TABLA1 DEC FIXED(2,2) INIT(1,2,3,4);
Asigna valores a cada elemento de la tabla:
TABLA1(1,1) = 1
TABLA1(1,2) = 2
TABLA1(2,1) = 3
TABLA1(2,2) = 4
DCL TABLA1 DEC FIXED(2,2) INIT(4(0));
Asigna ceros a los 4 elementos de la tabla.
CONDICIONES
Para expresar condiciones en PL/I se utilizará el IF/ELSE de toda la vida, pero con sus particularidades.
Ejemplo 1: IF.
IF CAMPO1 = CAMPO2
THEN CAMPO1 = 2;
Al poner el ; finalizamos la sentencia IF (no hay que cerrarla con un END-IF como en cobol).
Ejemplo 2: IF/ELSE.
IF CAMPO1 = CAMPO2
THEN CAMPO1 = 2;
ELSE CAMPO1 = 1;
La condición finaliza con el ; de la parte del ELSE.
Puede darse el caso de que no queramos realizar ninguna acción para la condición del IF, sino sólo en el caso contrario (ELSE):
IF CAMPO1 = CAMPO2 THEN;
ELSE CAMPO1 = 1;
Ejemplo 3: IF/ELSE con DO.
IF CAMPO1 = CAMPO2
THEN DO;
CAMPO1 = 2;
CAMPO2 = 1;
END;
ELSE DO;
CAMPO1 = 1;
CAMPO2 = 2;
END;
Cuando dentro de un IF o un ELSE hay más de una expresión, todas ellas se incluirán dentro de la sentencia DO/END.
Los operadores que se utilizan en las condiciones serán:
= : igual a
¬= : distinto
& : y
| : o
< : menor que
> : mayor que
<= : menor o igual
>= : mayor o igual
¬< : no menor que
¬> : no mayor que
Otra manera de incluir una condición es con la sentencia SELECT. Viene a ser el equivalente al EVALUATE de Cobol, pero hay que tener cuidado porque no funcionan exactamente igual.
Si queremos poner como condición el valor que tome una variable:
SELECT(CAMPO_1);
WHEN(1);
WHEN(2) CAMPO_2 = 2;
OTHERWISE CAMPO_2 = 0;
END;
Si queremos validar que se cumple una condición:
SELEC;
WHEN(CAMPO_1 = CAMPO_2);
WHEN(CAMPO_1 < CAMPO_2) CAMPO_3 = 2;
OTHERWISE CAMPO_3 = 0;
END;
Fijaos en el primer WHEN de los dos ejemplos. Cuando un WHEN finaliza con ; significa que para ese caso no haremos nada. Sería el equivalente a poner un CONTINUE en Cobol.
MUY IMPORTANTE no confundir con el caso del EVALUATE, donde al poner dos WHEN seguidos significa que el código que venga a continuación se realizará para los dos WHEN:
EVALUATE WX-CAMPO1
WHEN 1
WHEN 2
DISPLAY 'CAMPO1 ES 1 o 2'
WHEN OTHER
CONTINUE
END-EVALUATE
El display se mostrará para WX-CAMPO1 = 1 y WX-CAMPO1 = 2.
En el caso del SELECT, se indicarán los dos valores en el mismo WHEN:
SELEC CAMPO_1;
WHEN(1,2) PUT EDIT ('CAMPO_1 ES 1 o 2') (A);
OTHERWISE;
END;
Para terminar decir que en caso de que dentro de un WHEN queramos escribir más de una instrucción, tendremos que usar el DO/END como en el caso del IF.
BUCLES
En PL/I los bucles se codifican con la sentencia DO/END. Existen varias opciones para acompañar al DO:
DO WHILE
En este caso las sentencias entre el DO y el END se ejecutarán "mientras que" se cumpla una condición, es decir, mientras esa condición sea cierta.
DO WHILE CAMPO1 ¬= ' ';
sentencias a ejecutar;
END;
Si tuviésemos más de una condición, deberá ir entre paréntesis.
DO WHILE (CAMPO1 ¬= ' ' & CAMPO2 = 1);
sentencias a ejecutar;
END;
DO UNTIL
En este caso las sentencias entre el DO y el END se ejecutarán "hasta que" se cumpla la condición especificada.
DO UNTIL CAMPO_ANO = 2012;
sentencias a ejecutar;
END;
Si tuviésemos más de una condición, deberá ir entre paréntesis.
DO + TO
En este caso las sentencias entre el DO y el END se ejecutarán hasta que se cumpla la condición especificada.
DO INDICE = 1 TO 10;
sentencias a ejecutar;
END;
Las sentencias a ejecutar se harán 10 veces (desde INDICE = 1 hasta 10, de 1 en 1).
Para retorcerlo un poco más podemos usar la sentencia BY:
DO INDICE = 1 TO 10 BY 2
sentencias a ejecutar;
END;
Las sentencias a ejecutar se harán 5 veces (desde INDICE = 1 hasta 10, de 2 en 2).
También se puede combinar el DO/TO con la opción WHILE:
DO INDICE = 1 TO 10 WHILE CAMPO1 = ' ';
sentencias a ejecutar;
END;
En este caso, además de controlar el valor de INDICE, la expresión del WHILE debe ser cierta.
INFORMANDO VARIABLES
En PL/I la manera de informar variables es "asignándoles" un valor:
DCL CAMPO1 CHAR(3) INIT ('123');
DCL CAMPO2 CHAR(3);
CAMPO2 = CAMPO1;
Ahora CAMPO2 valdrá '123'.
Vamos a ver algunos ejemplos de asignaciones denominadas "simples", es decir, la asignación se hace entre variables del mismo tipo (numéricos con numéricos, alfanuméricos con alfanuméricos).
Ejemplo 1: Campos numéricos.
DCL CAMPO_NUM1 DEC FIXED (3,2) INIT (0);
DCL CAMPO_NUM2 DEC FIXED (6,3) INIT (0);
CAMPO_NUM1 = 1.23;
CAMPO_NUM2 = CAMPO_NUM1;
Ahora CAMPO_NUM2 valdrá 001.230.
CAMPO_NUM2 = 456.789;
CAMPO_NUM1 = CAMPO_NUM2;
Ahora CAMPO_NUM1 valdrá 6.78.
Como podéis ver, mantiene la posición del punto decimal.
En las asginaciones de campos numéricos también podremos guardar operaciones artiméticas:
CAMPO_NUM1 = CAMPO_NUM2/2 + CAMPO_NUM3 * (CAMPO_NUM4 - CAMPO_NUM5) ** 2;
Y se aplican las mismas reglas de prioridades que en matemáticas (el doble asterisco es la potencia).
Ejemplo 2: campos alfanuméricos.
DCL ALFANUM1 CHAR (5) INIT(' ');
DCL ALFANUM2 CHAR (11) INIT (' ');
ALFANUM1 = 'COBOL';
ALFANUM2 = ALFANUM1;
Ahora ALFANUM2 valdrá 'COBOL '.
ALFANUM2 = 'CONSULTORIO';
ALFANUM1 = ALFANUM2;
Ahora ALFANUM1 valdrá 'CONSU'.
Usando el operador de concatenación || podemos guardar varios campos en una variable:
DCL CAMPO1 CHAR(10) INIT ('COMO MOLA ');
DCL CAMPO2 CHAR(20) INIT ('EL CONSULTORIO COBOL');
DCL CAMPO3 CHAR(30);
CAMPO3 = CAMPO1||CAMPO2;
Ahora CAMPO3 contendrá 'COMO MOLA EL CONSULTORIO COBOL' :D
Ejemplo 3: matrices (tablas internas).
DCL TABLA(3) CHAR(1);
Para utilizar un elemento de una matriz tendremos que indicar el índice del elemento entre paréntesis.
TABLA(1) = 'A';
TABLA(2) = 'B';
TABLA(3) = 'C';
Ahora el elemento 1 de la tabla valdrá 'A', el elemento 2 valdrá 'B', y el elemento 3 valdrá 'C'.
Para tablas de 2 dimensiones se indicarán los dos índices entre paréntesis.
DCL TABLA_DOBLE(2,3) CHAR(1);
Y en las asignaciones también se indicarán los dos índices:
TABLA_DOBLE(1,1) = 'A';
INICIALIZANDO VARIABLES
La inicialización de variables en PL/I se hace en el momento de declararlas, con la sentencia INIT que vimos en el artículo del "Esquema de un programa pl/i".
Vamos a ver algunos ejemplos:
DCL CAMPO_ALFANUM CHAR(10) INIT(' '); Se rellena con espacios. Para campos alfanuméricos el valor se indica entre comillas simples ''.
DCL CAMPO_ALFANUM CHAR(100) INIT((100)'-'); Se rellena con 100 guiones.
DCL CAMPO_NUM PIC 10(9) INIT(0); Se rellena con ceros. Para campos numéricos, el valor se indica sin comillas.
DCL CAMPO_DEC DEC FIXED (10,3) INIT(0); Se rellena con ceros.
DCL TABLA1 DEC FIXED(2,2) INIT(1,2,3,4);
Asigna valores a cada elemento de la tabla:
TABLA1(1,1) = 1
TABLA1(1,2) = 2
TABLA1(2,1) = 3
TABLA1(2,2) = 4
DCL TABLA1 DEC FIXED(2,2) INIT(4(0));
Asigna ceros a los 4 elementos de la tabla.
CONDICIONES
Para expresar condiciones en PL/I se utilizará el IF/ELSE de toda la vida, pero con sus particularidades.
Ejemplo 1: IF.
IF CAMPO1 = CAMPO2
THEN CAMPO1 = 2;
Al poner el ; finalizamos la sentencia IF (no hay que cerrarla con un END-IF como en cobol).
Ejemplo 2: IF/ELSE.
IF CAMPO1 = CAMPO2
THEN CAMPO1 = 2;
ELSE CAMPO1 = 1;
La condición finaliza con el ; de la parte del ELSE.
Puede darse el caso de que no queramos realizar ninguna acción para la condición del IF, sino sólo en el caso contrario (ELSE):
IF CAMPO1 = CAMPO2 THEN;
ELSE CAMPO1 = 1;
Ejemplo 3: IF/ELSE con DO.
IF CAMPO1 = CAMPO2
THEN DO;
CAMPO1 = 2;
CAMPO2 = 1;
END;
ELSE DO;
CAMPO1 = 1;
CAMPO2 = 2;
END;
Cuando dentro de un IF o un ELSE hay más de una expresión, todas ellas se incluirán dentro de la sentencia DO/END.
Los operadores que se utilizan en las condiciones serán:
= : igual a
¬= : distinto
& : y
| : o
< : menor que
> : mayor que
<= : menor o igual
>= : mayor o igual
¬< : no menor que
¬> : no mayor que
Otra manera de incluir una condición es con la sentencia SELECT. Viene a ser el equivalente al EVALUATE de Cobol, pero hay que tener cuidado porque no funcionan exactamente igual.
Si queremos poner como condición el valor que tome una variable:
SELECT(CAMPO_1);
WHEN(1);
WHEN(2) CAMPO_2 = 2;
OTHERWISE CAMPO_2 = 0;
END;
Si queremos validar que se cumple una condición:
SELEC;
WHEN(CAMPO_1 = CAMPO_2);
WHEN(CAMPO_1 < CAMPO_2) CAMPO_3 = 2;
OTHERWISE CAMPO_3 = 0;
END;
Fijaos en el primer WHEN de los dos ejemplos. Cuando un WHEN finaliza con ; significa que para ese caso no haremos nada. Sería el equivalente a poner un CONTINUE en Cobol.
MUY IMPORTANTE no confundir con el caso del EVALUATE, donde al poner dos WHEN seguidos significa que el código que venga a continuación se realizará para los dos WHEN:
EVALUATE WX-CAMPO1
WHEN 1
WHEN 2
DISPLAY 'CAMPO1 ES 1 o 2'
WHEN OTHER
CONTINUE
END-EVALUATE
El display se mostrará para WX-CAMPO1 = 1 y WX-CAMPO1 = 2.
En el caso del SELECT, se indicarán los dos valores en el mismo WHEN:
SELEC CAMPO_1;
WHEN(1,2) PUT EDIT ('CAMPO_1 ES 1 o 2') (A);
OTHERWISE;
END;
Para terminar decir que en caso de que dentro de un WHEN queramos escribir más de una instrucción, tendremos que usar el DO/END como en el caso del IF.
BUCLES
En PL/I los bucles se codifican con la sentencia DO/END. Existen varias opciones para acompañar al DO:
DO WHILE
En este caso las sentencias entre el DO y el END se ejecutarán "mientras que" se cumpla una condición, es decir, mientras esa condición sea cierta.
DO WHILE CAMPO1 ¬= ' ';
sentencias a ejecutar;
END;
Si tuviésemos más de una condición, deberá ir entre paréntesis.
DO WHILE (CAMPO1 ¬= ' ' & CAMPO2 = 1);
sentencias a ejecutar;
END;
DO UNTIL
En este caso las sentencias entre el DO y el END se ejecutarán "hasta que" se cumpla la condición especificada.
DO UNTIL CAMPO_ANO = 2012;
sentencias a ejecutar;
END;
Si tuviésemos más de una condición, deberá ir entre paréntesis.
DO + TO
En este caso las sentencias entre el DO y el END se ejecutarán hasta que se cumpla la condición especificada.
DO INDICE = 1 TO 10;
sentencias a ejecutar;
END;
Las sentencias a ejecutar se harán 10 veces (desde INDICE = 1 hasta 10, de 1 en 1).
Para retorcerlo un poco más podemos usar la sentencia BY:
DO INDICE = 1 TO 10 BY 2
sentencias a ejecutar;
END;
Las sentencias a ejecutar se harán 5 veces (desde INDICE = 1 hasta 10, de 2 en 2).
También se puede combinar el DO/TO con la opción WHILE:
DO INDICE = 1 TO 10 WHILE CAMPO1 = ' ';
sentencias a ejecutar;
END;
En este caso, además de controlar el valor de INDICE, la expresión del WHILE debe ser cierta.
miércoles, 30 de marzo de 2011
Esquema de un programa pl/i
Un programa pl/i no tiene una estructura "fija", es decir, el programa compilará aunque no sigas un esquema determinado. Pero para facilitar la comprensión del código, siempre es mejor seguir algunas pautas : )
INICIO DEL PROGRAMA
Todo programa principal empezará con la sentencia:
PRUEBA1: PROCEDURE OPTIONS(MAIN);
Donde:
PRUEBA1 es el identificador del programa. No es necesario que coincida con el nombre externo del programa. Tendrá una longitud máxima de 7 caracteres.
PROCEDURE o PROC es la palabra clave que le indica al compilador que el programa es un procedimiento.
OPTIONS(MAIN): son las palabras clave que indican al compilador que se trata de un programa principal.
Para rutinas y programas online ya lo iremos viendo.
Los comentarios empezarán con /* y terminarán con */ y podrán codificarse en cualquier parte del código. No hay que colocar el inicio en ninguna columna en concreto.
PROCESO DEL PROGRAMA
En el proceso del programa incluiremos tanto la declaración de variables, como llamadas a otros procedimientos, como la funcionalidad del programa en sí.
Para las declaraciones utilizaremos la sentencia DECLARE o DCL para abreviar.
Declaración de funciones del sistema:
DCL (DATE,TIME) BUILTIN;
Donde DATE y TIME serían la fecha y hora del sistema respectivamente.
Declaración de ficheros:
DCL SYSPRINT FILE PRINT;
DCL SYSIN FILE STREAM INPUT;
DCL SALIDA FILE STREAM OUTPUT;
DCL SALIDA FILE RECORD OUTPUT;
DCL REG_SALIDA CHAR(100);
Donde:
FILE indica que se trata de un fichero.
STREAM indica que los datos se guardarán como una cadena de caracteres. El acceso siempre será secuencial.
INPUT/OUTPUT indica que es un fichero de entrada/salida respectivamente.
RECORD indica que los datos se guardarán en un formato especifico (en nuestro caso REG_SALIDA). Existen diferentes tipos de acceso que iremos viendo en futuros ejemplos.
Declaración de variables:
Para entenderlo mejor, veamos un cuadro con la equivalencia entre declaraciones COBOL y PL/I:
Donde:
CHAR indica campo alfanumérico.
INIT indica el valor que toma la variable (equivale a nuestro VALUE).
PIC (N)9 indica campo numérico.
DEC FIXED indica campo comprimido (equivale a COMP-3). En los campos con decimales hay que tener en cuenta que si en cobol indicábamos 9(N)V9(M), en pl/i se indica (N+M,M).
BIN FIXED indica campo binario (hexadecimal).
BIT indica variable booleana que tomará los valores de verdadera '1'B (SET campo a TRUE) y falsa '0'B (SET campo a FALSE).
Para definir tablas se indicará el número de filas entre paréntesis; como el ejemplo TABLA(3). Si fuese una tabla de dos dimensiones escribiríamos primero el número de filas y después el número de comumnas:
DCL TABLA_DOBLE(2,3) CHAR(3);
En PL/I no estamos obligados a declarar las variables, aunque es recomendable. Veamos que pasa cuando no declaramos variables, o no las declaramos "del todo":
Si sólo declaramos la base:
DEC = DEC FLOAT (6)
BIN = BIN FLOAT (21)
Si sólo declaramos la precisión:
FIXED = DEC FIXED (5,0)
FLOAT = DEC FLOAT (6)
Si declaramos base + precisión:
BIN FIXED = BIN FIXED (15,0)
DEC FIXED = DEC FIXED (5,0)
BIN FLOAT = BIN FLOAT (21)
DEC FLOAT = DEC FLOAT (6)
Sin declarar nada de nada:
COMIENZA POR: I-N = BIN FIXED (15,0)
COMIENZA POR: A-H O-Z Y CARACT. ESPECIALES = DEC FLOAT(6)
CALCULO DE LONGITUDES
Numéricos y alfanuméricos
Lo que venga indicado en el PIC (N)9 o en el CHAR(N).
DCL ALFANUM CHAR(5);
DCL NUMERICO PIC (5)9;
longitud = 5
Comprimidos
Si tenemos un campo DEC FIXED (N,M), la longitud será N+1/2. Si el resultado tiene decimales redondeamos hacia arriba. El máximo permitido es N = 15.
DCL COMPRIMIDO DEC FIXED (7,2);
longitud = 7+1/2 = 4
Binarios
Si tenemos un campo BIN FIXED (N,M), el número de bytes que se reservan en memoria para cada campo es:
2 posiciones para N entre 1 y 15.
4 posiciones para N ente 16 y 31(máximo permitido).
FINAL DEL PROGRAMA
Para finalizar el programa escribiremos la sentencia:
END PRUEBA1;
Donde PRUEBA1 es el nombre del proceso principal que habíamos definido al inicio del programa.
La parte de informar variables, condiciones, bucles, etc. lo dejaremos para el siguiente artículo : )
INICIO DEL PROGRAMA
Todo programa principal empezará con la sentencia:
PRUEBA1: PROCEDURE OPTIONS(MAIN);
Donde:
PRUEBA1 es el identificador del programa. No es necesario que coincida con el nombre externo del programa. Tendrá una longitud máxima de 7 caracteres.
PROCEDURE o PROC es la palabra clave que le indica al compilador que el programa es un procedimiento.
OPTIONS(MAIN): son las palabras clave que indican al compilador que se trata de un programa principal.
Para rutinas y programas online ya lo iremos viendo.
Los comentarios empezarán con /* y terminarán con */ y podrán codificarse en cualquier parte del código. No hay que colocar el inicio en ninguna columna en concreto.
PROCESO DEL PROGRAMA
En el proceso del programa incluiremos tanto la declaración de variables, como llamadas a otros procedimientos, como la funcionalidad del programa en sí.
Para las declaraciones utilizaremos la sentencia DECLARE o DCL para abreviar.
Declaración de funciones del sistema:
DCL (DATE,TIME) BUILTIN;
Donde DATE y TIME serían la fecha y hora del sistema respectivamente.
Declaración de ficheros:
DCL SYSPRINT FILE PRINT;
DCL SYSIN FILE STREAM INPUT;
DCL SALIDA FILE STREAM OUTPUT;
DCL SALIDA FILE RECORD OUTPUT;
DCL REG_SALIDA CHAR(100);
Donde:
FILE indica que se trata de un fichero.
STREAM indica que los datos se guardarán como una cadena de caracteres. El acceso siempre será secuencial.
INPUT/OUTPUT indica que es un fichero de entrada/salida respectivamente.
RECORD indica que los datos se guardarán en un formato especifico (en nuestro caso REG_SALIDA). Existen diferentes tipos de acceso que iremos viendo en futuros ejemplos.
Declaración de variables:
Para entenderlo mejor, veamos un cuadro con la equivalencia entre declaraciones COBOL y PL/I:
| 01 ALFAN PIC X(N) VALUE SPACES. | DCL ALFAN CHAR (N) INIT ' '; |
| 01 NUMER PIC 9(N) VALUE ZEROS. | DCL NUMER PIC '(N)9' INIT (0); |
| 01 COMPR PIC S9(N)V9(M) COMP-3. | DCL COMPR DEC FIXED (N+M,M); |
| 01 HEXA1 PIC S9(4) COMP. | DCL HEXA1 BIN FIXED (15) INIT(0); |
| 01 HEXA2 PIC S9(9) COMP. | DCL HEXA2 BIN FIXED (31) INIT (0); |
| 01 ESTRUCTURA. | DCL 1 ESTRUCTURA, |
| 05 ALFANUM PIC X. | 5 ALFANUM CHAR, |
| 05 NUMERICO PIC 9(2). | 5 NUMERICO PIC '(2)9', |
| 05 COM PIC 9(7)V9(2) COMP-3. | 5 COM DEC FIXED (9,2), |
| 05 BINHEXA PIC S9(4) COMP. | 5 BINHEXA BIN FIXED (15), |
| 05 BINHEXA2 PIC S9(9) COMP. | 5 BINHEXA2 BIN FIXED (31); |
| 01 EDITADO PIC ZZZ9,99. | DCL EDITADO PIC 'ZZZ9V,99'; |
| 01 SWITCH PIC X VALUE 'S'. | DCL BOOLEAN BIT; |
| 88 VERDAD VALUE 'S'. | DCL VERDAD BIT INIT('1'B); |
| 88 FALSO VALUE 'N'. | DCL FALSO BIT INIT('0'B); |
| 01 TABLA PIC X OCCURS 3 TIMES. | DCL TABLA(3) CHAR(1); |
Donde:
CHAR indica campo alfanumérico.
INIT indica el valor que toma la variable (equivale a nuestro VALUE).
PIC (N)9 indica campo numérico.
DEC FIXED indica campo comprimido (equivale a COMP-3). En los campos con decimales hay que tener en cuenta que si en cobol indicábamos 9(N)V9(M), en pl/i se indica (N+M,M).
BIN FIXED indica campo binario (hexadecimal).
BIT indica variable booleana que tomará los valores de verdadera '1'B (SET campo a TRUE) y falsa '0'B (SET campo a FALSE).
Para definir tablas se indicará el número de filas entre paréntesis; como el ejemplo TABLA(3). Si fuese una tabla de dos dimensiones escribiríamos primero el número de filas y después el número de comumnas:
DCL TABLA_DOBLE(2,3) CHAR(3);
En PL/I no estamos obligados a declarar las variables, aunque es recomendable. Veamos que pasa cuando no declaramos variables, o no las declaramos "del todo":
Si sólo declaramos la base:
DEC = DEC FLOAT (6)
BIN = BIN FLOAT (21)
Si sólo declaramos la precisión:
FIXED = DEC FIXED (5,0)
FLOAT = DEC FLOAT (6)
Si declaramos base + precisión:
BIN FIXED = BIN FIXED (15,0)
DEC FIXED = DEC FIXED (5,0)
BIN FLOAT = BIN FLOAT (21)
DEC FLOAT = DEC FLOAT (6)
Sin declarar nada de nada:
COMIENZA POR: I-N = BIN FIXED (15,0)
COMIENZA POR: A-H O-Z Y CARACT. ESPECIALES = DEC FLOAT(6)
CALCULO DE LONGITUDES
Numéricos y alfanuméricos
Lo que venga indicado en el PIC (N)9 o en el CHAR(N).
DCL ALFANUM CHAR(5);
DCL NUMERICO PIC (5)9;
longitud = 5
Comprimidos
Si tenemos un campo DEC FIXED (N,M), la longitud será N+1/2. Si el resultado tiene decimales redondeamos hacia arriba. El máximo permitido es N = 15.
DCL COMPRIMIDO DEC FIXED (7,2);
longitud = 7+1/2 = 4
Binarios
Si tenemos un campo BIN FIXED (N,M), el número de bytes que se reservan en memoria para cada campo es:
2 posiciones para N entre 1 y 15.
4 posiciones para N ente 16 y 31(máximo permitido).
FINAL DEL PROGRAMA
Para finalizar el programa escribiremos la sentencia:
END PRUEBA1;
Donde PRUEBA1 es el nombre del proceso principal que habíamos definido al inicio del programa.
La parte de informar variables, condiciones, bucles, etc. lo dejaremos para el siguiente artículo : )
¿Qué es PL/I?
PL/I (Programming Language 1) es un lenguaje de programación de IBM (al igual que COBOL) que os podréis encontrar en muchos entornos HOST. Incluso si trabajáis en COBOL, es probable que alguna aplicación tenga código en PL/I y seguro que tenéis acceso al compilador.
Veamos las principales diferencias con COBOL:
Estas son a grandes rasgos las principales diferencias entre los dos lenguajes. En próximos artículos iremos viendo como codificar un programa PL/I, su estructura, como informar variables, como hacer bucles, etc.
Veamos las principales diferencias con COBOL:
- No existe área A y área B. Existe un único área desde la columna 2 a la 72.
- No hay divisiones ni secciones.
- Acepta caracteres alfabéticos de la A a la Z (solo en mayúsuculas). Acepta los caracteres '@', '$', '#' ó 'Ñ' (según la instalación). Los números del 0 al 9. No acepta el guión '-' pero sí el guión bajo '_'.
- Operadores lógicos: negación (¬), igualdad (=), conjunción (&), disyunción (|), mayor que (>), menor que (<).
- No es necesario declarar las variables (aunque recomendable).
- En pl/i no existen las palabras reservadas, sólo palabras CLAVE pero que pueden utilizarse como variables.
- El final de una sentencia se termina con punto y coma (;) en lugar de con un punto (.), y además debe finalizarse cada sentencia, no vale con poner un ; al final de un procedimiento (como en COBOL que poníamos un . al final de párrafo).
Estas son a grandes rasgos las principales diferencias entre los dos lenguajes. En próximos artículos iremos viendo como codificar un programa PL/I, su estructura, como informar variables, como hacer bucles, etc.
Principiantes PL/I
Ahora que ya te habías hecho un experto en COBOL gracias al manual del Consultorio, resulta que a tu empresa se le ocurre cambiarte a un proyecto en PL/I.
¿¿¿Y ahora qué hago???
Que no cunda el pánico!! En el Consultorio Cobol estamos preparados para todo tipo de contratiempos. Con todos vosotros, el nuevo "manual de PL/I para principiantes"!
Manual de PL/I para principiantes
1. ¿Qué es PL/I?
2. Esquema de un programa PL/I.
3. Proceso de un programa PL/I.
4. Ficheros en PL/I.
5. Ejemplo 1: leer de SYSIN y escrbir en SYSPRINT (pl/i).
Continuará...
¿¿¿Y ahora qué hago???
Que no cunda el pánico!! En el Consultorio Cobol estamos preparados para todo tipo de contratiempos. Con todos vosotros, el nuevo "manual de PL/I para principiantes"!
Manual de PL/I para principiantes
1. ¿Qué es PL/I?
- Descripción del lenguaje de programación PL/I.
- Diferencias principales con COBOL.
2. Esquema de un programa PL/I.
- Esquema básico de un programa PL/I.
- Declaración de variables en PL/I.
3. Proceso de un programa PL/I.
- Informando variables: asignación de valores.
- Inicializando variables: sentencia INIT.
- Condiciones: IF/ELSE.
- Bucles: DO WHILE, DO UNTIL, DO/TO.
4. Ficheros en PL/I.
- Ficheros RECORD.
- Ficheros STREAM.
5. Ejemplo 1: leer de SYSIN y escrbir en SYSPRINT (pl/i).
- JCL que ejecuta un programa sin DB2.
- Programa que realiza un GET de la SYSIN y un PUT de la información recibida para mostrarla por SYSPRINT.
Continuará...
domingo, 31 de octubre de 2010
Errores PL/I. ONCODES.
ONCODE significado del ONCODE
_______________________________________________________________ 3 en un SELECT/WHEN/OTHERWISE, ningún WHEN satisface la condición y no hay cláusula OTHERWISE
4 instrucción SIGNAL FINISH, STOP ó EXIT ejecutados
9 SIGNAL ERROR declaración ejecutados
10 SIGNAL NAME ejecutado o se produjo condición NAME
20 SIGNAL RECORD instrucción ejecutada
21 variable más pequeño que el tamaño del registro
22 variable más grande que el tamaño del registro
23 longitud de la variable de registro es cero o es demasiado corto para contener la clave
24 un registro con una longitud de cero se leyó de un conjunto de datos REGIONAL
40 SIGNAL TRANSMIT declaración ejecutado.
41 error de transmisión en los datos de salida
42 error en la transmisión de datos de entrada
43 errores de transmisión en la salida al índice VSAM
44 errores de transmisión en la entrada del índice de VSAM
45 errores de transmisión en la salida de secuencia de VSAM
46 errores de transmisión en la entrada de la secuencia de VSAM
50 SIGNAL KEY instrucción ejecutada
51 clave especificada no se encuentra
52 clave especificada ya existe
53 claves está fuera de secuencia durante la creación de una base de datos indexada(INDEXED) o regionales(REGIONAL) creados
54 error de conversión clave
55 o la clave especificada es la cadena nula o comienza con X'FF'o una reescritura(REWRITE) que se intentó fue pero la clave incrustada ha cambiado
56 claves está fuera del conjunto de datos límites
57 No hay espacio disponible para insertar un registro
58 claves está fuera del rango
70 SIGNAL ENDFILE ejecutado o se produjo condición ENDFILE
80 SIGNAL UNDEFINEDFILE instrucción ejecutada
81 atributos en conflicto entre la instrucción DECLARE y sentencia OPEN
82 El conflicto entre los atributos del fichero y la organización física del conjunto de datos
83 especificación de datos está incompleta
84 DD declaración no se encuentra en JCL
85 un error de I/O se produjo durante la inicialización del fichero DIRECT OUTPUT
86 LINESIZE mayor que el máximo
87 atributos en conflicto entre la instrucción DECLARE y la declaración de JCL DD
88 atributos en conflicto entre la instrucción DECLARE y la declaración JCL DD
89 contraseña no está especificado o no es válido
90 declaración SIGNAL ENDPAGE ejecutado o se produjo condición ENDPAGE
91 ENV () la opción no es válida para acceder a archivos de datos VSAM.
92 error al abrir un conjunto de datos VSAM
93 error al abrir un conjunto de datos (subcódigos)
94 REUSE especificado, pero conjunto de datos no es reutilizable
95 índice alternativo especificado para un conjunto de datos VSAM vacío.
96 Intento de abrir(OPEN) el fichero MSGFILE(SYSPRINT) después de una subtarea se ha creado
99 el OPEN falló por datos (subcódigos)
100 declaración SIGNAL PENDING ejecutado o se produjo condición PENDING
150 declaración SIGNAL STRINGSIZE ejecutados o se produjo condición STRINGSIZE
151 truncamiento se produjo mientras la asignación de una cadena mixta de carácteres
290 declaración SIGNAL INVALIDOP ejecutados o se produjo condición INVALIDOP
300 declaración SIGNAL OVERFLOW (desbordamiento) ejecutados o se produjo condición de desbordamiento(OVERFLOW)
310 declaración SIGNAL FIXEDOVERFLOW ejecutados o se produjo condición FIXEDOVERFLOW
320 declaración SIGNAL ZERODIVIDE ejecutados o se produjo condición ZeroDivide
330 declaración SIGNAL UNDERFLOW ejecutados o se produjo condición de UNDERFLOW
340 declaración SIGNAL SIZE ejecutados o se produjo condición SIZE(tamaño)
341 condición SIZE ocurrió durante operación de I/O
350 declaración SIGNAL STRINGRANGE ejecutado o se produjo condición STRINGRANGE
360 almacenamiento libre insuficiente para la asignación de una variable de base
361 falta de espacio en el área objetivo para la distribución de área de origen
362 declaración SIGNAL AREA ejecutados
400 declaración SIGNAL ATTENTION ejecutado o se produjo condición ATTENTION
450 declaración SIGNAL STORAGE ejecutados
451 ASIGNAR(alocar) falló, no hay suficiente almacenamiento disponible
500 ESTADO DE SEÑAL/SIGNAL CONDITION (nombre) instrucción ejecutada
510 comando SIGNAL CHECK ejecutados
520 declaración SIGNAL SUBSCRIPTRANGE ejecutado, o se produjo condición SUBSCRIPTRANGE
521 subíndice de la variable iSub definido se encuentra fuera de los límites de la dimensión correspondiente de la variable de base
600 declaración SIGNAL CONVERSION ejecutados
601-684 intento de conversión no válida durante la entrada / salida de una cadena de caracteres.
1002 GET o PUT STRING especifica datos que exceden el tamaño de la cadena(string)
1003 salida(output) no permitida debido a la anteriormente planteadas TRANSMIT o condición KEY
1004 página(PAGE), línea(LINE) o SKIP se intentó para un archivo no imprimible(nonprint).
1005 DISPLAY () REPLY () instrucción utiliza la expresión de longitud cero
1007 REWRITE o una instrucción DELETE no ha sido precedida por una sentencia READ
1008 los datos no válidos para un GET STRING DATA.
1009 declaración I/O en conflicto con los atributos del fichero
1010 BUILTIN funcion o pseudovariable se refiere a un archivo, que no está abierto
1011 I / O error, sin más información proporcionada por el sistema operativo
1012 READ SET o READ INTO declaración no ha sido precedida por una declaración REWRITE
1013 Declaración REWRITE o DELETE no se puede ejecutar mientras que la anterior sentencia READ aún no ha terminado
1014 el número de operaciones incompletas alcanza máximo
1015 evento variable para una operación de entrada / salida ya está en uso.
1016 archivo no está abierto debido a una condición UNDEFINEDFILE
1018 EOF se encuentra en los datos antes de final de los datos de lista o lista de formato
1019 intento de cerrar archivo no abierto en la tarea actual
1020 I / O intentó antes de que la declaración WAIT se ejecutase para garantizar la conclusión de los anteriores READ
1021 registro no se puede acceder ya que está bloqueado por otro archivo de esta tarea
1022 no puede ampliar los datos VSAM
1023 archivo cerrado, pero los registros aún bloqueado por una subtarea
1024 secuencia de operaciones de I/O en archivo de dispositivo asociado es incorrecta
1025 insuficiente almacenamiento virtual disponible para VSAM para completar la solicitud
1026 ninguna posición establecida en el conjunto de datos VSAM
1027 Record o intervalo de VSAM de control ya declaró en el control exclusivo
1028 el volumen no está montado
1029 reposicionamiento fallido en conjunto de datos VSAM
1030 Error durante la actualización del índice en un conjunto de datos VSAM
1031 intento de escribir un secuencial inválido en conjunto de datos VSAM
1040 no más espacio disponible para datos de salida del sistema
1041 registro contiene un registro delimitador
1042 registro contiene un registro-delimitador no válido
1102 gestión de almacenamiento falló al liberar almacenamiento pues la dirección del almacenamiento para ser liberado no era válido
1104 error interno en una librería
1105 "ventana de objeto" no se pudo crear
1500-2531 error de cálculo durante la ejecución de una orden interna-función
2002 Declaración WAIT no se puede ejecutar debido a la facilidad del sistema restringido (comprobar o optimización de compilador sólo)
2050 Declaración WAIT causaría una espera permanente
3000 edición dirigida I/O llevaría a una pérdida de dígitos significativos o signos
3001 el valor del campo W en la especificación de formato F demasiado pequeño
3006 Descripción del PIC de destino no coinciden con la fuente
3009 cadena mixto de caracteres contiene un cambio gradual, pero ningún cambio
3010 mezcla de caracteres contiene datos no válidos
3011 MPSTR función incorporada contiene caracteres no válidos
3012 reintento de error de conversión de gráficos no permitido.
3013 serie gráfica es demasiado largo
3014 serie gráfica o mixta no se ajusta a las normas de mantenimiento
3015 X o GX constante tiene un número inválido de dígitos
3016 uso indebido de los datos gráficos en el flujo de I/O
3017 inválido gráfica, mixta, o la continuación DBCS al escribir flujo de I/O a un archivo que contiene registros de longitud fija
3500 error durante la ejecución de una instrucción WAIT
3501 error durante la ejecución de una declaración DETACH
3502 error durante la ejecución de una sentencia ATTACH
3503 error durante la ejecución de una instrucción STOP
3797 intento de convertir a o desde datos gráficos
3798 ONCHAR o pseudovariable ONSOURCE utilizado fuera de contexto
3799 unidad ON fue ingresado debido a una condición de la conversión(CONVERSION) y el caracter que causó la condición se utiliza pero no ha sido corregido por el uso de la pseudovariables ONSOURCE o ONCHAR.
3800 la longitud de la totalidad de los datos supera el límite del sistema
3801 elemento de la estructura Array no asignada
3808 no se puede asignar en COBOL o FORTRAN
3809 totalidad de los datos supera la longitud máxima
3810 el alcance de una matriz excede el máximo
3901 tarea variable ya está en uso
3904 pseudovariable COMPLETION especifica una variable caso que ya está en uso
3906 la asignación a una variable de evento que ya está activa
3907 DISPLAY declaración especifica una variable de evento que ya está activa
3909 almacenamiento principal disponibles son insuficientes para crear subtarea (con sentencia CALL)
3910 el número máximo de subtareas alcanzado
3911 WAIT declaración en unidad ON referencia una variable de la unidad de eventos que ya se esperaba
3912 CALL con la opción TASK en el bloque invocado durante la ejecución de PUT FILE(SYSPRINT) declaración
3913 sentencia CALL con la opción de TASK especifica un punto de entrada desconocida
3914 FORTRAN o COBOL ya invocado por otra tarea
3915 la librería de multitarea no seleccionadas en el paso de link-edit
3920 Un Abend fuera de almacenamiento se produjo
3951 OpenEdition llamada a servicio BPX1MPI falló
3952 OpenEdition llamada a servicio BPX1MP no
3953 OpenEdition llamada a servicio BPX1PTB no
4001 variable controladaCONTROLLED) no asignados durante el GET DATA
4002 CONTROLLED variable no asignada en el PUT DATA
4003 CONTROLLED variable no asignada durante el PUT DATA con la opción STRING
8091 operación excepción (código de instrucciones de la máquina no es válido)
8092 excepción operación privilegiada (una instrucción privilegiada no puede ser ejecutado en "estado problemático programa")
8093 excepción EXECUTE (una instrucción EXECUTE no debe apuntar a si mismo)
8094 excepción de protección (error de traducción de direcciones o almacenamiento protegido)
8095 excepción de direccionamiento (dirección se encuentra fuera del almacenamiento virtual disponible)
8096 especificación de excepción
8097 excepción de datos (valor decimal empaquetado no es válido)
8098 no es suficiente pila de almacenamiento (resultado de una operación de punto fijo es demasiado grande)
8099 excepción de división de punto fijo (resultado de una división de punto fijo es demasiado grande - la división por cero?)
9002 sentencia GOTO referencia etiqueta en un bloque inactivo
9003 etiqueta de la instrucción GOTO no existe
9050 programa terminado por un Abend
9051 Error en CICS (dirección de un parámetro podría ser inválido)
9200 programa de verificación en programa SORT/MERGE
9201 VM no admite SORT (si el compilador de la empresa: CMS no es compatible con SORT)
9202 TIPO DE REGISTRO(RECORD TYPE) falta en PLISRTx llamada
9203 TIPO DE REGISTRO(RECORD TYPE) no es válido en PLISRTx llamada
9204 la especificación de "LENGTH=" no se encuentra en PLISRTB o PLISRTD llamada
9205 la especificación de "LENGTH=" no es numérico en PLISRTB o PLISRTD llamada
9206 E15 oder E35 rutina devuelve un código inválido
9207 DFSORT falló (revisar los mensajes por separado)
9208 PLISRTx invocado, pero el entorno no admite ADMVS
9249 rutina no se puede liberar(RELEASED)
9250 procedimiento que se ha traído(fetched) no se puede encontrar
9251 error de transmisión durante la obtención(fetch) de un procedimiento
9252 FETCH/RELEASE no es compatible con VM (si compilador de la empresa: FETCH/RELEASE no es compatible con CMS)
9253 herramienta de depuración no está disponible (si el compilador de la empresa: PLITEST no está disponible)
9254 un procedimiento principal(MAIN) de una rutina PL/I no se pueden llamar bajo CICS
9255 intento de lanzar un módulo de carga que contiene un programa de lenguaje de alto nivel, que no es PL/I
9257 intento de buscar una subrutina con el punto de entrada PLICALLA
9999 invocación de un entorno en el lenguaje para un servicio MVS/VM falló
Subcódigos de los ONCODEs:
Para ONCODE 93 y 99 (Open falló por conjunto de datos) un subcódigo se suministra, que especifica la razón del fallo.
SUBCÓDIGO significado del SUBCÓDIGO
_________________________________________________________________
1,2 los atributos extendidos de un fichero REGIONAL(1) no se encontraron ni tampoco RECCOUNT ni RECSIZE se especificaron mediante ENV() o SET DD
3 posicionamiento de error para un archivo de salida secuencial
4 tipo de archivo es fijo(FIXED), pero el tamaño del archivo no es un múltiplo del RECSIZE
5,13 error de posicionamiento para archivo regional(1)
6-12 error de posicionamiento para el fichero de salida
21-23 AMTHD (DDM) especificado mediante SET DD, pero DDLs (DUBRUN y DUBLDM) no están disponibles
24 atributos erróneos de un fichero DDM
25 ORGANIZATION de la ENV() entra en conflicto con tipos de datos
26 uso de archivo inconsistente
27 compuestos de clave se encontraron al abrir con clave(KEY)
28-30 creación fallida por nuevos archivos DDM
31 errores de posicionamiento de DDM-archivo
35 AMTHD (BTRIEVE) especificado, pero los módulos BTRCALLS no están disponibles (o ni siquiera existen)
36 Error inesperado al abrir un archivo Btrieve
37 creación falló por nuevo archivo BTRIEVE
38 posicionamiento de error para BTRIEVE-archivo
40 AMTHD (ISAM) especificado, pero IBMW2x20x módulos no están disponibles (o ni siquiera existen)
41 Error inesperado al abrir un archivo ISAM
42 creación falló por nuevos archivos ISAM
43 posicionamiento de error para el archivo ISAM-
50 fichero ISAM no existe
51 Error inesperado al abrir un archivo ISAM (subcódigo 2 proporciona el código ISAM)
52-53 error inesperado al abrir un fichero regional(1)
54 BTRIEVE- archivo no existe
55 Error inesperado al abrir un archivo Btrieve (subcódigo 2 proporciona el código BTRIEVE)
56 Error inesperado al abrir un archivo DDM
57-58 error inesperado al abrir un archivo DDM (subcódigo 2 proporciona el código DDM)
59 el fichero ya está abierto
60 tipo de archivo no es válido (por ejemplo, VSAM bajo UNIX)
62 archivo informacional no se pudo determinar (archivo VSAM)
63 un fichero no-VSAM se abre como VSAM
64 tipo de archivo VSAM no es válido (no es de tipo KSDS, ESDS o RRDS)
65 fichero VSAM fue abierto en un entorno de proceso batch no MVS
66 error al abrir un archivo VSAM (subcódigo 2 proporciona el código VSAM)
67 un fichero VSAM fue abierto como un fichero no-VSAM
68 fichero VSAM inválido
69 información del fichero no se pudo determinar (archivo no VSAM)
70 error de posicionamiento para un archivo VSAM
71 fichero VSAM fue abierto en un entorno de proceso batch no MVS
72 fichero PL/I inválido
73 librería SFS no se pudo cargar
74 librería DCE no se pudo cargar
75 creación falló por nuevo fichero SFS
76 reintento-intento fallido al abrir un archivo SFS
77 posicionamiento de error para un fichero SFS
79 SFS-archivo no encontrado
80 archivo VSAM vacío fue abierto para UPDATE
Suscribirse a:
Entradas (Atom)