Alters

COBOL: flujo

Hola de nuevo!

Como veis, he actualizado el diseño del blog, ahora es algo más actual...

Siguiendo con el mini - curso de COBOL, en la entrada de hoy toca ver el flujo: es decir, sentencias que cambian el rumbo normal del un programa.

- Flujo en COBOL
* IF
* PERFORM
* GO TO
* Salir y continuar


IF

Un IF en COBOL es como cualquier otro if, es decir

IF condicion
sentencias
ELSE IF condicion
sentencias
ELSE
sentencias


Los operadores lógicos son escritos (es decir, NOT, AND, OR...). Los operadores aritméticos son los típicos (<, >, = - solo un "="). Este tema lo miramos después.

Un ejemplo de if:

IF opcion = 'A'
DISPLAY 'HOLA'
END-IF.

Hay una cosa a tener en cuenta: dentro de un bloque (un bloque es un conjunto de sentencias que va entre un token de apertura y uno de cierre - END -) no hay ningún punto. También fijaros que los IF acaban en END-IF. Si son de una línea se puede abrevias con IF con THEN sen., pero yo soy más de poner siempre el END-IF (evita confusiones).


PERFORM

Un PERFORM es una "llamada a función", pero recordad que va entre comillas porque realmente llamamos a un párrafo.

PERFORM también permite crear bloques, ya que, en realidad, PERFORM es un token polimórfico. Sirve para:

- Llamar párrafos
- Llamar conjunto de párrafos
- Llamar a bloques
- Llamar a sección
- Repetir párrafo / conjunto / bloque X veces (for)
- Repetir hasta condición (do/while, do/until).

Podemos hacer

PERFORM 5 TIMES
DISPLAY 'HOLA'
END-PERFORM.

Así como:

PERFORM SALUDO 5 TIMES.

SALUDO.
DISPLAY 'HOLA'.


Hemos visto que con "X TIMES" hace un for. Para hacer un "while/until", la cosa es algo más complicada. La sintaxis básica es:

PERFORM parrafo/seccion VARYING variable FROM inicio BY paso UNTIL condicion.

Para llamar a una serie de párrafos, añadimos la cláusula THRU. Esto hará que ejecute desde el primer al último párrafo indicado, por ejemplo:

PERFORM uno THRU cinco. , en el ejemplo que sigue, ejecutaría todo el código.

uno.
DISPLAY 'uno'.

dos.
DISPLAY 'dos'.

tres.
DISPLAY 'tres'.

cuatro.
DISPLAY 'cuatro'.

cinco.
DISPLAY 'cinco'.

Condicionales:

Se me había olvidado poner en el índice cómo usar las condiciones, así que las explico antes del GO TO:

Condiciones hay básicamente de dos tipos: aritmética y lógica.

- Lógica: Se usan unas tablas para verificar la veracidad de la sentencia. Son usados AND, OR, NOT... en este tipo de sentencias.

- Aritmética: Se calculan valores y comparan entre ellos, para decidir el resultado. Son usados símbolos aritméticos (=, <, >...) para comparar, así como operaciones aritméticas.

Un inciso: las operaciones aritméticas en COBOL son algo diferentes. Normalmente podemos hacer algo así como

COMPUTE var1 = expr.

Siendo expr una operación matemática, por ejemplo: "var1 - 5". En este tipo de sentencias se usan los signos típicos: *, /. +, -.

Se pueden hacer cálculos de otros tipos, como ADD, SUBSTRACT, MULTIPLY y DIVIDE.

En estas sentencias se sigue el siguiente formato:

ADD val TO var -> es como "var+=val"
ADD val TO var GIVING var2 -> es como "var2 = val+var"
SUBSTRACT val TO var (GIVING var2)
MULTIPLY val TO var (GIVING var2)
DIVIDE val TO var (GIVING var2) (REMAINDER var3) -> el resto va a var3

Adicionalmente, se pueden añadir las cláusulas ROUNDED y ON SIZE ERROR.

ROUNDED: va antes de "val", sirve para obtener un valor redondeado. Si no se pone ROUNDED y la precisión de nuestra variable es menor, se trunca.

ON SIZE ERROR: si no redondeamos, podemos poner esta cláusula al final de la sentencia, y esto añade un "handler" a la operación, por ejemplo

ADD 1 TO var ON SIZE ERROR MOVE 0 TO var2.

IF var2 = 0
...


Por ahora esto es lo básico de operaciones aritméticas.

GO TO


Sin duda, ésta es la sentencia más odiada por todos, y realmente no se porqué.
GO TO hace un salto incondicional hacia un párrafo. Es útil cuando tenemos que ir a un párrafo desde más de un sitio a la vez, independientemente del contexto en el que estemos.

Es cierto que el uso excesivo del GO TO puede confundir, pero si sabéis lo que hacéis no hay problemas.

Su uso es: GO TO parrafo.

Salir y continuar

Hay dos sentencias, similares a "continue" y "exit/break" que se pueden usar en bloques. Los equivalentes en COBOL son CONTINUE y NEXT SENTENCE.

CONTINUE hace que ejecute un "salto", es el típico continue
NEXT SENTENCE lleva la ejecución a la próxima sentencia (es decir, después del siguiente ".").


Como colofón, añadir que estas sentencias pueden ir anidadas, sin olvidar que sólo el último cierre de bloque ha de tener el punto.

Como os digo siempre, acepto sugerencias en los comentarios.

Saludos y hasta la próxima


¿Te han resultado útiles mis conocimientos de COBOL?
¡Llévatelos donde quieras!



COBOL: pantallas

Hola de nuevo!

En esta entrada hablaré sobre las pantallas en COBOL. Con esto, nuestras SECTION se ampliarán, pero por contra, ganaremos en diseño y usabilidad.

Esto todavía no lo he probado (se me acaba de ocurrir mientras escribía), pero estoy casi seguro que se puede hacer una biblioteca de pantallas, para llamarlas desde donde sea...


Bueno, vamos allá!

Pantallas:

