Docstoc

cours_ADA

Document Sample
cours_ADA Powered By Docstoc
					Algorithmique Procédurale




    IUP GMI 1ère année

    Denis Robilliard
Sommaire
Introduction
  Historique
  La machine de Turing
  Langages de programmation
  Arbres programmatiques et Ada
  Syntaxe, expressions régulières
Premier programme
  Premier programme en Ada
  Instructions
  Commentaires
  Variables, affectations
  Types de base
  Opérations arithmétiques de base
  Entrées/sorties sur les types de base
  Inclure des bibliothèques
  Conversions de types
Structures de contrôle du flux d ’instructions
  Structure d'alternative AP / ADA
  Expressions booléennes, opérateurs relationnels
  Structure de cas AP / ADA
  Expression statique ou dynamique
  Phases d'écriture d'un programme
  Structure de boucle AP /ADA
  Boucle "pour" AP / ADA
  Boucle avec sortie
  Résumé des différentes structures de boucle en ADA
  Bloc déclaratif AP /ADA
Types tableaux
  Tableaux AP / ADA
  Exemple sur les tableaux
  Règles, opérations et attributs de tableaux
  Les tranches
  Les agrégats
  Les chaînes de caractères AP / ADA
  Entrées / sorties sur les chaînes
  Attributs relatifs aux chaînes et aux caractères
  Les tableaux à plusieurs dimensions
Les sous-programmes : procédures et fonctions
  Paramètres et valeur de retour
  Paramètres par défaut
  Position des procédures et des fonctions
  Déclarations préliminaires
  Portée et visibilité
Récursivité
Retour sur les types, enregistrements
Introduction

Algorithmique : "art" d ’écrire des
 algorithmes ou programmes.
Synonyme : programmation.
Algorithme : procédé opératoire qui
 permet, à partir de données, d ’obtenir un
 résultat précis.
Ex : algo de l ’addition de deux nombres.
Algo procédurale (ou encore impérative) :
 les programmes sont conçus comme une
 liste d ’ordres / instructions, qui doivent
 s ’exécuter un par un, dans un ordre
 chronologique défini à l ’avance.
Il existe d ’autres formes d ’algo :
 parallèle, objet, fonctionnelle, déclarative,
 ...
Historique

Premiers algorithmes dès l ’Antiquité :
 Euclide, Eratosthène, …
Premières machines à calcul : Pascal,
 Descartes (17ème), algorithme "codé" par
 des engrenages.
Premier véritable ordinateur : la machine
 de Babbage (19ème), non achevée.
 Nouveauté : elle est programmable.
Première personne à programmer : Lady
 Ada Lovelace, "assistante" de Babbage.
Théorisation : Turing, Church (années
 30), définition de la notion mathématique
 de "fonction calculable" = ce qui peut être
 réalisé par un "ordinateur universel".
Premiers ordinateurs électroniques mis au
 point pendant la 2nde guerre mondiale.
La machine de Turing

Un "ordinateur" de papier :
  une bande de papier, finie mais aussi longue
   qu ’on le souhaite, divisée en cases qui
   peuvent contenir les symbole 0 ou 1
  une "tête" de lecture/écriture qui pointe sur
   une case, qui peut lire ou écrire un 0 ou un 1
   dans la case, et qui peut se déplacer d ’une
   case à droite ou à gauche
  … (voir page suivante)
 un programme, composé de règles de la
 forme : <q, s> ~ <q ’, s ’, p>
   avec {q, q ’} des états de la machine de Turing,
   dont le nombre, toujours fini, est dépendant du
   programme que l ’on exécute
   {s, s ’} dans {0,1} les symboles que l ’on peut
   écrire sur la bande
   p dans {g,d} une direction indiquant vers quelle
   case voisine (gauche ou droite) se déplace la tête
   de lecture pour exécuter la prochaine instruction
Représentation de la machine de Turing
   0   0    0    0    0   0    0    0   0    0    0    0   0      0   0 ...


  q0        Tête de lecture dans la configuration de départ



   1   0     0    0   0    0    0   0    0    0    0   0      0   0   0 ...


       q1        Position de la tête de lecture et état de la bande après
                 application de la règle : <q0, 0> ~ <q1, 1, d>
Exemple de programme
  Objectif : le programme va lire un nombre en
   base 1 composé de 2 chiffres au plus. Il va
   écrire le double de ce nombre, en base 1,
   plus loin sur la bande.
  Note : la bande sera donc divisée
   (virtuellement) en une zone de données de
   deux cases suivie d ’une zone de résultat. La
   donnée en entrée est écrite sur la bande par
   l ’utilisateur.
Le programme :
<q0, 0> ~ <q10, 0, d>     <q22, 0> ~ <q321, 1, d>
<q0, 1> ~ <q11, 1, d>     <q321, 0> ~ <q422, 1, d>
<q10, 0> ~ <q20, 0, d>    <q422, 0> ~ <q523, 1, d>
<q10, 1> ~ <q21, 1, d>    <q523, 0> ~ <qF, 1, d>
<q11, 0> ~ <q21, 0, d>
<q11, 1> ~ <q22, 1, d>     Note :
<q20, 0> ~ <qF, 0, d>
                             q0 est l ’état initial de la
<q21, 0> ~ <q311, 1, d>       machine
<q311, 0> ~ <qF, 1, d>        qF est l ’état final : quand la
                              machine passe dans l ’état qF
                              elle s ’arrête
