« Ada » : différence entre les versions

De Lea Linux
Aller à la navigation Aller à la recherche
m (Lea a déplacé la page Dev-ada vers Ada)
 
(2 versions intermédiaires par un autre utilisateur non affichées)
Ligne 1 : Ligne 1 :
[[Category:Développer sous Linux]]
[[Catégorie:Développement]]
 
= Introduction au langage Ada =
= Introduction au langage Ada =


<div class="leatitre">Introduction au langage Ada</div><div class="leapar">par [mailto:jiel@lea-linux.org Jiel]</div>
par [[Utilisateur:Jiel|Jiel]]


== Avant propos ==
== Avant propos ==
Ligne 33 : Ligne 34 :
Les procédures peuvent être définies comme des fonctions qui ne renvoient rien; elles peuvent néanmoins produire un résultat de sortie. Pour chaque paramètre de la procédure, on peut préciser la modalité de passage :
Les procédures peuvent être définies comme des fonctions qui ne renvoient rien; elles peuvent néanmoins produire un résultat de sortie. Pour chaque paramètre de la procédure, on peut préciser la modalité de passage :


- <code>in</code> : lecture du paramètre, comme pour l'argument d'une fonction.<br /> - <code>out</code> : écriture du paramètre uniquement (correspond à un résultat de sortie).<br /> - <code>in out</code> : lecture et écriture: la valeur du paramètre est prise en compte et peut être modifiée.<br />
- <span class="code">in</span> : lecture du paramètre, comme pour l'argument d'une fonction.<br /> - <span class="code">out</span> : écriture du paramètre uniquement (correspond à un résultat de sortie).<br /> - <span class="code">in out</span> : lecture et écriture: la valeur du paramètre est prise en compte et peut être modifiée.<br />


Voici la structure d'une procédure:
Voici la structure d'une procédure:
Ligne 41 : Ligne 42 :
==== Syntaxe et opérateurs de comparaison ====
==== Syntaxe et opérateurs de comparaison ====


Chaque instruction est terminée par un point virgule <code><nowiki>;</nowiki></code>. L'affectation se fait en utilisant <code> := </code>. Une ligne de commentaires est préfixée par deux tirets <code>--</code>. Les opérateurs de comparaison sont les suivants:
Chaque instruction est terminée par un point virgule <span class="code"><nowiki>;</nowiki></span>. L'affectation se fait en utilisant <span class="code"> := </span>. Une ligne de commentaires est préfixée par deux tirets <span class="code">--</span>. Les opérateurs de comparaison sont les suivants:


{|
{|
| <code> = </code>
| <span class="code"> = </span>
| égalité
| égalité
|-
|-
| <code> /= </code>
| <span class="code"> /= </span>
| inégalité
| inégalité
|-
|-
| <code> < </code>
| <span class="code"> < </span>
| strictement inférieur à
| strictement inférieur à
|-
|-
| <code> > </code>
| <span class="code"> > </span>
| strictement supérieur à
| strictement supérieur à
|-
|-
| <code> <= </code>
| <span class="code"> <= </span>
| inférieur à
| inférieur à
|-
|-
| <code> >= </code>
| <span class="code"> >= </span>
| supérieur à
| supérieur à
|-
|-
| <code> in </code>
| <span class="code"> in </span>
| appartenance à un intervalle
| appartenance à un intervalle
|-
|-
| <code> not in </code>
| <span class="code"> not in </span>
| non appartenance à un intervalle
| non appartenance à un intervalle
|}
|}
Ligne 73 : Ligne 74 :
La partie déclarative doit contenir:
La partie déclarative doit contenir:


- Les types et les sous-types.<br /> - Les variables sous la forme <code> ''Nom_variable''<nowiki>:</nowiki>''Nom_type''[:= ''Valeur_Initiale''];</code><br>
- Les types et les sous-types.<br /> - Les variables sous la forme <span class="code"> ''Nom_variable''<nowiki>:</nowiki>''Nom_type''[:= ''Valeur_Initiale''];</span><br>
- Les constantes telles que <code>Pi:constant FLOAT:= 3.14159;</code><br>
- Les constantes telles que <span class="code">Pi:constant FLOAT:= 3.14159;</span><br>
- Des procédures et des fonctions qu'on utilisera ensuite dans le corps.<br />
- Des procédures et des fonctions qu'on utilisera ensuite dans le corps.<br />


Ligne 81 : Ligne 82 :
==== Types discrets ====
==== Types discrets ====


Pour commencer, un peu de vocabulaire: les "types discrets" sont les types ordonnés où chaque élément a un successeur et un prédécesseur. Ils sont munis d'attributs, des fonctions exprimant les propriétés courantes du type. La syntaxe est <code>T'nom_attribut</code>, où T est un type discret. Ces attributs sont les suivants:
Pour commencer, un peu de vocabulaire: les "types discrets" sont les types ordonnés où chaque élément a un successeur et un prédécesseur. Ils sont munis d'attributs, des fonctions exprimant les propriétés courantes du type. La syntaxe est <span class="code">T'nom_attribut</span>, où T est un type discret. Ces attributs sont les suivants:


- <code>T'FIRST</code><br />
- <span class="code">T'FIRST</span><br />


Borne inférieure du type T.
Borne inférieure du type T.


<br /> - <code>T'LAST</code><br />
<br /> - <span class="code">T'LAST</span><br />


Borne supérieure du type T.
Borne supérieure du type T.


<br /> - <code>T'POS(X)</code><br />
<br /> - <span class="code">T'POS(X)</span><br />


X est de type T et <code>T'POS(X)</code> renvoie la position de X dans le type T.
X est de type T et <span class="code">T'POS(X)</span> renvoie la position de X dans le type T.


<br /> -<code>T'VAL(N)</code><br />
<br /> -<span class="code">T'VAL(N)</span><br />


N est de type entier et <code>T'VAL(N)</code> est l'élément de position N dans le type T.
N est de type entier et <span class="code">T'VAL(N)</span> est l'élément de position N dans le type T.


<br /> - <code>T'SUCC(X)</code><br />
<br /> - <span class="code">T'SUCC(X)</span><br />


X est de type T et <code>T'SUCC(X)</code> est le successeur de X dans T, ainsi <code>T'SUCC(X)= T'VAL(T'POS(X)+1)</code>.
X est de type T et <span class="code">T'SUCC(X)</span> est le successeur de X dans T, ainsi <span class="code">T'SUCC(X)= T'VAL(T'POS(X)+1)</span>.


<br /> - <code>T'PREC(X)</code><br />
<br /> - <span class="code">T'PREC(X)</span><br />


X est de type T et <code>T'PREC(X)</code> est le prédécesseur de X dans T, ainsi <code>T'SUCC(X)= T'VAL(T'POS(X)-1)</code>.
X est de type T et <span class="code">T'PREC(X)</span> est le prédécesseur de X dans T, ainsi <span class="code">T'SUCC(X)= T'VAL(T'POS(X)-1)</span>.


<br /> - <code>T'IMAGE(X)</code><br />
<br /> - <span class="code">T'IMAGE(X)</span><br />


X est de type T et <code>T'IMAGE(X)</code> est une chaîne de caractères qui contient l'image de X.
X est de type T et <span class="code">T'IMAGE(X)</span> est une chaîne de caractères qui contient l'image de X.


<br /> - <code>T'WIDTH</code><br />
<br /> - <span class="code">T'WIDTH</span><br />


Donne le nombre maximal de caractères pour une image d'une valeur de T.
Donne le nombre maximal de caractères pour une image d'une valeur de T.


- <code>T'VALUE(S)</code><br />
- <span class="code">T'VALUE(S)</span><br />


S est une chaîne de caractères qui est l'image d'un élément de type T; <code>T'VALUE(S)</code> est l'élément en question.
S est une chaîne de caractères qui est l'image d'un élément de type T; <span class="code">T'VALUE(S)</span> est l'élément en question.


==== Types prédéfinis ====
==== Types prédéfinis ====