Como he escrito, las pantallas amplían las section, específicamente la DATA DIVISION - SCREEN SECTION.

¿Y que es una screen (pantalla)? Pues un conjunto de datos previamente cargados que podemos mostrar y pedir datos sobre esos mismos datos.

Aquí dejo un ejemplo:


       SCREEN SECTION.
      *  Pantalla inicial
       01 PRINCIPAL.
          03 LINE 05 COL 10 VALUE "MENU PRINCIPAL".
          03 LINE 07 COL 10 VALUE "ELIGA OPCION: ".
          03 LINE 09 COL 10 VALUE "TRATAMIENTO (A)UTO. DE CLIENTES".
          03 LINE 11 COL 10 VALUE "TRATAMIENTO (M)ANUAL DE CLIENTES".
          03 LINE 13 COL 10 VALUE "OBTENCION DE (L)ISTADOS".
          03 LINE 15 COL 10 VALUE "(S)ALIR".
          03 LINE 17 COL 10 VALUE "> ".
          03 PIC X USING OPCION.

Esta pantalla es del trabajo final que hice para obtener el título de Experto en COBOL. Como se ve, están los parámetros LINE y COL (COL hace lo mismo que POSITION). También tenemos VALUE, PIC...

USING es un token que aún no habíamos visto; en este caso le dice a COBOL en qué variable tiene que meter los datos. Anotar que esta variable tiene que estar definida en la WSS (en esta screen, por así decirlo, le pasamos un "puntero" a la variable).

Os explico un poco el transfondo de esta pantalla: se supone que el usuario puede introducir tres opciones: A, M, y L (en mayúscula o minúscula, da igual). Este valor se guarda en OPCION, y luego se usa para dirigir a uno u otro sitio.

En este caso, siendo un ejemplo, haremos un programa que muestre la opción.

Para hacer bien el ejemplo, voy primeo a explicar un poco lo que haré.

- En la WSS crearé unas variables de hardcode, la variable de opción, y una variable "tonta" (dummy).
- En la Screen Section crearemos varias pantallas, incluyendo una pantalla vacía.
- En la procedure mostraremos la pantalla, y actuaremos en consecuencia.


       IDENTIFICATION DIVISION.
       PROGRAM-ID. MENU.
       REMARKS. MENÚ PRINCIPAL

       ENVIRONMENT DIVISION.

       DATA DIVISION.
       WORKING-STORAGE SECTION.
      * Opción de menú
       77   OPCION PIC X VALUE SPACE.

      *  Variables de hardcode
       01    HARDCO.
          02 M-MAY PIC X VALUE 'M'.
          02 M-MIN PIC X VALUE 'm'.
          02 A-MAY PIC X VALUE 'A'.
          02 A-MIN PIC X VALUE 'a'.
          02 L-MAY PIC X VALUE 'L'.
          02 L-MIN PIC X VALUE 'l'.
          02 S-MAY PIC X VALUE 'S'.
          02 S-MIN PIC X VALUE 's'.

      * Variable vacía
       77    DUMMY PIC X VALUE SPACE.

       SCREEN SECTION.
      *  Pantalla inicial
       01 PRINCIPAL.
          03 LINE 05 COL 10 VALUE "MENU PRINCIPAL".
          03 LINE 07 COL 10 VALUE "ELIGA OPCION: ".
          03 LINE 09 COL 10 VALUE "TRATAMIENTO (A)UTO. DE CLIENTES".
          03 LINE 11 COL 10 VALUE "TRATAMIENTO (M)ANUAL DE CLIENTES".
          03 LINE 13 COL 10 VALUE "OBTENCION DE (L)ISTADOS".
          03 LINE 15 COL 10 VALUE "(S)ALIR".
          03 LINE 17 COL 10 VALUE "> ".
          03 PIC X USING OPCION.

      * Pantalla de error
       01 ERROR-SCR.
          03 LINE 05 COL 10 VALUE "ERROR".
          03 LINE 07 COL 10 VALUE "NO EXISTE LA OPCION".
          03 LINE 09 COL 10 VALUE "ELIGA ENTRE LAS OPCIONES:".
          03 LINE 11 COL 10 VALUE "A, M, o L".
          03 PIC X USING DUMMY.

      *  Pantalla vacía
       01 VACIO.
          03 BLANK SCREEN.

       PROCEDURE DIVISION.
       INICIO.
      *    Mostramos la pantalla inicial
           DISPLAY PRINCIPAL.
           ACCEPT  PRINCIPAL.

      *    Limpiamos la pantalla
           DISPLAY VACIO.

      *   Hacemos cosas...

           DISPLAY 'HAS USADO LA OPCION' OPCION.
           DISPLAY 'PULSA CUALQUIER TECLA PARA SALIR.'.
           ACCEPT DUMMY.


           EXIT PROGRAM.


Como se puede ver, hay cosas que no usamos, como las variables de HC o la pantalla de error. Estas cosas las dejaré por ahora, ya las usaré cuando hable del flujo, en la siguiente entrada.


No es muy difícil de entender el funcionamiento de este programa... ahora podéis experimentar con las pantallas, usando las opciones que vimos ayer, por ejemplo.

Saludos, y,

Hasta la próxima!


¿Te han resultado útiles mis conocimientos de COBOL?
¡Llévatelos donde quieras!




COBOL: lo básico de COBOL

Hola de nuevo, en esta entrega trataremos el segundo punto del índice expuesto en la primera entrada del mini-curso de COBOL.

- Lo básico de COBOL
   * PIC
   * Display
   * Accept

PIC

PIC es la instrucción clave para declarar variables en COBOL. Esta cláusula establece una máscara de entrada de datos.

Esto significa que nos podemos ir olvidando de "int", "float", "char", "String"... en cobol no hay de esto. Que suceda así tiene sus ventajas e inconvenientes:

Ventajas:
   - Comprobación automática de valores: si pedimos una entrada de 10 caracteres y nos introducen un número, automáticamente cancela la entrada y la vuelve a pedir, con todo lo que ello comporta

   - Adecuación a ficheros: siempre sabremos la longitud de cada variable, ya que siempre son de longitud fija

Inconvenientes:
  - Tenemos que tener siempre en cuenta los desbordamientos
  - Perdemos algunas mejoras con los tipos (esto se puede salvar con un extra de código)

Antes de aprender a declarar con PIC, vamos a ver qué máscaras hay:

X -> caracter alfanumérico
9 -> caracter numérico
A -> caracter alfabético
S -> caracter de signo
V -> caracter de decimal

Para aclarar un poco, veamos unas conversiones mySQL a COBOL:

varchar(5) -> PIC XXXXX
                 -> PIC X(5)

float(8, 2) -> PIC 999999V99
                -> PIC 9(6)V99
                -> PIC 9(6)V9(2)
                -> PIC S9(6)V9(2)

Como se ve, las máscaras se pueden abreviar, haciendo que el caracter escrito se repita n veces, escribiendo (n).

Bien, el tema de PIC está explicado; ahora falta un tema fundamental para las variables: el NIVEL

en COBOL, toda variable ha de tener un nivel. Pero ¿de qué sirve? pues es fácil: una variable de nivel alto depende de una de nivel bajo. Esto nos sirve para crear estructuras de una manera muy rápida.

Aquí unos ejemplos para ver cómo funcionan los niveles:



       01    CLI.
          02 CODCLI PIC X(5).
          02 NOMCLI PIC X(25).
          02 DIRCLI PIC X(25).
          02 POBCLI PIC X(25).
          02 POSCLI PIC 9(5).
          02 ALTCLI PIC X(8).
          02 IMPCLI PIC 9(6)V9(2).

Aquí creamos una variable global "CLI" (de cliente). Como se ve, tiene nivel 1 (01, siempre tienen 2 dígitos).
Inmediatamente debajo tenemos varias declaraciones de nivel 2 (02), que corresponden a un código, nombre, dirección, población, código postal, fecha de alta e importe, respectivamente.

Todas estas variables dependen de CLI. Esto significa, que realmente CLI sería (no realmente) algo como

77 CLI PIC X(80)9(5)X(8)9(6)V9(2).

¿Y eso? Pues bien, a la hora de pedir datos a variables (accept, ahora lo vemos), podemos pedir la variable CLI, o, por ejemplo, CODCLI. Tenemos que tener cuidado con eso.

Un par de apuntes más:

Las variables de nivel 77 son siempre independientes. No pueden tener "hijos" ni formar parte de un nivel superior.



Los niveles se pueden otorgar arbitrariamente, siempre que se incremente el nivel en los hijos. Dejo un ejemplo de cómo se hace mal y cómo se hace bien:

 05 CLI.
    06 CODCLI PIC XXXXX.
    06 POSCLI.
         10 PRO PIC 99.
         10 RES PIC 999.
    06 NOMCLI.

Esto estaría bien, pero lo siguiente NO


 05 CLI.
    06 CODCLI PIC XXXXX.
    06 POSCLI.
         77 PRO PIC 99.
         77 RES PIC 999.
    06 NOMCLI.

ya que tiene una variable de nivel 77.


Siguiendo con PIC y las variables, hay ciertos valores preestablecidos que se pueden usar como constantes. Estos son, entre otros:

 - ZERO (también ZEROES, ZEROS): Rellena todo con 0, útil para iniciar numéricos
 - SPACE (también SPACES): Rellena todo con espacio (' '), útil para iniciar alfanuméricos
 - QUOTE (también QUOTES): Representa el caracter ', es como el \' de php o c.
 - ALL "texto": Rellena con el valor establecido (por ejemplo ALL "_" crearía un efecto línea)
 - HIGH-VALUE: inserta el valor más grande
 - LOW-VALUE: inserta el valor más pequeño.

Nótese que estas expresiones van sin encomillar.

Para usar estas expresiones, así como otras, podemos mover el valor en la PROCEDURE, o "settear" el valor de la variable a la par que la creamos.

Para settear variables, se añade la cláusula "VALUE" en la declaración, es decir, algo así:

77 SALUDO PIC X(4) VALUE 'HOLA'.
01 YO.
   02 FNAM PIC X(25) VALUE 'DAVID'.
   02 LNAM PIC X(25) VALUE 'SOLÉ'.
77 HR PIC X(80) VALUE SPACES.


Por otra parte, para mover valores en la PROCEDURE, se usa la instrucción MOVE.

MOVE ALL '_' TO HR.

Rellenaría la variable HR con 80 "_" (como un <hr> en HTML, por ejemplo).



Display


Esta instrucción se usa para mostrar cosas por pantalla.

¿Cosas? Si. Desde pantallas hasta registros completos. Por ahora lo dejamos ahí, y mostraré el funcionamiento básico de cómo usar DISPLAY:

DISPLAY SALUDO.
DISPLAY HR.
DISPLAY YO.

La instrucción DISPLAY tiene varias opciones, a saber:

- NO ADVANCING: evita un retorno de carro tras el display.
- LINE: en qué línea se mostrará
- POSITION: en qué columna se mostrará
- BEEP: emite un pitido tras el display
- ERASE (ERASE EOS, ERASE EOL): sirve para borrar zonas: ERASE borra toda la pantalla, ERASE EOS borra desde la posición del cursor hasta el final; ERASE EOL borra la línea en la que está el cursor.

Como se ve, se puede hacer un "print" indicando fila y columna... esto es realmente útil para las pantallas (ya lo veremos).

Accept

Sirve para recoger datos (de pantalla o no). Se suele usar así:

ACCEPT SALUDO.
ACCEPT LNAME.

También tiene opciones, las cuales son:

 - LINE, POSITION, NO BEEP, ERASE

Que hacen lo mismo que en DISPLAY.


Os dejo un pequeño ejemplo de display y accept:


77 SALUDO PIC X(4) VALUE 'HOLA'.
01 YO.
   02 FNAM PIC X(25) VALUE 'DAVID'.
   02 LNAM PIC X(25) VALUE 'SOLÉ'.
77 HR PIC X(80) VALUE SPACES.
01 DT PIC
     02 ANIO PIC X(2).
     02 MES PIC X(2).
     02 DIA PICX(2).

DISPLAY SALUDO LINE 3 POSITION 5.
DISPLAY 'COMO TE LLAMAS?' LINE 5 POSITION 5.
ACCEPT FNAM LINE 5 POSITION 22.
DISPLAY 'BIENVENIDO' FNAM ERASE LINE 3 POSITION 5.
ACCEPT DT FROM DATE.
DISPLAY 'HOY ES ' DIA ' DE ' MES ' DE '  ANIO LINE 5 POSITION 5.

Espero que podáis comprenderlo mejor con este pequeño ejemplo. Destacar que la sentencia "ACCEPT VAR FROM DATE/TIME" se usar para insertar la fecha (formato AAMMDD) o la hora (formato HHMMSSCC) en la variable.

En la siguiente entrega mejoraremos la presentación de este ejemplo, con pantallas.

Hasta la próxima!


¿Te han resultado útiles mis conocimientos de COBOL?
¡Llévatelos donde quieras!



COBOL: primeros pasos


Hola de nuevo,
Como comenté en entradas anteriores, voy a dar un pequeño paseo por el mundo Cobol. El hecho de que sea en Cobol es porque, ya que poseo el título de "Técnico Superior en Desarrollo de Aplicaciones Informáticas y Experto en COBOL", me gustaría transmitiros un poco de mi conocimiento en este buen lenguaje de programación.

Como las entradas anteriores, voy a dividir cada punto del curso en una entrada, para que sea más legible.

Sin más, empecemos

 - Primeros pasos
   * Algo de historia
   * ¿Por qué COBOL?
   * Aspectos a tener en cuenta
   * Visión global
      · Division
      · Section
      · Párrafo
      · Línea
      · Plantilla básica

Algo de historia:

COBOL fue un lenguaje de programación creado por "CODASYL", una comisión de varias entidades, entre la cual se encontraba el Departamento de Defensa de los Estados Unidos.
Vio la luz en el año 59, y ha sido sometido a diversas remodelaciones y adaptaciones. Actualmente hay versiones que incluyen soporte para "emular" OOP (programación orientada a objetos), incluso aspectos visuales. Se puede incluso programar webs con cobol.

Como anotación, decir que los conocimientos que tengo son de RM/COBOL-85. Éste fue el penúltimo estándar, aunque en el nuevo estándar (ANSI-COBOL) añadieron funciones matemáticas, por lo que con el 85 en realidad basta, ya que estas funciones matemáticas son relativamente avanzadas, y las podemos crear con código.

No me gusta aburrir mucho con la historia, así que este punto lo doy por zanjado con la siguiente conclusión: no se puede decir que COBOL es un lenguaje en desuso, y mucho menos que no es actual; ya que continuamente evoluciona. Es por eso que la historia de cobol todavía no está terminada.

¿Por qué COBOL?

Sencillo. Para explicar esto a grandes rasgos, usaré un fragmento de la wikipedia:

"Pese a que muchas personas creen que el lenguaje COBOL está en desuso, la realidad es que casi todos los sistemas que requieren gran capacidad de procesamiento por lotes (Batch), tanto las entidades bancarias como otras grandes empresas con sistemas mainframes utilizan COBOL. Esto permite garantizar la compatibilidad de los sistemas antiguos con los más modernos, así como tener la seguridad de que el lenguaje es perfectamente estable y probado. Según un informe de Gartner Group de 2005, el 75% de los datos generados por negocios son procesados por programas creados en COBOL, y en otro informe de 1997 estima que el 80% de los 300.000 millones de líneas de código existentes están creados en COBOL, escribiéndose 5.000 millones de líneas nuevas de COBOL cada año. Con todo eso, hoy por hoy, la programación en COBOL es uno de los negocios más rentables del mundo de la informática. En el resto de aplicaciones el COBOL ha caído en desuso, reemplazado por lenguajes más modernos o versátiles.

Pero no todo es así. Hoy (2012) siguen existiendo decenas de miles de usuarios Cobol e instituciones que siguen instruyendo este lenguaje dados los números informados. Cobol sigue estando soportado y sigue evolucionando permanentemente; esto principalmente por la cantidad de aplicaciones que hoy sigue funcionando y que superan en número a los demás lenguajes gracias a tanta difusión en el pasado. Esto sigue propiciando su continua evolución y, palabras del propio Bill Gates: "No sé qué lenguajes habrá en el futuro, pero seguro que Cobol estará todavía allí".

Si lo leéis completo, veréis que al año, 5.000 millones (sí, sí, 5.000.000.000, 5*10^9) de líneas se escriben cada año.


Otra razón es el conocimiento que tengo de este lenguaje. No todo el mundo sabe cobol, y me parecería algo egoísta no pasar mis conocimientos... es difícil encontrar alguien dispuesto a eso, a pasar conocimiento gratuito...


Más razones: velocidad de procesamiento, compatibilidad con casi cualquier sistema, curiosidad, gran capacidad de gestión de ficheros...

Aspectos a tener en cuenta:

Lo dicho anteriormente, uso estándar rm/cobol-85, y un consejo que quiero que os grabéis a fuego, si de verdad vais a seguir el cursillo.

COBOL está diseñado para trabajar sobre tarjetas perforadas, y esto da ciertas restricciones a la hora de programar:

  - Toda línea que no sea comentario debe empezar, por norma general, en el octavo espacio. Es decir, cada línea nueva, tendréis que pulsar siete espacios antes de escribir nada.