Tout ce qui peut être calculé par une
 machine de Turing = ensemble des
 fonctions calculables
Tous les ordinateurs actuels sont des
 machines de Turing, à la restriction près
 que leur mémoire est finie.
Il existe des fonctions non calculables !!!
 Un ordinateur ne peut pas tout faire...
Langages de programmation
Pour communiquer l ’idée d ’un algo, à une
 personne ou à un ordinateur, nécessité d ’un
 langage.
En général les langages informatiques sont
 universels (ils permettent de coder tous les
 programmes possibles).
Cependant, ils favorisent souvent une certaine
 approche des problèmes :
  Pascal, C : programmation procédurale
  Smalltalk, Eiffel, Java : programmation objet
  Prolog : programmation déclarative
Arbres Programmatiques
et Ada

Nous utiliserons 2 langages :
  Un langage pédagogique, en partie graphique,
   noté AP : les Arbres Programmatiques. Note : ce
    ne sont pas des organigrammes.
  Un langage "de la vraie vie" : ADA. C ’est un
   langage de programmation procédurale, créé en
   1983 sur appel d ’offre du Département de la
   Défense américain. Il possède, depuis 1995, des
    extensions objets, que nous n ’utiliserons pas.
Pourquoi les arbres programmatiques ?
  C ’est une notation "papier" (nous n ’exécuterons pas un
   AP sur machine). Nous nous permettrons une syntaxe
   plus souple.
  Les APs forcent le programmeur à une approche
   hiérarchique, descendante du problème.
C ’est la "programmation structurée" :
  On part des idées générales et on va progressivement
   de plus en plus dans le détail.
  Les branches d'un arbre programmatique sont assez
   indépendantes les unes des autres (au moins en ce qui
   concerne le déroulement des instructions).
La programmation procédurale structurée
 marche très bien pour concevoir de
 petites applications (- de 5000 lignes).
D ’autres approches, notamment la
 conception objet, seront vues plus tard
 dans le cursus pour les applis plus
 importantes.
  Note : le code de la navette spatiale
   américaine fait plus de 1.000.000 de lignes...
Syntaxe, expressions
régulières

Pas de langage sans syntaxe (ou orthographe)
  Nous utiliserons une forme restreinte des « expressions
   régulières » pour définir précisément la syntaxe
   autorisée, particulièrement en Ada.
  Exemple :
   identifiant ::= lettre { [ _ ] / lettre | chiffre / }
  Ce qui signifie qu ’un identifiant commence forcément
   par une lettre et se continue par une suite,
   éventuellement vide, de lettres et/ou chiffres, qui
   peuvent chacun être précédé d'un "blanc souligné".
Symboles formant les expressions rationnelles
   ::= introduit l ’expression rationnelle qui définit la
   syntaxe associée au concept;
   [ ] délimitent une sous-expression facultative;
   { } délimitent un motif qui peut être répété;
   … désigne un terme identique au terme précédent;
   | (barre verticale) "ou bien" dans une énumération;
   \ \ délimitent une série d'option d'options parmi
   lesquelles il faut choisir une;
   en_gras dénote un mot réservé (mot clé) de ADA ou
   un symbole à prendre littéralement.
   Premier programme
                                                    Nom de l ’unité/programme
                                 bonjour
 Déclaration de                  nb : entier
                                                            Connecteur séquence
 variable
                                    seq                     d ’instructions

           saluer            demander nombre                afficher nombre



 sortir("bonjour")    sortir("entrer votre nombre : ") sortir("le nombre est : ")
                      entrer(nb)                       sortir(nb)

Nom de bloc
d ’instructions      Bloc d ’instructions                                instruction
Premier programme en Ada
with text_io, integer_text_io;
use text_io, integer_text_io;

procedure bonjour is
  nb : integer;
begin
  -- saluer
  put_line("bonjour");
  -- demander nombre
  put("entrez votre nombre : "); get(nb);
  -- afficher nombre
  put("le nombre est : "); put(nb);
end bonjour; -- le rappel du nom d'unité est facultatif
Instructions
Un programme est composé d ’instructions. Une
 instruction peut elle-même contenir d ’autres
 instructions.
Par défaut, les instructions s'exécutent en
 séquence.
En Ada les instructions sont terminées par un
 point virgule (facultatif en AP).
Une instruction peut s ’étendre sur plusieurs
 lignes.
Pas de différence entre majuscules et minuscules
Commentaires
Les commentaires ont pour objectif de
 faciliter la compréhension du programme.
Les noms de bloc d ’instructions AP seront
 toujours reportés comme commentaires
 en Ada. Des commentaires
 supplémentaires seront évidemment les
 bienvenus.
Les commentaires débutent par -- et se
 poursuivent jusque la fin de ligne.
Variables, affectation

Chaque donnée (nombre, caractère, …)
 que l ’on veut réutiliser ultérieurement
 doit être stockée dans un emplacement
 mémoire appelé "variable".
Les 2 langages, AP et ADA, sont
 "fortement typés" : une variable ne peut
 contenir qu ’une seule sorte ou "type" de
 données (soit un caractère, soit un
 nombre entier, …)
Les variables utilisées par un programme
 doivent être "déclarées" avant leur
 utilisation : on précise leur nom et
 l ’unique type de valeur qu ’elles peuvent
 contenir.
L ’affectation est une instruction. Elle sera
 noté := en AP et en ADA.
  nb := 2; -- range la valeur 2 dans nb
