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

Ejemplo 1: Leer de SYSIN y escribir en SYSPRINT (pl/i).

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.

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 : )

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.

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:

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:
  • 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?
  • 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