Le type discret entier <code>INTEGER</code>. Il possède deux sous-types prédéfinis: <code>NATURAL</code> pour les entiers naturels et <code>POSITIVE</code> pour les entiers strictement positifs. Certains opérateurs sont prédéfinis, ce sont l'addition <code>+</code>, la multiplication <code><nowiki>*</nowiki></code>, la soustraction <code>-</code>, la division <code>/</code>, le reste de la division <code>mod</code>, l'exponentiation <code><nowiki>**</nowiki></code>.
Le type discret entier <span class="code">INTEGER</span>. Il possède deux sous-types prédéfinis: <span class="code">NATURAL</span> pour les entiers naturels et <span class="code">POSITIVE</span> pour les entiers strictement positifs. Certains opérateurs sont prédéfinis, ce sont l'addition <span class="code">+</span>, la multiplication <span class="code"><nowiki>*</nowiki></span>, la soustraction <span class="code">-</span>, la division <span class="code">/</span>, le reste de la division <span class="code">mod</span>, l'exponentiation <span class="code"><nowiki>**</nowiki></span>.


Le type discret caractère <code>CHARACTER</code>. Pour représenter un caractère, on utilise les apostrophes : 'a'.
Le type discret caractère <span class="code">CHARACTER</span>. Pour représenter un caractère, on utilise les apostrophes : 'a'.


Le type discret booléen <code>BOOLEAN</code>, composé de <code>TRUE</code> et de <code>FALSE</code>. Les opérateurs logiques sont <code>and</code>, <code>and then</code>, <code>or</code>, <code>or else</code> et <code>not</code>.
Le type discret booléen <span class="code">BOOLEAN</span>, composé de <span class="code">TRUE</span> et de <span class="code">FALSE</span>. Les opérateurs logiques sont <span class="code">and</span>, <span class="code">and then</span>, <span class="code">or</span>, <span class="code">or else</span> et <span class="code">not</span>.


le type <code>FLOAT</code> pour représenter les nombres réels.
le type <span class="code">FLOAT</span> pour représenter les nombres réels.


le type <code>STRING</code> pour les chaînes de caractères. Pour représenter une chaîne de caractères, on utilise les guillemets, par exemple: "La petite Léa est très jolie".
le type <span class="code">STRING</span> pour les chaînes de caractères. Pour représenter une chaîne de caractères, on utilise les guillemets, par exemple: "La petite Léa est très jolie".


==== Type énumérés ====
==== Type énumérés ====
Ligne 135 : Ligne 136 :
On peut définir un type énuméré, qui est un type discret fini (comme le type booléen), par exemple le type Jour:
On peut définir un type énuméré, qui est un type discret fini (comme le type booléen), par exemple le type Jour:


<code>type Jour is (lunae_dies, martis_dies, mercurii_dies, jovis_dies, veneris_dies, saturnus_dies, solis_dies);</code>
<span class="code">type Jour is (lunae_dies, martis_dies, mercurii_dies, jovis_dies, veneris_dies, saturnus_dies, solis_dies);</span>


L'ordre d'énumération définit un ordre. On a ainsi dans notre exemple ''lunae_dies'' < ''martis_dies'' < ... < ''solis_dies''.
L'ordre d'énumération définit un ordre. On a ainsi dans notre exemple ''lunae_dies'' < ''martis_dies'' < ... < ''solis_dies''.
Ligne 143 : Ligne 144 :
Un sous-type est défini comme la restriction d'un type parent discret, sous la forme:
Un sous-type est défini comme la restriction d'un type parent discret, sous la forme:


<code>subtype ''nom_sous_type'' is ''nom_type'' range ''val1'' .. ''val2''<nowiki>;</nowiki></code>
<span class="code">subtype ''nom_sous_type'' is ''nom_type'' range ''val1'' .. ''val2''<nowiki>;</nowiki></span>


où ''val1'' et ''val2'' sont deux éléments de type nom_type tels que val1 < val2. . Par exemple:
où ''val1'' et ''val2'' sont deux éléments de type nom_type tels que val1 < val2. . Par exemple:


<code>subtype Chiffre is INTEGER range 0..9;
<span class="code">subtype Chiffre is INTEGER range 0..9;
subtype Alphabet is CHARACTER range 'a'..'z';</code>
subtype Alphabet is CHARACTER range 'a'..'z';</span>


On peut appliquer à un sous-type les fonctions prévues pour son type parent, mais il faut faire attention à ce que le résultat reste dans l'intervalle.
On peut appliquer à un sous-type les fonctions prévues pour son type parent, mais il faut faire attention à ce que le résultat reste dans l'intervalle.
Ligne 156 : Ligne 157 :
Les types en Ada peuvent être divisés en deux catégories. Il y a d'une part types énumératifs, types tableaux etc. sans oublier les types prédéfinis, c'est à dire les types dont la structure est connue des utilisateurs. Ils sont dits publiques. D'autre part les types privés permettent de cacher les détails de structure afin de respecter le principe d'abstraction des données en masquant la représentation interne des données, exportant les opérations de manipulation de ce type, empêchant un usage non contrôlé.
Les types en Ada peuvent être divisés en deux catégories. Il y a d'une part types énumératifs, types tableaux etc. sans oublier les types prédéfinis, c'est à dire les types dont la structure est connue des utilisateurs. Ils sont dits publiques. D'autre part les types privés permettent de cacher les détails de structure afin de respecter le principe d'abstraction des données en masquant la représentation interne des données, exportant les opérations de manipulation de ce type, empêchant un usage non contrôlé.


La syntaxe d'une déclaration d'un type privé est: <code>type T_NOM_DU_TYPE is private;</code>.
La syntaxe d'une déclaration d'un type privé est: <span class="code">type T_NOM_DU_TYPE is private;</span>.


==== Types limités ====
==== Types limités ====
Ligne 166 : Ligne 167 :
==== Types privés limités ====
==== Types privés limités ====


Les types privés limités sont comme les types privés, mais où l'utilisation est encore plus limitée; logique, non? Ils ne possèdent plus ni la comparaison ni l'affectation. Avec un type privé limité on ne peut que déclarer des variables et utiliser les sous-programmes fournis par le paquetage (sans affectation ni comparaison). Ces techniques permettent un contrôle total sur leur utilisation. Un type privé limité se déclare de la façon suivante : <code>type T_EXEMPLE is limited private ;</code>
Les types privés limités sont comme les types privés, mais où l'utilisation est encore plus limitée; logique, non? Ils ne possèdent plus ni la comparaison ni l'affectation. Avec un type privé limité on ne peut que déclarer des variables et utiliser les sous-programmes fournis par le paquetage (sans affectation ni comparaison). Ces techniques permettent un contrôle total sur leur utilisation. Un type privé limité se déclare de la façon suivante : <span class="code">type T_EXEMPLE is limited private ;</span>


Ouf! C'en est fini pour les types ;-)
Ouf! C'en est fini pour les types ;-)
Ligne 177 : Ligne 178 :
Comme dans la majorité des langages on trouve une structure conditionnelle de type "si, alors, sinon" , elle se construit comme suit:
Comme dans la majorité des langages on trouve une structure conditionnelle de type "si, alors, sinon" , elle se construit comme suit:


<code> if ''condition'' then ... else ... end if;</code><br><code> if ''condition'' then ... elsif ''condition2'' ... elsif ''condition3'' ... end if;</code>
<span class="code"> if ''condition'' then ... else ... end if;</span><br><span class="code"> if ''condition'' then ... elsif ''condition2'' ... elsif ''condition3'' ... end if;</span>


==== Choix multiples ====
==== Choix multiples ====
Ligne 183 : Ligne 184 :
Il existe également une structure permettant de faire des choix multiples.
Il existe également une structure permettant de faire des choix multiples.


<code> case ''expression'' is
<span class="code"> case ''expression'' is
     when ''choix1'' => ...
     when ''choix1'' => ...
     when ''choix2'' => ...
     when ''choix2'' => ...
     ...
     ...
     when others => ...
     when others => ...
  end case; </code>
  end case; </span>


=== Les boucles ===
=== Les boucles ===
Ligne 198 : Ligne 199 :
les boucles "pour" se construisent comme suit:
les boucles "pour" se construisent comme suit:


<code> for ''indice'' in [reverse] ''debut .. fin'' loop ... end loop; </code>
<span class="code"> for ''indice'' in [reverse] ''debut .. fin'' loop ... end loop; </span>


