Estructuras de Control en ADA

Ada tiene tres estructuras de control: if, case y loop. A pesar que estas tres estructuras  son suficientes para escribir programas con claridad, el lenguaje también incluye la instrucción goto.
La sintaxis de estas estructuras de control es similar. Existe una palabra reservada de inicio: if, case o loop, la que es pareada al final de la estructura por la misma palabra reservada precedida por la palabra end. Entonces tenemos

if

case

loop


end if;


end case,


end loop;

La palabra loop puede ir precedida por un cláusula de iteración que comienza con for o while.

 

    • Instrucción if

La sintaxis de esta instrucción es: if_statement ::= if condition  then
sequence_of_statements
{elseif condition then
sequence_of_statements}


[else end if;


sequence _of_statements]


condition::= boolean_expression

La semántica de la instrucción if de Ada es semejante a sus análogas en otros lenguajes. Veamos algunos ejemplos:

if HUNGRY then
COOK; EAT; WASH_UP;
end if;

 

Esta es la variante más simple de la instrucción if. En este ejemplo la expresión booleana (condition) está dada por una variable booleana (HUNGRY) y las instrucciones (sequence_of_statements) son llamadas a procedimientos.
Las instrucciones internas al if (tanto en la rama then como en la else) pueden tener cualquier complejidad, incluso pueden ser instrucciones if anidadas. Por ejemplo, si deseamos encontrar las raíces de

ax2 + bx + c = 0

Lo primero que hay que chequear es el valor de a. Si a = 0 la ecuación cuadrática se transforma en una ecuación lineal con una única raíz igual a -c/b. Si a no es cero se debe analizar el discriminante b2-4ac para  ver si las raíces son reales o complejas. Esto podría programarse de la siguiente manera


if A = 0.0 then
— caso lineal

else

if B**2 – 4.0*A*C >= 0.0 then
— raíces reales

else


— raíces complejas


end if;


end if;


Obsérvese la repetición de end if. Esto no es muy estético y ocurre con la suficiente frecuencia para ameritar una construcción especial: elseif, cuyo uso se muestra a continuación

if A = 0.0 then
— caso lineal
elseif B**2 – 4.0*A*C >= 0.0 then
— raíces reales


else end if;


— raíces complejas


De esta forma se enfatiza el mismo status de los tres casos y la naturaleza secuencial de los chequeos. La rama elseif puede repetirse un número arbitrario de veces y la rama final else es opcional.

Ejercicio:

  • Las variables DAY, MONTH y YEAR contienen el día en curso, y están declaradas de la siguiente manera.

DAY: INTEGER range 1 .. 31; MONTH: MONTH_NAME;
YEAR: INTEGER range 1901 .. 2099;

donde

type MONTH_NAME IS (JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,
NOV,DEC);

Escriba una sección de programa Ada que determine la fecha del día siguiente ¿Qué ocurrirá                  si la fecha es 31 DEC 2099?

  • X e Y son dos variables reales. Escriba un bloque que intercambie sus valores, si es necesario, para asegurar que el valor mayor quede en X.

 

    • Instrucción Case

 

Una instrucción case permite elegir una secuencia de instrucciones de entre varias alternativas de acuerdo al valor de una expresión. Por ejemplo, para controlar los movimientos de un vehículo robot podríamos utilizar

case ORDER is
when LEFT => TURN_LEFT; when RIGHT => TURN_RIGHT; when BACK => TURN_BACK;
when ON => null; end case;

Es necesario explicitar todos los valores posibles (sólo una vez) para asegurar que no haya omisiones accidentales. Si para uno o más valores no se requiere una acción específica (como en el ejemplo) se debe usar la instrucción null, la cual no hace absolutamente nada, pero indica que eso es precisamente lo que se desea.
Es frecuente que se necesite realizar una misma acción para varios valores. Por ejemplo, para
expresar la idea que desde lunes a jueves se trabaja; el viernes se trabaja y se asiste a una fiesta; y los sábados y domingos no hay actividades fijas, podemos escribir

 

case TODAY is
when MON|TUE|WED|THU => WORK;


 

when FRI                                    => WORK; PARTY;
when SAT|SUN                          => null; end case;

Si para varios valores sucesivos se realiza una misma acción, se pueden usar rangos, en el ejemplo anterior podría haberse escrito

when MON .. THU => WORK;

A veces se requiere que una cierta acción se realice para todos los valores que no hayan sido explícitamente indicados; esto se realiza utilizando la palabra reservada others, la cual puede aparecer sólo en la última alternativa. Según esto, el ejemplo anterior podría reescribirse

case TODAY is
when MON|TUES|WED|THU => WORK;
when FRI                                    => WORK; PARTY;
when  others                               =>  null; end case;

Ejercicio: Reescriba la respuesta al ejercicio (a) de la pág. anterior usando la instrucción case.

 

    • Instrucciones de iteración

La forma más simple de una instrucción de iteración es

loop
sequence_of_statements
end loop;

Las instrucciones internas a la iteración se repiten indefinidamente hasta que una de ellas termina el loop de alguna manera.  Por ejemplo, consideremos el cálculo del número trascendental e.

e = 1 + 1/1! + ½! + 1/3! + ¼! + . . .

Una posible solución sería


declare

begin

end;


 

E:REAL := 1.0;
I:INTEGER := 0;
TERM:REAL :=1.0;

loop
I:=I+1;
TERM:= TERM / REAL(I); E:=E + TERM;
end loop;
. . .


Notemos que la variable I es de tipo entero porque la lógica del problema nos indica que es un contador, pero el valor de e a calcular debe ser real, por eso es necesario hacer el cambio de entero a real al calcular el nuevo valor de TERM en cada iteración.
Matemáticamente hablando la serie arriba indicada tiende al valor de e cuando n tiende a infinito. Sin embargo, al realizar el cálculo computacional no es posible desarrollar la serie hasta el infinito, puesto que así nunca obtendríamos el valor requerido y, por otra parte, sabemos que la representación de los reales en un computador no es exacta, por lo que tampoco tiene sentido desarrollar la serie hasta un valor muy grande de n. La forma más sencilla de finalizar el loop es determinar una cantidad fija iteraciones antes del inicio del loop. Por ejemplo, supongamos que se decide realizar el loop N veces (N puede ser una constante o una variable a la que de alguna manera se le asigna un valor antes del loop), éste quedaría


 

 

loop
if I = N then exit; end if; I:=I+1;
TERM:= TERM / REAL(I); E:=E + TERM;
end loop;

La instrucción exit detiene el proceso de iteración, pasando el control a la instrucción inmediatamente siguiente a end loop. Puesto que la construcción

if condition then exit; end if;

es bastante usada, el lenguaje provee una construcción análoga más abreviada

exit when condition;

Por lo que el loop quedaría

loop
exit when I = N; I:=I+1;
TERM:= TERM / REAL(I); E:=E + TERM;
end loop;

La instrucción exit puede aparecer en cualquier parte del loop: al principio, al medio o al final. Además, puede aparecer más de una vez (en distintas ramas de instrucciones if, posiblemente, anidadas), sin embargo se recomienda estructurar el loop de forma tal que exista una sola sentencia exit dentro de cada loop. Es bastante común que la instrucción vaya al comienzo del loop (antes de cualquier otra instrucción) como en nuestro ejemplo. Para estos casos se puede usar la palabra reservada while, de la siguiente manera

while I /= N loop
I:=I+1;
TERM:= TERM / REAL(I); E:=E + TERM;
end loop;

En los casos en que se requiere iterar un número específico de veces se puede usar una última variante de la instrucción loop, la que consiste en la utilización de la palabra reservada for. Nuestro ejemplo quedaría

for I in 1 .. N loop
TERM:= TERM / REAL(I); E:=E + TERM;
end loop;

La variable usada para controlar la iteración (en este caso I) se declara implícitamente y no requiere ser definida externamente. Su tipo se determina por el tipo indicado en el rango de variación, y para los efectos internos del loop debe considerarse como una constante, en el sentido en que en cada iteración tiene un valor (determinado por el mecanismo del loop) que no puede ser modificado. Cuando se termina la iteración (por el término del rango o por una instrucción exit) I deja de existir.
Para tomar los valores del rango en orden descendente se utiliza la palabra reservada reverse, de la manera siguiente

for I in reverse 1 .. N loop

Nótese que el rango siempre se escribe en forma ascendente. No es posible definir un paso distinto de 1. Esto no debería causar problema porque la gran mayoría de los ciclos controlados por una variable lo hacen con un paso de 1 (ascendente o descendente) y aquellos que tienen un paso diferente (que son los menos) pueden ser simulados agregando los factores correspondientes. Por ejemplo, para calcular

n
?1 / 2i
i=1


 

el código Ada más adecuado sería,

for I in 1 .. N loop

TERM:= 1.0 / (2.0 * REAL(I)); E:=E + TERM;
end loop;

ya que refleja mejor la notación matemática estandar.
El rango en un loop tipo for puede ser vacío (por ejemplo si N es cero en el caso anterior) en cuyo caso el loop termina en forma inmediata. Los límites de un rango no necesariamente son constantes y/ o variables, son en general expresiones de un cierto tipo discreto (obviamente, el mismo para ambos límites). Las expresiones que determinan los límites son evaluadas una sola vez antes del inicio de la primera iteración y no pueden ser cambiados dentro del loop. Por este motivo el loop

N:=4;
for I in 1 .. N loop
. . . N:=10;
end loop;

será ejecutado 4 veces a pesar que el valor de N haya sido cambiado a 10.
Como ya se dijo, el rango debe ser  de algún tipo discreto, es decir, no necesariamente de tipo entero.
Por ejemplo, para realizar una cierta acción para cada uno de los días de la semana escribiríamos

for TODAY in DAY loop
. . .
end loop;

si quisieramos sólo realizar la acción para los días lunes a viernes escribiríamos

 

for TODAY in MON … FRI loop
. . .
end loop;

pero una manera más adecuada sería

for TODAY in WEEKDAY  loop
. . .
end loop;

Como ya dijimos, la instrucción exit pasa el control al punto inmediatamente siguiente al loop dentro del cual se encuentra. Pero los loops pueden estar anidados y a veces ocurre que se desea salir de toda la estructura anidada y no solo del loop más interno. Por ejemplo, supongamos que estamos realizando una búsqueda en dos dimensiones.

for I in 1 .. N loop
for J in 1 .. M loop
— si los valores de I y J satisfacen una cierta
— condición terminar la búsqueda
end loop; end loop;

Una instrucción exit simple nos sacaría del loop interno, pero estaríamos obligados a chequear nuevamente la condición (agreguese el inconveniente de que J ya no existe) inmediatamente después de terminado el loop interno. Este problema puede ser resuelto dando un nombre al loop externo y usando dicho nombre para salir inmediatamente de ambos.


 

 

SEARCH:
for I in 1 .. N loop
for J in 1 .. M loop
if condition_O_K then I_VALUE :=  I; J_VALUE := J;
exit SEARCH;
end if;
. . .
end loop; end loop SEARCH;
— el control pasa a este punto

Un loop es bautizado colocando un identificador antes de su inicio seguido de dos puntos. (Esto se parece mucho a la forma en que en otros lenguajes se definen labels, pero en Ada no es así, ya que no es posible usar los nombres de loops para la instrucción Goto.) El identificador debe ser repetido entre el correspondiente end loop y el punto y coma final.
La instrucción exit  en su forma condicional también puede referenciar a un loop por su nombre.

exit SEARCH when condition;

 

Ejercicio:


  • Calcule


n
ada

1

 g = ? p ? ln n


p=1
n ? ?, g ? ?


= 0.577215665


La función Ada LN entrega el logaritmo natural, el parámetro debe ser real y el resultado también es real.

  • Calcule e con un error absoluto de 0.00005. Es decir, la diferencia en valor absoluto entre dos valores (calculados) de e consecutivos debe ser menor o igual a 0.00005.
    • Instrucción goto y labels

 

A muchos podría sorprender el que un lenguaje de programación moderno contemple la instrucción goto, puesto que su uso se ha considerado una mala práctica de programación. Ada incluye esta instrucción, pero no estimula su uso al entregar estructuras de control suficientemente variadas para expresar cualquier flujo de control normalmente usado.
La generación automática de programas es el motivo principal para incluir la instrucción goto en
Ada. Cuando se genera automáticamente un programa Ada desde una cierta especificación de más alto nivel, ésta última será considerada como “el programa fuente”, por lo que el código Ada no tiene porque ser muy legible y es posible realizar cierta licencias, entre ellas el uso del goto. Además, al traducir un programa desde Cobol o Fortran a Ada puede resultar conveniente usar goto para hacer una traducción literal del programa original.
La instrucción goto en Ada tiene una sintaxis semejante a la de otros lenguajes, la palabra reservada goto seguido de un nombre de label, el cual se define entre paréntesis angulares dobles. Por ejemplo el label de nombre INICIO se define

<<INICIO>>

colocándolo en el lugar donde se desea que continúe el control del flujo de ejecución del programa. La instrucción en sí tendrá la siguiente forma

goto  INICIO;

Una instrucción goto no puede ser usada para transferir el control al interior de un if, case o loop, ni entre las ramas de las instrucciones if o case.

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 *