Types de base
Nous utiliserons 4 types de base
  entier (Ada : integer) : nombres sans virgule
  flottant (Ada : float) : nombres avec virgule.
   Un flottant s'écrit toujours :flottant ::=
   chiffre+ "." chiffre+
    ex :       0.0   0.5   123.45
    ctr-ex :   .0    3     324.
  Notation exponentielle pour les flottants
    1.23e2 = 1.23E2 = 1.23 * 10^2 = 123.0
caractère (Ada : character) : 'A', 'b', '?', ...
booléen (Ada : boolean) : valant Vrai ou
 Faux (Ada : True, False)
Opérations arithmétiques
de base

Les 4 opérations + - * /
  Attention, sur des entiers le résultat est
   arrondi à l ’entier le plus proche
    nb := 3 / 2; -- nb contient 1
  Il est interdit de mélanger des types
   différents dans une opération quelconque
    nbf := 3.0 / 2; -- erreur de compilation
    nbf := 3.0 / 2.0; -- ok, nb vaut 1.5
Reste et modulo de la division entière de 2
 nombres : rem, mod
     nb := 3 rem 2; -- nb vaut 1
     nb := 10 mod 5; -- nb vaut 0
Exponentiation (entiers et flottants) : **
     nb := 3 ** 2; -- nb vaut 9
     fonctionne aussi sur les flottants
Valeur absolue (entiers et flottants) : abs()
     nb := abs(-3); -- nb vaut 3
Entrées/sorties sur les
types de base
Lecture (ou saisie) d ’une donnée
  AP : entrer (nom_de_variable)
  Ada : get (nom_de_variable);
    Ada permet de spécifier le nombre maximum de
     caractères (largeur de champ) à prendre en
     compte : get (nom_variable, largeur_champ)
  Le programme s ’arrête, l ’utilisateur tape
   une donnée au clavier suivie d ’un retour
   chariot.
  Une donnée est toujours saisie dans une
   variable.
Ecriture (ou sortie) d ’une donnée
  AP : sortir (variable | donnée )
  Ada : put (variable | donnée );
    Ada permet de donner un format à la donnée :
     nombre de chiffres, …
    entiers : put (variable | donnée , nb_chiffres);
    flottants : put (variable | donnée,
     nb_chiffres_avant_virg , nb_chiffres_apres_virg ,
      nb_chiffres_exposant);
Exemples de sorties
  put(123); put(12345678); put(123,2); put('A');
   put('A'); -- écrit 123 12345678123AA
  Note : le format par défaut des entiers est 8 caractères
    de large. Un format trop petit est ignoré.
  put(123.456); -- écrit 1.23456E2
  put(123.456, 2, 2, 0); -- écrit 123.45
  Note : par défaut les flottants sont écrits en notation
    scientifique. Si la mantisse est trop grande, le format
    est partiellement ignoré.
Inclure des bibliothèques

En Ada, les entrées/sorties ne sont pas
 intégrées au langage : il est nécessaire
 d ’inclure les bibliothèques spécifiques qui
 contiennent ces instructions optionnelles.
  Text_io : saisie et sortie de caractères
  Integer_text_io : d ’entiers
  Float_text_io : de flottants
 Note : d'autres constructions peuvent nécessiter
  d'inclure d'autres bibliothèques...
Inclusion de biblis :
  with bibli_1, bibli_2;
  les instructions contenues dans la bibli sont
   accessible en les préfixant du nom de la bibli:
  with text_io;
  procedure aaa is
  begin
    text_io.put('A');
  end aaa;
Si on utilise fréquemment une instruction
 en provenance d'une bibli, le préfixage
 devient vite fatiguant, on le supprime
 avec "use" :
with text_io;
use text_io;
…
put('A');
…
Pourquoi devoir préfixer par défaut ?
  Utile si 2 biblis apportent des instructions de
   même nom
 bibli1
                 programme
 mon_put
                 with bibli1, bibli2;   lequel est-ce ?
                 ...
 bibli2          mon_put(123);
                 ...
  mon_put
 Conversions de types
AP et Ada sont fortement typés : on ne peut
 pas mélanger des données de types
 différents dans une même expression.
Il est nécessaire de pouvoir convertir des
 données d ’un type dans un autre :
 conversion de type (ou changement de type
 ou transtypage).
 conversion_de_type ::= nom_de_type ( donnée | variable )
 nb := integer(3.5); -- nb vaut 3
Structures de contrôle du
flux d'instructions

Il est souvent nécessaire que l'état d'un
 programme (contenu des variables, …)
 puisse influer sur l'ordre d'exécution des
 intructions.
C'est le rôle des structures de contrôle de
 préciser comment et à quelles conditions
 l'ordre d'exécution des instructions peut
 varier.
Structure d'alternative AP
                           si


                     bloc "si"        bloc "sinon"
   condition


                     instructions      instructions


 Les instructions du bloc "si" ne sont exécutées que si la
  condition est vérifiée.
 Les instructions du bloc "sinon" sont exécutées
  seulement dans le cas contraire.
Structure d'alternative ADA
if condition then    if condition_1 then
    bloc instr.          bloc instr.
else -- facultatif   elsif condition_2 then
    bloc instr.          bloc instr.
end if;              elsif condition_3 then
                         bloc instr.
                      ...
                     else -- facultatif
                         bloc instr.
                     end if;
Expressions booléennes,
opérateurs relationnels
Une condition est une expression booléenne.
Elle est vérifiée si elle vaut vrai (true).
Opérateurs relationnels :
  <, <=, >, >=, =, /=
  et (and), ou (or), non (not)
  ou exclusif (xor)
  et alors (and then), ou sinon (or else)
  dans (in), dehors (not in)
Structure de cas AP
                              cas : expression



 expr_1         expr_2              ...           expr_n           défaut



bloc_1         bloc_2                            bloc_n         bloc_défaut



instructions   instructions                      instructions    instructions
La valeur de expression doit correspondre à une
 et une seule des valeurs données dans les
 losanges.
Seul le bloc situé sous la bonne valeur est
 exécuté.
Après exécution de ce bloc, on sort de la
 structure de cas, les autres blocs sont ignorés.
Structure de cas ADA
case expr is
  when \ expr | interv_discr | others \ {| …} =>
      statement {…}
  {…}
end case;
 Exemple :
case nb is         -- nb est une variable entiere
  when 1 | 2 | 3 => put("1,2 ou 3); new-line;
  when 5..10 => put("entre 5 et 10"); new_line;
  when others => null; -- instruction vide
end case;
3 règles à retenir pour l'ensemble des
 choix :
  il doit être exhaustif (d'où l'utilisation
    fréquente de others)
  il ne doit pas y avoir de répétitions
  les choix doivent être "statiques" (c'est à dire
    évaluables lors de la compilation)
Expression statique ou
dynamique
Une expression "statique" est une expression
 dont la valeur peut être calculée lors de la
 compilation du programme.
Une expression "dynamique" dépend, à priori, de
 l'exécution du programme.
 Ex : le contenu d'une variable est susceptible de changer
  lors de l'exécution d'un programme (par définition…). Par
  conséquent, toute expression qui comporte une variable
  est considérée comme dynamique, même si l'auteur du
  programme sait que le contenu de la variable en question
  ne sera pas changé !
Phases d'écriture d'un
programme
Écriture du source
Compilation : traduction du source en objet
   Préprocesseur (nettoie le source)
   Compilateur (traduit en assembleur)
   Assembleur (traduit en code machine)
Éditeur de liens : traduction de l'objet en
  exécutable, regroupement en un seul fichier des
  différents modules qui constituent le programme
Chargeur : installe l'exécutable en mémoire, puis
  l'exécute
Structure de boucle AP
                 tantque

                              nom_bloc
     condition


                              instructions



Le bloc d ’instruction est exécuté tant que
 la condition est vraie.
Structure de boucle ADA

while condition loop
  bloc_instr
end loop;

 Exemple :
while (nb < 12) loop
  put(nb);
  nb := nb + 1;
end loop;
 Boucle « pour » AP
variable de                    pour
  boucle
                                           nom_bloc
              variable dans
               envers a..b
                                           instructions
   facultatif                 intervalle

 Le bloc d ’instruction est exécuté autant de fois que
  d'éléments dans l ’intervalle discret [a..b].
 La boucle "pour" n'est à utiliser que si on connait à
  l'avance le nombre de tours à effectuer.
La variable de boucle :
  Ne doit pas être déclarée.
  Masque toute autre variable déjà déclarée de même
   nom, dans tout le sous-arbre du bloc d'instruction.
  Contient la valeur courante dans l ’intervalle.
  Est considérée comme une constante dans le bloc
   d ’instruction : on ne peut pas la modifier.
Attention :
  Si b < a, l ’intervalle est vide, on ne le parcourt pas !
  Si on souhaite parcourir l ’intervalle à l ’envers,
   utiliser le mot-clé « envers ».
 Boucle « pour » ADA

 for variable in reverse intervalle loop
   bloc_instr
 end loop;


 Exemples :
for i in 1..10 loop   for i in character'('A')..character'('Z') loop
   put(i);               put(i);
end loop;             end loop;
                              -- affiche 1 à 10, puis 3 !
-- n ’affiche rien !          i := 3;
for i in 10..1 loop           for i in 1..10 loop
   put(i);                       put(i);
end loop;                     end loop;
                              put(i);
 -- affiche de 10 à 1
for i in reverse 1..10 loop   -- ne compile pas !
   put(i);                    for i in 1..10 loop
end loop;                        i := i + 1;
                              end loop;
Boucle avec sortie

loop
  instr
  {…}
  exit when condition; -- facultatif
  instr
  {…}
end loop;
Exemple :
-- compte une séquence de nombres terminée par 0
-- nb et compteur sont des variables entières
put("Entrez vos nombres, terminez par 0"); new_line;
loop
   get(nb);
   exit when nb = 0;
   compteur := compteur + 1;
end loop;
put("Decompte = "); put (compteur); new_line;
De plus, les boucles ADA peuvent recevoir un
 identifiant de boucle, qui peut se combiner avec
 l'instruction exit.

Bcl1: loop
               {…}
Bcl2:          loop
                      {…}
                      exit Bcl1;
               end loop;
        end loop;
Résumé des différentes
structures de boucle en ADA

 [id:] [while bool_expr | for id in [reverse]
       discrete_range] loop
       statement {…}
  end loop [id];

 exit [loop_id] [when bool_expr];
Bloc déclaratif AP

Il peut être utile de déclarer des variables pour
 un usage momentané : leur portée peut être
 réduite au bloc d'instruction où elles servent.
En AP :
                      nom_bloc
                var1, var2 : type1;
                var3, var4, var5 : type2;



                      bloc_instr
Bloc déclaratif ADA

[id:]   declare
               declarative_item
         begin
               handled_statement
         end [id];
handled_statement ::=
    statement {…}
    [exception_handler]
Le "handled_statement" est un simple bloc
 d'instructions, qui se termine par un traitant
 d'exceptions : des instructions servant à rattraper
 d'éventuelles erreurs lors de l'exécution.
Exemple de bloc déclaratif :
declare
  tmp : integer;
begin
  tmp := A; A := B; B := tmp;
end;
Types tableaux
De nombreuses applications nécessitent de
 mémoriser des séries de variables :
 composantes de vecteurs ou de matrices, tables
 de température ou de pression, …
On peut stocker ces données dans une structure
 simple appelée tableau, à l'intérieur de laquelle
 chaque donnée est associée à un ou plusieurs
 numéros appelé indices.
On accède à une donnée en rappelant le nom
 du tableau et son ou ses indices.
Tableaux AP
Représentation d'un tableau à 1 dimension :
                 indices
                               1 2 3 4 5 6 7 8
       temperatures           16 14 14 13 16 14 12 12

nom du tableau         temperatures(1)   temperatures(6)   variables

Une variable de type tableau doit être déclarée,
 en précisant le type unique des valeurs contenues
 dans le tableau et les bornes du tableau :
    temperatures : tableau (1..8) d'entiers;
Tableaux ADA

On peut les déclarer comme des variables :
  tab1 : array(1..8) of integer;
  tab2 : array(1..8) of integer;
Attention, tab1 et tab2 sont considérés comme
 étant de types différents :
  pas d'affectation possible au niveau tableau sans une
   conversion.
  pas de possibilité de les passer en paramètre à une
   fonction ou à une procédure (voir plus loin).
En général, on déclare un type tableau avant de
 déclarer les variables :
  type tab_int_8 is array(1..8) of integer;
  tab1, tab2 : tab_int_8;
Pas de problème d'affectation, ni de passage en
 paramétre.
Les déclarations de types se placent dans la
 partie déclarative d'une unité de compilation ou
 d'un bloc déclaratif.
Nous utiliserons la même convention en AP.
   Exemple sur les tableaux
                              max_tab
                              max : entier
                              type tab20int est tableau(1..20) d'entiers
                              tab : tab20int;

                                             seq


            saisie                déterminer_max                                     afficher_max

            pour                        seq
                                                                                      Sortir(max)

i dans
1..taille   Entrer(tab(i))    initialiser                      Comparer avec tous
                                                                  pour
                             max := tab(1)
                                                                                si
                                                   i dans
                                                   2..taille
                                                                 max < tab(i)         max := tab(i)
Procedure max_tab is                   -- comparer avec tous
   Taille : constant := 20;            for i in 2..Taille loop
   type Tab20Int is array(1..Taille)          if max < tab(i) then
          of integers;                                 max := tab(i);
   max : integer;                             end if;
   tab : Tab20Int;                     end loop;
begin                                  -- afficher max
   -- saisie                           put("le max est :");
   put_line("entrez le tableau");      put(max);
   for i in 1..Taille loop             new_line;
          get(tab(i));               end max_tab;
   end loop;
   -- determiner max
   -- initialiser
   max := tab(1);
Règles, opérations et attributs
de tableaux
un tableau ne peut contenir qu'un seul type
 d'éléments;
on ne peut pas utiliser un indice en dehors des
 bornes définies à la déclaration du tableau, sous
 peine de "plantage";
on peut affecter un tableau à un autre tableau s'ils
 sont compatibles : même taille, même type
 d'éléments (une conversion de type peut être
 nécessaire) :
           a, b : tab_int;
           a := b;
Un tableau connaît
  ses bornes : a'first, a'last
  l'intervalle des indices corrects : a'range (équivalent
   à a'first..a'last)
  la longueur de cet intervalle : a'length
On peut comparer des tableaux (<, >, <=, >=)
 selon le principe de l'ordre lexicographique
  quand tout est égal, un tableau plus court est
   considéré comme plus "petit" ou "avant" dans l'ordre.
 On peut concaténer des tableaux avec &
  a(1..10) := b(1..5) & c(2..6);
Les tranches

On peut extraire un "morceau" de tableau, il
 suffit que les indices soient contigus :
   a, b : tab_int;
   a(1..5) := b(6..10);
Attention lors d'une telle affectation à vérifier
 que les 2 tranches soient de même taille.
Les tranches peuvent se superposer :
   a(1..5) := a(2..6) -- décale la tranche 2..6 d'une case
Les agrégats

Permettent d'initialiser les tableaux :
  declare
    type TABLE is array(4..9) of integer;
    t : TABLE := (1, 2, 3, 4, 5, 6);
  begin
    t := TABLE'(4 | 6 => 1, others => 0);
    t := TABLE'(4..7 => 2, 8..9 => 3);
  end;
Les chaînes de caractères AP
Les chaînes de caractères sont des données très
 utilisées : il existe un type chaine prédéfini.
Le type chaine est un en fait un tableau de
 caractère, avec une syntaxe raccourcie :
  ch1, ch2 : chaine(1..8); -- conseillé
  ch3 : tableau(1..8) de caractères; -- déconseillé
Attention, dans l'exemple précédent ch1 et ch2
 sont de même type, mais pas ch3, bien que ces 3
 objets soient représentés de manière identique
 en mémoire.
Les chaînes de caractères
ADA
En ADA, on dispose du type STRING :
  ch1, ch2 : string(1..8); -- conseillé
  ch3 : array(1..8) of character; -- déconseillé
Comme en AP, ch1 et ch2 sont de même type,
 mais pas ch3, bien que ces 3 objets soient
 représentés de manière identique en mémoire.
Accès :
  ch1(1) := ch2(8);
  ch1(1..5) := ch2(1..2) & ch2(2..4);
Entrées/sorties sur les
chaînes

Entrée :
  get(ch1); -- attention, taper exatement 8 caractères!!!
  get_line(ch1, lng1); -- le nombre de cars tapés sera
     -- rangé dans lng1, qu'il faut déclarer (var. entière).


Sortie :
  put(ch1);
  put_line(ch1); -- passe à la ligne suivante
    -- !!! Put_line ne fonctionne qu'avec des chaînes !!!
Attributs relatifs aux
chaînes et aux caractères

Image : renvoie la représentation d'un type
 sous forme de chaîne.
Value : renvoie la "valeur" d'une chaine.
Pred, Succ : le précédent et le suivant.
Pos, Val : la position et son inverse

Integer'image(300) = "300"       Character'pred('2') = '1'
Character'image('z') = "z"       Character'succ('A') = 'B'
Integer'value("300") = 300       Character'pos('0') = 48
Character'value(" 'z' ") = 'z'   Character'val(48) = '0'
Les tableaux à plusieurs
dimensions

Array_type_def ::=
  array (discrete_range {, …}) of type
Exemple :
  type MATRICE is array(1..10, 1..10, 1..10) of
    float;
  type TAB_2D is array(1..5, -1..0) of integer;
  m1, m2 : MATRICE;
  t : TAB_2D;
Accès :
  m1(1,1,1) := m2(1,1,10);
  get(m1(i,j,k));
Agrégats :
  t :=   TAB_2D'((1,1), (2,2), (3,4), (4,5), (5,5));
  t :=   TAB_2D'((1,1), (2,2), others => (3,3));
  t :=   TAB_2D'(1 | 3 => (1,1), others => (0,0 );
  t :=   TAB_2D'(others => (-1 => 1, others =>
   0));
  t :=   TAB_2D'(others => (others => 0));
Attributs :
  first(i), last(i), range(i), length(i) où i est le
   numéro de la dimension :
     t'first(1) = 5
     t'first(2) = -1
     t'range(1) = 1..5
     t'range(2) = -1..0
  first(1), last(1), range(1), length(1) se notent
   aussi first, last, range, length.
Les sous-programmes :
procédures et fonctions
Subprogram_body ::=
  subprogram_spec is
    {declarative_item}
  begin
    handled_statement
  end;
Subprogram_spec ::=
  procedure [parent_name.]id [formals]
  | function [parent_name.]id [formals] return
    subtype_name
Formals ::=
  (id {, id} : [in | in out | out] subtype_name
    [:= expr] {; …})
Exemples :
  procedure efface_ecran is …
  procedure passe_lignes (x : integer) is …
  function lire_entier return integer is …
  function perimetre (rayon : float) return float is …
  procedure peri_surf (rayon : in float; perimetre, surface :
    out float) is ...
 Un sous-programme est exécuté à chaque appel
 Lors de l'appel, le paramètre formel prend la valeur du
 paramètre effectif

  Paramètre effectif
                       Flux des instructions           Paramètre formel
procedure exemple is
…
…                                  procedure passe_lignes(X : integer) is
begin                              begin
    …                                  for cpt in 1..X loop
    passe_lignes(2);                        new_line;
    …                                  end loop;
    N := 10;                       end passe_lignes;
    passe_lignes(N);
    …
                                         Spécification de sous-programme
end exemple;
          Appels de sous-programme
Les sous-programmes servent :
  à éviter les répétitions inutiles de code, lorsqu'un
   ensemble d'instructions sert à plusieurs endroits.
  à structurer le programme en isolant des fonctionnalités
   spécifiques dans des sous-programmes séparés : c'est
   comme si on ajoutait de nouvelles instructions de base.
Les sous-programmes doivent :
  éviter au maximum d'utiliser des variables déclarées en
   dehors d'eux-mêmes : utiliser les paramètres pour
   communiquer les données.
  conserver une taille raisonnable pour pouvoir être
   compris et mis au point sans pb : au maximum 60 lignes
Position des procédures et
fonctions
1) Dans des fichiers séparés, un par
 procédure/fonction :
  On les inclus dans le programme principal avec "with
   nom_proc" (le fichier doit avoir le même nom).
  La clause "use" n'est pas nécessaire.
  Elles ne connaissent pas les types/variables du
   programme principal !
2) Dans la procédure principale, dans la section
 déclarative (là où on place les déclarations de
 types, de variables, …)
  Elles connaissent les déclarations placées avant.
Déclarations préliminaires
Une procédure ne peut en appeler une autre qui
 soit déclarée après :
  C'est génant, obligation de bouger le morceau de code
   à la bonne place.
  C'est parfois inextricable : si p1 appelle p2 et p2 appelle
   p1, bouger le code n'est pas la solution.
On recourt à une déclaration préliminaire, que l'on
 place le plus haut possible :
  Même syntaxe qu'une déclaration ordinaire, sauf qu'on
   s'arrête au "is", qui est remplacé par ";"
  procedure lire_somme (s : out integer) ; -- decl. prelim.
Paramètres et valeur de
retour
Les paramètres des sous-programmes et la
 valeur de retour des fonctions servent à échanger
 des données avec le programme appelant.
  dans la déclaration du ss-prog : paramètres formels
  dans l'appel au ss-prog : paramètres effectifs
Une procédure ne retourne pas de valeur, mais
 elle peut prendre des paramètres qui peuvent
 être modifiés.
Une fonction retourne obligatoirement une
 unique valeur. Ses paramètres ne peuvent être
 modifiés (penser aux fonctions mathématiques).
La valeur d'une fonction est retournée par
 l'instruction : return expression;

Si le flux d'instruction atteint le "end" final d'une
 fonction sans rencontrer de "return", l'exception
 "program_error" est levée.

On peut utiliser return ; dans une procédure : on
 quitte la procédure en cours et on revient à
 l'appelant (rien n'est retourné).
Les modes des paramètres :
  in : lecture seule (comme une constante)
  out : écriture seule
  in out : lecture / écriture (comme une variable)
Si on n'indique pas de mode, c'est le mode "in"
 par défaut.
Une fonction a toujours ses paramètres en
 mode "in".
Attention, en mode "out" on ne peut pas
 consulter (lire) la valeur du paramètre, ce qui
 peut être déconcertant.
Procedure lire_somme (s : out integer) is
  -- met dans s la somme des entiers saisis par l'utilisateur

  n, tmp : integer := 0;
begin
  put_line("entrer vos entiers (terminer par -1)");
  get(n);
  while n /= -1 loop
      -- s := s + tmp; est interdit (car mode "out")
      tmp := tmp + n;
      get(n);
  end loop;
  s := tmp; -- on a seulement le droit d'ecrire dans s
end;
Paramètres par défaut

Les paramètres peuvent recevoir une valeur
 par défaut : on n'est alors pas obligé de les
 fournir.

Dans text_io, "new_line" est déclaré ainsi :
  procedure new_line (spacing : positive := 1) is …


On peut appeler new_line sans paramètre,
 dans ce cas new_line passe 1 seule ligne.
Portée et visibilité
Portée d'une entité (type, variable, constante…)
 : partie du code où sa déclaration est effective,
 c'est à dire où l'entité existe.
Visibilité d'une entité : partie du code où l'entité
 est accessible.
La visibilité est toujours incluse dans la portée :
 on ne peut accéder qu'à une entité qui existe.
La visibilité est souvent plus réduite que la
 portée : masquages temporaires par des entités
 portant le même nom et plus locales.
Toute entité déclarée dans la partie
 déclarative d'un sous-programme ou d'un
 bloc "declare" :
  n'est visible que dans ce sous-programme ou
   ce bloc.
  disparaît une fois le sous-programme ou le
   bloc terminé.