Luego veremos que hay más, entrando en la A-Zone y B-Zone.

 - Toda línea no puede pasar los 80 caracteres de ancho. Esto incluye ancho de variables (es decir, por ejemplo, una cadena de texto de más de 80 caracteres.

 - Se ha de tener siempre en cuenta las zonas de código.

 - El fin de sentencia no es el habitual (";"), sino el punto (".").

 - El sistema de codificación, al tratarse de un lenguaje tan viejo, cambia radicalmente.

Visión global:

Al igual que cualquier lenguaje (de programación o no), cobol se divide en vario elementos, de manera que los elementos grandes contienen los pequeños, y diversos pequeños pueden formar uno grande.

      · Division
      · Section
      · Párrafo
      · Línea
      · Plantilla básica

Division:

Una division (es inglés, por aquello del acento...) está formado por un conjunto de instrucciones, que empieza por una declaración.

En COBOL hay 4 division:

IDENTIFICATION DIVISION
ENVIRONMENT DIVISION
DATA DIVISION
PROCEDURE DIVISION

La primera se encarga de la identificación del programa (una de las instrucciones sirve para crear un nombre interno para cobol). También se puede añadir algún otro tipo de información, como algún comentario de documentación. La única instrucción obligatoria que requiere es la primera (la de identificación

La environment division trata los datos relacionados con el programa: I/O, tipo de caracteres... en esta sección podemos decirle qué tipo de caracteres usaremos, y especificar los archivos a los que accederá. Normalmente esta sección estará vacía, menos cuando accedamos a archivos.

La data division se usa para declarar variables y constantes. COBOL no trabaja con variables locales, solo con globales. Sin embargo esto se puede "apañar" con el flujo externo. En esta division estarán todas las variables y constantes que vayamos a usar en nuestro programa.

Finalmente, la procedure division es aquella en la que va el código puro.

Section:

Una section (sección, en castellano) es una parte de una division.
Una division puede no tener sections, o puede tener varias; de manera opuesta, una section no puede existir si no es dentro de una division.

Las section agrupan los datos de las division en grupos más concretos, como la SCREEN SECTION dentro de DATA DIVISON.

Párrafo:

Un párrafo es un grupo de instrucciones, siempre dentro de la PROCEDURE DIVISION, que se diferencia del resto de párrafos por un identificador.

Es posible (aunque no recomendable) crear una procedure sin párrafos, pero un párrafo siempre estará dentro de la procedure.

Usar párrafos sirve como método de estructuración. Llamar a un párrafo es como llamar a una función.

Línea:

Una línea es un conjunto de palabras finalizadas por punto. Todo está formado por líneas. Sin líneas no hay ni párrafo, ni section, ni division.

Las líneas están en todos los ámbitos.

Plantilla básica:

Como plantilla básica, entendiendo por ello una plantilla de texto que sirva para crear un programa básico (sin ficheros, ni flujo externo, ni pantallas) puede ser algo así:



       IDENTIFICATION DIVISION.
       PROGRAM-ID. ID.
       REMARKS. Comentarios varios.

       ENVIRONMENT DIVISION.
     
       DATA DIVISION.
       WORKING-STORAGE SECTION.
      *   Varialbes y constantes...

       PROCEDURE DIVISION .
      *    Sentencias...
           EXIT PROGRAM.

Revisemos rápidamente, por líneas:

1. Declara la IDENTIFICATION DIVISION
2. Creamos un id. el "ID" lo cambiamos por el que queramos (sin pasar de 8 caracteres)
3. Podemos añadir, opcionalmente, algún comentario. Esta línea es omisible.
4. Declaramos una ENVIRONMENT vacía.
5. Declaramos la DATA.
6. Iniciamos la WSS (Working-storage Section), donde van los datos dedicados a memoria
7. Declaramos la PROCEDURE
8. Salimos del programa

Finalmente, comentar que el EXIT PROGRAM hace que salga por completo del programa. Cuando veamos el flujo externo veremos otras sentencias que son diferentes. También remarcar el tema de los espacios: 7 par una línea, 6 y "*" para un comentario.

Los comentarios son todos de línea entera.

Añadir que he marcado los tokens (palabras reservadas) en negrita.

Por ahora, este es el fin de la primera parte del curso.

Hasta la próxima!


¿Te han resultado útiles mis conocimientos de COBOL?
¡Llévatelos donde quieras!





Mini - Curso: COBOL

Ayer fue la última entrada acerca del tema de la pseudo-capa. Quedo abierto a mejoras, dudas, sugerencias...

En las siguientes entradas voy a tratar de hacer un pequeño "curso" de COBOL.

Lo haré partiendo de la base que aquellos que leen estas entradas conocen, por lo menos, como funciona un IF y un FOR, por lo menos (ya que no explicaré cómo funcionan este tipo de sentencias, a no ser que alguien lo pida).

Dejo un pequeño índice:

 - Primeros pasos
   * Algo de historia
   * ¿Por qué COBOL?
   * Aspectos a tener en cuenta
   * Visión global
      · Division
      · Section
      · Párrafo
      · Línea
      · Plantilla básica

 - Lo básico de COBOL
    * PIC
    * Display
    * Accept

 - Pantallas

 - Flujo en COBOL
   * IF
   * PERFORM
   * GO TO
   * Salir y continuar

 - Flujo externo
 - Ficheros
    * Tipos
    * Declarar
    * Usar

 - Ejemplo completo

En la próxima entrega empezaré con el primer punto.

Por ahora, y para abrir boca, comentar que COBOL, por muy obsoleto que parezca, es uno de los lenguajes de programación más antiguos que se mantienen. Según la wiki, el 80% del código fuente mundial es COBOL...

Si estáis acostumbrados a hacer proyectos en los que os exigen una codificación óptima para obtener un resultado lo más rápido con un mínimo de consumo, os dejo una anotación: en una tarea tan simple como contar del 0 al 99999 (esto es, 1.000.000 de números), poniendo un número en cada fila, COBOL tarda aproximadamente 7 veces menos en hacerlo que C.

Por último, decir que COBOL tiene una sentencia para ejecutar archivos externos (es decir, un .bat, o incluso un comando de consola). Si reflexionáis sobre esta última frase, y lo ligáis a la velocidad que tiene, podréis encontrar una gran utilidad al anterior proyecto que comenté (el bridge). Si bien COBOL, con su sistema de fichero, podría emular perfectamente una base de datos, no se encuentran muchos sistemas que funcionen con sistemas de ficheros, por lo que conectar a una base de datos desde un JAR externo suena bien, ¿no?

Hasta la próxima!


¿Te han resultado útiles mis conocimientos de COBOL?
¡Llévatelos donde quieras!



La pseudo-capa: conectar todo

Esta será la útlima entrada de la creación de nuestro bridge aplicación - base de datos.

Ahora explicaré de que sirve tener las cosas como lo he ido explicando. Para este caso lo haré únicamente con JAVA (ya que es el código más portable).

Conectar todo

Imaginad que, como me pasó a mí, tenéis que crear una aplicación que conecte VB.NET con MySQL.
Para hacer esto hay un método; se descarga un paquete, se instala, se referencia en el proyecto... ¿Pero a la hora de hacer un instalador? Pues ahí surgen las dudas...

Pero, si tenéis una clase que conecta con mysql, recupera datos, los mete en objetos, y más cosas (como crear un XML, escapar las consultas, recuperar id...), ¿para qué hace falta ese plug-in?

Tan sencillo como modificar ligeramente nuestro código java para que recupere los parámetros por línea de comando, creamos un jar (si queréis) y lo metemos en una ruta fija. Luego desde VB.NET hacemos una llamada a la línea de comandos y voliá.

Yo esto lo hago bastante con un sistema de intercambio de ficheros; mi JAR acepta los parámetros de entrada para la query (id, datos, ...), y también una ruta.

Desde VB creo un fichero temporal con la siguiente sentencia:

Dim temp As String = My.Computer.FileSystem.GetTempFileName.ToString

Con esta variable, llamo a la consola, así (esto es solo un ejemplo):

Shell("java -jar " + GlobalsVar.IDAPath + " 0 " + temp + " 0", AppWinStyle.Hide, True)

Esto inicia una shell y le pasaría la siguiente cadena:

java -jar *direccion/Bridge.jar* 0 *temp* 0

Lo que incluyo entre ** son variables. En este caso mi JAR recibe tres parámetros: 0, fichero, 0. Esto le indica que tiene que hacer cierto select, y plasmar el resultado en XML en el fichero pasado.

Finalmente, desde VB leo el XML y hago con él lo que necesite.

Es una forma rápida de conectar varias cosas a la vez.

Otra utilidad que tiene es la de kernel. Para hacer algo así solo tenemos que definir todas las querys, hacer varios métodos (parse a XML, rellenar selecciones, hacer updates, deletes, enviar correos...), los que hagan falta para que sea algo completo; una vez está el proyecto java, lo conectamos a cualquier aplicación que hagamos, así solo tenemos que preocuparnos del front-end.

Espero que os haya gustado

Hasta la próxima!

La pseudo-capa: abstracción

Buenas de nuevo!

En esta entrega veremos cómo sacarle algo más de partido a nuestras funciones.
En este caso, intentaré no hacer dos versiones, sino hacer una especie de "pseudocódigo" que pueda ser entendido y extrapolado al lenguaje de programación que uséis.

- Abstracción de conceptos
    · Clases auxiliares
    · Tablas auxiliares

Clases auxiliares:

Clase auxiliar, para mí, es toda aquella que apoya el desarrollo de un proyecto, pero es "secundaria"; es decir, podríamos prescindir de ella.

Un ejemplo sería una clase que solo tuviera variables globales, cadenas de formato, métodos para formatear, sacar diferencias (por ejemplo añadir un porcentaje - IVA - a una cantidad)... todos estos métodos se podrían incluir en diversas clases que lo necesitaran, pero los metemos en un utilitario para no replicar código. Ésta se convierte en una clase auxiliar.

Así, para el IDA, podemos crear la clase auxiliar esbozada en la entrega anterior.
Pero, aparte, podemos hacer una serie de métodos que agilicen el proceso de montar listas de objetos, las selecciones...

Para ello hay varias cosas que podríamos hacer. Es obvio que esto son solo algunas de las cosas que se podrían hacer, y siempre aceptaré nuevos aportes.

 - Lista de select:

 Se puede crear una lista de selects, updates... (de SQL me refiero) y usar un índice único para invocarlos.

Un ejemplo:

SelectList = array("select * from personas", "update personas set telefono = 0")

Entonces solo tendríamos que llamar a SelectList[0] para usar la primera selección.

No obstante, como habréis visto, cosas tan generales (como hacer un set a todos los registros de personas) pueden no servir. Para arreglar esto, se pueden hacer varias cosas:

   * Sublistas de select:

Se puede hacer algo similar a ésto:

Select1 = array("select nombre, telf from personas where nombre like('", "');
Select2 = array("update personas set telefono=", " where id=");
SelectList = array(Select1, Select2);

function getSelect(int id, array values){
  String ret = "";
  Array aux = SelectList[id]
  for(i=0;i<length(aux);i++)
     ret = concat(aux[i], values[i]);

 return ret;
}

Como veis, haciendo una lista de listas se pueden intercalar valores. Esto produciría sentencias personalizadas, lo que es más útil. AVISO que esta función es un prototipo. Al copiar esta función es posible que tengáis que retocar algo (añadir un if, quitar algo innecesario...). Esto está hecho de manera rápida y en una sintaxis propia más del pseudocódigo.

Retomando el ejemplo de objetos de la anterior entrada

/*
$bridge = new MyBridge(); //suponiendo que la clase la llaméis así
$array = $bridge->execute("select curdate() from dual");
$bridge->disconnect();
*/

y, si este método lo metemos en nuestra clase Utilities, podríamos modificar lo anterior, y hacer:

bridge = new MyBridge(); //para lanzar SQL
array = bridge.execute(Utilities.getSelect(0, {{David}}); //hacemos un select, los {{ }} indican un inicio y //fin de "array rápido"
bridge.disconnect();

No obstante, tendríamos que tener una lista de objetos e ir iterando sobre "array" para crear objetos...

- Generador de objetos

Esta parte es posible que no funcione con ciertos lenguajes de programación, aunque siempre se puede hacer algo parecido (desde luego, en php, que es donde más se usa la base de datos funciona).

Supongamos que tenemos el siguiente objeto

Class Persona{
  private String nombre;
  private String apellido;
  private String telf;
  private int id;
}

podemos añadir un método, al que podemos llamar "setVal", que sea así:

function setVal(Array values){
 vars = array(&this.nombre, &this.apellido, &this.telf, &this.id);

  for(i=0;i<length(vars);i++)
  vars[i] = value[$i];
}

y voliá, como pasamos la dirección de memoria (puntero) de los atributos de la clase (por eso el &), se modifican los valores de la propia clase, desde cualquier sitio.

Por tanto, podríamos hacer, siguiendo con el ejemplo anterior:

for(i=0;i<length(array);i++){
 per = new Persona();
 per.setVal({{array.next()}}); //en php se tendría que hacer un mysql_fetch_array y arreglarlo un poco
 objArray.add(per);
}

¡Pero vayámos un poco más allá!

- Generador de array dinámico

Podemos crear en Utilities una función así:

/*
params:

[0] ->id sql
[1] ->parámetros para el id
[2] ->tipo de objeto
[3] -> patrón de llenado
*/
fill(Array params){
  Object o = new Object();
  Array ret = new Array();
  bridge = new MyBridge(); 
  array = bridge.execute(this.getSelect(params[0], params[1]);
  bridge.disconnect();

  if(params[2] == 1){
     o = new Persona();
  }

  for(i=0;i<length(array);i++){
  aux = array(); 
    for(j=0;j<strlen(params[3];j++){
       val = "";

       if(substr(params[3], i, 1) == 1)
         val = array[j];

       aux.add(val);
    }

  o.setVal(aux);
  ret.add(o)
 } 

 return ret;
}

Bien, parece confuso, pero veamos un ejemplo:

objArray = Utilities.fill({{0, {{David}}, 1, 1010}});

Esto llenaría con una lista de personas (porque le paso un 1), y solamente nombre y telf (1010), con el select 0.

Como digo, puede parecer confuso. Es cuestión de mirar bien el código, adaptarlo a vuestro lenguaje favorito (recomiendo php en este caso) e ir probando.

Creo que sacar un array con una sola función es algo que puede servir...

Tablas auxiliares:

Para no cargar las clases con un montón de arrays, se pueden crear una serie de tablas en nuestra base de datos (incluso en una aparte), y que contenga las listas de sentencias, agrupadas por un id, por ejemplo.

Solo sería cosa de modificar la función getSelect para que conectase con la tabla y recuperase los fragmentos, el resto sería todo igual.

De momento termino esta entrega aquí.

Es posible que la próxima sea una continuación de ésta, ya veré...

Hasta la próxima!

La pseudo-capa: generalizando


Hola de nuevo,

Vamos a empezar una nueva entrega de cómo crear esta pseudo-capa con la que llevo dando la brasa desde el primer día.

En la entrada anterior vimos cómo se conecta, pide y recogen datos tanto desde java como desde php a una base de datos mysql.

En esta entrada, os voy a comentar un poco en detalle la generalización de los coneceptos vistos anteriormente. Esto es para poder desarrollar con más rapidez, ya que tener que ir poniendo todo el código cada vez resultaría engorroso.

Parto de la base de que todo aquel que lee esto sabe lo que es una función y cómo funcionan.

Sin más, empecemos el siguiente punto!


- Generalizar: funciones y objetos
   · Crear las funciones
   · Crear los objetos


Crear las funciones

Con php

$con = null;
$connection = null;
$H = "localhost";
$U = "user"; //el que tengáis vosotros
$P = "pass"; //el password
$D = "database"; //la base de datos
$started = false;

function execute($sql){
 if(!$started){
  return null;
 }

 return mysql_query($sql) or die($sql."<br />
".mysql_error());
}

function getId(){
 if(!$started){
  return null;
 }

 return mysql_insert_id($con);
}

function getRowNum(){
 if(!$started){
  return null;
 }

 return mysql_affected_rows($this-&gt;con);
}

function connect($host, $usr, $pass){
 if(!$started){
  return $conection = mysql_connect($host, $usr, $pass);
 }else{
    return $con;
 }
}

function setdb($name, $database){
 return mysql_select_db($name, $database);
}

function free($launched){
 if($started){
  mysql_free_result($launched);
 }
}

function disconnect(){
 if($started){
  mysql_close($con);
   $started = false;
 }
}

function start(){
 if(!$started){
  $con = $connect($H, $U, $P);
  $connection = $setdb($D, $con);
  $started = true;
 }
}

Como veis, he declarado varias variables, que uso en las funciones. Además he añadido algunas funcinoes que pueden ser útiles. A continuación explico todas:

 - execute: ejecuta una sentencia sql (de cualquier tipo)
 - getId: retorna el último id insertado
 - getRowNum: retorna el número de filas afectadas por la última sentencia
 - connect: conecta a la base de datos
 - setdb: establece una base de datos. Es llamada desde connect
 - free: libera los recursos usados por la última sentencia
 - disconnect: desconecta de la base de datos
 - start: conecta a una base de datos dada.

Seguramente hayáis visto que no tienen mucha conexión entre sí. Esto es porque estas funciones están diseñadas para estar dentro de un mismo objeto.

Yo he quitado el tema de encapsulamiento (private, public...) así como constructores y demás. En la siguiente sección (objetos) veremos qué hacemos con esto.

Como último apunte, fijaros que he añadido algo de control con la variable "started", para evitar que se haga una conexión dos veces.

Con java


Connection connect(){
 Connection con = null;

 try{
         Class.forName("com.mysql.jdbc.Driver");

  con = DriverManager.getConnection("jdbc:mysql://localhost/db", "user", "pass");
 }catch (ClassNotFoundException e){
  //ToDo
 }catch (SQLException e){
  //ToDo
 }

 return con;
}

ResultSet ask(String     sql,
           Connection con){
 ResultSet rs = null;

 try{
  rs = con.createStatement().executeQuery(sql);
 }catch (SQLException e){
  //ToDo
 }

 return rs;
}


void execute (String     sql,
            Connection con){
 try{
  con.createStatement().executeUpdate(sql);
 }catch (SQLException e){
  //ToDo
 }
}



Crear los objetos

Como había escrito antes, las funciones precedentes iban a ser parte de un objeto. Para aquellos que no estén familiarizados con las clases, decir que se tienen que crear en un fichero aparte.

La estructura básica es:

Class clase{
  atributo1;
  atributo2:

  funcion1(){}
  funcion2(){}
}

Con php

Solo tenemos que crear la clase, un constructor que llame a start, y encapsular las funciones y atributos. Mis recomendaciones son:

 - Declarar $con como public, y el resto de atributos como private
 - Declarar connect y setdb como private, el resto public

¿Y cómo usaríamos la clase? Así:

$bridge = new MyBridge(); //suponiendo que la clase la llaméis así
$array = $bridge-&gt;execute("select curdate() from dual");
$bridge-&gt;disconnect();

Como se ve, se elimina bastante código, ya que en 3 líneas se hace prácticamente todo.

Con java

Connection con = null;
ResultSet  rs  = null;
String     sql = "select curdate() from dual";

try{
 con = this.connect();
 rs  = this.ask(sql, con);
 
 try{
  while(rs.next())
   //ToDo
         }catch (SQLException e){
              //ToDo
         }
}catch (ParseErrorException e){
     //ToDo
}


Aquí el código también se ve más limpio y el desarrollo se puede hacer más rápido.

En la siguiente entrada entraré más en detalle en la creación de clases y tablas auxiliares para generalizar todo el código y hacer que la programación sea más fácil.

Hasta la próxima!

la pseudo-capa: primeros pasos


Aquí estoy de nuevo,

Voy a empezar con el bridge, tal como escribí en la anterior entrada.
Pero antes me gustaría hacer un poco de presentación.

Soy David, actualmente vivo en Cataluña. Soy técnico superior en desarrollo de aplicaciones informáticas; también poseo un título de técnico experto en COBOL. Actualmente estoy en proceso de obtener una certificación ISPA (Informatino Security Profesional Acreditation). En cuanto termine la acreditación (o incluso antes) empezaré un bachelor. Mi idea es terminarlo (son tres años), hacer un curso puente para conseguir el título de grado en ingeniería informática (esto es opcional), luego algún master(preferiblemente en IA), y finalmente doctorarme.

Se que es mucho suponer que todo saldrá así, pero bueno.

Empecemos con el bridge!

- Primeros pasos
   · Conectando una aplicación a mySql
     * php -> mySql
     * java -> mySql
   · Lanzar peticiones a mySql
   · Recuperar los datos

Conectarse a mySql

Lo primero es conectarse a mySql. Lo veremos desde dos lenguajes diferentes: php y java. Esta norma se aplicará a casi toda la construcción del puente.

Desde php:

$connection = mysql_select_db(nuestra_database, ($con = mysql_connect("localhost", user, pass)));

Una aclaración: normalmente siempre trabajamos en local, por eso conectamos en "localhost".

Desde java:

Para conectar desde java, primero tenemos que tener el driver de conexión (en la página de mysql está para bajar gratis).

Una vez bajado, añadimos una referencia a nuestro proyecto, e incluímos "import java.sql.*;" en la sección de imports de nuestra clase.

Para conectar, podemos hacer lo siguiente:


Connection con = null;

try{
Class.forName("com.mysql.jdbc.Driver");

con = DriverManager.getConnection("jdbc:mysql://localhost/database", user, pass);
}catch (ClassNotFoundException e){
//ToDo
}catch (SQLException e){
//ToDo
}

Lanzar peticiones

Con esto me refiero a ejecutar sentencias SQL, tanto select, como update, delete...

Lo primero, decir que las peticiones, dentro de php y java, se dividen en dos grupos: los SELECT, y el resto. Esto es debido a que el SELECT retorna algo, y el resto no (aunque luego se pueden recuperar datos de ellos, como el número de filas afectadas).

Desde php

$result = mysql_query(sentencia);

$result se pondría solo para los select. Para limpiar los resultados, tendríamos que ejecutar:

mysql_free_result($result);

Desde java


ResultSet rs = null;

try {
rs = con.createStatement().executeQuery(sql);
} catch (SQLException e) {
//ToDo
}

Para los select, y para el resto:


try{
con.createStatement().executeUpdate(sql);
}catch (SQLException e){
//ToDo
}

Recuperar datos

Los datos quedan recuperados, en el Select, en sendas variables "$result" y "rs".

Sin embargo, para accesar los datos tenemos que emplear métodos nativos de php y java:

Para este punto necesitamos una serie de datos concretos.

  - Sentencia ejecutada: "select nombre, apellido, telf from usuarios";
  - Estructura de datos:
      * nombre: varchar(100)
      * apellido: varchar(100)
      * telf: int(9)

Desde php

$nom = "";
$ape = "";
$tel = 0;

while($row = mysql_fetch_array($res)){
   $nom = $row[0];
   $ape = $row['apellido'];
   $tel = $row[2];
}

Como se ve, se puede acceder por índice (empezando de 0), o por el nombre del campo. Esto último, cabe remarcar que si, por ejemplo, escribirmos "select nombre, concat(apellido, ' ' coalesce(telf, 'no tiene')) from usuarios", el equvalente a "$row[1]" sería "$row['concat(apellido, ' ' coalesce(telf, 'no tiene'))']".

Desde java



try {
while(rs.next()){
            String name = new String(rs.getString(1));
            String sName = (String)rs.getObject(2);
            int telf = rs.getInt(3);
        }
}catch (SQLException e){
//ToDo
}

Como se ve, aquí se accede por índice, y mediante métodos varios: los getXXX. Si no sabemos exactamente qué recuperamos, podemos hacer un getObject, y luego hacer un cast. En caso de saberlo, podemos hacer un getString, o getInt, o getDate...

Remarcar que el índice de acceso empieza por 1, no por 0.


Aquí termina la primera parte, quizás la más corta. En la siguiente entrada trataremos las funciones y objetos.

Hasta la próxima!