Iniciacion a la programacion ADA





Uno de los aspectos más importantes en la programación es el reuso de partes de  programas existentes para que el esfuerzo de generar nuevo código sea mínimo. Así el concepto de biblioteca de programas emerge en forma natural y un aspecto importante de un lenguaje de programación es su habilidad para expresar el cómo rehusar ítems de una biblioteca.

Ada reconoce esta necesidad e introduce el concepto de unidades de biblioteca (library units). Un programa Ada completo es concebido como un programa principal (en sí mismo una unidad de biblioteca) que solicita los servicios de otras unidades.

Supongamos que queremos escribir un programa que imprime la raíz cuadrada de un cierto número, por ejemplo, 2.5. Podría esperarse que estén disponibles bibliotecas que nos provean servicios para calcular raíces cuadradas y entregar datos. De este modo, nuestro trabajo se reduciría a escribir un programa principal que haga uso de estos servicios en el modo que deseemos.

Supondremos que en nuestra biblioteca existe una función de nombre SQRT que permite calcular raíces cuadradas, y que, además, nuestra biblioteca cuenta con un paquete (package) llamado SIMPLE_IO que contiene servicios simples de entrada-salida (lectura y escritura de números, escrituras de cadenas de caracteres, etc.). Nuestro programa sería:

with SQRT, SIMPLE_IO;

procedure PRINT_ROOT is use SIMPE_IO;

begin

PUT(SQRT(2.5));

end PRINT_ROOT;

El programa está escrito como un procedimiento llamado PRINT_ROOT precedido por una cláusula with donde se dan los nombre de las unidades de biblioteca que se desea usar. El cuerpo del procedimiento contiene una única instrucción:

PUT(SQRT(2.5));

Al escribir

use SIMPLE_IO;

se obtiene acceso inmediato a los servicios del paquete SIMPLE_IO. Si se hubiese omitido la cláusula use

hubiese sido necesario usar la “notación punto”.

SIMPLE_IO.PUT(SQRT(2.5));

para indicar dónde debe buscarse el procedimiento PUT.

Podemos hacer nuestro programa más útil haciendo que lea el número cuya raíz cuadrada se desea obtener.  El programa quedaría:

with SQRT, SIMPLE_IO;

procedure PRINT_ROOT is use SIMPE_IO;

X : FLOAT;

begin

GET(X); PUT(SQRT(X));

end PRINT_ROOT;

La estructura general del procedimiento es clara: entre is y begin podemos escribir declaraciones, y entre begin y end escribimos instrucciones (operaciones). En términos generales podemos decir que las declaraciones presentan las entidades que queremos manipular y las instrucciones indican la secuencia de acciones a realizar.

Notemos algunos detalles:

  1. Todas las declaraciones e instrucciones terminan con un punto y coma a diferencia de otros lenguajes como Algol y Pascal  donde los punto y coma son utilizados como separadores en lugar de terminadores.
  2. El programa contiene varios identificadores tales como procedure , PUT y X. Los identificadores se dividen en dos grandes grupos. Unos pocos (63 en Ada 83) como procedure e is , que son utilizados para indicar la estructura del programa; son palabras reservadas y no pueden ser usados para otros propósitos. Los otros tales como PUT y X pueden ser usados para cualquier propósito que se desee. Algunos de ellos (en nuestro ejemplo FLOAT) tienen un significado predefinido, pero podrían ser usados para otros propósitos, aunque se corre el riesgo de confusión en el código.

 

Finalmente observemos que el nombre del procedimiento, PRINT_ROOT, se repite entre el end final y el punto y coma. Esto es opcional, pero se recomienda para aclarar la estructura general, el cual es obvio en un ejemplo tan pequeño.

Nuestro ejemplo es demasiado simple, sería más útil si se lee una serie de números y se imprime cada respuesta en una línea separada. Arbitrariamente definiremos que el proceso terminará al ingresarse un valor igual a cero.

 

with SQRT, SIMPLE_IO;

procedure PRINT_ROOTS is use SIMPLE_IO;

X : FLOAT;

begin

PUT(“Roots of various numbers”); NEW_LINE(2);

loop

GET(X);

exit when X = 0.0; PUT(“Root of”); PUT(X); PUT(“is”);

if X < 0.0 then

PUT(“not calculable”);

 

else

end if;

 

PUT(SQRT(X));

 

NEW_LINE;

end loop; NEW_LINE;

PUT(“Program finished”); NEW_LINE;

end PRINT_ROOTS;

 

La salida del programa ha sido mejorada mediante la llamada a los procedimientos NEW_LINE y PUT incluidos en el paquete SIMPLE_IO. El parámetro numérico entero del procedimiento NEW_LINE indica cuantas líneas se deberá escribir, si no se entrega el parámetro se asume un valor igual a 1 (uno). También hay una llamada a PUT con una cadena como argumento. Este es de hecho un procedimiento diferente al que escribe el número X. El compilador diferencia cual corresponde en cada caso de acuerdo al tipo (y/o cantidad) de parámetros utilizado.