Si on veut préciser que l'intervalle doit être parcouru en sens inverse, on utilise le mot clef <code>reverse</code>.
Si on veut préciser que l'intervalle doit être parcouru en sens inverse, on utilise le mot clef <span class="code">reverse</span>.


==== Tant que ====
==== Tant que ====
Ligne 206 : Ligne 207 :
Les boucles "tant que" se construisent comme suit:
Les boucles "tant que" se construisent comme suit:


<code> while ''condition'' loop ... end loop; </code>
<span class="code"> while ''condition'' loop ... end loop; </span>


=== Les tableaux ===
=== Les tableaux ===
Ligne 214 : Ligne 215 :
La taille des tableaux est précisée lors de la définition du type :
La taille des tableaux est précisée lors de la définition du type :


<code>type ''Nom_Type_Tableau'' is array(''Intervalle_fini_d'un_type_discret'') of ''Type_Element''<nowiki>;</nowiki></code>
<span class="code">type ''Nom_Type_Tableau'' is array(''Intervalle_fini_d'un_type_discret'') of ''Type_Element''<nowiki>;</nowiki></span>


Les bornes d'un tableau ne sont pas nécessairement statiques. Exemple:
Les bornes d'un tableau ne sont pas nécessairement statiques. Exemple:
Ligne 220 : Ligne 221 :
<div class="code"> type T is array (1..5) of INTEGER ;<br /> tab1 : T;<br /> type MATRICE is array(1..4, 1..4) of INTEGER;<br /> ma_matrice : M;<br /> </div>
<div class="code"> type T is array (1..5) of INTEGER ;<br /> tab1 : T;<br /> type MATRICE is array(1..4, 1..4) of INTEGER;<br /> ma_matrice : M;<br /> </div>


On accède au i-ème élément d'un tableau ''tab'' en tapant <code>tab(i)</code>. On peut manipuler les cases d'un tableau avec des agrégats, par exemple <code>Tab1:Tableau(1..6):=(1|2=>3, others=>4);</code> ou <code>Tab2:Tableau:=(1..10=>3);</code>.
On accède au i-ème élément d'un tableau ''tab'' en tapant <span class="code">tab(i)</span>. On peut manipuler les cases d'un tableau avec des agrégats, par exemple <span class="code">Tab1:Tableau(1..6):=(1|2=>3, others=>4);</span> ou <span class="code">Tab2:Tableau:=(1..10=>3);</span>.


L'opérateur <code>&</code> permet de concaténer deux tableaux de même type. Ainsi, <code>T1 & T2</code> donne un tableau de taille T1'length+T2'length, contenant les éléments de T1 suivis de ceux de T2. <code>&</code> permet également de concaténer un élément à un tableau. Attention aux erreurs de dépassements, un tableau en Ada a une taille fixe une fois pour toutes lorsqu'il est déclaré.
L'opérateur <span class="code">&</span> permet de concaténer deux tableaux de même type. Ainsi, <span class="code">T1 & T2</span> donne un tableau de taille T1'length+T2'length, contenant les éléments de T1 suivis de ceux de T2. <span class="code">&</span> permet également de concaténer un élément à un tableau. Attention aux erreurs de dépassements, un tableau en Ada a une taille fixe une fois pour toutes lorsqu'il est déclaré.


==== Tableaux non contraints ====
==== Tableaux non contraints ====
Ligne 228 : Ligne 229 :
Le type des indices et du type des éléments est précisé lors de la définition du type mais pas la taille du tableau. On peut faire sur les tableaux non contraints toutes les manipulations qu'on peut faire sur les tableaux contraints. Voici l'exemple d'un tableau de nombres naturels indexé par des entiers:
Le type des indices et du type des éléments est précisé lors de la définition du type mais pas la taille du tableau. On peut faire sur les tableaux non contraints toutes les manipulations qu'on peut faire sur les tableaux contraints. Voici l'exemple d'un tableau de nombres naturels indexé par des entiers:


<code> type T is array (INTEGER range <>) of NATURAL ; </code>
<span class="code"> type T is array (INTEGER range <>) of NATURAL ; </span>


Un objet de type T doit alors être contraint lors de sa déclaration, soit en précisant l'intervalle d'indexation, soit en lui affectant un autre tableau.
Un objet de type T doit alors être contraint lors de sa déclaration, soit en précisant l'intervalle d'indexation, soit en lui affectant un autre tableau.
Ligne 234 : Ligne 235 :
==== Chaînes de caractères ====
==== Chaînes de caractères ====


Le type STRING est un type pré-défini du paquetage STANDARD. Il est défini comme un tableau non contraint de caractères et indexé d'entiers strictement positifs. Les chaînes de caractères se manipulent donc exactement comme des tableaux, ainsi : <code>S:STRING(1..18);</code>. Quand on ne connait pas la longueur d'une chaîne de caractères, on est obligé de fixer lors de la déclaration une taille maximum et de gérer ensuite explicitement la vraie longueur.
Le type STRING est un type pré-défini du paquetage STANDARD. Il est défini comme un tableau non contraint de caractères et indexé d'entiers strictement positifs. Les chaînes de caractères se manipulent donc exactement comme des tableaux, ainsi : <span class="code">S:STRING(1..18);</span>. Quand on ne connait pas la longueur d'une chaîne de caractères, on est obligé de fixer lors de la déclaration une taille maximum et de gérer ensuite explicitement la vraie longueur.


==== Attributs de tableaux ====
==== Attributs de tableaux ====
Ligne 240 : Ligne 241 :
Les tableaux bénéficient d'attributs spécifiques. Soit T un objet de type tableau, on a:
Les tableaux bénéficient d'attributs spécifiques. Soit T un objet de type tableau, on a:


- <code>T'FIRST</code> indice du premier élément. <code>T(T'FIRST)</code> nous donne la première valeur.<br /><br /> - <code>T'FIRST(n)</code> indice du premier élément de la dimension ''n''.<br /><br /> - <code>T'LAST</code> indice du dernier élément de la première dimension.<br /><br /> - <code>T'LAST(n)</code> indice du dernier élément de la dimension ''n''.<br /><br /> - <code>T'RANGE</code> intervalle d'indexation de la première dimension de T.<br /><br /> - <code>T'RANGE(n)</code> intervalle d'indexation de la dimension ''n'' de T.<br /><br /> - <code>T'LENGTH</code> longueur de la première dimension du tableau.<br /><br /> - <code>T'LENGTH(n)</code> longueur de la dimension n du tableau.<br />
- <span class="code">T'FIRST</span> indice du premier élément. <span class="code">T(T'FIRST)</span> nous donne la première valeur.<br /><br /> - <span class="code">T'FIRST(n)</span> indice du premier élément de la dimension ''n''.<br /><br /> - <span class="code">T'LAST</span> indice du dernier élément de la première dimension.<br /><br /> - <span class="code">T'LAST(n)</span> indice du dernier élément de la dimension ''n''.<br /><br /> - <span class="code">T'RANGE</span> intervalle d'indexation de la première dimension de T.<br /><br /> - <span class="code">T'RANGE(n)</span> intervalle d'indexation de la dimension ''n'' de T.<br /><br /> - <span class="code">T'LENGTH</span> longueur de la première dimension du tableau.<br /><br /> - <span class="code">T'LENGTH(n)</span> longueur de la dimension n du tableau.<br />


=== Les structures ===
=== Les structures ===
Ligne 248 : Ligne 249 :
<div class="code"> type ''Nom_structure'' is record<br />  ''champ1''<nowiki>: </nowiki>''type1''<nowiki>;</nowiki><br />  ''champ2''<nowiki>: </nowiki>''type2''<nowiki>;</nowiki><br />  ''champ3''<nowiki>: </nowiki>''type3''<nowiki>;</nowiki><br /> end record; </div>
<div class="code"> type ''Nom_structure'' is record<br />  ''champ1''<nowiki>: </nowiki>''type1''<nowiki>;</nowiki><br />  ''champ2''<nowiki>: </nowiki>''type2''<nowiki>;</nowiki><br />  ''champ3''<nowiki>: </nowiki>''type3''<nowiki>;</nowiki><br /> end record; </div>


On peut donner des valeurs initiales aux champs des structures, en mettant <code><nowiki>:= </nowiki>''valeur''</code> après le nom du type.
On peut donner des valeurs initiales aux champs des structures, en mettant <span class="code"><nowiki>:= </nowiki>''valeur''</span> après le nom du type.


On accède aux champs d'une structure avec un point <code>.</code> : <code>S: Nom_structure; ... Nom_structure.champ1 Nom_structure.champ2 Nom_structure.champ3</code>
On accède aux champs d'une structure avec un point <span class="code">.</span> : <span class="code">S: Nom_structure; ... Nom_structure.champ1 Nom_structure.champ2 Nom_structure.champ3</span>


Pour affecter une valeur complète à une structure, on peut utiliser des agrégats:
Pour affecter une valeur complète à une structure, on peut utiliser des agrégats:
Ligne 262 : Ligne 263 :
=== Traitement des exceptions ===
=== Traitement des exceptions ===


Ada possède des exceptions prédéfinies, dont le nom est explicite: <code>CONSTRAINT_ERROR</code>, <code>STORAGE_ERROR</code>, <code>PROGRAM_ERROR</code>, <code>NUMERIC_ERROR</code>, <code>TASKING_ERROR</code>. Il y a également des exceptions prédéfinies liées aux entrées-sorties que l'on trouve dans la bibliothèque <code>ADA.IO_EXCEPTIONS</code>. Une exception, lorsqu'elle est déclenchée, interrompt l'exécution des blocs qu'elle traverse.
Ada possède des exceptions prédéfinies, dont le nom est explicite: <span class="code">CONSTRAINT_ERROR</span>, <span class="code">STORAGE_ERROR</span>, <span class="code">PROGRAM_ERROR</span>, <span class="code">NUMERIC_ERROR</span>, <span class="code">TASKING_ERROR</span>. Il y a également des exceptions prédéfinies liées aux entrées-sorties que l'on trouve dans la bibliothèque <span class="code">ADA.IO_EXCEPTIONS</span>. Une exception, lorsqu'elle est déclenchée, interrompt l'exécution des blocs qu'elle traverse.


On peut lancer une exception grâce au mot clef <code>raise</code>. On peut aussi capturer les exceptions avec <code>when</code>. En Ada, le traitement des exceptions doit se faire dans les instructions bloc, les sous-programmes, les paquetages, les tâches ou les unités génériques. Ces traitements sont regroupés sous la rubrique <code>exception</code> comme dans l'exemple suivant:
On peut lancer une exception grâce au mot clef <span class="code">raise</span>. On peut aussi capturer les exceptions avec <span class="code">when</span>. En Ada, le traitement des exceptions doit se faire dans les instructions bloc, les sous-programmes, les paquetages, les tâches ou les unités génériques. Ces traitements sont regroupés sous la rubrique <span class="code">exception</span> comme dans l'exemple suivant:


<code> exception when CONSTRAINT_ERROR => put_line("une contrainte n'a pas été respectée"); raise CONSTRAINT_ERROR; </code>
<span class="code"> exception when CONSTRAINT_ERROR => put_line("une contrainte n'a pas été respectée"); raise CONSTRAINT_ERROR; </span>


Il est possible de définir une exception, de la même manière que l'on définit un type ou déclare une variable. On la manipule ensuite comme une exception prédéfinie.
Il est possible de définir une exception, de la même manière que l'on définit un type ou déclare une variable. On la manipule ensuite comme une exception prédéfinie.
Ligne 272 : Ligne 273 :
=== Entrées-sorties ===
=== Entrées-sorties ===


Les fonctionnalités d'entrées-sorties sont disponibles dans le paquetage <code>ADA.TEXT_IO</code> pour les chaînes de caractères et <code>ADA.INTEGER_TEXT_IO</code> pour les entiers. Les procédures les plus utiles sont <code>get(...)</code>, <code>put(...)</code>, <code>put_line(...)</code> et <code>new_line</code>.
Les fonctionnalités d'entrées-sorties sont disponibles dans le paquetage <span class="code">ADA.TEXT_IO</span> pour les chaînes de caractères et <span class="code">ADA.INTEGER_TEXT_IO</span> pour les entiers. Les procédures les plus utiles sont <span class="code">get(...)</span>, <span class="code">put(...)</span>, <span class="code">put_line(...)</span> et <span class="code">new_line</span>.


=== Les pointeurs ===
=== Les pointeurs ===
Ligne 280 : Ligne 281 :
==== Déclaration ====
==== Déclaration ====


Les pointeurs en Ada s'utilisent grâce au mot clef <code>access</code>. Soit T_Quelconque un type quelconque, un type "pointeur sur un objet de type T_Quelconque" se déclare comme ceci: <code>type ''T_Pointeur_T_Quelconque'' is access ''T_Quelconque'' ;</code>. Désormais, toute variable (ou instance) de ce nouveau type ''T_Pointeur_T_Quelconque'' sera considérée comme pouvant pointer sur un objet de type ''T_Quelconque''. On notera que le "type pointeur" n'existe pas en soi, seul un type "pointeur sur un type donné" peut être défini. On déclare deux pointeurs de ce type de la façon suivante: <code>Pointeur_1, Pointeur_2 : T_Pointeur_T_Quelconque ;</code>. Ils pourront ainsi désigner chacun un objet de type ''T_Quelconque''. A ce moment là , ils ne pointent sur rien : leur valeur est automatiquement initialisée à NULL lors de la déclaration.
Les pointeurs en Ada s'utilisent grâce au mot clef <span class="code">access</span>. Soit T_Quelconque un type quelconque, un type "pointeur sur un objet de type T_Quelconque" se déclare comme ceci: <span class="code">type ''T_Pointeur_T_Quelconque'' is access ''T_Quelconque'' ;</span>. Désormais, toute variable (ou instance) de ce nouveau type ''T_Pointeur_T_Quelconque'' sera considérée comme pouvant pointer sur un objet de type ''T_Quelconque''. On notera que le "type pointeur" n'existe pas en soi, seul un type "pointeur sur un type donné" peut être défini. On déclare deux pointeurs de ce type de la façon suivante: <span class="code">Pointeur_1, Pointeur_2 : T_Pointeur_T_Quelconque ;</span>. Ils pourront ainsi désigner chacun un objet de type ''T_Quelconque''. A ce moment là , ils ne pointent sur rien : leur valeur est automatiquement initialisée à NULL lors de la déclaration.


==== Création et accès à  l'objet pointé ====
==== Création et accès à  l'objet pointé ====


A tout moment l'utilisateur peut créer des objets dans le corps d'un sous-programme au moyen de l'allocateur <code>new</code> portant sur le type de l'objet qui doit être pointé. La valeur de retour est l'adresse mémoire dynamique que le système lui a allouée:
A tout moment l'utilisateur peut créer des objets dans le corps d'un sous-programme au moyen de l'allocateur <span class="code">new</span> portant sur le type de l'objet qui doit être pointé. La valeur de retour est l'adresse mémoire dynamique que le système lui a allouée:


<div class="code"> Pointeur_1 := new T_Quelconque ;<br /> Pointeur_2 := new T_Quelconque ; </div>
<div class="code"> Pointeur_1 := new T_Quelconque ;<br /> Pointeur_2 := new T_Quelconque ; </div>


Les zones mémoire pour chaque objet pointé sont réservées; cependant elles n'ont toujours pas de valeurs. Celles-ci vont pouvoir leur être données comme suit, avec <code>.all</code><nowiki>:</nowiki>
Les zones mémoire pour chaque objet pointé sont réservées; cependant elles n'ont toujours pas de valeurs. Celles-ci vont pouvoir leur être données comme suit, avec <span class="code">.all</span><nowiki>:</nowiki>


<div class="code"> Pointeur_1.all := XXX ;<br /> Pointeur_2.all := YYY ; </div>
<div class="code"> Pointeur_1.all := XXX ;<br /> Pointeur_2.all := YYY ; </div>
Ligne 304 : Ligne 305 :
=== Les paquetages ===
=== Les paquetages ===


Le programme principal Ada utilise en général des paquetages, qui correspondent à des bibliothèques ou d'autres programmes. Pour cela, La clause <code>with ''nom_paquetage''</code> au début d'un programme permet d'accéder aux fonctionnalités du paquetage ''nom_paquetage''. On peut ajouter une clause <code>use ''nom_paquetage''</code> qui permet d'invoquer les fonctionnalités de ''nom_paquetage'' directement, sans préfixer l'appel de ''nom_paquetage''.
Le programme principal Ada utilise en général des paquetages, qui correspondent à des bibliothèques ou d'autres programmes. Pour cela, La clause <span class="code">with ''nom_paquetage''</span> au début d'un programme permet d'accéder aux fonctionnalités du paquetage ''nom_paquetage''. On peut ajouter une clause <span class="code">use ''nom_paquetage''</span> qui permet d'invoquer les fonctionnalités de ''nom_paquetage'' directement, sans préfixer l'appel de ''nom_paquetage''.


Un paquetage se partage en deux fichiers :
Un paquetage se partage en deux fichiers :
Ligne 318 : Ligne 319 :
=== Programme source ===
=== Programme source ===


Le code écrit par un programmeur est constitué d'unités de bibliothèques qui doivent être placées dans des fichiers sources. Ces fichiers ont un suffixe <u>obligatoire</u> qui est pour la partie spécification <code>.ads</code> et pour l'implémentation <code>.adb</code>.
Le code écrit par un programmeur est constitué d'unités de bibliothèques qui doivent être placées dans des fichiers sources. Ces fichiers ont un suffixe <u>obligatoire</u> qui est pour la partie spécification <span class="code">.ads</span> et pour l'implémentation <span class="code">.adb</span>.


Le point d'entrée d'un programme Ada est la procédure principale par laquelle doit commencer l'exécution. Cette procédure peut porter un nom quelconque mais ne doit pas avoir d'arguments.
Le point d'entrée d'un programme Ada est la procédure principale par laquelle doit commencer l'exécution. Cette procédure peut porter un nom quelconque mais ne doit pas avoir d'arguments.
Ligne 356 : Ligne 357 :
=== Compilation et édition de liens d'un programme ===
=== Compilation et édition de liens d'un programme ===


La façon la plus simple de compiler un programme est d'utiliser ''gnatmake''. Ainsi, la commande <code>gnatmake prog</code> compilera le fichier ''prog.adb'' et donnera un exécutable ''./prog''. En fait, ''gnatmake'' réalise trois opérations. Il remplace les instructions suivantes:
La façon la plus simple de compiler un programme est d'utiliser ''gnatmake''. Ainsi, la commande <span class="code">gnatmake prog</span> compilera le fichier ''prog.adb'' et donnera un exécutable ''./prog''. En fait, ''gnatmake'' réalise trois opérations. Il remplace les instructions suivantes:


<div class="code"> $ gcc -c prog.adb # compilation du source<br /> $ gnatbind # test de cohérence des différentes unités<br /> $ gnatlink # édition des liens<br /> </div>
<div class="code"> $ gcc -c prog.adb # compilation du source<br /> $ gnatbind # test de cohérence des différentes unités<br /> $ gnatlink # édition des liens<br /> </div>
Ligne 364 : Ligne 365 :
=== Compilation de paquetages ===
=== Compilation de paquetages ===


La compilation de paquetage est simple, elle aussi. Prenons le cas d'un programme constitué d'un fichier contenant la procédure principale (''principal.adb'') et de deux autres fichiers contenant la spécification (''paq.ads'') et le corps (''paq.adb'') d'un paquetage. Il suffit simplement de taper <code>gnatmake principal</code> et ''gnatmake'' s'occupera de compiler automatiquement tous les fichiers auxiliares. Il va en fait procéder de la sorte:
La compilation de paquetage est simple, elle aussi. Prenons le cas d'un programme constitué d'un fichier contenant la procédure principale (''principal.adb'') et de deux autres fichiers contenant la spécification (''paq.ads'') et le corps (''paq.adb'') d'un paquetage. Il suffit simplement de taper <span class="code">gnatmake principal</span> et ''gnatmake'' s'occupera de compiler automatiquement tous les fichiers auxiliares. Il va en fait procéder de la sorte:


<div class="code"> $ gcc -c principal.adb<br /> $ gcc -c paq.adb<br /> $ gnatbind principal<br /> $ gnatlink principal<br /> </div>
<div class="code"> $ gcc -c principal.adb<br /> $ gcc -c paq.adb<br /> $ gnatbind principal<br /> $ gnatlink principal<br /> </div>
Ligne 370 : Ligne 371 :
== Mêler Ada et d'autres langages ==
== Mêler Ada et d'autres langages ==


Ada est peu utilisé. Qu'à cela ne tienne! On peut mêler du code Ada avec un autre langage normalisé. Actuellement, on peut par exemple interfacer Ada avec les langages C, C++, Cobol et Fortran. Cela est possible par le biais du paquetage <code>Interfaces</code> et de ses fils (<code>Interfaces.C</code>, <code>Interfaces.C.STRINGs</code>, <code>Interfaces.C.Pointers</code>, <code>Interfaces.Fortran</code>...). Ce paquetage <code>Interfaces</code> définit les types élémentaires de la machine. Il est muni d'enfants qui définissent la vue Ada des types des autres langages. Par exemple, le paquetage Interfaces.C définit un type int, un type C_Float, etc. dont on garantit qu'ils correspondent aux types de C.
Ada est peu utilisé. Qu'à cela ne tienne! On peut mêler du code Ada avec un autre langage normalisé. Actuellement, on peut par exemple interfacer Ada avec les langages C, C++, Cobol et Fortran. Cela est possible par le biais du paquetage <span class="code">Interfaces</span> et de ses fils (<span class="code">Interfaces.C</span>, <span class="code">Interfaces.C.STRINGs</span>, <span class="code">Interfaces.C.Pointers</span>, <span class="code">Interfaces.Fortran</span>...). Ce paquetage <span class="code">Interfaces</span> définit les types élémentaires de la machine. Il est muni d'enfants qui définissent la vue Ada des types des autres langages. Par exemple, le paquetage Interfaces.C définit un type int, un type C_Float, etc. dont on garantit qu'ils correspondent aux types de C.


== Conclusion ==
== Conclusion ==
Ligne 376 : Ligne 377 :
=== En savoir plus ===
=== En savoir plus ===


- Association Ada-France: [http://www.ada-france.org/ http://www.ada-france.org]<br /> - Les groupes français et anglais: [http://www.ada-france.org/mailman/listinfo/comp.lang.ada fr.comp.lang.ada] et [http://www.ada-france.org/mailman/listinfo/fr.comp.lang.ada comp.lang.ada].<br /> - Le manuel de référence sur GNAT (en anglais): http://gcc.gnu.org/onlinedocs/gcc-3.3.5/gnat_rm/.<br /> - Le guide de l'utilisateur de GNAT pour UNIX (en anglais): http://gcc.gnu.org/onlinedocs/gcc-3.3.5/gnat_ug_unx/.<br /> - Le manuel de GCC: <code>man gcc</code> vous dira tous les secrets de la compilation.<br /> - Le [http://lea-linux.org/pho/list/7 forum Développement] de Léa-Linux.<br />
- Association Ada-France: [http://www.ada-france.org/ http://www.ada-france.org]<br /> - Les groupes français et anglais: [http://www.ada-france.org/mailman/listinfo/comp.lang.ada fr.comp.lang.ada] et [http://www.ada-france.org/mailman/listinfo/fr.comp.lang.ada comp.lang.ada].<br /> - Le manuel de référence sur GNAT (en anglais): http://gcc.gnu.org/onlinedocs/gcc-3.3.5/gnat_rm/.<br /> - Le guide de l'utilisateur de GNAT pour UNIX (en anglais): http://gcc.gnu.org/onlinedocs/gcc-3.3.5/gnat_ug_unx/.<br /> - Le manuel de GCC: <span class="code">man gcc</span> vous dira tous les secrets de la compilation.<br /> - Le [http://lea-linux.org/pho/list/7 forum Développement] de Léa-Linux.<br />


=== C'est parti ! ===
=== C'est parti ! ===


Ada est un langage facile, il peut s'apprendre en quelques heures! Cependant, rien n'est mieux que la pratique. Osez faire de petits exercices pour vous entraîner! Bon courage :-)
Ada est un langage facile, il peut s'apprendre en quelques heures! Cependant, rien n'est mieux que la pratique. Osez faire de petits exercices pour vous entraîner! Bon courage :-)
<br/>
<br/>
'''<b>[[Dev-index|@ Retour à la rubrique Développement]]</b>'''
<br/>


<div class="merci">Cette page est issue de la documentation 'pré-wiki' de Léa a été convertie avec HTML::WikiConverter. Elle fut créée par Jiel Beaumadier le 12/02/2005.</div>
<div class="merci">Cette page est issue de la documentation 'pré-wiki' de Léa a été convertie avec HTML::WikiConverter. Elle fut créée par Jiel Beaumadier le 12/02/2005.</div>


= Copyright =
{{Copy|12/02/2005|[[Utilisateur:Jiel|Jiel Beaumadier]]|FDL}}
Copyright &copy; 12/02/2005, Jiel Beaumadier
{{FDL}}

Dernière version du 1 décembre 2023 à 17:40


Introduction au langage Ada

par Jiel

Avant propos

Avertissement

Ceci n'est qu'une introduction au langage Ada, car il existe des livres entiers avec des centaines de pages sur ce sujet ! Par conséquent ne vous attendez pas à faire le tour de la question... Ce n'est pas non plus un cours de programmation : cet article s'adresse à des personnes possédant des bases de programmation et voulant se mettre à Ada. Cela dit, le langage est relativement simple à comprendre et pourrait constituer un bon choix pour se lancer dans le merveilleux monde du développement. :-)

Téléchargement

GNAT GPL 2006 : https://libre2.adacore.com/

Présentation du langage

Ada est un langage de programmation conçu en réponse à un cahier des charges établi par le département de la Défense des Etats-Unis. Son développement a commencé au début des années 1980 (Ada 83). Il a été ensuite repris et amélioré au milieu des années 1990, pour donner Ada 95, 2006, le premier langage objet standardisé de manière internationale.

Le nom Ada a été choisi en honneur d'Ada Lovelace. Ada est un langage à typage statique, modulaire et offrant une syntaxe claire non ambigûe inspirée de Pascal. Il est souvent utilisé dans des systèmes temps-réel et/ou embarqués nécessitant un haut niveau de fiabilité (armée, transports ferroviaires, technologies aéronautiques, technologies spatiales...). Ada est un langage assez strict qui oblige à coder proprement, il est souvent enseigné pour des raisons pédagogiques.

Bases du langage

Fonction et procédures

Fonctions

En Ada, les arguments d'une fonction sont accessibles uniquement en lecture: il n'est donc pas question de modifier leur valeur lors de l'exécution de la fonction. Les fonctions retournent toujours quelque chose. Voici un exemple:

function Nom_fonction(arg1:type1;arg2:type 2...) return type_resultat is
déclarations
begin
instructions
return ...;
end Nom_fonction;

Procédures

Les procédures peuvent être définies comme des fonctions qui ne renvoient rien; elles peuvent néanmoins produire un résultat de sortie. Pour chaque paramètre de la procédure, on peut préciser la modalité de passage :

- in : lecture du paramètre, comme pour l'argument d'une fonction.
- out : écriture du paramètre uniquement (correspond à un résultat de sortie).
- in out : lecture et écriture: la valeur du paramètre est prise en compte et peut être modifiée.

Voici la structure d'une procédure:

procedure Nom_procedure(arg1:mode1 type1; arg2:mode2 type 2...) is
déclarations
begin
instructions
end Nom_procedure;

Syntaxe et opérateurs de comparaison

Chaque instruction est terminée par un point virgule ;. L'affectation se fait en utilisant  := . Une ligne de commentaires est préfixée par deux tirets --. Les opérateurs de comparaison sont les suivants:

= égalité
/= inégalité
< strictement inférieur à
> strictement supérieur à
<= inférieur à
>= supérieur à
in appartenance à un intervalle
not in non appartenance à un intervalle

Déclarations

La partie déclarative doit contenir:

- Les types et les sous-types.
- Les variables sous la forme Nom_variable:Nom_type[:= Valeur_Initiale];
- Les constantes telles que Pi:constant FLOAT:= 3.14159;
- Des procédures et des fonctions qu'on utilisera ensuite dans le corps.

Les types

Types discrets

Pour commencer, un peu de vocabulaire: les "types discrets" sont les types ordonnés où chaque élément a un successeur et un prédécesseur. Ils sont munis d'attributs, des fonctions exprimant les propriétés courantes du type. La syntaxe est T'nom_attribut, où T est un type discret. Ces attributs sont les suivants:

- T'FIRST

Borne inférieure du type T.


- T'LAST

Borne supérieure du type T.


- T'POS(X)

X est de type T et T'POS(X) renvoie la position de X dans le type T.


-T'VAL(N)

N est de type entier et T'VAL(N) est l'élément de position N dans le type T.


- T'SUCC(X)

X est de type T et T'SUCC(X) est le successeur de X dans T, ainsi T'SUCC(X)= T'VAL(T'POS(X)+1).


- T'PREC(X)

X est de type T et T'PREC(X) est le prédécesseur de X dans T, ainsi T'SUCC(X)= T'VAL(T'POS(X)-1).


- T'IMAGE(X)

X est de type T et T'IMAGE(X) est une chaîne de caractères qui contient l'image de X.


- T'WIDTH

Donne le nombre maximal de caractères pour une image d'une valeur de T.

- T'VALUE(S)

S est une chaîne de caractères qui est l'image d'un élément de type T; T'VALUE(S) est l'élément en question.

Types prédéfinis

Le type discret entier INTEGER. Il possède deux sous-types prédéfinis: NATURAL pour les entiers naturels et POSITIVE pour les entiers strictement positifs. Certains opérateurs sont prédéfinis, ce sont l'addition +, la multiplication *, la soustraction -, la division /, le reste de la division mod, l'exponentiation **.

Le type discret caractère CHARACTER. Pour représenter un caractère, on utilise les apostrophes : 'a'.

Le type discret booléen BOOLEAN, composé de TRUE et de FALSE. Les opérateurs logiques sont and, and then, or, or else et not.

le type FLOAT pour représenter les nombres réels.

le type STRING pour les chaînes de caractères. Pour représenter une chaîne de caractères, on utilise les guillemets, par exemple: "La petite Léa est très jolie".

Type énumérés

On peut définir un type énuméré, qui est un type discret fini (comme le type booléen), par exemple le type Jour:

type Jour is (lunae_dies, martis_dies, mercurii_dies, jovis_dies, veneris_dies, saturnus_dies, solis_dies);

L'ordre d'énumération définit un ordre. On a ainsi dans notre exemple lunae_dies < martis_dies < ... < solis_dies.

Sous-types

Un sous-type est défini comme la restriction d'un type parent discret, sous la forme:

subtype nom_sous_type is nom_type range val1 .. val2;

val1 et val2 sont deux éléments de type nom_type tels que val1 < val2. . Par exemple:

subtype Chiffre is INTEGER range 0..9; subtype Alphabet is CHARACTER range 'a'..'z';

On peut appliquer à un sous-type les fonctions prévues pour son type parent, mais il faut faire attention à ce que le résultat reste dans l'intervalle.

Types privés

Les types en Ada peuvent être divisés en deux catégories. Il y a d'une part types énumératifs, types tableaux etc. sans oublier les types prédéfinis, c'est à dire les types dont la structure est connue des utilisateurs. Ils sont dits publiques. D'autre part les types privés permettent de cacher les détails de structure afin de respecter le principe d'abstraction des données en masquant la représentation interne des données, exportant les opérations de manipulation de ce type, empêchant un usage non contrôlé.

La syntaxe d'une déclaration d'un type privé est: type T_NOM_DU_TYPE is private;.

Types limités

Si pour un type, on ne peut pas utiliser l'affectation et l'égalité prédéfinies, alors ce type est appelé un type limité. Attention, un type composé qui contient un composant limité doit obligatoirement être déclaré limité. Exemple:

