La PROCEDURE DIVISION es la parte del programa donde se codifica el proceso en sí. Es decir, aquí escribiremos las sentencias cobol para llevar a cabo la función del programa.
INFORMANDO VARIABLES
En cobol lo que se hace es "mover" la información de una variable a otra utilizando la sentencia MOVE.
A la hora de mover información tendremos que tener en cuenta 2 cosas:
- Formato(PIC) de ambas variables
- Longitud de ambas variables
Ejemplo 1.
01 WX-TELEFONO PIC X(9) VALUE '666111333'.
01 WX-TELEFONO-2 PIC X(9).
Tienen mismo formato y misma longitud, por lo que no habrá problemas. La sentencia sería:
MOVE WX-TELEFONO TO WX-TELEFONO-2
Ahora WX-TELEFONO-2 tendrá el valor '666111333'.
Ejemplo 2.
01 WX-TELEFONO PIC X(9) VALUE '666111333'.
01 WX-TELEFONO-NUM PIC 9(9).
Ahora tenemos misma longitud pero distinto formato. En este caso la variable alfanumérica sólo tiene números, por lo que no habrá problema.
MOVE WX-TELEFONO TO WX-TELEFONO-NUM
Ahora WX-TELEFONO-NUM tendrá el valor 666111333.
Ejemplo 3.
01 WX-TELEFONO PIC X(9) VALUE 'AAA111333'.
01 WX-TELEFONO-NUM PIC 9(9).
Ahora tenemos caracteres alfabéticos en la variable alfanumérica, esto no dará error, aunque no tiene mucho sentido hacerlo.
Dependiendo de la instalación, este tipo de movimientos donde pasamos caracteres alfabéticos a campos numéricos darán, o no, un error en ejecución: el MOVE dará un estupendo "casque" al ejecutar con código error S0C7. Lo mismo ocurre si lo movemos a un campo COMP-3 o COMP.
En cualquier caso, NO debemos mover caracteres alfabéticos a un campo numérico, COMP o COMP-3.
Ejemplo 4.
01 WX-TELEFONO PIC X(9) VALUE '666111333'.
01 WX-TELEFONO-NUM PIC 9(6).
En este caso no coinciden ni las longitudes ni los formatos. Como el campo alfanumérico sólo lleva números no habrá problema, pero al no coincidir las longitudes el campo se "truncará".
MOVE WX-TELEFONO TO WX-TELEFONO-NUM
Ahora el campo WX-TELEFONO-NUM tendrá valor 111333. Hemos perdido los 3 primeros dígitos.
Si fuese al revés:
01 WX-TELEFONO-NUM PIC 9(9) VALUE 666111333.
01 WX-TELEFONO PIC X(6).
MOVE WX-TELEFONO-NUM TO WX-TELEFONO
El valor del campo WX-TELEFONO sería 666111.
Cuando se mueve a un campo alfanumérico, el movimiento se hace de la posición 1 del campo inicial a la posición 1 del campo alfanumérico.
Cuando se mueve a un campo numérico, el movimiento se hace de la última posición del campo inicial a la última posición del campo numérico.
Ejemplo 5.
01 WX-NUMERO-ALF PIC X(4) VALUE '12 '.
01 WX-NUMERO PIC 9(4).
Puede darse el caso de que valores numéricos nos vengan con espacios en lugar de ceros a la izquierda.
Una manera de solventar esto es utilizando el COMPUTE FUNCTION NUMVAL:
COMPUTE WX-NUMERO = FUNCTION NUMVAL(WX-NUMERO-ALF)
Ahora la variable WX-NUMERO tendrá el valor 0012. Es una manera de asegurarnos de que no casque el programa porque algún vago no haya escrito los ceros^^
El movimiento en sí no daría error, pero no debe hacerse.
Un ejemplo más claro:
01 WX-NUMERO-ALF PIC X(4) VALUE '12,00 '.
01 WX-NUMERO PIC 9(4)V9(2).
Con el COMPUTE FUNCTION NUMVAL conseguiríamos que WX-NUMERO tuviese el valor 00120{ (aplantillado con la coma decimal).
Campos COMP-3 y COMP.
Ejemplo 6.
01 WX-SUELDO-COMP3 PIC S9(6) COMP-3 VALUE 100000.
01 WX-SUELDO-NUM PIC 9(6).
MOVE WX-SUELDO-COMP3 TO WX-SUELDO-NUM
Sin problema. WX-SUELDO-NUM valdrá 100000.
Ejemplo 7.
01 WX-SUELDO-COMP3 PIC S9(6) COMP-3 VALUE 100000.
01 WX-SUELDO-ALF PIC X(6).
MOVE WX-SUELDO-COMP3 TO WX-SUELDO-ALF
Sin problema. WX-SUELDO-ALF valdrá 100000.
Ejemplo 8.
01 WX-SUELDO-COMP PIC S9(6) COMP VALUE 100000.
01 WX-SUELDO-NUM PIC 9(6).
MOVE WX-SUELDO-COMP TO WX-SUELDO-NUM
Sin problema. WX-SUELDO-ALF valdrá 100000.
Ejemplo 9.
01 WX-SUELDO-COMP PIC S9(6) COMP VALUE 100000.
01 WX-SUELDO-ALF PIC X(6).
MOVE WX-SUELDO-COMP TO WX-SUELDO-ALF
Sin problema. WX-SUELDO-ALF valdrá 100000.
Ejemplo 10.
01 WX-SUELDO-COMP3 PIC S9(6) COMP-3 VALUE 100000.
01 WX-SUELDO-COMP PIC 9(6) COMP.
MOVE WX-SUELDO-COMP3 TO WX-SUELDO-COMP
Sin problema, WX-SUELDO-COMP valdrá 100000 pero en formato hexadecimal: 186A0
Ejemplo 11.
01 WX-SUELDO-COMP PIC 9(6) COMP VALUE 100000.
01 WX-SUELDO-COMP3 PIC S9(6) COMP-3.
MOVE WX-SUELDO-COMP TO WX-SUELDO-COMP3
Sin problema, WX-SUELDO-COMP valdrá 100000.
Para campos numéricos existe también la sentencia COMPUTE para pasar información de uno a otro:
Ejemplo 12.
01 WX-NUMERO-1 PIC 9(5) VALUE 12345.
01 WX-NUMERO-2 PIC 9(5).
COMPUTE WX-NUMERO-2 = WX-NUMERO-1
Ahora WX-NUMERO-2 valdrá 12345.
Aunque la sentencia COMPUTE se usa en general para operaciones aritméticas: suma, resta, multiplicación, división, potencia...
COMPUTE WX-NUMERO1 =
((WX-NUMERO2 + WX-NUMERO3) - (WX-NUMERO4 * WX-NUMERO5) / WX-NUMERO6) ** 2
Y se aplican las mismas reglas de prioridades que en matemáticas.(el doble asterisco es la potencia)
Es en estos casos cuando un campo numérico que lleve caracteres o espacios pierde su sentido, pues adivinad que sucede si intentamos dividir 'ABC?%&' entre 1000 al ejecutar el programa...
Premio! Un S0C7!!
Nunca va a tener sentido dividor letras entre números, imagino que en esto estamos todos de acuerdo : P
Para operaciones aritméticas existen también:
ADD: operador suma. "ADD 1 TO WX-CAMPO"
SUBTRACT: operador resta. "SUBTRACT 1 FROM WX-CAMPO"
MULTIPLY: operador multiplicación. "MULTIPLY WX-CAMPO BY 1"
DIVIDE: operador división. "DIVIDE WX-CAMPO BY 1"
REMAINDER: es el resto de una división. "DIVIDE WX-CAMPO BY 1 REMAINDER WX-RESTO"
Ejemplo 13.
01 WX-TELEFONO-NUM PIC 9(9) VALUE 666111333.
01 WX-TELEFONO-ALF PIC X(9) VALUE '666111333'.
01 WX-TELEFONO PIC X(6).
Para campos alfanuméricos y numéricos sin comprimir existe la posibilidad de mover sólo determinadas posiciones del campo.
MOVE WX-TELEFONO-NUM(1:6) TO WX-TELEFONO
En este caso estamos cogiendo 6 posiciones, empezando desde la posición 1. Ahora WX-TELEFONO valdrá '666111'.
MOVE WX-TELEFONO-ALF(4:) TO WX-TELEFONO
En este caso estamos cogiendo todas las posiciones hasta final de campo desde la posición 4. Ahora WX-TELEFONO valdrá '111333'.
Para mover posiciones de un campo que pertenece a un array o tabla, primero habrá que indicar el occurs o índice y después la posición:
01 WX-TABLA OCCURS 5 TIMES.
05 WX-TELEFONO1 PIC X(9) VALUE '111111111'.
05 WX-TELEFONO2 PIC X(9) VALUE '222222222'.
05 WX-TELEFONO3 PIC X(9) VALUE '333333333'.
05 WX-TELEFONO4 PIC X(9) VALUE '444444444'.
MOVE WX-TELEFONO3(3)(4:) TO WX-TELEFONO
Ahora WX-TELEFONO valdrá '333333'.
CONCATENANDO CAMPOS
En COBOL también existe la opción de concatenar campos usando la sentencia STRING. Lo que haremos será indicar las variables a concatenar, el modo en que se unirán y el campo donde se guardará el resultado.
01 WX-CAMPO1 PIC X(17) VALUE 'CONSULTORIO COBOL'.
01 WX-CAMPO2 PIC X(10) VALUE ' SON GUAYS'.
01 WX-RESULTADO PIC X(41).
STRING 'LOS TIPOS DEL ' WX-CAMPO1 WX-CAMPO2
DELIMITED BY SIZE
INTO WX-RESULTADO
Donde DELIMITED BY SIZE indica que los campos se unirán según el tamaño que ocupen, y el INTO indicará el campo donde guardar la información concatenada.
Si por ejemplo tuviésemos campos con espacios al final podríamos indicarle un DELIMITED BY SPACES, para que cortase la información al encontrarse el primer espacio. Vamos a ver el ejemplo:
01 WX-DIA PIC 9(2) VALUE 31.
01 WX-MES PIC X(10).
01 WX-FECHA PIC X(19).
MOVE 'MAYO' TO WX-MES
Ahora WX-MES valdrá 'MAYO '.
STRING 'HOY ES ' WX-DIA ' DE ' DELIMITED BY SIZE
WX-MES DELIMITED BY SPACE
'.' DELIMITED BY SIZE
INTO WX-FECHA
El resultado:
HOY ES 31 DE MAYO.
Si no hubiésemos indicado el DELIMITED BY SPACE, el resultado sería:
HOY ES 31 DE MAYO .
Recordad: el DELIMITED BY se aplica a todos los campos que lo preceden. Usad el DELIMITED BY correcto en cada caso!
INICIALIZANDO CAMPOS
Para "vaciar" un campo podríamos moverle ceros o espacios (según su formato). Pero
en cobol existe una instrucción más sencilla que es el INITIALIZE.
01 WX-NUMERO PIC 9(5) VALUE 12345.
(...)
INITIALIZE WX-NUMERO
Ahora WX-NUMERO valdrá 00000. Si fuese alfanumérico valdría ' ' (cinco espacios).
Las variables "vacías" en cobol pueden tener 3 tipos de información:
ceros: 00000
espacios: ' '
low-values: '.....'
Por eso a la hora de preguntar si un campo está vacío en cobol preguntaremos:
IF WX-CAMPO EQUAL ZEROES OR SPACES OR LOW-VALUES
(...)
Nota: Tanto LOW-VALUES como HIGH-VALUES son palabras reservadas en cobol, y se pueden definir como "el valor más bajo posible" y "el valor más alto posible" respectivamente. Veremos su uso en otros artículos.
BUCLES Y CONDICIONES
Las condiciones en cobol se escriben de la siguiente manera:
IF WX-CAMPO = 1
MOVE 1 TO WX-CAMPO2
ELSE
MOVE WX-CAMPO TO WX-CAMPO2
END-IF
Podemos escribir IFs dentro de IFs (IFs anidados) y La sentencia ELSE no es obligatoria:
IF WX-CAMPO1 = 1
IF WX-CAMPO2 = 2
MOVE WX-CAMPO1 TO WX-CAMPO3
END-IF
ELSE
MOVE 1 TO WX-CAMPO3
END-IF
No tienen más ciencia que cualquier IF de cualquier otro lenguaje.
Los operadores lógicos serán OR, AND, EQUAL, NOT EQUAL.
Los operadores de mayor, menor, serán GREATER y LESS.
También se pueden utilizar combinaciones como GREATER OR EQUAL (mayor o igual), y también con símbolos: >= (mayor o igual), <= (menor o igual).
Otra forma de preguntar por una condición es con un EVALUATE.
Preguntando si se cumple una condición, es decir, si es TRUE:
EVALUATE TRUE
WHEN WS-CAMPO1 EQUAL WS-CAMPO2
(instrucciones a realizar)
WHEN WS-CAMPO1 NOT EQUAL WS-CAMPO2
(instrucciones a realizar)
WHEN OTHER
(instrucciones a realizar)
END-EVALUATE
Preguntando por el valor de un campo:
EVALUATE WS-CAMPO1
WHEN 1
(instrucciones a realizar)
WHEN 2
(instrucciones a realizar)
WHEN OTHER
(instrucciones a realizar)
END-EVALUATE
Preguntando por el valor de varios campos:
EVALUATE WS-CAMPO1 ALSO WS-CAMPO2
WHEN 1 ALSO 1
(instrucciones a realizar)
WHEN 2 ALSO 2
(instrucciones a realizar)
WHEN OTHER
(instrucciones a realizar)
END-EVALUATE
ó
EVALUATE TRUE ALSO TRUE
WHEN WS-CAMPO1 = 1 ALSO WS-CAMPO2 = 1
(instrucciones a realizar)
WHEN WS-CAMPO1 = 2 ALSO WS-CAMPO2 = 2
(instrucciones a realizar)
WHEN OTHER
(instrucciones a realizar)
END-EVALUATE
ó
EVALUATE WS-CAMPO1 ALSO TRUE
WHEN 1 ALSO WS-CAMPO2 = 1
(instrucciones a realizar)
WHEN 2 ALSO WS-CAMPO2 = 2
(instrucciones a realizar)
WHEN OTHER
(instrucciones a realizar)
END-EVALUATE
Los bucles son diferentes debido a que en cobol no existe la sentencia "while" de otros lenguajes. Aquí los bucles son siempre "UNTIL", es decir, hasta que se cumpla la condición especificada.
MOVE 0 TO WX-CAMPO
PERFORM UNTIL WX-CAMPO = 5 -> aquí es donde pregunta por la condición
proceso a realizar
ADD 1 TO WX-CAMPO
END-PERFORM
El proceso se realizará para:
WX-CAMPO = 0
WX-CAMPO = 1
WX-CAMPO = 2
WX-CAMPO = 3
WX-CAMPO = 4
MOVE 5 TO WX-CAMPO
PERFORM UNTIL WX-CAMPO = 5 -> aquí es donde pregunta por la condición
proceso a realizar
END-PERFORM
El proceso no se llega a realizar.
Si quisiésemos preguntar por la condición al final del bucle, tendríamos que codificar el bucle con un "WITH TEST AFTER":
MOVE 0 TO WX-CAMPO
PERFORM WITH TEST AFTER
UNTIL WX-CAMPO = 5
proceso a realizar
ADD 1 TO WX-CAMPO
END-PERFORM -> aquí es donde pregunta por la condición
El proceso se realizará para:
WX-CAMPO = 0
WX-CAMPO = 1
WX-CAMPO = 2
WX-CAMPO = 3
WX-CAMPO = 4
MOVE 5 TO WX-CAMPO
PERFORM WITH TEST AFTER
UNTIL WX-CAMPO = 5
proceso a realizar
ADD 1 TO WX-CAMPO
END-PERFORM -> aquí es donde pregunta por la condición
El proceso se realiza una vez, antes de comprobar si se cumple la codición.
Como veíamos en la estructura general de un programa cobol, un párrafo entero también se puede repetir hasta que se cumpla una condición:
PERFORM 2000-PROCESO
UNTIL CUMPLA-CONDICION
Otro tipo de bucles son los "PERFORM VARYING". En este caso tendremos un contador que se irá incrementando automáticamente según le indiquemos:
PERFORM VARYING WI-INDICE FROM 1 BY 1 UNTIL WI-INDICE = 10
código a ejecutar
END-PERFORM
El "FROM" le indica desde que valor empezar. El "BY" le indica cuanto le ha de sumar cada vez.
Como en el otro caso, el "UNTIL" le indicará la condición de final de bucle.
Con todo esto, ya podemos empezar a ver un ejemplo de un programa sencillo : )
18 comentarios:
parece interesante,deja leerlo bien y ponerlo en pràctica,habia estado buscando un manual asì,muchas gracias
BUENA INFORMACIÓN, GRACIAS! ;)
Encontré un errorcillo: en vez de REMINDER en la división, debe ser REMAINDER
Corregido! Gracias : )
Resulta que me han contratado para trabajar con Cobol y DB2 pero en mi vida había trabajado con ello y este curso me está siendo de gran ayuda. Gracias y enhorabuena por el curso.
De nada Juan. Nos alegramos de que te sea útil. Pregunta lo que necesites!
Talli.
muy bueno muchachos! muy bien explicado! gracias!
HOLA ALGUINE PODRIA AYUDARME PARA ENTENDER ESTE PERFORM :. PERFORM CLEAR-CNTRL-TABLE-1 THRU CLEAR-CNTRL-TAB-2
VARYING X-1 FROM 1 BY 1 UNTIL
X-1 GREATER THAN 25
AFTER IND1 FROM 1 BY 1 UNTIL
IND1 GREATER THAN NUM-MARKETS
AFTER IND2 FROM 1 BY 1 UNTIL
IND2 GREATER THAN 2. GRACIAS
Hola David.
Si no me equivoco, el AFTER lo que hace es que por cada valor del índice X-1, incrementa de 1 en 1 el índice IND1. Algo así como un bucle dentro de un bucle.
Lo mismo el segundo AFTER.
Un saludo!
El ejemplo 5 me ha venido de maravillas. Muchas gracias!!
Que tal, solo para aportar... En EVALUATE también se puede dar la combinación:
EVALUATE WS-CAMPO1 ALSO TRUE
Saludos desde México.
Gracias bto! Lo añado :-)
Este comentario ha sido eliminado por el autor.
Saludos y muchas gracias por este tutorial que me está poniendo al día para mi inminente futuro trabajo. Un comentario en cuanto al output del ejemplo del WITH TEST AFTER ya que pienso que la variable WX-CAMPO tomará los valores del 0 al 5 y no sólo al 4 como haría SIN la cláusula WITH TEST AFTER. mUchas gracias.
Saludos. En el ejemplo 13 creo que en vez de la sentencia MOVE WX-TELEFONO-ALF(3)(4:) TO WX-TELEFONO se trata de MOVE WX-TABLA(3)(4:) TO WX-TELEFONO y también sería válida MOVE WX-TELEFONO3(4:) TO WX-TELEFONO ¿es esto correcto?
Hola Francisco.
Sobre el ejemplo 13, efectivamente estaba mal, lo he corregido. Gracias!
Sobre el "with test after", te explico:
PERFORM WITH TEST AFTER
UNTIL WX-CAMPO = 5
proceso a realizar
ADD 1 TO WX-CAMPO
END-PERFORM -> aquí es donde pregunta por la condición
Cuando pregunto por la condición "until wx-campo = 5", ya he añadido 1 a wx-campo, por lo tanto en cuanto toma valor 5 finaliza el bucle :-)
Hola. Una duda.
¿Habría algún problema en hacer la siguiente resta donde difieren tanto la precisión de la parte entera como la precisión de los decimales de ambos operandos?
01 WK-RESTA PIC S9(12)V9(08).
01 WK-CAMBIO1 PIC S9(08)V9(05).
01 WK-CAMBIO2 PIC S9(12)V9(08).
COMPUTE WK-RESTA = WK-CAMBIO1 - WK-CAMBIO2
Muchas gracias.
Ningún problema Sebas. Puesto que el resultado lo estás guardando en el formato del número de mayor valor. De esa forma no perderás ni decimales ni enteros.
01 WK-RESTA PIC S9(12)V9(08).
01 WK-CAMBIO1 PIC S9(08)V9(05) VALUE 99999999,99999.
01 WK-CAMBIO2 PIC S9(12)V9(08) VALUE 111111111111,11111111.
COMPUTE WK-RESTA = WK-CAMBIO1 - WK-CAMBIO2
WK-RESTA:1110111111111111211J
:-)