En Ada se debe observar reglas estrictas para cerrar estructuras; loop es cerrado con end loop e if con enf if. Todas las estructuras de control de Ada tienen sus cierres en lugar de la forma abierta de Pascal que puede conducir a errores.

Veamos ahora la posible estructura de la función SQRT y el paquete SIMPLE_IO que en nuestro
ejemplo se han supuesto como existentes.

La función SQRT tendrá una estructura similar a nuestro programa, la mayor diferencia radica en la existencia de parámetros.

 

function SQRT (F:FLOAT) return FLOAT is

R: FLOAT;

 

begin

 

— calcular la raíz cuadrada de F y guardarla en R

return R;

 

end SQRT;

E

l paquete SIMPLE_IO consta de dos partes, la especificación que describe su interfaz con el mundo externo (es decir, las otras unidades de biblioteca que hacen uso de el paquete) y el cuerpo (body) que contiene los detalles de cómo han sido implementados los componentes del paquete. Si el paquete contiene sólo los procedimientos que hemos usado en nuestro ejemplo, su especificación sería:

 

package SIMPLE_IO is

procedure GET(F: out FLOAT); procedure PUT(F: in FLOAT); procedure PUT(S: in STRING);

procedure NEW_LINE(N: in INTEGER:=1);

end SIMPLE_IO;

 

El parámetro de GET es un parámetro out (salida) puesto que el efecto de llamar a este procedimiento en  GET(X) es entregar un valor “desde dentro” del procedimiento por medio del parámetro real X (actual parameter X). Los demás parámetros son in puesto que sirven para ingresar datos a los procedimientos.

Sólo una parte de los procedimientos está presente en la especificación del paquete; esta parte se conoce como la “especificación de los procedimientos” donde sólo se entrega la información que permite llamar a los procedimientos. Es decir, para que nuestro programa PRINT_ROOTS use el procedimiento GET sólo necesita saber el nombre de éste y sus parámetros, los detalles de implementación en esta etapa no importan. Esto significa que para compilar el programa PRINT_ROOTS sólo es necesario que esté presente la declaración del paquete SIMPLE_IO. Lógicamente, para poder ejecutar el programa se necesitará la implementación de todos los procedimientos.

En nuestro ejemplo podemos ver dos especificaciones superpuestas de PUT, una con un parámetro de tipo FLOAT y otro con un parámetro de tipo STRING. Es importante recalcar que estos son dos procedimientos diferentes, el compilador Ada discriminará de acuerdo a los parámetros de cada uno de ellos. Finalmente, notemos  como se asigna un valor por omisión al parámetro del procedimiento NEW_LINE.

El cuerpo del paquete (package body) SIMPLE_IO contendrá la totalidad de los cuerpos de los procedimientos especificados, además de otros elementos (variables, estructuras de datos, otras funciones o procedimientos) que se requieran para su implementación y que quedan de una forma natural escondidas de los usuarios externos. Esto quiere decir que los usuarios del paquete (otras unidades de biblioteca: funciones, procedimientos, paquetes, tareas) sólo “conocen” lo indicado en la especificación del paquete. En términos generales el cuerpo del paquete tendría la siguiente estructura:

 

with INPUT_OUTPUT;

package body SIMPLE_IO is

. . .

procedure GET (F: out FLOAT) is

. . .

end GET;

— otros procedimientos parecidos

end SIMPLE_IO

 

La cláusula with muestra que la implementación (pero, en este caso, no la especificación) de los procedimientos en SIMPLE_IO requiere de un hipotético paquete más general llamado INPUT_OUTPUT. Notemos, además, que en el cuerpo de GET se repite la especificación del procedimiento que fue entregada en la especificación del paquete.

Es importante mencionar el paquete especial STANDARD. Este es un paquete que existe en toda implementación del lenguaje y contiene las declaraciones de todos los identificadores predefinidos tales como FLOAT y NUMERIC_ERROR. Se asume el acceso automático a este paquete y por lo tanto no es necesario dar su nombre en una cláusula with.

En resumen, un programa Ada es concebido como un conjunto de componentes (procedimientos,

funciones, paquetes, tareas) que se proveen servicios mutuamente.

Ejercicio: Seguramente la función SQRT no estará directamente disponible en una biblioteca, sino que será parte de un paquete junto con otras funciones matemáticas. Supongamos que dicho paquete tiene por nombre SIMPLE_MATHS y los otras funciones son LOG, EXP, SIN y COS. Se pide que escriba la especificación de dicho paquete (utilice la especificación de SIMPLE_IO como modelo) ¿Qué cambios habría que hacerle al programa PRINT_ROOTS?





También te podría gustar...

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *