Initiation à Algorithmique et programmation en ADA
-
Upload
kadeem-chase -
Category
Documents
-
view
54 -
download
6
description
Transcript of Initiation à Algorithmique et programmation en ADA
Initiation à Algorithmique et programmation en ADA
Infos pratiques
Organisation du semestre :– Cours/TDs– Les TDs sont réalisés en binôme et notés.– Un partiel en janvier.
Bibliographie :– Programmer en ADA95 par John Barnes, 2ième
édition, Vuibert, ISBN 2-7117-8651-X– http://crb.univ-littoral.fr/coursada/index.htm
L’algorithmique
Définition :– Un algorithme est une suite d’instructions qui une fois
exécutée, conduit à un résultat donné. Exemple :
– Fabriquer un brownie :• 1 Préparer la pâte• 2 Faire fondre le chocolat• 3 Mélanger le chocolat et la pâte• 4 Faire cuire 35 minutes
Les instructions sont séquentielles, elle se suivent et doivent être réalisées l’une après l’autre
L’algorithmique
Il est possible de raffiner l’algorithme afin qu’il soit plus explicite :– Faire fondre le chocolat :
• 2.1 Placer le chocolat dans un récipient• 2.2 Placer le récipient dans une casserole avec de l’eau
bouillante• 2.3 Attendre que le chocolat soit fondu
Réaliser un algorithme pour un ordinateur consiste à raffiner suffisamment l’algorithme afin qu’il soit compréhensible pour la machine.
Le pseudo-code
Définition– Le pseudo-code est une façon de décrire un algorithme
sans référence à un langage de programmation en particulier
Exemple :Programme DabovilleTantque Gérard n’est pas fatigué
ramerFin Tantque
Remarquez l’indentationPour rendre le code pluslisible
Les arbres programmatiques
Il est possible de représenter le programme précédent sous la forme d’un arbre programmatique
Début
Si Gérard n’est pas fatigué
Ramer
Fin
VRAI
FAUX
Architecture des ordinateurs
2103 75
2102 45
2101 0
2100 18
2099 254
1032 Multiplier la valeur de case 2102 par 5
1031 Sauter à l’instruction de la case 1029
1030 Tester si la valeur de la case 2101 est nulle
1029 Incrémenter la valeur de la case 2101
1028 Soustraire 18 à la valeur de la case 2099
Mémoire centrale
Unité Centrale
• Lecture de l’instruction • Exécution de l’instruction• Mise à jour de la mémoire
Le programme en langagemachine, logé en mémoire, est exécuté par le processeur
Les différents langages
Ajoutons 5 à la valeur d’une case mémoire– En langage machine :
• 80 06 00 00 05– En assembleur :
• Add [I],0x05– En ADA :
• I:=I+5;
Le langage machine/assembleur
Avantages– Très rapide à l’exécution, car au plus près de la machine– Adapté au développement de petits programmes critiques
tels que :• Les drivers• Des parties du noyau des SE
Inconvénients– Peu lisible -> source d’erreurs– Inadapté au développement de programmes de grandes
tailles, au développement par plusieurs équipes– ………
Les langages évolués
Exemples– ADA, C/C++, Java, ….
Avantages– Adaptés à la réalisation de gros projets grâce à :
• Un style « plus humain » des programmes• L’abstraction des données (par exemple I)• ….
Inconvénients– Plus lent que l’assembleur– …..
L ’ADA
Historique :– Commande du département Américain de la défense
nationale (DoD)– Hommage à Augusta Ada Byron, comtesse de Lovelace
(1815-1852), assistante de Charles Babbage qui travaillait sur sa machine analytique mécanique. Dans un sens très réel, elle est donc le premier programmeur du monde !
La compilation
Position du problème :– L’ordinateur ne comprend que le langage machine– D’où la nécessité de traduire les autres langages en langage
machine. C’est le processus de compilation. En 2 phases :
– La compilation elle-même qui est la traduction du programme en langage machine
– L’édition ࠠde$Liens : qui est l’ajout des éventuelles librairies pour former au final l’exécutable (le .exe sous windows)
Entrée / Sortiede
Données
Les variables
Définition :– Une variable correspond à un emplacement précis de la
mémoire En ADA, les variables ont :
– Un identificateur : un nom– Un type : entier, nombre réel, chaîne de caractères,…– Une valeur : le contenu de la case
Exemple : I:Integer:=2;– Déclaration d’une variable I de type integer (entier) et dont la
valeur est 2.
Les variables
2103 75
2102 45
2101 0
2100 2
2099 254
Mémoire centrale
L’ordinateur choisit une case mémoire pour stockernotre variable. Le langage ADA fait que l’on peutréférencer la variable via son identificateur : I
I
Les variables
En ADA, il faut déclarer une variable avant de pouvoir s’en servir. Le choix de l’identificateur doit respecter certaines règles :– Uniquement des lettres majuscules/minuscules, – Le trait bas– Les chiffres de 0 à 9– Et il faut commencer par une lettre.
Exemple : « Surface :Float; » Attention, l’ADA ne fait pas de distinction entre les
majuscules et les minuscules. On dit qu’il est insensible à la casse.
Les variables
Les identificateurs suivants sont corrects :– X1– Variable_X_12
Les identificateurs suivants sont incorrects :– 12x (on commence par un chiffre)– Revenu&recette (un caractère non permis dans
l’identificateur : le « & »)
Les variables
Deux types essentiels :– Les entiers : Integer en ADA, pour stocker des variables qui sont par
nature entières. (un nombre d’objets, un compteur,…)– Les flottants : Float en ADA, pour stocker des nombres réels. (les
coordonnées x et y d’un point, le résultat d’une division,…) Remarque n°1 : il est possible de déclarer plusieurs variables
simultanément, par exemple : « X1,X2 :Integer ; » Remarque n°2 : Les types en ADA possèdent des attributs :
– Integer ’First désigne la plus petite valeur possible du type Integer– Integer ’Last désigne la plus grande valeur possible du type Integer
Attention à la notation des constantes en ADA :– 23 est nécessairement un nombre de type Integer– 23.0 est nécessairement un nombre de type Float
Les variables
Les opérateurs classiques s’appliquent sur ces types :– Les 4 opérations de base. Attention 3/2 donne 1, mais 3.0/2.0 donne
1.5 car la première opération se fait sur des entiers et la deuxième sur les flottants.
– ** pour l’exponentiation– Abs pour la valeur absolue
Exemple :I,J:Integer;K:Integer:=4;…I:=K*4;J:=K*I+78**2;
Les variables
Opérateurs réservés aux entiers :– rem pour le reste de la division entière. La division euclidienne tronque vers
zéro. Cela signifie que la valeur absolue du résultat est toujours la même que celle obtenue en divisant les valeurs absolues des opérandes :
• 7/3 = 2 donc 7 rem 3 = 1• -7/3 = -2 donc –7 rem 3 = -1
– mod pour le modulo arithmétique usuel. Pour b positif, a mod b est toujours dans l’intervalle [0;b-1] et pour b négatif, a mod b est toujours dans l’intervalle [b+1;0]
• 11 mod 5 donnera 1 • (- 11) mod 5 donnera 4 • 11 mod (–5) donnera -4
Les variables
Opérateurs réservés aux flottants :– sqrt pour la racine carrée :
• sqrt(4.0) donne 2.0– cos, sin, tan, log, ...
Attention à l’ordre de priorité des opérateurs, ne pas hésiter à utiliser les parenthèses :– 2+3*4=14 !
Les variables
Attention bis : On ne peut pas mélanger différents types dans une opération.
Exemple :I,J:Float;K:Integer;….I:=J*2.0; --OKI:=J*K; --illégal
Il faut effectuer une conversion de type, en plaçant le type devant la variable, par exemple :I:=J*Float(K);
L’affectation
Définition :– L’affectation consiste à donner une valeur à une variable
Exemple :– En pseudo-code :
I 3J I+4
– En ADA : I:=3;J:=I+4;
– A la fin, I:=3 et J:=7. Conclusion « := » est le symbole d’affectation en
ADA.
Structure général d’un programme ADA
with Ada.Text_Io;use Ada.Text_Io;
procedure Mon_Programme is
I:Integer:=3;J,K:Float;
beginI:=I+5;K:=3;J:=3*K-7;
end Mon_Programme;
Déclaration des packagesutilisés
Déclaration des variables
Corps de la procédure
Sortie de données
La sortie de données à l’écran s ’effectue via l’instruction « Put », par exemple :Put(« Bonjour le monde »);Put(45);Put(4.1);Put(I);
Put(Integer)
Attention, il faut inclure la directive suivante avant de pouvoir utiliser Put avec les Integer :with Ada.Integer_Text_Io;use Ada.Integer_Text_Io;
Put possède un argument supplémentaire (qui vaut 8 par défaut), la taille minimale des nombres :Put(4,3); affiche : _ _ 4, maisPut(4,4); affiche : _ _ _ 4.
Put(Float)
Attention, il faut inclure la directive suivante avant de pouvoir utiliser Put avec les Float :with Ada.Float_Text_Io;use Ada.Float_Text_Io;
Put possède 3 arguments supplémentaires :– Put(X,N1,N2,N3); avec :
• X : le nombre à afficher• N1 : le nombre de chiffres avant la virgule• N2 : le nombre de chiffres après la virgule• N3 : le nombre de chiffres de l ’exposant
Autre commande
« New_Line » pour passer à la ligne :New_Line; passe une ligneNew_Line(4); passe 4 lignes
Entrée de données
L ’entrée de données se fait via l’instruction « Get ». Elle s’utilise de la même façon que « Put ».
Exemple :with Ada.Integer_Text_Io;use Ada.Integer_Text_Io;…..I:Integer;…Get(I);
Autre commande
Get pioche dans le tampon clavier les données dont il a besoin et laisse les autres :On tape 12 28 44Get(I) va affecter la valeur 12 à la variable I et le tampon
deviendra : 28 44 Pour palier à ce fonctionnement, il est possible de
vider le tampon en utilisant l’instruction « Skip_Line »
Les structures alternatives
Les booléens
Définition :– Le type booléen (boolean en ADA) correspond à une
variable pouvant prendre uniquement 2 valeurs : VRAI ou FAUX (True ou False). Le nom est en hommage à George Boole qui développa l’algèbre de Boole.
Exemple :Test: boolean;…..Test:=True;
Les booléens
De nouveaux opérateurs sur les entiers et les flottants :« a = b » prend la valeur True si a est égal à b« a /= b » prend la valeur True si a est différent de b« a > b » prend la valeur True si a est supérieur à b« a >= b » prend la valeur True si a est supérieur ou égal à bIdem pour « < »
Les booléens
Exemple :Test:Boolean;A,B:Integer;….A:=3;B:=4;…..Test:=A<=B;..A la fin du programme Test prend la valeur True.
Les booléens
Les opérateurs réservés aux booléens :– « not » l’opérateur unitaire qui change True en False– « and » l’opérateur binaire : et logique. Le résultat est True
uniquement si les 2 opérandes valent True– « or » l’opérateur binaire : ou logique. Le résultat est True si
l’un ou l’autre des opérandes vaut True, et False si les 2 opérandes sont False
– « xor » l’opérateur binaire : ou exclusif. Le résultat est True si l’un des 2 opérandes (mais pas les 2) vaut True. On peut aussi le considérer comme l’opérateur donnant True uniquement quand les 2 opérandes sont différents.
Les booléens
Exemple :T1,T2:Boolean:=True;…..T1:=not T2; (T1 vaut False)T2:=T1 or T2; (T2 vaut True)T2:=T1 and T2; (T2 vaut False)T2:=(2<3) or T1; (T2 vaut True)
La structure « if »
Définition :– Elle permet au programme de prendre des décisions, par
exemple en pseudo-code :A3Lire BSi A<B alors
Ecrire « A est inférieur à B »Sinon
Ecrire « B est inférieur à A »Fin Si
La structure « if »
Le même exemple en ADA :A:=3;Get(B);if A<B then
Put(« A est inférieur à B »);else
Put(« B est inférieur à A »);end if;
Les différentes formes du « if »
La plus simple :if condition then
instructions ….end if;
Avec un else :if condition then
instructions ….else
instructions ….end if;
Les différentes formes du « if »
Avec un ou plusieurs elsif :if cond1 then
instructions ….elsif cond2 then
instructions ….elsif cond3 then
instructions ….….
elseinstructions ….
end if;
Les « if » imbriqués
Les instructions placés au sein des parties du « if » peuvent être quelconques. On peut par conséquent insérer une deuxième structure « if » à l’intérieur de la première, par exemple :
if a/=0 thenif b**2-4*a*c>0 then
instructions ….end if;
elseinstructions ….
end if;
La structure « case »
Celle-ci peut remplacer avantageusement une série de elsif dans certains cas particuliers.
case variable iswhen valeur1 => instructions; ….when valeur2 => null;when valeur3..valeur4 => instructions; ….….when others => instructions;
end case; Explications :
– Quand la variable prend la valeur « valeur1 » alors c’est uniquement les instructions correspondantes à cette valeur qui sont exécutées. La troisième condition est une plage de valeurs entre valeur3 et valeur4. Enfin, others, correspond au comportement par défaut si aucune condition n’est réalisée.
Les structures répétitives
L’instruction « loop »
La forme la plus simple des structures répétitives est l’instruction loop, exemple :loop
instructions…end loop;
Il est possible de sortir de la boucle en utilisant le mot-clé « exit ». Par exemple :loop
instructions…if a/=0 thenexit;end if;
end loop;
L’instruction « loop »
La structure « if cond then exit ...» est si commune qu’elle possède une notation particulière : « exit when cond ». Ainsi on peut écrire :loop
instructions….exit when cond;instructions….
end loop;
L’instruction « while »
Si le test a effectuer pour sortir de la boucle doit se faire au début de celle-ci, on peut alors utiliser une construction avec « while », dont voici la syntaxe :while cond loop
instructions….end loop;
En pseudo-code, on écrira :Tantque cond
instructions…Fin Tantque
Remarque : l’instruction est répétée tant que la condition est VRAI
L’instruction « for »
Le nombre de répétitions d’une même suite d’instructions est souvent connu. On utilisera dans ce cas une structure « for ».
La syntaxe est la suivante :for X in V1..V2 loop
instructions….end loop;
Dans cette exemple, la variable X va prendre toutes les valeurs entre V1 et V2 puis la répétition va se terminer.
Remarque 1 : Dans ce cas précis, il n’est pas nécessaire de déclarer la variable X avant son utilisation.
L’instruction « for »
Remarque 2 : V1 est obligatoirement inférieur à V2. Si l’on veut parcourir la plage de valeurs dans le sens contraire, il faut ajouter « reverse » à l’entête :for I in reverse 14..45 loop
Put(I);end loop;
Le programme précédent va afficher les nombres de 45 à 14 dans cet ordre.
En pseudo-code on écrira :Pour I allant de 45 à 14
Ecrire IFin Pour
Les tableauxPremière partie
Définition
Un tableau est une structure permettant de stocker un ensemble de variables du même type.
Par exemple : Supposons la nécessité de stocker les notes d’une classe à une épreuve. On déclare alors un tableau de dimension la taille de la classe, puis on y stocke les notes.
La note N°4 est 6
1 2 3 4 5 6 7 8 9 107 14 18 6 15 10 12 18 20 3
Définition en ADA
En Ada, un tableau à une dimension se déclare de la façon suivante : Nom_variable : array (V1..V2) of Type ;Où :– Nom_variable est le nom du tableau– V1..V2 la plage de valeurs définissant le tableau– Et enfin Type pour le type des variables contenues dans le
tableau.
Définition en ADA
Ainsi pour un tableau de 10 notes (type flottant) :Mon_Tab : array (1..10) of Float;
On accède ensuite aux valeurs via Mon_Tab(i), où i est l’indice recherché. Exemple :
Mon_Tab : array (1..10) of Float;…..Mon_Tab(4):=17.0; --on fixe la 4ième valeur à 17Get(Mon_Tab(8)); --on utilise directement le tableau au sein d’un GetMon_Tab(1):=2.0*Mon_Tab(2); --la 1er note est le double de la 2ième.
Mon_Tab(2) s’utilise donc exactement comme une variable flottante traditionnelle.
Retour sur les attributs
Une variable de type tableau possède un certain nombre d’attributs, sur l’exemple précédent :
Mon_Tab : array (1..10) of Float;
Mon_Tab’First : contient la borne inférieure pour l’indice (ici 1)Mon_Tab’Last : contient la borne supérieure pour l’indice (ici 10)Mon_Tab’Length : contient le nombre de valeurs pour l’indice (ici 10)Mon_Tab’Range : contient directement la plage 1..10
Par exemple, l’affichage du tableau peut se faire via l’instruction suivante : for i in Mon_Tab’Range loop
Put(Mon_Tab(i));New_line;
end loop;
Retour sur les attributs
Remarque N°1 : l’utilisation des attributs permet de simplifier l’écriture des programmes.
Remarque N°2 : et surtout, elle permet de faire des modifications au sein des programmes rapidement et de façon sûre.
Exemple : la modification de la taille du tableau n’entraîne pas la réécriture des boucles for si celles-ci sont programmées avec l’attribut Range.
Les agrégats
Les agrégats sont des tableaux constants. Ils servent, par exemple, à l’initialisation des tableaux.
La syntaxe est la suivante :(1.2 , 3.0 , 4.7) pour un tableau contenant 3 flottants.
Exemple :Mon_Tab : array (1..3) of Float:= (1.2 , 3.0 , 4.7);
Les tableaux à 2 dimensions
Il est possible de faire des tableaux de dimension quelconque. La syntaxe pour déclarer un tableau de dimension 2 est la suivante :
Nom_variable : array (V1..V2 , V3..V4) of Type;Pour déclarer un tableau où la deuxième dimension a la plage V3..V4.
Pour accéder aux valeurs on utilise la syntaxe suivante : Mon_Tab(i,j) pour avoir la valeur (i,j) ième valeur.
Il est toujours possible d’utiliser les attributs, mais il faut les faire suivre du numéro de l’indice, par exemple :
Mon_Tab(1..10,1..5) of integer;……For i in Mon_Tab’Range(1) loop….
Les tableaux à 2 dimensions
L’agrégat de tableau à 2 dimensions prend une forme emboîtée, par exemple :
Tab : array (1..3, 1..2) of Integer :=( (1 , 3), (2 , 7), (18, 2) );
La complexité
Notion de complexité
Introduction– Par nature, plus un programme a de données à traiter, plus il prend du
temps à le faire.– Certains algorithmes se comportent mieux que d’autres lorsque le nombre
de données à traiter augmente. Exemple
– Supposons que pour exécuter une tâche précise sur N objects, l’algorithme A ait besoin de N secondes et l’algorithme B: N**2. Alors si l’on triple le nombre d’objects, l’algo A prend 3 fois plus de temps, mais l’algo B prend 9 plus de temps. L’algo B est donc moins efficace que l’algo A, on dit que sa complexité est supérieure à celle de l’algo A.
Notion de complexité
Définition– La complexité d’un algorithme est la donnée du terme prépondérant dans la
fonction donnant le nombre d’opérations élémentaires effectuées en fonction du nombre des données à traiter.
La notation de Landau– Edmund Landau, Mathématicien Allemand, a mis en place une notation
permettant de « comparer » des fonctions entre elles.– 1er formulation
• Soit – 2ieme formulation: en plus l’infini, avec des fonctions positives
)()(,/),()(, 000
xgkxfvxkXVvgOfXX
≤∈∀ℜ∈∃∈∃⇔=ℜ∈
)()(0,/,)( 00 NkgNfNNkNgOf ≤≤≥∀ℜ∈ℜ∈∃⇔=∞+
Notion de complexité
Exemples
Remarque 1 :– La notion de grand O permet de donner une borne supérieure pour une
fonction donnée. Remarque 2 :
– Calculer la complexité d’un algorithme revient par conséquent à trouver une fonction simple qui est un grand O de la fonction donnant le nombre d’opérations élémentaires effectuées en fonction du nombre de données à traiter
)(734 22 nOnn =−+
?1132=+
−−n
nn
Notion de complexité
Calculer la complexité des algorithmes suivants :– Exemple 1 :
Pour i allant de 1 à N Tab(i)2*Tab(i)
Fin Pour
– Exemple 2
Pour i allant de 1 à NS0Pour j allant de 1 à N
SS+Tab(j)Fin PourTab(i)S
Fin Pour
Notion de complexité
Quelques constations :– Un algorithme en O(1) est constant, il ne dépend pas de la quantité
d’informations en entrée.– Un algorithme en O(n) est dit linéaire– Un algorithme en O(n**2) a une complexité quadratique– Un algorithme en O(ln(n)) a une complexité logarithmique– Un algorithme en O(n**p) a une complexité polynomiale– Un algorithme en O(2**n) a une complexité exponentielle
Quelques remarques :– On peut démontrer que le meilleur algorithme de tri de tableau possède en
moyenne une complexité de O(n ln(n))– Les problèmes NP-complets : toute une classe de problèmes qui sont
résolus qu’avec des algorithmes qui ont une complexité exponentielle. Par exemple le problème du voyageur de commerce.
Les tableauxDeuxième partie
Les constantes
Il est possible lors de la déclaration d’une variable d’indiquer que cette variable est constante. Sa valeur ne pourra pas changer. Il est par conséquent nécessaire d’initialiser cette variable lors de sa déclaration.
Exemple :A : constant Integer:=19;Tab : constant array(1..3) of Integer :=(2,4,8);
On va utiliser A ou Tab dans un programme exactement de la même façon qu’une variable classique, mais il sera impossible de les modifier lors d’une affectation.
Les tranches
Il est possible de manipuler les tableaux par tranche de valeurs. Exemple 1:
Mon_Tab(2..5) correspond à un petit tableau contenant les valeurs numérotées de 2 à 5.
Exemple 2 :Mon_tab(1..4):=Mon_Tab(5..8); --affecte les valeurs des cases 5 à 8 aux cases
1 à 4. Remarque : Mon_Tab(1..4) est à considérer exactement comme un
nouveau tableau de taille 4. Il possède donc des attributs différents de Mon_Tab.
Les agrégats II
Nous avons vu la déclaration de tableaux « constants » via les agrégats. Il existe une syntaxe particulière pour simplifier l’écriture de ces agrégats.
Il est possible de spécifier des plages de valeurs pour l’affectation des cases, par exemple :
Tab : array (1..10) of Integer:=(1..5=>15 , 6..10=>23);
Ainsi, les cases de 1 à 5 sont initialisées à 15, et les cases de 6 à 10 sont initialisées à 23.
Il est également possible d’utiliser le mot-clé others, par exemple :Tab : array (1..10) of Integer:=(1=>14, 3=>17, others=>23);
pour cet exemple le tableau sera initialisé de la façon suivante :Tab:=(14,23,17,23,23,23,23,23,23,23);
Les agrégats II (suite)
La même logique s’applique pour les agrégats de tableaux à plusieurs dimensions. Par exemple :
Tab:array(1..3,1..3) of Integer:=(1=>(others=>7),others=>(2,3,6));
le tableau sera initialisé de la façon suivante :Tab:=((7,7,7),(2,3,6),(2,3,6));
Les types
Integer, Float,… sont des types prédéfinis de l’ADA. Il est possible de créer ses propres types afin d’accélérer la déclaration des variables, créer une unité logique, mais également de pouvoir comparer des variables entre elles,….
La syntaxe est la suivante :type Mon_Type is Sa_déclaration;Où :
– « Mon_type » est le nom choisi pour le type déclaré– « Sa_déclaration » spécifie le type.
Exemple :type Mes_Tab is array(1..20) of Integer;Nous pouvons alors utiliser Mes_Tab pour déclarer des tableaux d’entiers de taille 20.
Les types (suite)
Suite de l’exemple :Tab1,Tab2 : Mes_Tab;Tab3 : Mes_Tab;
où nous avons déclaré 3 tableaux d’entiers de taille 20. Ainsi les 2 déclarations suivantes sont « équivalentes » :
Tab1 : Mes_Tab;Tab1 : array(1..20) of Integer;
L’utilisation des types ne permet pas seulement de raccourcir les déclarations, mais également de créer un nouveau type, donc des variables de ce type. Il est intéressant de faire cette démarche afin de regrouper tous les objets ayant la même fonction.
Les types (suite)
Ainsi, si l’exemple précédent était :Tab1,Tab2 : Mes_Tab;Tab3 : array (1..20) of Integer;
Alors :Tab1:=Tab2; --Est possibleTab1:=Tab3; --Est impossible
De même que :Tab1(1..5):=Tab2(3..7); --Est possibleTab1(1..5):=Tab3(3..7); --Est impossible
Les types de tableaux
« type Mes_Tab is array(1..20) of Integer; » définit un tableau dit contraint car la taille du tableau est fixe (20 entiers). Il est possible de définir des tableaux non contraints, où la taille est spécifiée non pas à la déclaration du type mais à la déclaration de la variable tableau, par exemple :type Mes_Tab is array (Integer range <>) of Float;Tab1 : Mes_Tab(1..20);Tab2 : Mes_Tab(0..29);
Remarque 1 : <> peut se traduire par « à compléter » Remarque 2 : Tab1 et Tab2 sont toujours 2 objets du même
type, ainsi, il est possible de faire :« Tab1(1..10):=Tab2(11..20); »
Les types non contraints
Il est possible de généraliser les types non contraints aux tableaux à plusieurs dimensions. Ainsi par exemple un type Matrice pourrait se définir comme suit :
type Matrice is array(Integer range <>, Integer range <>) of Float;
ADA peut se servir de l’initialisation du tableau pour deviner sa taille, il est donc possible de taper :
type Mes_Tab is array(Integer range <>) of Float;Tab1 : Mes_Tab:=(1.23,2.0,4.8);
Tab1 est alors automatiquement créé comme un tableau de taille 3.
La concaténation
Définition : la concaténation de tableaux consiste à mettre bout à bout 2 tableaux afin de former un tableau de plus grande taille. L’opérateur de concaténation est le « et commercial » &
Exemple :type Mes_Tab is array(Integer range <>) of Float;Tab1 : Mes_Tab := (1.0,2.0);Tab2 : Mes_Tab := (3.0,4.0,5.0);Tab : Mes_Tab(1..5);….
Tab:=Tab1&Tab2; --Tab contient (1.0,2.0,3.0,4.0,5.0)Tab:=(2.0,3.0)&(1.0,4.0,5.0); --Tab (2.0,3.0,1.0,4.0,5.0)
Les chaînes de caractères
Définition : Une chaîne de caractères est un type servant à stocker des mots ou des phrases en ADA.
Syntaxe : Les chaînes de caractères en ADA sont simplement des tableaux de « Character ». Un type non contraint « string » est défini ainsi :
type String is array (Integer range <>) of Character; La manipulation des chaînes de caractères se fait donc
exactement de le même façon que les tableaux, par exemple on déclare une variable de la façon suivante :
Phrase : String (1..20); Ou encore « Phrase(1..5):=Phrase2(3..7); » pour affecter un
morceau d’une chaîne à une autre.
Les chaînes de caractères
Les chaînes de caractères étant fréquemment utilisées il existe une syntaxe particulière pour les agrégats : du texte entre guillemets, par exemple :
Phrase : String:=« Hello »; --va déclarer une variable Phrase de type String et va l’initialiser avec l’agrégat tableau (‘H’,’e’,’l’,’l’,’o’), notation habituelle pour les tableaux. Ces agrégats s’utilisent partout où il possible de mettre des agrégats normaux, par exemple :
Phrase : String(1..20);….Phrase(1..5):=« Hello »;
Les chaînes de caractères
L’opérateur de concaténation s’applique également sur les string. Ainsi il est possible de taper :
Phrase:=« Bonjour » & « le monde »; Put, Put_Line sont en fait des procédures qui acceptent en entrée
(comme arguments) des variables de type string. On peut par conséquent avoir des instructions comme :
Put_Line(Phrase); --avec Phrase une variable StringPut_Line(« Hello » & « le monde »);
Remarque : L’attribut Image du type Integer et Float fabrique un string avec son argument, par exemple : Integer’Image(X) avec X une variable Integer qui contient la valeur 3 est un string qui contient « 3 ».
Conclusion : on peut taper l’instruction suivante :Put_Line(« Le résultat est : » & Integer’Image(X));
Les chaînes de caractères
La saisie des chaînes et l’affichage des chaînes de caractères posent un dernier problème, il faut afficher le même nombre de caractères que l’on a tapé. On utilise pour cela la procédure Get_Line. Elle s’utilise de la façon suivante :Get_Line(Phrase,N);où :
• Phrase est une variable String qui sera affectée par le texte tapé• N est une variable Integer qui sera affectée par la longueur du texte tapé
Récapitulatif : l’extrait de programme suivant demande à l’utilisateur d’entrer une phrase, puis il la réaffiche à l ’écran.Phrase : String(1..20);N:Integer;…..Get_Line(Phrase,N);Put_Line(« Vous avez tapé » & Phrase(1..N));
Les Procédureset
les Fonctions
Problématique
Le raffinement d’un algorithme doit se traduire au sein du programme par un découpage des tâches.
Un programme est souvent amené à répéter la même suite d’instructions plusieurs fois, il serait intéressant de regrouper ces instructions dans un bloc, et « appeler » ce bloc au sein du programme quand nécessaire.
La réponse à ces questions passe par l’utilisation des fonctions et des procédures !
Les procédures
Définition : Une procédure permet de regrouper une suite d’instructions dans un programme ADA.
Syntaxe :procedure Ma_Proc is
Mes_Variables….begin
Le corps de la procédure….end Ma_Proc;
Les procédures
Portée et visibilité :with Ada.Text_Io;use Ada.Text_Io;procedure Mon_Programme is
A: Integer;
procedure Affiche isB: Integer;
beginGet(B);
end Affiche;begin
Put_Line(« Hello »);Affiche;Get(A);
end Mon_Programme;
Déclaration des packagesutilisés
Déclaration des variablespour le programme Mon_Programme
Procédure AFFICHE
Corps du programme principal
Les procédures
Règles : • Une procédure peut être appelée uniquement après avoir été définie• Cette règle s’applique également aux variables• Une variable définie au sein d’une procédure n’est accessible que dans
cette procédure. On dit que sa portée est limitée à la procédure.• Par contre les variables définies dans la partie déclarative du
programme principale sont accessibles pour toutes les procédures. Exemples :
• La procédure Affiche peut être appelée dans le corps du programme principal mais ne pourra pas être appelée dans une procédure définie avant elle-même.
• La variable B n’existe qu’à l’intérieur de la procédure Affiche. Ainsi le corps du programme principal n’a pas accès à B.
• Par contre la variable A est accessible à tous.
Un exemple completwith Ada.Text_Io;use Ada.Text_Io;with Ada.Integer_Text_Io; use Ada.Integer_Text_Io;
procedure exemple1 isA: Integer;
procedure Erreur isbegin
Put_Line(« Vous avez fait une erreur ! »);end Erreur;
beginPut_Line(« Saisissez un nombre pair divisible par 9 »); get(A);if A mod 2/=0 then
Erreur;elsif A mod 9/=0 then
Erreur;else
Put_Line(« Ok »);end if;
end exemple1;
Les paramètres
Définition : il est possible de passer des paramètres à la procédure afin de spécifier plus précisément son comportement.
Exemple 2 : On va appeler une procédure avec un entier et elle va le réafficher entr% cpochets.
Exemple 3 : On désire réaliser une procédure qui va afficher un tableau de type prédéfini Mes_Tab.
Exemple 2with Ada.Text_Io; use Ada.Text_Io;with Ada.Integer_Text_Io; use Ada.Integer_Text_Io;
procedure Exemple2 is
procedure Affiche(A : Integer) isbegin
Put(« [ »); Put(A,1); Put_Line(« ] »);end Affiche;
beginAffiche(17);Affiche(23);
end Exemple2;
Remarquez la syntaxepour le passage du paramètre
Exemple 3with Ada.Text_Io; use Ada.Text_Io;with Ada.Integer_Text_Io; use Ada.Integer_Text_Io;
procedure Exemple3 istype Mes_Tab is array (Integer range <>) of Integer;
Tab1 : Mes_Tab(1..10):=(others=>17);Tab2 : Mes_Tab(1..5):=(others=>12);
procedure Affiche(Tab : Mes_Tab) isbegin
for I in Tab’Range loopPut(« La note »); Put(I,1); Put(« est : »);Put(Tab(I),1); New_Line;
end loop;end Affiche;
beginAffiche(Tab1);Affiche(Tab2);
end Exemple3;
Les modes
Il est possible de spécifier un mode de passage des paramètres à une procédure.
Il existe 3 modes pour les paramètres :– in : C’est le mode par défaut, la procédure connaît la valeur
de la variable transmise mais elle ne pourra pas la modifier.– out : La procédure est alors appelée nécessairement avec
une variable (et non une constante) pour ce paramètre et tout changement du paramètre affecte cette variable.
– in out : Identique au mode out mis a part que le paramètre est initialisé avec la valeur d’appel de la variable.
Syntaxe : on spécifie le mode juste avant le type du paramètre. Cf exemple.
Exemple 4with Ada.Text_Io; use Ada.Text_Io;with Ada.Integer_Text_Io; use Ada.Integer_Text_Io;
procedure Exemple4 isB : Integer:=12;
procedure Change(A : out Integer) isbegin
A:=17;end Change;
BeginPut(B);Change(B);Put(B);
end Exemple4;
Mode « out » pour le paramètre A
Exemple 4 (suite)
Après l’exécution de la procédure Change, la variable B contient 17, si l’on avait omis le mode out, ce changement aurait été impossible.
Les paramètres (suite)
Une procédure peut comporter un nombre quelconque de paramètres tous avec leurs propres modes. Dans ce cas, les différents paramètres sont séparés par des points-virgules
Exemple 1 :procedure Ma_proc1(X : in Integer; Ok : out boolean)….
Ici, on définit une procédure avec 2 paramètres. Exemple 2 :
procedure Ma_proc2(X,Y : in Integer; Ok : out boolean)….
Ici, on définit une procédure avec 3 paramètres, les 2 premiers ayant le même type/mode, ils sont simplement séparés par une virgule.
Les fonctions
Définition : une fonction est simplement une procédure qui renvoie elle-même une valeur.
Syntaxe : function Ma_Fonction return Son_Type is
Mes_Variables….begin
Le corps de la fonction….end Ma_Fonction;
Où : Son_Type est le type renvoyé par la fonction Une fonction peut avoir des paramètres, mais ils sont tous
obligatoirement du mode in.
Exemple 5with Ada.Text_Io; use Ada.Text_Io;with Ada.Integer_Text_Io; use Ada.Integer_Text_Io;
procedure Exemple5 isB : Integer;
function Carre(A : Integer) return Integer isbegin
return A**2;end Carre;
beginB:=Carre(4);Put(B);
end Exemple5; Le programme affiche 16 !
Les fonctions (suite)
L’utilisation du mot clé return à l’intérieur du corps de la fonction a 2 utilités :
– Spécifier la valeur à retourner– Arrêter la fonction et rendre la main à l’appelant.
Il est donc possible d’avoir plusieurs return dans le corps de la fonction, par exemple :…..if A/=0 then
return 12;else
return 44;end if;…..
La récursivité
Définition : Résoudre un problème à l’aide de la récursivité consiste à utiliser une fonction qui s’appelle elle-même.
Exemple classique : le calcul de la factorielle. Le principe est l’écriture d’une fonction qui retourne la factorielle de son argument (paramètre). La récursivité est basée sur la formule : n!=n*(n-1)! La fonction va s’utiliser elle-même pour le calcul de (n-1)! et va simplement multiplier le résultat par n. Il ne reste plus qu’à définir la factorielle de 0 au sein de la fonction.
Exemple 6with Ada.Text_Io; use Ada.Text_Io;with Ada.Integer_Text_Io; use Ada.Integer_Text_Io;
procedure Exemple6 isB : Integer;
function Factorielle(N : Integer) return Integer isbegin
if N=0 thenreturn 1;
elsereturn N*Factorielle(N-1);
end if; end Factorielle;
beginPut(Factorielle(4));
end Exemple6;
Les articles
Les articles
Définition : créer un article, c’est créer un groupe de variables qui ont un sens commun.
Exemple : on veut sauvegarder une date au sein d’une variable, on crée alors un article « Date » composé de 3 entiers pour enregistrer le jour, le mois et l’année.
Syntaxe :– Pour la déclaration, on doit créer un nouveau type de la façon
suivante :type Date is
recordJour : Integer;Mois : Integer;Annee : Integer;
end record;
Les articles
Syntaxe (suite) :– Et pour la déclaration d’une variable, on utilise le format habituel
Ma_Date : Date;– Pour accéder au contenu de la variable « Ma_Date », c’est-à-dire
accéder aux différents champs qui la composent, on utilise le point :
Ma_Date.Jour:=14;Ma_Date.Mois:=7;Ma_Date.Annee:=1789;
– Ainsi « Ma_Date.Jour » peut être utilisée comme une variable de type Integer quelconque.
Exemple 1with Ada.Text_Io; use Ada.Text_Io;with Ada.Integer_Text_Io; use Ada.Integer_Text_Io;
procedure Exemple1 istype Date is
recordJour, Mois, Annee : Integer;
end record;Ma_Date : Date;
beginPut(« Entrer le jour : » ); Get(Ma_Date.Jour);Put(« Entrer le mois : »); Get(Ma_Date.Mois);Put(« Entrer l’année : »); Get(Ma_Date.Annee);Put(« Votre Date est : »);Put(Ma_Date.Jour,1); Put(« / »);Put(Ma_Date.Mois,1); Put(« / »);Put(Ma_Date.Anne,1); New_Line;
end Exemple1;
Définition du type
Déclaration de la variable
Les articles
Remarque : on constate bien l’intérêt de l’article dans l’exemple pour son rôle d’unité logique englobant dans une seule variable la notion de date. Il devient alors possible de copier des dates, échanger des dates, passer des dates comme arguments à une procédure ou une fonction,….
Deuxième exemple : la procédure suivante va afficher une variable Date passée en argument,….
procedure Affiche(X : Date) isbegin
Put(X.Jour,1); Put(« / »); Put(X.Mois,1);Put(« / »); Put(X.Anne,1);
end Affiche; Ainsi, pour afficher Ma_Date, il suffit de faire dorénavant :
Affiche(Ma_Date);
Les articles
Remarque 1 : il est possible d’initialiser un article avec des articles constants. Par exemple :
Ma_Date : Date := (14,7,1789); Ou encore au sein du programme :
Ma_Date := (14,7,1789); Remarque 2 : il est également possible de donner des valeurs
par défaut aux variables d’un article :type Date is
recordJour : Integer := 14;Mois : Integer := 7;Anne : Integer :=1789;
end record;
Les articles
Suite des 2 remarques : attention l’initialisation et les valeurs par défaut ne donne pas le même résultat :
– Avec les valeurs par défaut chaque variable créée sera initialisée automatiquement avec ces valeurs
– Quand à l’initialisation avec un article constant, c’est une initialisation ponctuelle réservée uniquement à la variable concernée. Il est d’ailleurs possible d’initialiser une variable avec un article constant même si l’article possède des valeurs par défaut.
Remarque 3 : puisque « Date » est maintenant un nouveau type, on peut l’utiliser partout où l’on peut mettre un type. Il est donc possible de faire, par exemple, un tableau de « Date »
Mes_Dates : array (1..10) of Date;
qui va déclarer un tableau de 10 variables de type « Date ». On accède au « Mois » de la variable 5 par :
Mes_Dates(5).Mois:=7;
Le type énumératif
Les énumérations
Définition : il est parfois nécessaire de manipuler des variables pouvant prendre des valeurs parmi un groupe fini fixé, on utilise pour cela le type énumératif.
Exemple : on veut définir un type « Couleur » pouvant prendre 3 valeurs : le vert, l’orange et le rouge. On va alors créer un type énumératif « Couleur », composé des 3 couleurs possibles (Vert, Orange, Rouge).
Syntaxe : en Ada on réalise cela via la déclaration de type :type Couleur is (Vert, Orange, Rouge);
on peut ensuite déclarer une variable du type « Couleur »Ma_Couleur : Couleur;
puis l’utiliser au sein du programme avec des instructions du style : Ma_Couleur:=Orange; --dans une affectation…..If Ma_Couleur=Rouge then --au sein d’un test….
….
Les énumérations
Remarque 1 : de nouveau, on crée une unité logique avec la déclaration d’une énumération. Nous pouvons manipuler la notion de couleur avec facilité via l’utilisation du type « Couleur ».
Remarque 2 : « Couleur » est maintenant un nouveau type, nous pouvons par conséquent l’utiliser partout à la place d’un type quelconque. Par exemple, un tableau de couleur, ou encore au sein d’un article.
type Rectangle isrecord
largeur, longueur : Integer;C : Couleur;
end record;
Les énumérations
Remarque syntaxique : Tous les types énumératifs possèdent un certain nombre d’attributs parmi :
– First : qui renvoie la première valeur possible : ici Vert– Last : qui renvoie la dernière valeur possible : ici Rouge– Succ : qui renvoie la valeur située juste après son argument, par
exemple : Couleur’Succ(Orange) donne Rouge– Pred : la même chose avec le prédécesseur.– Pos : qui renvoie la position dans la liste de son argument, par
exemple : Couleur’Pos(Orange) donne 2.– Val : qui renvoie la valeur à la position de son argument, par
exemple : Couleur’Val(2) donne Orange. – Enfin, il est possible d’utiliser les opérateurs < > <= >= avec les
énumérations, par exemple Vert<Rouge retourne VRAI mais Orange>=Rouge retourne FAUX.
Les énumérations
Remarque 1 : le type Booleen n’est rien d’autre qu’une énumération particulière:
type Booleen is (False, True); Remarque 2 : comme tout type il est possible d’initialiser les
variables lors de leurs déclarations.Ma_Couleur : Couleur := Vert;
La surcharge
La surcharge
Définition : la surcharge consiste à donner le même nom à 2 procédures (ou à 2 fonctions), la distinction entre les 2 procédures va se faire sur le type des arguments de la procédure.
Exemple :procedure Affiche(X : Integer) isbegin
Put(X,1);end Affiche;
procedure Affiche(X : Float) isbegin
Put(X,1);end Affiche;
La surcharge
Exemple (suite) : alors si on a :X: Integer;Y:Float;
alors « Affiche(X) » va appeler la première procédure et « Affiche(Y) » la seconde.
Remarque 1 : on comprend maintenant pourquoi la procédure « Put » est capable d’afficher plusieurs types de variables. En effet il s’agit en fait de procédures différentes portant toutes le même nom.
Remarque 2 : le cas des fonctions n’est pas différent de celui des procédures, la distinction entre 2 fonctions portant le même nom se fait sur les arguments de ces fonctions, et dans certain cas sur le type renvoyé. Attention cependant, le compilateur doit toujours être capable de savoir quelle fonction appeler, dans le cas contraire, on parle d’ambiguïtés.
function Carre(X:Integer) return Integer is ….function Carre(X:integer) return Float is…. Cette surcharge peut-être ambiguë.
La surcharge
Remarque 3 : la surcharge est très pratique, elle permet de nouveau de créer une unité logique : on peut donner un même nom à une même action mais sur des objets différents. L’exemple le plus évident étant l’instruction « Put ».
L’exemple suivant est le début du TP N°8 : on désire travailler avec les complexes en ADA. Pour cela on définit un type C pour enregistrer un nombre complexe, puis une série de fonctions/procédures se reportant aux complexes. L’exemple propose une implémentation de la procédure « Put » pour l’affichage de ce nouveau type, il est rudimentaire, vous aurez l’occasion de l’améliorer lors du TP.
La surcharge
…..type C is
recordRe,Im : Float;end;
procedure Put(Z : C) isbegin
Put(Z.Re,1,4,0); Put(« + »);Put(Z.Im,1,4,0); Put(« *i »);
end Put;…….
A,B:C;begin
….Put(A);…..Put(B);….
La surcharge d’opérateurs
La surcharge d’opérateurs
Définition : il est possible avec les langages modernes et avec l’ADA en particulier de surcharger les opérateurs eux-mêmes afin d’étendre le champ d’action de ces opérateurs.
Exemple : Continuons l’exemple des complexes vu précédent. On désire maintenant pouvoir taper dans un programme directement le code suivant :
….X,Y,Z : C
begin…..Z:=X+Y;…..
La surcharge d’opérateurs
Le code suivant pose problème puisque l’opérateur « + » n’est pas défini pour fonctionner avec nos articles « C ». Il faut donc créer une définition de « A+B » avec A et B de type « C ». Pour cela on va surcharger l’opérateur « + » de la façon suivante :
….function « + » (X,Y : C) return C isbegin
return (X.Re+Y.Re,X.Im+Y.Im);end « + »;
On remarque que la définition correspond à celle d’une fonction classique, mis à part son nom « + », les guillemets faisant parti de la syntaxe.
La surcharge d’opérateurs
Remarque 1 : ceci reste logique avec la notion d’opérateur, car finalement l’addition peut être vu comme une fonction de RxRR, …..
Remarque 2 : Encore une fois la surcharge d’opérateur permet de continuer l’unité logique réalisée sur les complexes. Maintenant, il est possible additionner 2 complexes au sein d’un programme aussi simplement que 2 entiers. Ce concept peut bien-sûr être étendu à tous les types définis par l’utilisateur….
La liste des opérateurs qu’il est possible de surcharger est la suivante :
abs and mod not or rem xor= /= < <= > >=+ - * / ** &
La structure declare
La structure declare
Définition : il est possible de déclarer des variables dans le corps d’une procédure ou d’une fonction. On utilise pour cela une structure declare
Syntaxe :declare
Déclaration des variablesbegin
Corps de la structure declareend
On remarque que la syntaxe est la même que pour une fonction ou une procédure, son utilisation est donc identique.
Remarque 2 : l’ensemble de la structure de declare à end porte également le nom de bloc
La structure declarewith Ada.Text_Io; use Ada.Text_Io;procedure Exemple1 is
function Get_String return String isTampon : String(1..256);N : Integer;
beginGet_Line(Tampon,N);return Tampon(1..N);
end Get_String;begin
loopPut_Line(« Saisissez une phrase »);declareTexte:String:=Get_String;beginPut_Line(« Vous avez saisi : « & Texte);end;end loop;
end Exemple1;
La structure declare
L’exemple précédent réalise la saisie d’une phrase via la fonction Get_String. La variable Texte du programme principale est recréée à chaque passage de la boucle, sa taille n’est pas fixe, elle varie avec le texte servant à l’initialisation.
On remarque également dans cet exemple qu’il est possible d’utiliser des calculs ou des fonctions dans l’initialisation d’une variable.
L’exemple suivant montre l’intérêt des blocs avec les tableaux
La structure declare
with Ada.Text_Io; use Ada.Text_Io;with Ada.Integer_Text_Io; use Ada.Integer_Text_Io;
procedure Exemple2 isN: Integer;
beginPut(« Quelle taille pour le tableau : »); Get(N);declare
Tab : array(1..N) of Integer;begin
for i in Tab’range loopGet(Tab(I));
end loop;…..
end;end Exemple2;
La structure declare
On voit sur l’exemple qu’il est possible de déclarer le tableau après avoir saisi sa taille et ainsi utiliser exactement le bon nombre de cases en mémoire. Les avantages étant :
– Il n’y a pas de gaspillage de mémoire– Et surtout l’utilisateur n’est pas restreint à un choix arbitraire de
taille fixée lors de l’écriture du programme. (taille fixée à 50 dans les 1er TPs)
Les paquetages
Les paquetages
Définition : les paquetages (packages en anglais) facilitent l’écriture de grands programmes :
– En découpant le code source en plusieurs fichiers plus petits donc plus lisibles.
– En regroupant par unité logique toutes les fonctions/procédures/types ayant un sens commun.
Exemple : reprenons le type complexe défini dans les diapos précédentes. Une fois toutes les fonctions/procédures relatives aux complexes écrites, on comprend l’utilité de les regrouper dans un paquet. Ceci fait, il est possible pour chaque programme désirant travailler avec les complexes de spécifier dans l’en-tête l’utilisation du paquet complexe.
Syntaxe
L’écriture d’un paquetage se fait en 2 étapes :– La première consiste à créer un fichier de spécification d’extension
« ads » (s pour spécification), fichier qui va contenir la description du paquet pour les futurs programmes désirant utiliser notre paquetage.
– La deuxième consiste à écrire un fichier d’extension « adb » (b pour body) qui contient notre paquetage proprement dit.
L’exemple suivant illustre le concept par la création d’un paquetage « Politesse » contenant 2 procédures.
Exemple1
Le fichier politesse.ads :package Politesse is
procedure Bonjour (Qui : String);procedure Formule_Fin;
end Politesse; Le fichier politesse.adb :
package body Politesse isprocedure Bonjour(Qui : String) isbegin
Put_Line(« Cher Monsieur »&Qui);end Bonjour;procedure Formule_Fin is
Put_Line(« Veuillez accepter mes salutations bla bla bla…. »);end Formule_Fin;
end Politesse;
Exemple 1 (Suite)
Un exemple de programme utilisant notre paquetage :with Ada.Text_Io; use Ada.Text_Io;with Politesse;use Politesse;
procedure Exemple1 isbegin
Bonjour(« Henri »);Put_Line(« Ramène le CD-ROM,…. »);Formule_Fin;
end Exemple1; La compilation de « Exemple1 » se fait comme d’habitude :
« gnatmake exemple1 », le compilateur va automatiquement voir qu’il y a un paquetage utilisé et vérifier son contenu.
With/Use
Avant de pouvoir utiliser un paquetage dans un programme, il est nécessaire de le préciser avec « with Mon_Paquet ».
Le mot-clé « use » a une autre utilité, il permet d’utiliser les procédures/fonctions/… du paquet sans devoir préciser le nom du paquetage devant chaque procédures/fonctions/…
L’exemple suivant reprend le programme Exemple1 précédent, mais sans la ligne « use Politesse ». Remarquez alors les changements dans le reste du programme.
Exemple2
with Ada.Text_Io; use Ada.Text_Io;with Politesse;
procedure Exemple2 isbegin
Politesse.Bonjour(« Henri »);Put_Line(« Ramène le CD-ROM,…. »);Politesse.Formule_Fin;
end Exemple2; Comme vous pouvez le constater il est nécessaire de spécifier
« Politesse. » devant chaque objet du package afin de pouvoir l’utiliser. On va utiliser cette possibilité dans les cas où plusieurs objets sont susceptibles de porter le même nom.
E/S fichiers
Introduction But : On veut pouvoir lire et écrire des fichiers textes ou de
données à partir d’un programme ADA. Mise en œuvre : l’ADA fournit plusieurs techniques permettant
de réaliser cette tâche. Ces différentes techniques correspondent à des niveaux d’abstractions différents (du plus simple au plus compliqué). On va voir 2 techniques différentes :– Une première générique, afin de lire/écrire dans des fichiers des
données quelconques, avec le package Sequential_Io– Une deuxième technique utilisant le package Ada.Text_Io, plus
simple, mais ne permettant de lire uniquement que des fichiers textes.
Sequential_Io Sequential_Io est un paquet particulier car c’est un paquet
générique. La généricité permet l’écriture en une seule fois de paquets quasi-identiques, paquets qui différent uniquement par exemple sur un type de variable manipulée. (cf les vecteurs, les piles, les conteneurs en général, …)
Il est nécessaire par conséquent d’instancier le paquet en spécifiant en argument « la variable » utilisée. Par exemple, si on veut lire/écrire des Integer dans un fichier, on commence par créer un nouveau paquet de cette façon:package Lecture_Integer is new Sequential_Io(Integer);
Une fois créé ce paquet s’utilise comme les autres, par exemple avec un use, même si pour ce paquet ce n’est pas conseillé.
Sequential_Io Une fois créé le paquet Lecture_Integer possède les
fonctions/procédures/types suivants :– File_Type : type a instancier pour manipuler les fichiers– File_Mode : ùn䁭 ération pour spécifier le type d’accès
désiré (In_File pour lire, Out_file pour écrire, Append_File pour ajouter à la fin)
– Les procédures Create(…) et Open(…) pour créer ou ouvrir un fichier
– Read(…) et Write(…) pour lire et écrire dans le fichier.– La fonction End_Of_File(File: in File_Type) return Boolean
qui renvoie VRAI si la fin du fichier est atteinte.– … cf John Barnes
Exemplewith Sequential_Io;with Ada.Integer_Text_Io;use Ada.Integer_Text_Io;
procedure Exemple ispackage Lecture_Integer is new Sequential_Io(Integer);use Lecture_Integer;Mon_Fichier:File_Type;Valeur:Integer;
beginOpen(Mon_Fichier,In_File, « fichier.dat »);while not End_Of_File(Mon_Fichier) loopRead(Mon_Fichier,Valeur);Put(Valeur,1); New_Line;end loop;Close(Mon_Fichier);
end Exemple;
Ada.Text_Io Outre les fonctions Put_Line, … le package
Ada.Text_Io contient les procédures/fonctions/types suivants :
File_Type : pour manipuler des fichiers textesFile_Mode: qui prend également les valeurs In_File, Out_file ou
Append_Fileprocedure Create(File: in out File_Type;Mode in
File_Mode:=Out_File; Name: in String:=« »; Form: in String:=« ») pour créer un fichier de nom name sur le HD.
procedure Open(… idem create …) pour ouvrir un fichierprocedure Close(File: in out File_Type)procedure Get(File: in out File_Type; Item: out Character) qui va
lire le prochain caractère dans le fichier et le stocker dans Itemprocedure Put(File: in out File_Type;Item: in Character) qui va
écrire le caractère dans le fichier « File »
Ada.Text_Io L’exemple qui va suivre va ouvrir un fichier
« texte.txt » supposé dans le répertoire courant puis va afficher les 10 premiers caractères du fichier à l’écran. (Le fichier est donc supposé assez grand). Puis ferme l’accès au fichier.
Ada.Text_Iowith Ada.Text_Io;use Ada.text_Io;procedure Exemple2 is
Mon_Fichier:File_Type;Mon_Caractere:Character;
beginOpen(Mon_Fichier,In_Type, « texte.txt »);for I in 1..10 loop
Get(Mon_Fichier,Mon_Caractere);Put(Mon_Caractere);
end loop;Close(Mon_Fichier);
end Exemple2;
Ada.Command_Line
Ada.Command_Line Ce package permet aux programmes ADA d’accéder aux
arguments de la ligne de commande qui a servi à invoquer le programme.
Exemple : quand on tape «emacs exemple.adb»– emacs est le nom du programme à exécuter et– exemple.adb est son argument.
Ada.Command_Line Pour accéder aux arguments ce package contient (entre autres)
les 3 fonctions suivantes:
function Argument_Count return Natural; qui renvoie le nombre d’arguments situés sur la ligne de commande.
function Argument(Number: in Positive) return String; qui renvoie l’argument numéro Number
function Command_Name return String; qui renvoie le nom du programme lancé.
L’exemple suivant affiche tous les arguments situés sur la ligne de commande. Donc si ce programme est appelé avec « essai riri fifi loulou », il va afficher riri, fifi et loulou.
Ada.Command_Linewith Ada.Text_Io;use Ada.Text_Io;with Ada.Command_Line;use Ada.Command_Line;
procedure Essai isbegin
for i in 1..Argument_Count loopPut_Line(Argument(i));
end loop;end Essai;
Le traitement des exceptions
Exception
Définition : lorsque le programme se trouve dans une situation qu’il ne sait pas gérer une erreur durant l’exécution d’un programme ou alors pour gérer un cas exceptionnel
Le programme va récupérer, ou générer, une exception pour que cette erreur soit :
1. Prise en compte2. Interprétée3. Gérée
Exemple
with Ada.Text_io;use Ada.Text_io;with Ada.Integer_Text_io;use Ada.Integer_Text_io;with Ada.Float_Text_io;use Ada.Float_Text_io;procedure Erreur is Val:Integer range 1..9;begin Put("Entrer une valeur : "); Get(Val); New_Line; Put(Val,2); New_Line;end Erreur;
Exemple
Cas d’utilisation normal :Entrer une valeur : 1La valeur saisie est : 1 Premier cas d’erreur :Entrer une valeur : Totoraised ADA.IO_EXCEPTIONS.DATA_ERROR Deuxième cas d’erreur :Entrer une valeur : 12raised CONSTRAINT_ERROR
Exception
Les évènements qui déclenchent des exceptions sont:– end_of_file– queue_overflow– divise_by_zero– storage_overflow– …
Exceptions prédéfinies
Constraint_Error (Numeric_Error) : qui correspond généralement à un dépassement des bornes, ce qui inclut le cas des problèmes en arithmétique tel que la division par zéro;
Program_Error : qui apparaît si nous tentons de violer d’une certaine façon la structure de contrôle, comme lorsqu’on atteint un end dans une fonction, lorsque l’on viole les règles d’accessibilité ou qu’on appelle un sous-programme dont le corps n’a pas encore été élaboré;
Storage_Error : qui apparaîtra en cas de dépassement mémoire, par exemple, en cas d’appel de la fonction récursive Factorielle avec un paramètre trop grand;
Tasking_Error : qui est levée si une tâche fait appel à une tâche avortée ou est le résultat d’un échec de communication entre 2 tâches
Cadre de Traite Exception
La syntaxe d'un bloc avec une partie traite_d'exception est la suivante:
beginSuite_D_Instructions
exceptionTraite_Exception{Traite_Exception}
end;Traite_Exception ::=
when Choix_D_Exception{ | Choix_D_Exception} =>Suite_D_Instruction
Choix_D_Exception ::= Nom_D_Exception | [paramètre_de_choix :] others
Cadre de Traite Exception
Exemplebegin
-- suite d'instructionsexception
when Singularité | Numeric_Error =>Put ("La matrice est singulière");
when Storage_Error =>Put ("Mémoire insuffisante");
when others =>Put ("Erreur fatale");raise Erreur;
end;
Blocs
Ada permet des déclarations locales et le traitement d'exception dans une suite d'instructions par l'intermédiaire des instructions de bloc.
La syntaxe est:instruction_bloc ::=
[identificateur_de_bloc:][declare
liste_de_déclaration]begin
suite_d_instructionsexception
traite_d_exception{traite_d_exception}
end; Les blocs sont utilisés pour optimiser un programme et pour traiter
localement les exceptions.
Déclaration d’exceptions
Les exceptions peuvent être déclarées dans la partie déclarative d'un module.
La syntaxe est:nom_d_exception : exception;
Déclenchement d’exceptions
Une exception est déclenchée par l'énoncé raise:– raise [nom_d_exception] [with littéral_chaîne];
Exemple :– raise; -- lever l’exception courante– raise Une_Exception;– raise Une_Autre_Exception with “Un message relié à
l’exception”; La vérification des exceptions prédéfinies peut être
supprimée à l'exécution par l'utilisation du pragma SUPPRESS.– pragma Suppress ( Index_Check, Service);– pragma Suppress (Range_Check);
Exemple de programme : Lecture d’un entier sécuriséwith Ada.Text_io; use Ada.Text_io;with Ada.Integer_Text_io; use Ada.Integer_Text_io;procedure Erreur is function Lit_Entier return Integer is Val: Integer range 1..8; begin loop begin Get(Val); exit; exception when DATA_ERROR => Skip_Line; Put("Valeur incorrecte !"); New_Line; Put("Recommencez..."); New_Line;
end; end loop; return Val; end Lit_Entier;begin Put(Lit_Entier);end Erreur;
Exemple de programme : Lecture d’un entier sécurisé Exécution :
Entrez une valeur : TotoValeur incorrecte !Recommencez...Entrez une valeur : 44
Mais :Entrez une valeur : TotoValeur incorrecte !Recommencez...Entrez une valeur : 100raised CONSTRAINT_ERROR
On a pas géré le cas où on rentre une valeur plus grande que 8, il faut donc modifier le programme
Exemple de programme : Lecture d’un entier sécuriséwith Ada.Text_io; use Ada.Text_io;with Ada.Integer_Text_io; use Ada.Integer_Text_io;with Ada.Float_Text_io; use Ada.Float_Text_io;procedure Erreur is function Lit_Entier return Integer is Val: Integer range 1..8; begin loop begin Put("Entrez une valeur : "); Get(Val); exit; exception when DATA_ERROR => Skip_Line; Put("Valeur incorrecte !"); New_Line; Put("Recommencez..."); New_Line;
when CONSTRAINT_ERROR => Skip_Line; Put("Vous devez entrez une
valeur entre 1 et 8 !"); New_Line; Put("Recommencez..."); New_Line; end; end loop; return Val; end Lit_Entier;begin Put(Lit_Entier,1);end Erreur;
Exemple de programme : Lecture d’un entier sécurisé