Cours 4: Instructions suite

Objectif: Instruction cas. Instruction de boucle.
Exemples: calcul de la date du lendemain entre 1901 et 2099.
Calcul de xˆn (itération bornée sans compteur).
Calcul de n! (itération bornée avec compteur en progression).
Décalage à droite des éléments d'un tableau (itération bornée avec compteur en régression).
Fusion d'un tableau trié (itération non bornée à sortie en milieu de corps).
Racine carrée entière (itération non bornée à sortie en début de corps).
Logarithme entier en base 2 (sortie en fin de corps).

L'instruction case se compose d'une expression d'un type discret et d'un ensemble de cas.
Chaque cas est gardé par un ensemble de valeurs du type de l'expression.
Un éventuel dernier cas est gardé par la valeur symbolique other.
Les cas doivent être deux à deux disjoints.

Extrait du manuel de référence (RM95):


       case_statement ::=
          case expression is
              case_statement_alternative
             {case_statement_alternative}
          end case;

       case_statement_alternative ::=
          when discrete_choice_list =>
             sequence_of_statements

       discrete_choice_list ::= discrete_choice {| discrete_choice}

       discrete_choice ::= expression | discrete_range | others

L'expression est évaluée.
Si sa valeur figure parmi l'une des gardes, la suite d'instructions du cas est exécutée.
Sinon, et si un cas other est proposé, sa suite d'instructions est exécutée.

Extrait du manuel de référence (RM95):


       case Sensor is
          when Elevation  => Record_Elevation(Sensor_Value);
          when Azimuth    => Record_Azimuth  (Sensor_Value);
          when Distance   => Record_Distance (Sensor_Value);
          when others     => null;
       end case;

       case Today is
          when Mon        => Compute_Initial_Balance;
          when Fri        => Compute_Closing_Balance;
          when Tue .. Thu => Generate_Report(Today);
          when Sat .. Sun => null;
       end case;

       case Bin_Number(Count) is
          when 1      => Update_Bin(1);
          when 2      => Update_Bin(2);
          when 3 | 4  =>
             Empty_Bin(1);
             Empty_Bin(2);
          when others => raise Error;
       end case;

Autre exemple:


       case Mois_Aujourdhui is
          when Avril | Juin | Septembre | Novembre =>
                  Fin_de_Mois := 30;
          when Fevrier =>
               if Bissextile(Annee_Aujourdhui) then
                  Fin_de_Mois := 29;
               else 
                  Fin_de_Mois := 28;
               end if;
          when others =>
                  Fin_de_Mois := 31;
       end case;
       if (Quantieme_Aujourdhui /= Fin_de_Mois) then
           Quantieme_Demain := Quantieme_Aujourdhui + 1;
           Mois_Demain := Mois_Aujourdhui;
           Annee_Demain := Annee_Aujourdhui;
       else
           Quantieme_Demain := 1;
           if (Mois_Aujourdhui /= Decembre) then
               Mois_Demain := Mois'Succ(Mois_Aujourdhui);
               Annee_Demain := Annee_Aujourdhui;
           else
               Mois_Demain := Janvier;
               Annee_Demain := Annee_Aujourdhui + 1;
           end if;
       end if;

L'instruction de boucle comprend un éventuel schéma d'itération fixant les conditions de répétition du corps de boucle.
Lorsqu'aucun schéma n'est présent, le corps de boucle peut contenir une instruction de sortie.
Un schéma while c répète le corps de boucle tant que la condition c est vraie.
Un schéma for i in range répète le corps de boucle pour chacune des valeurs de i dans l'intervalle range.
La variable i est implicitement déclarée du type de l'intervalle range.


       loop_statement ::=
          [loop_statement_identifier:]
             [iteration_scheme] loop
                sequence_of_statements
              end loop [loop_identifier];

       iteration_scheme ::= while condition
          | for loop_parameter_specification

       loop_parameter_specification ::=
          defining_identifier in [reverse] discrete_subtype_definition

Extrait du manuel de référence (RM95):


       Examples
       Example of a loop statement without an iteration scheme:

       loop
          Get(Current_Character);
          exit when Current_Character = '*';
       end loop;

       Example of a loop statement with a while iteration scheme:

       while Bid(N).Price < Cut_Off.Price loop
          Record_Bid(Bid(N).Price);
          N := N + 1;
       end loop;

       Example of a loop statement with a for iteration scheme:

       for J in Buffer'Range loop     --  works even with a null range
          if Buffer(J) /= Space then
             Put(Buffer(J));
          end if;
       end loop;

       Example of a loop statement with a name:

       Summation:
          while Next /= Head loop
             Sum  := Sum + Next.Value;
             Next := Next.Succ;
          end loop Summation;

Autres exemples


       Ite'ration borne'e sans compteur:

       function "**"(X: Integer; N: Natural) return Integer is
         P: Integer:= 1;
       begin
         for I in 1..N loop -- I de'clare'
           P:= P*X;         -- Corps inde'pendant de I
         end loop;
         return P;          -- I n'existe plus
       end "**";

       Ite'ration borne'e avec compteur en progression:

       function Factorielle(N: Natural) return Positive is
         -- Factorielle(0)=1
         P: Positive:= 1;
       begin
         for I in 1..N loop 
           P:= P*I;         -- Corps de'pendant de I
         end loop;
         return P;
       end Factorielle;

       Ite'ration borne'e avec compteur en re'gression:

       procedure Decale_a_droite(T: in out Table) is
       begin
         for I in reverse Indice'Succ(Table'First)..Table'Last loop
           T(I):= T(Indice'Pred(I));
         end loop;
       end Decale_a_droite;

       Ite'ration non borne'e a` N tours et demi:

       procedure Fusion(T: in out Table; Nb: Indice; Nb_restants: out Indice) is
         -- Fusionner un tableau trie' pour en e'liminer les doublons
         -- Nb est le nombre de places occupe'es dans le tableau avant fusion
         -- Nb_restants est le nombre de places occupe'es dans le tableau apre`s fusion
         Lecture, Ecriture: Indice:= T'First;
       begin
         loop
           T(Ecriture):= T(Lecture);
           while Lecture<=Nb and then T(Lecture)=T(Ecriture) loop
             Lecture:= Indice'Succ(Lecture);
           end loop:
           exit when Lecture>Nb;
           Ecriture:= Indice'Succ(Ecriture);
         end loop;
         Nb_restants:= Ecriture;
       end Fusion;

       Ite'ration non borne'e a` au moins un tour:

       function Log2(N: Positive) return Natural is
         L: Natural:= 0;
       begin
         loop
           L:= L+1;
           exit when 2**L>N;
         end loop;
         return (L-1);
       end Log2;

       Ite'ration non borne'e a` ze'ro tour ou plus:

       function Racine(X: Natural) return Natural is
         R: Natural:= 1;
       begin
         while R*R<=X loop
           R:= R+1;
         end loop;
         return (R-1);
       end Racine;