type Rationnel is limited record
numérateur : POSITIVE := 1;
dénominateur : POSITIVE := 1;
end record;

Types privés limités

Les types privés limités sont comme les types privés, mais où l'utilisation est encore plus limitée; logique, non? Ils ne possèdent plus ni la comparaison ni l'affectation. Avec un type privé limité on ne peut que déclarer des variables et utiliser les sous-programmes fournis par le paquetage (sans affectation ni comparaison). Ces techniques permettent un contrôle total sur leur utilisation. Un type privé limité se déclare de la façon suivante : type T_EXEMPLE is limited private ;

Ouf! C'en est fini pour les types ;-) Les types privés limités sont des types privés dont l'utilisation est encore plus restreinte; ils ne possèdent plus ni la comparaison ni l'affectation.

Branchements conditionnels

Si, alors, sinon

Comme dans la majorité des langages on trouve une structure conditionnelle de type "si, alors, sinon" , elle se construit comme suit:

if condition then ... else ... end if;
if condition then ... elsif condition2 ... elsif condition3 ... end if;

Choix multiples

Il existe également une structure permettant de faire des choix multiples.

case expression is

    when choix1 => ...
    when choix2 => ...
    ...
    when others => ...
end case; 

Les boucles

Attention, l'indice d'une boucle est de type discret et c'est une variable muette. Cela signifie que cette variable n'a pas à être déclarée et que sa valeur ne peut pas être modifiée par des instructions explicites.

Pour

les boucles "pour" se construisent comme suit:

for indice in [reverse] debut .. fin loop ... end loop;

Si on veut préciser que l'intervalle doit être parcouru en sens inverse, on utilise le mot clef reverse.

Tant que

Les boucles "tant que" se construisent comme suit:

while condition loop ... end loop;

Les tableaux

Tableaux contraints

La taille des tableaux est précisée lors de la définition du type :

type Nom_Type_Tableau is array(Intervalle_fini_d'un_type_discret) of Type_Element;

Les bornes d'un tableau ne sont pas nécessairement statiques. Exemple:

type T is array (1..5) of INTEGER ;
tab1 : T;
type MATRICE is array(1..4, 1..4) of INTEGER;
ma_matrice : M;

On accède au i-ème élément d'un tableau tab en tapant tab(i). On peut manipuler les cases d'un tableau avec des agrégats, par exemple Tab1:Tableau(1..6):=(1|2=>3, others=>4); ou Tab2:Tableau:=(1..10=>3);.

L'opérateur & permet de concaténer deux tableaux de même type. Ainsi, T1 & T2 donne un tableau de taille T1'length+T2'length, contenant les éléments de T1 suivis de ceux de T2. & permet également de concaténer un élément à un tableau. Attention aux erreurs de dépassements, un tableau en Ada a une taille fixe une fois pour toutes lorsqu'il est déclaré.

Tableaux non contraints

Le type des indices et du type des éléments est précisé lors de la définition du type mais pas la taille du tableau. On peut faire sur les tableaux non contraints toutes les manipulations qu'on peut faire sur les tableaux contraints. Voici l'exemple d'un tableau de nombres naturels indexé par des entiers:

type T is array (INTEGER range <>) of NATURAL ;

Un objet de type T doit alors être contraint lors de sa déclaration, soit en précisant l'intervalle d'indexation, soit en lui affectant un autre tableau.

Chaînes de caractères

Le type STRING est un type pré-défini du paquetage STANDARD. Il est défini comme un tableau non contraint de caractères et indexé d'entiers strictement positifs. Les chaînes de caractères se manipulent donc exactement comme des tableaux, ainsi : S:STRING(1..18);. Quand on ne connait pas la longueur d'une chaîne de caractères, on est obligé de fixer lors de la déclaration une taille maximum et de gérer ensuite explicitement la vraie longueur.

Attributs de tableaux

Les tableaux bénéficient d'attributs spécifiques. Soit T un objet de type tableau, on a:

- T'FIRST indice du premier élément. T(T'FIRST) nous donne la première valeur.

- T'FIRST(n) indice du premier élément de la dimension n.

- T'LAST indice du dernier élément de la première dimension.

- T'LAST(n) indice du dernier élément de la dimension n.

- T'RANGE intervalle d'indexation de la première dimension de T.

- T'RANGE(n) intervalle d'indexation de la dimension n de T.

- T'LENGTH longueur de la première dimension du tableau.

- T'LENGTH(n) longueur de la dimension n du tableau.

Les structures

Une structure, ou enregistrement, est un objet composé d'une séquence de membres de types divers, portant des noms. On la construit comme suit:

type Nom_structure is record
champ1: type1;
champ2: type2;
champ3: type3;
end record;

On peut donner des valeurs initiales aux champs des structures, en mettant := valeur après le nom du type.

On accède aux champs d'une structure avec un point . : S: Nom_structure; ... Nom_structure.champ1 Nom_structure.champ2 Nom_structure.champ3

Pour affecter une valeur complète à une structure, on peut utiliser des agrégats:

type Date is record
jour: POSITIVE range 1..31;
mois: STRING(1..9);
annee: POSITIVE;
end record;

D:=(18, "février", 1983);
D:=(mois=>"février", jour=>18, annee=>1983);

Il est possible de passer des paramètres à une structure. Dans l'exemple suivant, le recours à une structure avec paramètres permet d'avoir des chaînes de caractères variables, et on mettra les dimensions que lors de la déclaration:

type Adresse_Manchot(I, B: Natural) is record
Igloo: STRING(1..I);
Banquise: STRING(1..B);
end record;

A: Adresse_Manchot(10,20);

Traitement des exceptions

Ada possède des exceptions prédéfinies, dont le nom est explicite: CONSTRAINT_ERROR, STORAGE_ERROR, PROGRAM_ERROR, NUMERIC_ERROR, TASKING_ERROR. Il y a également des exceptions prédéfinies liées aux entrées-sorties que l'on trouve dans la bibliothèque ADA.IO_EXCEPTIONS. Une exception, lorsqu'elle est déclenchée, interrompt l'exécution des blocs qu'elle traverse.

On peut lancer une exception grâce au mot clef raise. On peut aussi capturer les exceptions avec when. En Ada, le traitement des exceptions doit se faire dans les instructions bloc, les sous-programmes, les paquetages, les tâches ou les unités génériques. Ces traitements sont regroupés sous la rubrique exception comme dans l'exemple suivant:

exception when CONSTRAINT_ERROR => put_line("une contrainte n'a pas été respectée"); raise CONSTRAINT_ERROR;

Il est possible de définir une exception, de la même manière que l'on définit un type ou déclare une variable. On la manipule ensuite comme une exception prédéfinie.

Entrées-sorties

Les fonctionnalités d'entrées-sorties sont disponibles dans le paquetage ADA.TEXT_IO pour les chaînes de caractères et ADA.INTEGER_TEXT_IO pour les entiers. Les procédures les plus utiles sont get(...), put(...), put_line(...) et new_line.

Les pointeurs

Les pointeurs sont sans doute la notion la moins explicite du langage. Pas de panique! Il se peut que vous mettiez quelques temps à les prendre en main.

Déclaration

Les pointeurs en Ada s'utilisent grâce au mot clef access. Soit T_Quelconque un type quelconque, un type "pointeur sur un objet de type T_Quelconque" se déclare comme ceci: type T_Pointeur_T_Quelconque is access T_Quelconque ;. Désormais, toute variable (ou instance) de ce nouveau type T_Pointeur_T_Quelconque sera considérée comme pouvant pointer sur un objet de type T_Quelconque. On notera que le "type pointeur" n'existe pas en soi, seul un type "pointeur sur un type donné" peut être défini. On déclare deux pointeurs de ce type de la façon suivante: Pointeur_1, Pointeur_2 : T_Pointeur_T_Quelconque ;. Ils pourront ainsi désigner chacun un objet de type T_Quelconque. A ce moment là , ils ne pointent sur rien : leur valeur est automatiquement initialisée à NULL lors de la déclaration.

Création et accès à l'objet pointé

