Mostrando entradas con la etiqueta variables. Mostrar todas las entradas
Mostrando entradas con la etiqueta variables. Mostrar todas las entradas

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

miércoles, 26 de enero de 2011

WORKING-STORAGE: definiendo variables.

Las variables que se usan en un programa cobol deben haber sido previamente definidas en la WORKING-STORAGE SECTION.

Existen diferentes tipos de variables en cobol. Cada variable que definamos debe terminar con un punto ".".
Si la variable va a tener un valor inicial lo indicaremos con la cláusula VALUE.

Alfanuméricas: se indican con un PIC X(número de caracteres). Podrán tener como valores números y letras.

01 WX-VARIABLE-ALFNUM PIC X(10) VALUE 'LOQUESEA10'.


Numéricas normales: se indican con un PIC 9(número de dígitos). Sólo tendrán valor numérico. La V indica la coma decimal.

01 WX-VARIABLE-NUM PIC 9(5)V9(2) VALUE 12345,67.
(value sin las comillas)

Numéricos comprimidos: se indican con un PIC 9(número de dígitos) COMP-3. Sólo valores numéricos. Estas variables ocuparán, en espacio, menos que un numérico normal.
El cálculo de longitudes lo veremos más adelante. La S indica que lleva signo decimal que puede ser positivo o negativo.

01 WX-VARIABLE-COMP3 PIC S9(5)V9(2) COMP-3 VALUE 12345,67.


Numéricos hexadecimales: se indican con un PIC 9(número de dígitos) COMP. Sólo valor numérico. OJO! Aceptan letras porque el número va en formato hexadecimal, pero eso no significa que podamos informarlas con caracteres alfabéticos.

01 WX-VARIABLE-COMP PIC 9(5)V9(2) COMP VALUE 12345,67.


Editados: se indican con la cláusula PIC seguida por tantas "zetas" Z como necesitemos. Se utilizan para dar formato a campos numéricos.

01 WX-VARIABLE-EDI PIC -Z.ZZZ.ZZ9,99.


Esto equivaldría a un campo numérico PIC S9(7)V9(2). El último dígito antes de la coma decimal se indica con un 9 para que aparezca el valor numérico del 0 al 9. Las Zs sustituirán los "ceros" 0 a la izquierda por espacios.

01 WX-VARIABLE-NUM PIC S9(7)V9(2) VALUE -0001234,56.
01 WX-VARIABLE-EDI PIC -Z.ZZZ.ZZ9,99

DISPLAY 'WX-VARIABLE-NUM:'WX-VARIABLE-NUM

MOVE WX-VARIABLE-NUM TO WX-VARIABLE-EDI

DISPLAY 'WX-VARIABLE-EDI:'WX-VARIABLE-EDI


El resultado sería:
WX-VARIABLE-NUM:00012345O
WX-VARIABLE-EDI:-    1.234,56



Si queremos que el signo aparezca pegado al número, podemos definir el campo editado de la siguiente manera:
01 WX-VARIABLE-EDI PIC -.---.--9,99.

Para que se muestre como "-1.234,56".

Ahora que sabemos definir variables, vamos a ver que las variables pueden estar definidas en diferentes "niveles". Estos niveles vienen indicados por un número a la izquierda:

01 WX-INFORMACION-PERSONA.
   05 WX-NOMBRE    PIC X(10).
   05 WX-APELLIDO1 PIC X(10).
   05 WX-APELLIDO2 PIC X(10).
   05 WX-DIRECCION.
      10 WX-CALLE  PIC X(10).
      10 WX-NUMERO PIC 9(3).
      10 WX-PISO   PIC 9(2).

Y así sucesivamente.

Si tenemos algún subnivel que sea una constante, en lugar de ponerle nombre al campo podemos utilizar la cláusala FILLER:

01 WX-FECHA.
   05 WX-DIA PIC 9(2).
   05 FILLER PIC X VALUE '-'.
   05 WX-MES PIC 9(2).
   05 FILLER PIC X VALUE '-'.
   05 WX-ANO PIC 9(4).


La diferencia del FILLER con un campo "con nombre", es que el FILLER no se puede utilizar para "mover" la información que contenga. Es un campo fijo (la traducción sería "RELLENO") que no se puede informar (a no ser que informásemos el nivel superior y nos cargásemos todo, claro... xd).
El resultado del campo informado sería por ejemplo:
Fecha = 01-01-2011

Existe una forma de definir variables con dos o más tipos de formato (PIC) distintos. Se trata de la cláusula REDEFINES.
Se suele utilizar para evitar mover campos alfanuméricos a numéricos, o bien para agrupar un campo que tenga subniveles:

01 WX-CAMPO1 PIC X(3).
01 WX-CAMPO2 REDEFINES WX-CAMPO1 PIC 9(3).

01 WX-CAMPO1.
   05 WX-SUBCAMPO1 PIC X(3).
   05 WX-SUBCAMPO2 PIC 9(5).
01 WX-CAMPO2 REDEFINES WX-CAMPO1 PIC X(8).


