Académique Documents
Professionnel Documents
Culture Documents
WWW - Cours Gratuit - Com CoursAda Id4912
WWW - Cours Gratuit - Com CoursAda Id4912
Tour d'horizon --
des --
with Ada.text_io; use Ada.text_io; -- ignorer pour l'instant
fonctionnalités clefs du langage ADA procedure Exemple2 ; is
Stéphane MARIEL Package int_io is new Ada.Text_Io.integer_io(Integer); use
Int_Io; -- idem
value : integer;
Avant Propos procedure Bar(a: in integer) is
Le langage ADA est un langage à part parmi tous les dialectes informatiques. Défini comme la i: integer := 1;
réponse à un appel d'offre du ministère américain à la défense (DoD), norme ISO, il présente begin
i := 4;
une richesse fonctionnelle étonnante (ceci dès sa première version en end Bar;
1983) tout en mettant en oeuvre des mécanismes stricts garantissant la function Foo(B: in Integer) return integer is
conformité des programmes à l'exécution. I: integer := 3;
Aujourd'hui ce langage peu mis en avant est utilisé dans l'industrie begin
aéronautique et de défense dans le monde entier. return i;
end Foo;
Le nom du langage fut choisi en hommage à Lady Ada Byron, comtesse
begin
de Lovelace, assistante de Babbage et considérée comme le premier bar(Value);
programmeur de l'histoire. Value := foo(4);
put("hello world!"); new_line;
put(value); new_line;
I. Structure d'un programme
La base syntaxique d'ADA est le langage Pascal. Rien d'original en la matière donc. Leend;
langage distingue procédures et fonctions comme il se doit et toute procédure peut être
choisie pour sous-programme principal (en C il s'agit de main). Il faut noter que les fonctions n'acceptent que des paramètres en lecture seule. Ceci afin de
-- mon premier programme ada limiter les effets de bord. Enfin, en ADA, toutes les procédures et fonctions sont
-- hello world ! surchargeables, sous réserve d'avoir des signatures (prototypes) différentes, valeurs par défaut
with text_io; use text_io;
procedure exemple1 is exclues.
appelées non pas avec la notation pointée habituelle mais avec la quote. II. Exceptions
-- un exemple de type enuméré, avec utilisation de la qualification
with Ada.text_io; use Ada.text_io; ADA complète la syntaxe de base du langage par le support des
procedure exemple4 is exceptions. Un support qui pourra paraître simpliste au regard des
type couleur is ( blanc, bleu, jaune, rouge, vert, orange); mécanismes offerts par exemple dans Java. La réalité est qu'un tel
package couleur_io is new ada.Text_io.enumeration_io(couleur); niveau est probablement très suffisant.
ale
use couleur_io;
Le langage propose un type de données : exception. Chacun peut
ion norm
c : couleur := bleu;
naturellement déclarer de nouvelles exceptions (en plus de celles
Exécut
begin définies par défaut). L'exception en ADA s'assimile à un signal
put(c); new_line; nommé, elle ne porte pas d'information additionnelle.
put(Couleur'pred(C)); New_line; Lorsque qu'une exception est déclenchée (on dit levée) le signal se
end exemple4;
propage en remontant la pile des blocs d'instructions puis des sous-
programmes, ceci tant qu'aucun bloc de traitement n'est rencontré.
Au pire, si même le sous-programme principal ne comporte aucun
Les tableaux : intervalles et agrégats bloc pour traiter l'exception, l'exécution du programme est stoppée.
Le bloc de traitement des exceptions peut être vu comme le switch du langage C. Chaque
Contrairement au langage C, un tableau peut être indexé par tout intervalle d'un type discret,exception peut recevoir un traitement dédié, ou un traitement global peut être exécuté pour un
cela inclut donc les types énumérés, les entiers, et les types dérivés. ensemble d'exceptions.
Les bornes de l'intervalle sont librement fixables. L'instruction raise permet de lever une exception explicitement. Les exceptions définies dans le
langage sont elles le plus souvent levées par le runtime.
Enfin il est possible d'utiliser la notion d'agrégat (un équivalent à { ... } en C) pour initialiserA noter que les exceptions sont présentes dans le langage depuis 1983.
un tableau en une seule fois. En ADA l'agrégat est donné entre parenthèses, on peut initialiserwith text_io; use text_io;
les valeurs par position, par nom (notamment pour les index de types énumérés), enfin laprocedure Exemple6 is
clause others permet de donner une valeur par défaut à tous les éléments non encore Monexception : exception;
procedure Foo(I : in Integer := 0) is
initialisés du tableau. begin
with ada.text_io; if I < 0 then
procedure exemple5 is raise Constraint_Error;
type couleur is ( bleu, rouge, vert, jaune , blanc ); elsif I > 10 then
package int_io is new ada.text_io.integer_io(integer); raise Monexception;
end if;
end Foo;
begin with text_io; use text_io;
begin package body ComplexPkg is
Foo(-4); package real_io is new float_io(float); use real_io;
exception procedure Set ( Z: out Complex; A, B : in Float := 0.0) is
when Constraint_Error => begin
put("Ok, il n'y a pas mort d'homme."); new_line; Z.X := A; Z.Y := B;
raise Monexception; end Set;
end; function Getr (Z : in Complex) return Float is
exception begin
when others => return Z.X;
Put("Rah! Mieux vaut en finir"); new_line; end Getr;
end Exemple6; function Geti (Z : in Complex) return Float is
begin
return Z.Y;
end Geti;
III. Modèle de composants function I return Complex is
tmp : complex ;
Au delà des améliorations apportées au langage Pascal, ADA introduit une approche begin
modulaire du développement en permettant la compilation séparée de portions du code. Ces Set ( tmp, 0.0, 1.0);
return Tmp;
différents unités de compilation vont permettre de mettre en oeuvre des approches dites top-
end I;
down et bottom-up. procedure Put(Z: in Complex) is
begin
Parmi les unités de compilation, ADA introduit la notion de Packages. Ces packages vont
Put("["); Put(Z.X); Put(", "); Put(Z.Y); Put("]");
permettre la définition de bibliothèques (approche bottom-up). end Put;
begin -- initialisation optionnelle
III.1. Packages null;
end ComplexPkg;
Les packages ADA sont donc des librairies réutilisables. Chacun dispose d'une spécification et
d'une ou plusieurs implantations.
A ce stade on dispose d'un modèle de composant satisfaisant mais n'offrant aucun niveau de
Cette séparation va permettre de tirer profit des différents modes de développement (top-downprotection des données. Ainsi un type de données défini dans la spécification d'un composant
ou bottom-up). En effet, spécification comme implantation sont des unités de compilation etverra son implantation librement accessible, avec le risque évident de dysfonctionnement à la
sont compilables séparément. On pourra donc compiler un programme principal avant sesmoindre mise à jour.
composants, tester des composants en priorité ou encore développer des implantations de
Pour contrer ces mauvaises pratiques potentielles, ADA complète son modèle composant en
test.
affinant la notion de spécification, désormais partitionnée en deux blocs : une partie publique
L'instruction package est utilisée seule pour définir les spécifications d'une librairie. Pouret une partie privée.
l'implantation on utilisera le couple : package body.
On pourra donc se contenter d'indiquer l'existence d'un type de donnée dans la partie
package ComplexPkg is publique, quand son implantation sera réservée à la partie privée. Pour un tel type de données
type Complex is record aucun accès direct à l'implantation n'est possible. Seules les primitives proposées par le
X,Y : Float := 0.0;
end record; package permettront d'obtenir ou de fixer les valeurs de variables du type concerné.
procedure Set ( Z: out complex; A, B : in Float := 0.0); package ComplexPkg is
function Getr (Z : in Complex) return float; type Complex is private;
function Geti (Z : in Complex) return Float; procedure Set ( Z: out complex; A, B : in Float := 0.0);
function i return complex; function Getr (Z : in Complex) return float;
procedure Put(Z: in Complex); function Geti (Z : in Complex) return Float;
end ComplexPkg; function i return complex;
procedure Put(Z: in Complex); En outre il est possible de définir des extensions privées d'une librairie, soit pour traiter des
private éléments internes, soit encore pour permettre des extensions vendeur (en fonction du matériel
type Complex is record
X,Y : Float := 0.0; par exemple).
end record; with Ada.Numerics;
end ComplexPkg; private package Complexpkg.Internals is
type PolComplex is private;
function Cart2pol(Z: in Complex) return Polcomplex;
Lorsqu'une unité de compilation doit faire appel à un package, l'instruction with est utilisée. private
subtype Positivefloat is Float range 0.0 .. Float'Last;
Elle permet à la fois de disposer d'une visibilité sur les types et sous-programme définis, mais subtype Angle is Float range -Ada.Numerics.PI .. Ada.Numerics.PI;
instruit aussi le compilateur pour les opérations de link futures. On peut imaginer que type Polcomplex is record
l'instruction with équivaut au couple #include, -lXXX du langage C. R : Positivefloat := 0.0;
A : Angle := 0.0;
with ComplexPkg; end record;
procedure exemple7 is end Complexpkg.Internals;
z1, z2: ComplexPkg.complex;
begin
ComplexPkg.set(z1, 6.0, 8.0); Avec ces librairies hiérarchiques il devient possible de faire évoluer des composants sans
ComplexPkg.set(a =>9.0, b =>3.0, z => z2); remettre en cause l'existant et notamment sans devoir procéder à de nouvelles campagnes de
ComplexPkg.put(z2);
end exemple7; tests sur les éléments existants.
Pa ty leu ion
e
IV. Généricité
ag
ra p e rs s
ck
On couple le plus souvent l'instruction with à la clause use. Ceci va importer l'ensemble des
m s ,
pa
èt ,
va nct
re
de
fo
symboles définis dans le package directement le contexte courant. Il devient alors inutile dePour compléter son modèle composant ADA dispose de
s
:
e
èl
od
préfixer les noms de types, variables, sous-programmes par le nom du package. En cas demécanismes permettant la réalisation de composants génériques.
M
conflit, notamment entre deux packages, il suffira de préfixer au cas par cas.
On peut voir un composant générique comme un élément paramétré.
with complexPkg; use complexPkg; Lors de l'utilisation effective on précisera les paramètres et une version
procedure exemple8 is
z1, z2: complex; spécifique du composant sera créée et utilisable. De manière imagée on
begin peut se représenter le composant générique comme un moule qui va
set(z1, 6.0, 8.0); permettre de créer autant de composants que nécessaires.
set(a =>9.0, b =>3.0, z => z2); Nouveau package
Accept hello
la tâche appelée (tâche serveur) soit prête à traiter l'appel. correspondante est utilisée. En cas de demandes multiples, un rendez-vous est choisi
Pendant le traitement, l'appelant est suspendu. Il reprend le aléatoirement. En plaçant select au sein d'une boucle les demandes de rendez-vous ignorés
déroulement de ses instructions une fois l'appel terminé. seront traitées lors d'un prochain tour de boucle.
Coté appelé (tâche serveur), à supposer que l'on soit en attente
t1.bye with Text_Io; use Text_Io;
Accept bye
with Ada.Numerics.Discrete_Random;
d'appel on reste bloqué tant qu'aucun appel n'est reçu. Lorsqu'un procedure exemple17 is
appel arrive, les instructions associées à ce point d'entrée sont -- on veut des valeurs entre 0 et 10
exécutées. Ceci fait, les deux tâches reprennent le déroulement -- il suffit de definir le sous-type adhoc
de leurs instructions, chacune de leur coté. subtype Smalldelay is Integer range 0 .. 10;
-- d'instancier le package fournissant un générateur
Dans la pratique, pour appeler une tâche on utilise la notation -- de nombres aléatoires pour notre type à nous
pointée : <nom de tâche>.<nom du point d'entrée> ( <paramètres éventuels>); package Random_Smalldelay is new Ada.Numerics.Discrete_Random
(Smalldelay);
Coté tâche appelée, ou serveur, on utilise l'instruction accept use Random_Smalldelay;
pour attendre un appel. Ce sont les spécifications de ce bloc qui gen : generator;
package int_io is new integer_io(integer); use int_io;
sont reprises dans les spécifications de la tâche serveur en utilisant l'instruction entry. task Server is
with text_io; use text_io; -- le serveur répond à 3 appels entrant
procedure exemple16 is entry Init(I : in Integer);
task T1 is entry Set(I : in Integer);
entry Bye; entry Get(I : out Integer);
end T1; end Server;
task T2 is -- le client à aucun
entry Hello; task type Client;
end T2; Clients : array ( 1..10) of Client;
task body T1 is task body Server is
begin local : integer;
T2.Hello; begin
accept Bye do accept Init(I : in Integer) do
Put_Line("T2 a eu notre bonjour et nous dit au revoir"); local := i;
end Bye; end Init;
end T1; put_line("le server est initialisé");
task body T2 is loop
begin select
accept Hello do accept Set(I: in Integer) do
Put_Line("T1 nous dit bonjour, mais on ne veut pas parler"); Local := I;
end Hello; end Set;
T1.Bye; or
end T2; accept Get(I : out Integer) do
begin I := Local;
null; end Get;
end exemple16; or
terminate;
end select;
end loop; begin
end Server; Put("hello from simple");
task body Client is end simple;
s : integer := 5; t1, t2 : simple;
begin begin
put_line("je suis un client"); Put("hello from main");
for I in 1 .. 10 loop end exemple18;
if (I mod 2) = 0 then
Server.Get(S);
delay duration(random(gen));
Put("lecture de la variable :"); Enfin, il est possible de définir un type pointeur sur le type tâche précédemment défini. Avec
Put(s); dans ce cas l'opportunité de créer de nouvelles tâches dynamiquement au coeur d'un bloc
New_Line; d'instructions.
else
Server.Set(S + 10 - I);
delay duration(random(gen)); VII. Distribution des tâches
Put_Line ("ecriture de la variable"); A suivre.
end if ;
delay 0.0;
end loop;
end Client;
begin
delay 2.0;
Put_Line("Initialisation server");
server.init(5);
Put_Line("programme principal");
end exemple17;
Avec select une tâche serveur va donc pouvoir répondre à de multiples rendez-vous. Mais
l'instruction select recèle de nombreux raffinements :
• la possibilité de sortir de la phase d'attente, soit sur timeout (clause delay) ou lorsqu'il n'est
plus possible pour la tâche d'être appelée (clause terminate, qui achève la tâche),
• la possibilité de conditionner (on parle de gardes) chaque bloc accept à une expression
booléenne.