A tout moment l'utilisateur peut créer des objets dans le corps d'un sous-programme au moyen de l'allocateur new portant sur le type de l'objet qui doit être pointé. La valeur de retour est l'adresse mémoire dynamique que le système lui a allouée:

Pointeur_1 := new T_Quelconque ;
Pointeur_2 := new T_Quelconque ;

Les zones mémoire pour chaque objet pointé sont réservées; cependant elles n'ont toujours pas de valeurs. Celles-ci vont pouvoir leur être données comme suit, avec .all:

Pointeur_1.all := XXX ;
Pointeur_2.all := YYY ;

La permutation des deux valeurs s'obtient par permutation des valeurs des deux pointeurs (les valeurs ne changeront pas de place):

Pointeur_3 := Pointeur_1 ;
Pointeur_1 := Pointeur_2 ;
Pointeur_2 := Pointeur_3 ;

Opérations sur les pointeurs

Les seules opérations de comparaison sur les pointeurs sont l'égalité et la non-égalité. Le type pointeur est donc un type private. Cela est dû au fait que les valeurs d'un pointeur représentent des adresses mémoires (virtuelles), elles n'appartiennent pas à un ensemble ordonné. La représentation des adresses dépend de l'implémentation, et ce ne sont à priori pas forcément des entiers.

Ecrire un programme

Les paquetages

Le programme principal Ada utilise en général des paquetages, qui correspondent à des bibliothèques ou d'autres programmes. Pour cela, La clause with nom_paquetage au début d'un programme permet d'accéder aux fonctionnalités du paquetage nom_paquetage. On peut ajouter une clause use nom_paquetage qui permet d'invoquer les fonctionnalités de nom_paquetage directement, sans préfixer l'appel de nom_paquetage.

Un paquetage se partage en deux fichiers :

- nom_paquetage.ads qui contient la spécification du paquetage (fonctionnalités visibles): énumération des types, entête des fonctions et procédures proposées par le paquetage.

package nom_paquetage is
déclarations des types, fonctions, procédures...
end nom_paquetage;

- nom_paquetage.adb qui contient l'implémentation du paquetage. Cette partie peut également définir des procédures ou des fonctions cachées à l'utilisateur.

package body nom_paquetage is
définitions des fonctions, procédures...
end nom_paquetage;

Programme source

Le code écrit par un programmeur est constitué d'unités de bibliothèques qui doivent être placées dans des fichiers sources. Ces fichiers ont un suffixe obligatoire qui est pour la partie spécification .ads et pour l'implémentation .adb.

Le point d'entrée d'un programme Ada est la procédure principale par laquelle doit commencer l'exécution. Cette procédure peut porter un nom quelconque mais ne doit pas avoir d'arguments.

Exemple de programme

Après toutes ces présentations nous sommes pleinement capables d'écrire un petit programme. Voici un exemple de petit programme Ada que l'on stockera dans le fichier "bonjour.adb":

with Ada.Text_io;

procedure bonjour is
begin
Ada.Text_io.put_line ("bonjour le monde");
end bonjour;

Quels outils utiliser ?

Compilateurs

Il existe plusieurs compilateurs pour Ada. Dans ce qui va suivre, nous ne parlerons que de GNAT (GNU Ada Translator) qui fait partie de GCC (GNU Compiler Collection). C'est actuellement le meilleur compilateur, et il est entièrement libre. GNAT est installé par défaut dans la plupart des distributions GNU/Linux; si ce n'est pas le cas, il faut chercher le paquet qui s'appelle en général gcc-gnat.

Débuggueurs

Pour les programmes compilés avec GNAT, l'outil approprié est GDB (GNU Project Debugger). Eh oui, le projet GNU est partout :-). De plus, GDB possède une interface graphique, appelée GVD (GNU Visual Debugger), qui a été développée entièrement en Ada. Si GDB n'est pas installé, il faut chercher le paquet éponyme auprès de sa distribution.

Générateurs de documentation

Deuis quelques années on s'intéresse beaucoup aux outils qui permettent de générer facilement de la documentation à partir d'un code source, tels que JavaDoc pour le Java. Il existe des outils similaires pour Ada, mais ils sont peu connus. Pour n'en citer que deux, nous pourrions parler de AdaDoc et AdaBrowse. Puisqu'ils sont peu connus, il y a fort à parier que vous soyez obligés de les compiler.

Environnements de développements

La lecture d'un code en Ada étant très explicite, n'importe quel éditeur de texte fera l'affaire. On notera cependant qu'Emacs possède un mode Ada très abouti avec un menu et des raccourcis bien adaptés au langage, comme on peut le voir sur la capture d'écran ci-dessous:

Créations d'applications graphiques

C'est possible aussi grâce à GtkAda, une bibliothèque permettant de créer des applications graphiques portables en Gtk+. On peut également créer une application graphiquement. GtkAda est interfacé avec Glade, le logiciel de GNOME permettant de construire des interfaces graphiques.

Compilation

Compilation et édition de liens d'un programme

La façon la plus simple de compiler un programme est d'utiliser gnatmake. Ainsi, la commande gnatmake prog compilera le fichier prog.adb et donnera un exécutable ./prog. En fait, gnatmake réalise trois opérations. Il remplace les instructions suivantes:

$ gcc -c prog.adb # compilation du source
$ gnatbind # test de cohérence des différentes unités
$ gnatlink # édition des liens

L'étape de compilation produit un fichier objet .o et un fichier .ali par unité. Les fichiers .ali (pour Ada Library Information) contiennent les informations nécessaires ensuite à gnatbind et gnatlink.

Compilation de paquetages

La compilation de paquetage est simple, elle aussi. Prenons le cas d'un programme constitué d'un fichier contenant la procédure principale (principal.adb) et de deux autres fichiers contenant la spécification (paq.ads) et le corps (paq.adb) d'un paquetage. Il suffit simplement de taper gnatmake principal et gnatmake s'occupera de compiler automatiquement tous les fichiers auxiliares. Il va en fait procéder de la sorte:

$ gcc -c principal.adb
$ gcc -c paq.adb
$ gnatbind principal
$ gnatlink principal

Mêler Ada et d'autres langages

Ada est peu utilisé. Qu'à cela ne tienne! On peut mêler du code Ada avec un autre langage normalisé. Actuellement, on peut par exemple interfacer Ada avec les langages C, C++, Cobol et Fortran. Cela est possible par le biais du paquetage Interfaces et de ses fils (Interfaces.C, Interfaces.C.STRINGs, Interfaces.C.Pointers, Interfaces.Fortran...). Ce paquetage Interfaces définit les types élémentaires de la machine. Il est muni d'enfants qui définissent la vue Ada des types des autres langages. Par exemple, le paquetage Interfaces.C définit un type int, un type C_Float, etc. dont on garantit qu'ils correspondent aux types de C.

Conclusion

En savoir plus

- Association Ada-France: http://www.ada-france.org
- Les groupes français et anglais: fr.comp.lang.ada et comp.lang.ada.
- Le manuel de référence sur GNAT (en anglais): http://gcc.gnu.org/onlinedocs/gcc-3.3.5/gnat_rm/.
- Le guide de l'utilisateur de GNAT pour UNIX (en anglais): http://gcc.gnu.org/onlinedocs/gcc-3.3.5/gnat_ug_unx/.
- Le manuel de GCC: man gcc vous dira tous les secrets de la compilation.
- Le forum Développement de Léa-Linux.

C'est parti !

Ada est un langage facile, il peut s'apprendre en quelques heures! Cependant, rien n'est mieux que la pratique. Osez faire de petits exercices pour vous entraîner! Bon courage :-)




@ Retour à la rubrique Développement

Cette page est issue de la documentation 'pré-wiki' de Léa a été convertie avec HTML::WikiConverter. Elle fut créée par Jiel Beaumadier le 12/02/2005.

Copyright

© 12/02/2005 Jiel Beaumadier

Tête de GNU Vous avez l'autorisation de copier, distribuer et/ou modifier ce document suivant les termes de la GNU Free Documentation License, Version 1.2 ou n'importe quelle version ultérieure publiée par la Free Software Foundation; sans section invariante, sans page de garde, sans entête et sans page finale.