IMPORTANTE: sólo se pueden "redefinir" campos que estén al mismo nivel, es decir, para redefinir un campo de un nivel 01, tendremos que hacerlo en otro campo de nivel 01.

También podemos definir tablas o arrays:
01 WX-TABLA-INTERNA OCCURS 5 TIMES.
   05 WX-CAMPO1 PIC X VALUE 'A'.
   05 WX-CAMPO2 PIC X VALUE 'B'.


De tal manera que el conjunto de los campos 1 y 2 se repiten 5 veces:
ABABABABAB

Existen otro tipo de niveles que son los niveles "88":
01 WX-RESPUESTA   PIC X.
   88 RESPUESTA-SI      VALUE 'S'.
   88 RESPUESTA-NO      VALUE 'N'.


De tal forma que la variable WX-RESPUESTA podrá tomar los valores S ó N según queramos.
Para hacer que la variable tome un valor:

SET RESPUESTA-SI TO TRUE
   tomará el valor S.
SET RESPUSETA-NO TO TRUE    tomará el valor N.

Imaginemos que tenemos una serie de campos que definen la estructura de un fichero. Si tenemos varios programas que usan ese fichero, tendremos que escribir esos campos tantas veces como programas tengamos. Para ahorrarnos trabajo tenemos la cláusula COPY.
Una "COPY" es un trozo de código cobol que puede contener la definición de variables (COPY de WORKING) o una parte del código del programa (COPY de PROCEDURE):

COPY WORKING
Se incluirán dentro de la WORKING-STORAGE.
COPY WSCOPY.

Donde WSCOPY contendrá algo de este estilo:
01 WX-WSCOPY.
   05 WX-CAMPO1 PIC X(5).
   05 WX-CAMPO2 PIC X(5).
   05 WX-CAMPO3 PIC X(5).
   05 WX-CAMPO4 PIC X(5).


COPY PROCEDURE
Se incluirán dentro de la PROCEDURE DIVISION.
COPY PDCOPY.

Donde PDCOPY contendrá algo de este estilo:
MOVE WX-CAMPO1 TO WX-REGISTRO1
MOVE WX-CAMPO2 TO WX-REGISTRO2
MOVE WX-CAMPO3 TO WX-REGISTRO3
MOVE WX-CAMPO4 TO WX-REGISTRO4
MOVE WX-CAMPO5 TO WX-REGISTRO5



CÁLCULO DE LONGITUDES

Numéricos y alfanuméricos: lo que venga indicado en el PIC X(n) ó PIC 9(n) respectivamente.

01 WX-VARIABLE-ALFNUM PIC X(5).
01 WX-VARIABLE-NUM    PIC 9(5).

longitud = 5

Numéricos COMP-3: si tenemos un PIC 9(n) COMP-3, la longitud será (n+1)/2. Si el resultado tiene decimales redondeamos hacia arriba. Hay que tener en cuenta que la coma decimal no ocupa espacio, y que el signo ocupa sólo media posición.

01 WX-VARIABLE-COMP3 PIC S9(5) COMP-3.

longitud = (5 + 1)/2 = 3

Numéricos COMP:
Un campo con PICTURE numérica y COMP se almacena en formato binario puro (base 2); el signo lo representa el bit de la derecha. El número de bytes que se reservan en memoria para cada campo es:
2 posiciones para números de 1 a 4 dígitos.
4 posiciones para números de 5 a 9 dígitos.
8 posiciones para números de 10 a 18 dígitos.

01 WX-VARIABLE-COMP PIC 9(5) COMP.

longitud = 4


VISUALIZANDO CAMPOS

Como ya hemos comentado, existen campos en cobol q no se ven "tal cual", como son los comprimidos o los hexadecimales. Vamos a ver como se verían en un fichero estos campos:

----+----1----+----2----+----3----+----4
999999999          q Íì%      00000  S 
FFFFFFFFF444444444493716000000FFFFF00E2
99999999900000000008265C000000000000122
----------------------------------------


* El campo que va de la posición 1 a la 9 sería un campo numérico normal con valor 999999999.
* El campo que va de la posición 10 a la 19 sería un campo alfanumérico con valor '         ' (9 espacios).
* El campo que va de la posición 20 a la 24 sería un campo numérico COMP-3 con valor 983276156 positivo (letra C, letra D para negativos*).
* El campo que va de la posición 25 a la 30 sería un campo informado con low-values.
* El campo que va de la posición 31 a la posición 35 sería un campo informado con 5 ceros 00000.
* El campo que va de la posición 36 a la 39 sería un campo numérico COMP con valor 1E222 (en hexadecimal) / 123426(en decimal).

*Para campos numéricos con signo del tipo S9(3)V99, podemos distinguir el signo fijándonos en la última posición:
A = +1
B = +2
C = +3
D = +4
E = +5
F = +6
G = +7
H = +8
I = +9
J = -1
K = -2
L = -3
M = -4
N = -5
O = -6
P = -7
Q = -8
R = -9
{ = +0
} = -0


En el próximo artículo veremos la PROCEDURE DIVISION, donde se codifica la "miga" del programa. Veremos como informar campos, como inicializarlos y como codificar bucles y condiciones.