With … ; use … ;
Procedure portee_visibilite is
   A : constant := 123;
   B : integer := A + 1; -- debut de la visibilite de A
   C : integer := 12; -- debut de la visibilite de B
   function f (B : character := integer'image(C)(2)) -- debut visibilite C
         return integer is
         C : integer := 0; -- debut de la visibilite de B de f
   begin -- debut de la visibilite de C de f
         return character'pos(B) + C;
   end;
begin -- retour de la visibilite de B et C après masquage dans f
   put(A); put(f('A')); put(f); put (B); put(C); put(integer'image(C));
   -- affiche :   123     65     49    124     12 12
end portee_visibilite;
Récursivité

Un sous-programme peut s'appeler lui-même :
 function factorielle(N : integer) return integer is
 begin
     if N = 0 then
             return 1; -- condition d'arrêt
     else
             return N * factorielle(N - 1); -- appel récursif
     end if;
 end factorielle;
CE QU'IL FAUT COMPRENDRE :

chaque niveau d'appel récursif crée sa propre copie
 des paramètres formels et des variables locales.
lors du retour d'un appel récursif on retrouve donc
 intactes les valeurs des paramètres et des variables
 (sauf si elles ont été passées récursivement en
 mode "out", bien entendu !)
dans le code du sous-programme, il doit y avoir
 une alternative où on ne relance pas un appel
 révursif, sinon la récursion est infinie
 (concrètement ça plante après avoir saturé la
 mémoire de la machine).
  Plusieurs sous-programmes peuvent
   s'appeler les uns les autres :
function syracuse1(N : integer) return integer is
begin
    if N /= 1 and N % 2 = 0 then                  -- conjecture de syracuse
         return syracuse1(N / 2);                 get(N);
    elsif N /= 1 then                             put(syracuse1(N));
         return syracuse2(N);
    else
         return N;
    end if;               function syracuse2(N : integer) return integer is
end;                      begin
                              if N /= 1 and N % 2 /= 0 then
                                   return syracuse2(3 * N + 1);
                              else
                                   return syracuse1(N);
                              end if;
                          end;
  Attention, dans l'exemple précédent on a besoin de
   déclarations préliminaires pour compiler.


Comment aborder un problème récursif ?
  Il faut avoir l'intuition qu'il se traite récursivement. Si
   on ne sait pas le traiter de manière classique, ça ne
   coûte rien de se poser la question…
  Il faut déterminer sur quelle "variable" (ex: N) on fait
   la récurrence.
  Il faut avoir une solution d'arrêt de la récursivité
   (quand N est petit).
  Supposant avoir la solution au rang N-1, trouver ce
   qu'il faut faire pour passer au rang N.
Retour sur les types
Type / Sous-type
  une déclaration de type est statique
    type mon_entier is range 1..100; -- ok
    N : integer := 100; -- variable, non statique
    type mon_entier2 is range 1..N; -- interdit !!!
  une déclaration de sous-type peut être
   dynamique, elle s ’appuie sur un type pré-
   existant
    N : integer := 100; -- variable
    subtype mon_entier3 is integer range 1..N;
Types entiers
with ada.text_io; use ada.text_io;

procedure test_instanciation is
  type mon_entier is range 1..100;
  package mon_entier_io is new
   ada.text_io.integer_io(mon_entier);
  use mon_entier_io; -- autorise les E/S sur ce nouveau type
  n : mon_entier;

begin
 put("entrer un entier : ");
 get(n); -- raise DATA_ERROR si pas dans 1..100
 put(n * 2); -- raise CONSTRAINT_ERROR si pas dans
  1..100
Types énumératifs
with ada.text_io, ada.integer_text_io;
use ada.text_io, ada.integer_text_io;
procedure test_type_enumere is
  type JOUR is (LUNDI, MARDI, MERCREDI, JEUDI,
   VENDREDI, SAMEDI, DIMANCHE);
  package jour_io is new ada.text_io.enumeration_io(jour);
  use jour_io;
  n : integer;
begin
  put("entrer un entier : ");
  get(n);
  put(JOUR'VAL(n mod 7));
end;
Attributs pour types énumérés
  jour'first # LUNDI
  jour'last # DIMANCHE
  jour'succ(LUNDI) # MARDI
  jour'pred(MARDI) # LUNDI
  jour'pos(LUNDI) # 0
  jour'val(0) # LUNDI
  jour'value("LUNDI") # LUNDI
  jour'image(LUNDI) # "LUNDI"
Type booléen
  type boolean is (FALSE, TRUE); -- type énuméré
Types flottants
  On peut préciser le nombre de chiffres
   significatifs : digits N = précision au 1/10^N
  On peut limiter l'intervalle des valeurs possibles
    type REEL is digits 6;
    type VOLTAGE is digits 5 range 0.0 .. 1.0E+9;
  Attributs
     type FL is digits D range I..S
    FL'digits # D        FL'first # I     FL'last # S
  E/S : instancier ada.text_io.float_io(nom_type)
Types tableaux contraints / non contraints
  tableaux contraints
    type vecteur1 is array(1..10) of float;
    v1, v2 : vecteur1;
    toutes les variables de type vecteur1 ont mêmes
      dimensions
  tableaux non contraints
    type vecteur2 is array(integer range <>) of float;
    v1 : vecteur2(1..10);
    v2 : vecteur2(-5..15);
    v1 et v2 sont de même type, mais de dimensions
      différentes
    on doit fournir les bornes lors d'une déclaration
      de variable de type vecteur2
Intérêt des tableaux non contraints



  Quand ils apparaissent en tant que paramètres
    formels, il n'est pas nécessaire de préciser leur taille
    (car ce n'est pas une déclaration de variable) :
  Procedure truc(v : in out vecteur2) is …
  On utilise les attributs de tableau pour connaître
    l'intervalle des indices.
Rappel : les chaînes de caractères
  En fait le type STRING est simplement un type
    tableau de caractères non contraint :
  type STRING is array(integer range <>) of character;
Type Article / Enregistrement (record)

  Si un tableau est une collection de variables
    de même type accessibles via leur numéro,
   un article est une collection de variables de
   types qui peuvent être différents, accessibles
   par leur nom.
  Les différentes variables de l'article
   s'appellent des champs.
  La variable de type article possède son
   propre nom, on accède à ses champs par la
   notation pointée :
          nom_d_article.nom_de_champ
Exemple :
type MOIS is (Janvier, Fevrier, …, Decembre);
type DATE is record
  jour : integer range 1..31;
  mois : MOIS;
  an : integer;
end record;

d : DATE;
d := (14, Juillet, 1789);
d := (jour => 14, an => 1789, mois => Juillet);
d.mois := Mars; d.jour := 12; d.an := d.an + 1;
Type Article avec partie variante
 type Genre_Figure is (un_cercle, un_point, un_carre);
 type Point is record
   X, Y : Integer;
 end record;
 type Figure (Sorte : Genre_Figure := un_point) is record
   Position : Point;
   case Sorte is
     when un_cercle => Rayon : Integer;
     when un_carre => Coin_Inf_Droit : Point;
     when others => null;
   end case;
 end record;

 F : Figure := (un_point, (10,15));
 F := (un_cercle, position => (20, 25), rayon => 50);
Partie variante : comment ça marche ?

  Entre les différents contructions rendues possibles
   dans la partie variante, le compilateur calcule celle
   qui occupe le plus de place et alloue cette place à
   la variable.
  Dans l'exemple, c'est le carré qui prend le plus de
   place. Si on charge la variable avec un point ou un
   cercle, une partie de la mémoire reste inutilisée,
   tout simplement.
  On ne peut changer le discriminant (variable qui
   sélectionne la partie variante) que si on change
   tout le reste de l'article.

				
DOCUMENT INFO
Shared By:
Categories:
Tags:
Stats:
views:3
posted:10/18/2011
language:French
pages:109