MIAGE CRÉTEIL: Algorithmique & Génie Logiciel avec ADA 1999 – 2008





Algorithmique & Génie Logiciel avec ADA






Une Introduction



Version 1.0 , le lundi 30 juillet 2007






La version la plus récente est disponible à http://www.dgaudry.com







Pour toute correspondance, utiliser : daniel@dgaudry.com




Download :



HTTP download open office version: VERSION OPEN OFFICE


HTTP download pdf version: Version PDF



Table des matières

1 Introduction au langage 8

2 La structure de base 8

2.1 ce qu'il faut savoir 8

2.1.1 Les mots réservés 8

2.1.2 Les attributs 8

2.1.3 Des noms créés par l'utilisateur 9

2.1.4 Des lignes de code 9

2.1.5 Des structures 9

2.1.6 Des opérateurs 9

2.2 création d'un programme 10

2.2.1 Le fichier texte contenant le code source 10

2.2.2 Zone 1 10

2.2.3 Zone 2 10

2.2.4 Zone 3 10

2.3 Le code source et sa traduction en exécutable 10

2.3.1 La compilation 10

2.3.2 Le link 10

2.3.3 L'éditeur 11

2.3.4 Un premier exemple 11

3 Les variables 11

3.1 Les différents types de variables 12

3.2 Les déclarations de type de variables et les déclarations de variables à partir de leur type 12

3.2.1 Les nombres constants 12

3.2.2 Les entiers 12

3.2.2.1 Integer ou long_integer 12

3.2.2.2 Range 13

3.2.2.3 Modulo 13

3.2.2.4 Positive 13

3.2.2.5 Natural 14

3.2.2.6 Les attributs applicables aux types entier ou dérivés 14

3.2.3 Les options pour les types 14

3.2.3.1 Subtype 15

3.2.3.2 New 15

3.2.3.3 Private 15

3.2.3.4 Limited private 15

3.2.3.5 Aliased 16

3.2.4 Les réels 16

3.2.4.1 Digits 16

3.2.4.2 Float ou long_float 16

3.2.4.3 Delta 16

3.2.4.4 Delta et digits 16

3.2.4.5 Les attributs applicables aux types float ou dérivés 17

3.2.5 Les booléens 17

3.2.6 Les caractères 17

3.2.6.1 La table ASCII 18

3.2.7 Les énumérations 19

3.2.8 Les tableaux et matrices 19

3.2.8.1 L'index et le contenu 19

3.2.8.2 Index de limites définies par des nombres 19

3.2.8.3 Index de limites définies par type 19

3.2.8.4 Index de limites définies par les limites d'un subtype 20

3.2.8.5 Exemples de matrices 20

3.2.9 Les chaînes de caractères 21

3.2.10 Les records 21

3.2.10.1 Les records simples 21

3.2.10.2 Les records avec discriminants 22

3.2.10.3 Les records avec des parties variables et des choix discrets 22

3.2.11 Les pointeurs 22

3.2.11.1 Déclaration de base 23

3.2.11.2 Déclarations incomplètes 24

3.2.11.3 Terminaison d'une déclaration incomplète 24

3.2.11.4 Pointeurs vers des objets composés (records et tableaux) 24

3.2.11.5 Assignation et test avec pointeurs 25

3.2.11.6 Effacement d'un pointeur et des données associées 25

3.2.12 Programmation objet 25

3.2.13 Abstract 25

3.2.14 Tagged 26

3.2.15 Extension et héritabilité des types "tagged" 26

3.2.16 Le type task (tâche) 26

3.3 Domaine d'existence des variables 26

3.3.1 Domaine d'existence limité à quelques lignes dans un code 26

3.3.2 Domaine d'existence limité à toutes les lignes d'une procédure / fonction 27

3.3.3 Domaine d'existence limité à une partie des procédures / fonctions d'un package 27

3.3.4 Domaine d'existence limité à toutes les lignes d'un package 27

3.3.4.1 Le domaine est limité à toutes les lignes du package avec impossibilité d'accès externe 27

3.3.4.1.1 Déclaration dans le "body" 27

3.3.4.1.2 Déclaration dans la spécification 28

3.3.4.2 Le domaine est limité à toutes les lignes du package avec possibilité d'accès externe 28

3.3.5 Domaine d'existence limité à toutes les lignes de tous les packages en utilisant "with ..." 29

3.3.6 Utilisation de "finalize" pour illustrer le domaine d'existence 29

4 Le découpage des routines externes en Fichier ‘ADS' et ‘ADB' 30

4.1 Le choix entre une fonction et une procédure 30

4.1.1 Le passage de paramètres 30

4.1.1.1 Le mode in 30

4.1.1.2 Le mode out 31

4.1.1.3 Le mode in out 31

4.1.1.4 Access 31

4.1.2 Les fonctions 31

4.1.3 Les procédures 32

5 La syntaxe du code 32

5.1 La syntaxe des affectations 32

5.1.1 Opérateurs logiques 33

5.1.2 Opérateurs de comparaison 33

5.1.3 Opérateurs d'addition 34

5.1.4 Opérateurs de signe 34

5.1.5 Opérateurs de multiplication 34

5.1.6 Opérateurs de rang le plus haut 35

5.1.7 Modification du sens des opérateurs classiques 35

5.1.8 Conversion entre types 35

5.1.8.1 Entier vers réel 35

5.1.8.2 Réel vers entier 35

5.1.8.3 Conversion par utilisation d'une adresse mémoire commune 35

5.2 La syntaxe des tests 35

5.2.1 Le test if 35

5.2.2 Le test case 36

5.3 La syntaxe des boucles 36

5.3.1 Boucle simple 37

5.3.2 Boucle while 37

5.3.3 Boucle for 37

5.4 La syntaxe d'appel des fonctions 37

5.5 La syntaxe d'appel des procédures 38

5.6 La segmentation en parties indépendantes par ‘declare' ou begin 38

5.7 Gestion des erreurs durant l'exécution du programme 39

5.7.1 La notion d'exception 39

5.7.2 Les exception intégrées au langage 39

5.7.3 Définition d'une exception 39

5.7.4 Gestion des exceptions 39

5.7.5 Impression écran du type d'erreur rencontré 40

6 Entrées et Sorties 40

6.1 entrée clavier 40

6.2 Utilisation de read_write 40

6.2.1 Entrée d'un entier 40

6.2.2 Sortie écran d'un entier 40

6.2.3 Entrée d'un entier long 41

6.2.4 Sortie écran d'un entier long 41

6.2.5 Entrée d'un réel 41

6.2.6 Sortie écran d'un réel 41

6.2.7 Entrée d'un réel long 41

6.2.8 Sortie écran d'un réel long 41

6.2.9 Entrée d'une chaîne de caractères 42

6.2.10 Sortie écran d'une chaîne de caractères 42

6.3 Utilisation de Ada.Text_Io 42

6.3.0.1 Lecture de nombre après instantiation: 42

6.3.0.1.1 Entier: 42

6.3.0.1.2 Réel: 42

6.3.0.1.3 Chaîne de caractères 43

6.3.1 Sortie écran 44

6.3.1.1 Principes généraux 44

6.3.1.2 Chaîne de caractères 44

6.3.1.3 Entier 44

6.3.1.4 Réels 45

6.3.1.4.1 Sans mise en forme 45

6.3.1.4.2 Avec mise en forme 45

6.3.1.5 Énumération / booléens 46

6.4 Lecture et écriture de fichiers 46

6.4.1 Lecture de fichier texte 46

6.4.2 Écriture de fichier texte 47

7 Les routines: procedures et fonctions 47

7.1 Premier exemple: la somme d'un tableau d'entiers 47

7.2 Second exemple: Manipulation des bits, application à la lecture d'un fichier texte par bloc pour codage 48

7.2.1 Utilisation des opérateurs logiques 48

7.2.1.1 Masque 49

7.2.2 Assignation 49

7.2.3 Décalage gauche et droite 49

7.2.3.1 Rotation 49

7.2.4 Détails du stockage des entiers, caractères et réels dans un mot de 32 bits 50

7.2.4.1 Partage de zone de mémoire 50

7.2.4.2 Transformation little endian big endian 51

7.2.5 La lecture d'un fichier texte par bloc pour codage 53

7.3 programmation d'un code à exécuter au début et la fin du domaine de validité d'une variable 56

8 Générique 57

8.1 Un cas d'école 57

8.1.1 La solution (ici elle est plus longue que la duplication mais c'est un exemple simpliste!) se compose de trois fichiers: 57

8.1.1.1 Une partie générique, fichier s.ads 57

8.1.1.2 Une partie générique, fichier s.adb 57

8.1.1.3 Un exemple de procédure d'utilisation, fichier d.adb 58

8.2 L'Intérêt du générique 58

8.3 Les variables génériques 58

8.3.1 Les variables de type private 59

8.3.2 Les variables de type discrètes 59

8.3.3 Les variables de type entier 59

8.3.4 Les variables de type Modulo 59

8.3.5 Les variables de type Réel 59

8.4 Les procédures et fonctions génériques 59

8.4.1 Les changements dans le code 59

8.4.2 La spécification 59

8.4.3 Le body 60

8.5 Le programme principal 61

8.5.1 Premier type de données 61

8.5.2 Instantiation du générique pour le premier type de données 61

8.5.3 Second type de données 62

8.5.4 Instantiation du générique pour le second type de données 62

8.5.5 Le code du programme principal 63

8.5.6 Le résultat du programme principal 64

8.6 Les fonctions et procédures dont un générique a besoin 65

8.7 Les fonctions Logiques: égal supérieur et inférieure 65

8.7.1 La fonction < 65

8.7.2 La fonction > 65

8.7.3 Instantiation du générique 66

8.7.4 programme principal 66

8.7.5 résultat du programme principal 68

8.8 Autres exemples 68

8.8.1 Utilisation de générique déjà écrits: Un exemple de tri commenté 68

8.8.2 Fichier t.adb 69

8.8.3 fichier sort.ads 69

8.8.4 fichier sort.adb 69

8.8.5 Le résultat écran 70

9 programmation objet 70

9.1 Le type 'tagged' 70

9.2 l'extension d'un type 'tagged' et héritabilité 71

9.3 Le polymorphisme en utilisant le concept de 'dispatching operations' 72

9.4 Exemple de dispatching pour le calcul des surfaces de triangles 74

9.5 Calcul d'une expression arithmétique postscript en utilisant un arbre d'expressions et un stack 77

10 Task 79

10.1 Introduction 79

10.2 Un premier exemple: écriture SUR L'ÉCRAN PAR DEUX TÂCHES NON COORDONNÉES 79

10.2.1 Le programme principal 79

10.2.1.1 Définition des tâches 79

10.2.1.2 Activation des tâches 79

10.2.1.3 Démarrage et arrêt des tâches 80

10.2.2 La tâche numéro 1 80

10.2.2.1 Les différentes parties d'une tâche 80

10.2.2.2 La partie s'exécutant seule 81

10.2.2.3 La partie s'exécutant simultanément avec le programme principal 81

10.2.3 La tâche numéro 2 81

10.3 Second exemple : utilisation d'un sémaphore pour COORDONNER LES DEUX TÂCHES 81

10.3.1 Introduction 81

10.3.2 But d'un sémaphore 82

10.3.2.1 Seize 82

10.3.2.2 Release 82

10.3.3 Le sémaphore écrit en protected type 82

10.3.4 Fonctionnement du sémaphore 83

10.3.5 Le même problème avec synchronisation par sémaphore 83

10.4 Troisième exemple: utilisation de Ada.Finalization pour la gestion du sémaphore 83

10.4.1 Introduction à Ada.Finalization 84

10.4.1.1 Fichier final.ads 84

10.4.1.2 Fichier final.adb 84

10.4.1.3 Fichier final-protects.ads 84

10.4.1.4 Fichier final-protects.adb 85

10.4.1.5 Fichier t_final.adb 85

10.4.2 Utilisation pour la gestion du sémaphore 85

10.4.3 Le code avec Ada.Finalization 85

10.5 Quatrième exemple: création dynamique de plusieurs tâches 85

10.5.1 Le discriminant d'une tâche 86

10.5.2 La déclaration d'une tâche en vue de sa création dynamique 86

10.5.3 L'appel d'une tâche avec discriminant 86

10.5.4 Création dynamique d'une tâche 86

10.5.5 Transmission de la variable d'appel à la partie de la tâche s'exécutanten parallèle et Utilisation du discriminant 87

10.5.6 Résultat du fonctionnement 88

10.6 Cinquième exemple: le dinner des philosophes 88

10.7 Les codes complets 92

10.8 Premier exemple 92

10.8.1 Task_1.adb 92

10.8.2 Task_1_a.ads 93

10.8.3 Task_1_a.adb 93

10.9 second exemple 95

10.9.1 Task_2.adb 95

10.9.2 Task_2_a.ads 96

10.9.3 Task_2_a.adb 96

10.10 troisième exemple 98

10.10.1 Fichier semaph.ads 98

10.10.2 Fichier semaph.adb 99

10.10.3 fichier Semaph-Protects.ads 100

10.10.4 fichier Semaph-Protects.adb 101

10.10.5 fichier task_3_a.ads 102

10.10.6 fichier task_3_a.adb 102

10.10.7 fichier task_3.adb 104

10.11 quatrième exemple 105

10.11.1 Fichier a.adb 105

10.11.2 Fichier call_task.ads 105

10.11.3 Fichier call_task.adb 105

10.11.4 Fichier task_global.ads 106

10.11.5 Fichier task_global.adb 106

10.12 Cinquième exemple 106

10.12.1 Fichier Philosopher_Main.adb 106

10.12.2 Fichier Philosopher_Data.ads 107

10.12.3 Fichier Philosopher_Task.ads 107

10.12.4 Fichier Philosopher_Task.adb 107

10.12.5 Fichier Random_Normal.ads 110

10.12.6 Fichier Random_Normal.adb 111

11 Algorithmique 115

11.1 introduction 115

11.1.1 Grammaires et langage formel, automates à états finis 115

11.1.2 Table de hashing 115

11.1.3 Stack 115

11.1.4 Queue 115

11.1.5 Arbre binaire 115

11.1.6 Arbre dictionnaire 115

11.1.7 Graphe 115

11.1.8 Tris 115

11.1.9 Ensemble 116

11.1.10 Anneau 116

11.2 grammaires et langage formel, automates à états finis 116

11.2.1 Les abréviations 116

11.2.2 Fonction 116

11.2.3 Procédure 116

11.2.4 L'algorithme 116

11.2.5 La déclaration 116

11.2.6 L'instruction 117

11.2.7 L'expression multiple 117

11.2.8 Le test 117

11.2.9 L'itération 117

11.2.10 Le block d'instruction 117

11.3 Invariant de boucle et validation 117

11.3.1 Utilisation de l'invariant de boucle 117

11.4 Complexité des algorithmes 118

11.5 Temps d'exécution des algorithmes 118

12 Les structures Classiques 118

12.1 L' itérateur 118

12.2 Introduction 119

12.3 La table de hashing 119

12.3.1 Vitesse de traitement 120

12.3.2 Traduction de la clé en un nombre 120

12.3.2.1 Numérisation par addition 120

12.3.2.2 Partage d'emplacement mémoire 120

12.3.2.3 Attribution d'une valeur numérique à chaque caractère 121

12.3.2.4 Numérisation par multiplication 122

12.3.2.5 Numérisation par division 123

12.3.2.6 Numérisation quadratique 123

12.3.2.7 Numérisation par décalage et manipulation des bits 123

12.3.3 Les collisions et leur résolution 124

12.3.4 Table de Hashing: Implémentation avec un tableau simple 124

12.3.4.1 Données et Types de données: 124

12.3.4.2 Initialiser 126

12.3.4.3 Ajout 126

12.3.4.4 Recherche 126

12.3.4.5 Suppression 127

12.3.4.6 itérateur 127

12.3.4.6.1 Initialiser 127

12.3.4.6.2 Suivant 128

12.3.4.6.3 Valeur 128

12.3.4.6.4 Fini 128

12.3.5 Table de Hashing: Implémentation avec un tableau Chaîné et des pointeurs 128

12.3.5.1 Données et Types de données: 129

12.3.5.2 Initialiser 131

12.3.5.3 Ajout 131

12.3.5.4 Recherche 132

12.3.5.5 Suppression 133

12.3.5.6 itérateur 134

12.3.5.6.1 Initialiser 134

12.3.5.6.2 Suivant 134

12.3.5.6.3 Fini 134

12.3.5.6.4 Valeur 134

12.4 Le stack 134

12.4.0.1 Données et Types de données: 135

12.4.1 Le stack (pile) : Implémentation avec un tableau 136

12.4.1.1 Ajout (push) 136

12.4.1.2 Délétion (pop) 136

12.4.1.3 Dernière valeur (top) 136

12.4.1.4 Initialiser 137

12.4.1.5 itérateur 137

12.4.2 Le stack: Implémentation avec des pointeurs 137

12.4.2.1 Données et Types de données: 137

12.4.2.2 Ajout (push) 139

12.4.2.3 Délétion (pop) 139

12.4.2.4 Dernière valeur (top) 139

12.4.2.5 Initialiser 140

12.4.2.6 Itérateur 140

12.4.2.6.1 Initialiser 140

12.4.2.6.2 Valeur 140

12.4.2.6.3 Suivant 140

12.4.2.6.4 Fini 141

12.5 La queue 141

12.5.1 La queue: Implémentation avec un tableau 141

12.5.1.1 Données et Types de données: 141

12.5.1.2 Ajout 142

12.5.1.3 Délétion 143

12.5.1.4 Dernière valeur 143

12.5.1.5 Initialiser 143

12.5.1.6 Itérateur 143

12.5.1.6.1 Initialiser 143

12.5.1.6.2 Valeur 144

12.5.1.6.3 Suivant 144

12.5.1.6.4 Fini 144

12.5.2 La queue: Implémentation avec des pointeurs 144

12.5.2.1 Données et Types de données: 145

12.5.2.2 Ajout 146

12.5.2.3 Délétion 148

12.5.2.4 Dernière valeur 149

12.5.2.5 Initialiser 149

12.5.2.6 Itérateur 149

12.5.2.6.1 Initialiser 149

12.5.2.6.2 Valeur 149

12.5.2.6.3 Suivant 149

12.5.2.6.4 Fini 150

12.6 L'anneau 150

12.6.1 L'anneau: Implémentation avec des pointeurs 150

12.6.1.1 Ajout 152

12.6.1.2 Délétion 156

12.6.1.3 Valeur 157

12.6.1.4 Initialiser 158

12.6.1.5 Rotation 158

12.6.1.6 Itérateur 158

12.6.1.6.1 Initialiser 158

12.6.1.6.2 Valeur 158

12.6.1.6.3 Suivant 159

12.6.1.6.4 Fini 159

12.7 L'arbre binaire 159

12.7.1 L'arbre binaire: Implémentation avec un tableau 160

12.7.1.1 Données et Types de données: 163

12.7.1.2 Ajout 163

12.7.1.3 Délétion 164

12.7.1.3.1 La recherche de l'élément à supprimer 164

12.7.1.3.2 Suppression: le choix entre les trois cas 164

12.7.1.3.3 Le cas où il n'y a aucun fils 164

12.7.1.3.4 Le cas où il n'y a qu'un seul fils 164

12.7.1.3.5 Le cas où il y a deux fils. 165

12.7.1.3.6 Remplacement par le sous arbre 165

12.7.1.4 Recherche 169

12.7.1.5 Initialiser 170

12.7.1.6 itérateur (pre-order, in-order & post-order) 170

12.7.1.6.1 Initialiser 170

12.7.1.6.2 Valeur 171

12.7.1.6.3 Suivant 171

12.7.1.6.4 Fini 172

12.7.2 L'arbre binaire: Implémentation avec des pointeurs 172

12.7.2.1 Données et Types de données: 172

12.7.2.2 Ajout 174

12.7.2.3 Délétion 176

12.7.2.3.1 Recherche avec direction depuis le parent 176

12.7.2.3.2 Suppression: le choix entre les QUATRE cas 176

12.7.2.4 Initialiser 180

12.7.2.5 Recherche 180

12.7.2.6 Itérateur (pre-order, in-order & post-order) 181

12.7.2.6.1 Initialiser 181

12.7.2.6.2 Valeur 181

12.7.2.6.3 Suivant 182

12.7.2.6.4 Fini 184

13 Les algorithmes de tri classiques 184

13.1 Le tri bulle (bubble sort) 184

13.2 Le tri par tas (heap sort) 185

13.2.1 Algorithme 185

13.2.2 Pseudo code 190

13.2.2.1 Swap 190

13.2.2.2 transformation d'un sous arbre en tas 190

13.2.2.3 Construction du tas à partir d'un arbre quelconque 191

13.2.2.4 Tri à partir d'un tas 192

13.2.2.5 Programme principal 192

13.3 Le tri fusion (melt sort) 192

13.3.1 Le Rôle de la double récursion 192

13.3.2 La partie tri fusion 192

13.3.3 Le code en Ada 197

13.4 Introduction aux grammaires et langage formel, automates à états finis 198

13.4.1 Implémentation par un automate 198

13.4.1.1 Le problème 200

13.4.1.2 La solution 201

13.4.2 Implémentation par une série de fonctions d'un exemple récursif 202

13.4.2.1 Le problème 202

13.4.2.2 La solution 202

13.4.2.2.1 Les types de données 202

13.4.2.2.2 L'objet token et les opérations associées 202

13.5 L'arbre dictionnaire 204

13.5.0.1 Données et Types de données: 204

13.6 Tirage au hasard 205

13.6.1 Utilisation des packages inclus dans le langage 205

13.6.2 Utilisation d'un algorithme particulier: "mersenne twister" 207

14 Annexes: les codes complets 211

14.1 Le package read_write 211

14.2 Le code de la table de hashing en tableau simple 220

14.3 Le code de la table de hashing en tableau chaîné 225

14.4 Le code du stack (tableau) 231

14.5 Le code du stack (pointeurs) 235

14.6 Le code de la queue (tableau) 240

14.7 Le code de la queue (pointeurs) 244

14.8 Le code de l'anneau 249

14.9 Le code de l'arbre binaire (tableau) 260

14.10 Le code de l'arbre binaire (pointeurs) 268

14.11 Le code du tri bulle 277

14.12 Le code du tri en tas 277

14.13 Le code du tri fusion 280

14.14 Le code du test de l'expression algébrique: automate 282

14.15 Le code du test de l'expression algébrique: Fonctions 283

14.16 Le code de l'arbre dictionnaire 287

15 L'algorithmique en action, exemple 1: un calculateur simple 293

15.1 Analyse 293

15.1.1 Première approche du découpage 293

15.1.2 Entrée du calcul 293

15.1.3 Test de la validité 293

15.1.4 Traduction du découpage précédent en postfix pour le calcul 293

15.1.5 Calcul à partir de la traduction postfix. 293

15.1.6 Affichage du résultat 293

15.1.7 Découpage en tâches indépendantes 294

15.1.8 Dépendances des modules 294

15.2 Définitions des données 294

15.2.1 Identification des données 294

15.2.2 Le stockage des données 294

15.2.3 Les types de données 294

15.2.3.1 Chaîne de caractères 294

15.2.3.2 Tableau de chaînes de caractères 294

15.2.4 Les données dans la spécification d'un « package » commun 295

15.2.4.1 Le code 295

15.3 Relations entre les modules 295

15.3.0.1 Nom du module 295

15.3.0.2 Données en sortie 295

15.3.1 Le module principal 295

15.3.1.1 Nom du module 295

15.3.1.2 Données à l'entrée 295

15.3.1.3 Traitement des données 296

15.3.1.4 Données en sortie 296

15.3.2 Le module entrée utilisateur 296

15.3.2.1 Nom du module 296

15.3.2.2 Données à l'entrée 296

15.3.2.3 Traitement des données 296

15.3.2.4 Données en sortie 296

15.3.3 Le module test de la validité 296

15.3.3.1 Nom du module 296

15.3.3.2 Données à l'entrée 296

15.3.3.3 Traitement des données 296

15.3.3.4 Données en sortie 296

15.3.3.5 Le Module découpage en opérateur opérande 297

15.3.3.5.1 Nom du module 297

15.3.3.5.2 Données à l'entrée 297

15.3.3.5.3 Traitement des données 297

15.3.3.5.4 Données en sortie 297

15.3.4 Le module traduction du découpage précédent en postfix 297

15.3.4.1 Nom du module 297

15.3.4.2 Données à l'entrée 297

15.3.4.3 Traitement des données 297

15.3.4.4 Données en sortie 297

15.3.5 Le module Calcul à partir du postfix 297

15.3.5.1 Nom du module 297

15.3.5.2 Données à l'entrée 297

15.3.5.3 Traitement des données 297

15.3.5.4 Données en sortie 298

15.3.6 Le module affichage du résultat 298

15.3.6.1 Nom du module 298

15.3.6.2 Données à l'entrée 298

15.3.6.3 Traitement des données 298

15.3.6.4 Données en sortie 298

15.3.7 Le code : le point de départ 298

15.3.7.1 data.ads 298

15.3.7.2 main.adb 298

15.3.7.3 calcul.ads 299

15.3.7.4 calcul.adb 299

15.3.7.5 data_io.ads 299

15.3.7.6 data_io.adb 299

15.3.7.7 decoupage.ads 300

15.3.7.8 decoupage.adb 300

15.3.7.9 traduction.ads 300

15.3.7.10 traduction.adb 300

15.3.7.11 validation.ads 300

15.3.7.12 validation.adb 301

15.4 Le Traitement des données 301

15.4.1 Le module définition des données 301

15.4.1.1 Définition des procédure et fonctions 301

15.4.1.2 Traitement 301

15.4.2 Le module principal 301

15.4.2.1 Définition des procédure et fonctions 301

15.4.2.2 Traitement 301

15.4.3 Le module entrée utilisateur 301

15.4.3.1 Définition des procédure et fonctions 301

15.4.3.2 Traitement 302

15.4.3.2.1 Lecture de la commande 302

15.4.3.2.2 Analyse du problème 302

15.4.3.2.3 Lecture de la ligne de commande 302

15.4.3.2.4 Entrée par l'utilisateur s'il n'y a pas d'arguments sur la ligne de commande. 304

15.4.3.3 Le code complet 304

15.4.4 Le module test de la validité 305

15.4.4.1 Définition des procédure et fonctions 305

15.4.4.2 Traitement 305

15.4.4.2.1 Introduction: la grammaire d'une expression arithmétique 305

15.4.4.2.2 Traduction de la grammaire dans un automate à états finis 305

15.4.4.2.3 Les transitions 305

15.4.4.2.4 La table de traduction caractères ==> transitions 305

15.4.4.2.5 La matrice états transitions 307

15.4.4.2.6 Le fonctionnement de l'automate 308

15.4.4.3 Le code complet 308

15.4.5 Le Module découpage en opérateur opérande 309

15.4.5.1 Définition des procédure et fonctions 309

15.4.5.2 Traitement 309

15.4.5.2.1 Le résumé 309

15.4.5.2.2 Les détails 310

15.4.5.2.3 Parties copiées et collées du module précédent 310

15.4.5.2.4 Les variables 310

15.4.5.2.5 La table de vérité 311

15.4.5.2.6 Les détails du déroulement 311

15.4.5.3 Le code complet 312

15.4.6 Le module traduction du découpage précédent en postfix 313

15.4.6.1 Définition des procédure et fonctions 313

15.4.6.2 Traitement 314

15.4.6.3 Nature des données d’entrée de l’algorithme 314

15.4.6.4 Algorithme de Traduction 314

15.4.6.4.1 Le stack 314

15.4.6.4.2 Priorité Des Opérateurs 315

15.4.6.5 Partie principale 316

15.4.6.6 L'algorithme plus détaillé 316

15.4.6.7 Analyse de l'algorithme détaillé 317

15.4.6.8 Le code du stack 317

15.4.6.8.1 Les variables 317

15.4.6.8.2 Le code 317

15.4.6.8.3 Push 317

15.4.6.8.4 Pop 317

15.4.6.8.5 Value 317

15.4.6.8.6 Clear 318

15.4.6.9 le code du test de priorité des opérateurs 318

15.4.6.9.1 Les variables 318

15.4.6.9.2 Le code 318

15.4.6.10 Le code du test opérande 319

15.4.6.11 Le code du programme principal 319

15.4.7 Calculs à partir du postfix 322

15.4.7.1 Définition des procédure et fonctions 322

15.4.7.2 Traitement 322

15.4.7.2.1 Résumé 322

15.4.7.2.2 Exemple 322

15.4.7.2.3 Détails des opérations 324

15.4.7.2.4 Le stack de réels 325

15.4.7.3 Le code complet 325

15.4.8 Le module affichage du résultat 326

15.4.8.1 Définition des procédure et fonctions 326

15.4.8.2 Traitement 326

15.4.8.2.1 Exploration des possibilités du langage 327

15.4.8.2.2 Utilisation de « image » 327

15.4.8.2.3 Utilisation du générique « Float_Io » 327

15.4.8.2.4 Utilisation du générique « Float_Io » avec une chaîne de caractères 328

15.4.8.2.5 Traduction du réel en une chaîne de caractères. 329

15.4.8.2.6 Élimination des espaces au début. 329

15.4.8.2.7 Remplacement de tous les chiffres non significatifs par des zéros. 329

15.4.8.2.8 Élimination des zéros non significatifs. 329

15.4.8.2.9 Affichage de la chaîne de caractères sur l'écran. 329

15.4.8.2.10 La gestion d'exception avec affichage en format scientifique. 330

15.4.8.3 Le code complet 330

16 L'algorithmique en action, exemple 2: Le codage et décodage "lzw" 331

16.1 Introduction 331

16.1.1 L'algorithme de compression 331

16.1.1.1 Initialisation de l'algorithme de compression 332

16.1.1.2 Détails de l'algorithme de compression 332

16.1.2 L'algorithme de décompression 332

16.1.2.1 Initialisation de l'algorithme de décompression 332

16.1.2.2 Détails de l'algorithme de décompression 332

16.1.3 L'algorithme LZW, détails supplémentaires 333

16.1.3.1 Exemple de codage 333

16.1.3.2 Exemple de décodage 334

16.2 Structures et opérations nécessaires 335

16.2.1 Chaînes de caractères de longueur variable 335

16.2.2 Table de hashing et opérations associées au codage 335

16.2.2.1 Initialisation de la table de hashing du codage 336

16.2.2.2 Ajout à la table de hashing du codage 336

16.2.2.3 Existe dans la table de hashing du codage 336

16.2.2.4 Lecture de la table de hashing du codage 337

16.2.3 Tableau de chaînes de caractères de longueur variable et opérations associées au décodage 337

16.2.3.1 Initialisation du tableau de chaînes de caractères du décodage 337

16.2.3.2 Ajout au tableau de chaînes de caractères du décodage 337

16.2.3.3 Existe dans le tableau de chaînes de caractères du décodage 338

16.2.3.4 Lecture du tableau de chaînes de caractères du décodage 338

16.2.4 Gestion de variables, codées sur 8, 9, 10, 11 ou 12 bits sans signe 338

16.2.5 Lecture d'un fichier par bytes, envoi au décodage et écriture codée sur 8, 9, 10, 11 ou 12 bits sans signe dans un fichier 338

16.2.5.1 Lecture des caractères depuis le fichier à coder et mise à disposition pour la routine de codage. 338

16.2.5.2 Réception des codes depuis la routine de codage, traduction en bytes et écriture dans un fichier. 340

16.2.6 Réception de variables codées sur 8, 9, 10, 11 ou 12 bits sans signe, envoi au décodage et écriture dans un fichier par bytes 341

16.2.6.1 Lecture des codes depuis le fichier à décoder et mise à disposition pour la routine de décodage. 341

16.2.6.2 Réception des caractères depuis la routine de décodage et écriture dans un fichier. 343

16.2.7 Le codage 343

16.2.8 Le décodage 344

16.3 Le code complet 345

16.3.1 Fichier Lzw_1.ads 345

16.3.2 Fichier Lzw_1.adb 346

16.3.3 Fichier Lzw_2.ads 349

16.3.4 Fichier Lzw_2.adb 350

16.3.5 Fichier Lzw_Data.ads 352

16.3.6 Fichier Lzw_Debug.ads 352

16.3.7 Fichier Lzw_Debug.adb 353

16.3.8 Fichier Lzw_Io_Compress.ads 353

16.3.9 Fichier Lzw_Io_Compress.adb 354

16.3.10 Fichier Lzw_Io_Expand.ads 358

16.3.11 Fichier Lzw_Io_Expand.adb 359

16.3.12 Fichier Lzw.adb 361

16.3.13 Fichier Linked_Hash.ads 363

16.3.14 Fichier Linked_Hash.adb 365



1 Introduction au langage


Ce langage a été développé pour permettre la traduction directe de l'analyse intellectuelle d'un problème dans un code sans étape intermédiaire. Il permet de coder depuis l'application la plus simple jusqu'au code orienté objet multi-tâche. Il permet la capture complète au niveau de chaque élément du code des contraintes issues de l'analyse du problème. Ada permet également un traitement efficace et élégant des erreurs survenues pendant le déroulement du programme.

2 La structure de base

La structure de base d'un langage est la grammaire (avec sa ponctuation) et le vocabulaire. La grammaire gouverne l'ordre des mots dans la ‘phrase' et le vocabulaire est défini par:

2.1 ce qu'il faut savoir

2.1.1 Les mots réservés



abort else new return

abs elsif not reverse

abstract end null

accept entry select

access exception separate

aliased exit of subtype

all or synchronized

and for others tagged

array function out task

at overriding terminate

generic package then

begin goto pragma type

body private

if procedure

case in protected until

constant interface raise use

declare is range when

delay limited record while

delta loop rem with

digits renames

do mod requeue xor


2.1.2 Les attributs



access address adjacent aft

alignment all base bit_order

body_version callable caller ceiling

class component_size compose constrained

copy_sign count definite delta

denorm digits exponent external_tag

first first_bit floor fore

fraction identity image input

last last_bit leading_part length

machine machine_emax machine_mantissa machine_overflows

machine_radix machine_rounds max max_size_in_storage_elements

min model_emin model_epsilon model_mantissa

model_small modulus new output

pos pred range read

remainder round rounding_safe_first safe_last

scale scaling signed_zeros size

small storage_size succ tag

terminated truncation unbiased_rounding unchecked_access

val valid value version

wide_image wide_value wide_width width

write



2.1.3 Des noms créés par l'utilisateur

Il suivent une règle bien précise (voir plus loin), et servent à identifier les variables, le noms de procédure et les noms de fonctions.

Quelques exemples (en ada il n'y a pas de différence entre majuscule et minuscule):

A

bonjour

Ma_feuille

a_1

2.1.4 Des lignes de code

Chaque 'phrase' se termine par ;


a := 1;

dsort(a => b);

x := 1 + X;

2.1.5 Des structures

Ces structures (procédure, boucle, test if, ….) récursives qui s'emboîtent un peu à la façon des poupées gigognes, elles se terminent SYSTÉMATIQUEMENT par END (loop, if, ….);


2.1.6 Des opérateurs

Assignation :=

Addition +

Soustraction -

multiplication *

Division /

Puissance **

Et and

Ou or

Non not.

Ou exclusif xor

Supérieur >

Inférieur <

Supérieur ou égal. >=

Inférieur ou égal. <=

égal =

Différent /=

Concaténation (de tableaux, de chaîne de caractères) &

Choix multiple. (dans les «case» et les initialisation de tableaux) |

Explicitation de paramètres dans un appel fonction/procédure =>



2.2 création d'un programme

Pour créer un programme il faut:

2.2.1 Le fichier texte contenant le code source

Créer un fichier texte résidant sur le disque de votre ordinateur, par exemple aaa.adb (noter l'extension adb, et le nom aaa) dont voici un exemple valable (qui ne fait rien !). Il est divisé en plusieurs zones:


--zone 1

With bbb;



Procedure aaa

Is


--zone 2


Begin


--zone 3

Null;



End aaa;


Les lignes de code commençant par – sont des commentaires non pris en compte.

2.2.2 Zone 1

C'est ici que l'utilisateur déclare les procédures, fonctions et packages (qui sont des collections de procédures et de fonctions) contenues dans D'AUTRES FICHIERS ou déjà incorporés au langage. Cette zone s'arrête au mot clef «procedure» (ou «package» ou «function»).

2.2.3 Zone 2

Dans cette zone on déclare:


2.2.4 Zone 3

C'est là que se trouve le code source qui D O I T être segmenté en parties indépendantes. Ce code doit être ABONDAMMENT COMMENTÉ pour rendre sa logique lisible et facile à suivre.

2.3 Le code source et sa traduction en exécutable

Une fois le code écrit il faut le traduire dans un programme par un procédé qui s'effectue par:

2.3.1 La compilation

Le compilateur vérifie d'abord que les règles de grammaire et de syntaxe sont respectées et traduit le code source en un fichier ‘objet' qui représente, pour simplifier, le code source en un code machine intermédiaire.

2.3.2 Le link

Le linker transforme le fichier objet et tous les fichiers objet associés dans la zone 1 (et ceux implicitement associes) en un programme que l'on peut exécuter. Il faut, dés le début, prendre comme habitude de créer des structures complètes et de demander SYSTÉMATIQUEMENT AU COMPILATEUR DE TESTER LA SYNTAXE.

2.3.3 L'éditeur

L'utilisation d'un éditeur spécialisé, et de conception moderne, permet en outre une productivité accrue, et facilite beaucoup l'apprentissage.


Les possibilités de l'éditeur doivent comprendre:


2.3.4 Un premier exemple

Tous les détails seront expliqués plus tard, voici le texte du code stocké dans le fichier premier.adb et le résultat après compilation, link et exécution:


with Ada.Text_Io;


procedure Premier

is

Resultat : Integer;


begin

Resultat := 2;

Resultat := Resultat ** 10;

Ada.Text_Io.Put_Line("2 puissance 10 = " & Integer'Image(Resultat));


end Premier;



La compilation se fait directement depuis l'éditeur ou en ouvrant un fenêtre «dos» ou «xterm» selon l'O.S. employé, puis en utilisant la commande

gnatmake premier


Utilisation du compilateur GNAT (fenêtre DOS sous windows)


F:\ada\current\w\miage>gnatmake premier

gcc -c premier.adb

gnatbind -x premier.ali

gnatlink premier.ali

F:\ada\current\w\miage>


et le résultat:


F:\ada\current\w\miage>premier

2 puissance 10 = 1024

F:\ada\current\w\miage>


Utilisation du compilateur GNAT (fenêtre xterm sous linux)



[daniel@localhost miscellaneous]$ gnatmake premier

gcc -c premier.adb

gnatbind -x premier.ali

gnatlink premier.ali

[daniel@localhost miscellaneous]$ ./premier

2 puissance 10 = 1024

[daniel@localhost miscellaneous]$


D'autres compilateurs peuvent aussi être utilisés (Janus, Aonis,……)


Quelques détails pour les curieux:


Sauf entre " et " les espaces et les retours à la ligne sont ignorés et sont seulement utilisés pour rendre le code lisible.

3 Les variables

Tous les langages de programmation modernes imposent une déclaration préalable des variables (basic n'est pas, de ce point de vue, un langage moderne).

ADA impose les règles suivantes pour la création de nom (variable, type de variable, nom de fonction de procédures de package, …….)


Les règles pour inventer un nom valable (identifier) sont décrites comme suit:


Identifier ::= identifier_letter { [ underline ] letter_or_digit }

letter_or_digit ::= identifier_letter | digit

identifier_letter ::= upper_case_identifier_letter | lower_case_identifier_letter

digit ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'

underline ::= '_'


Les abréviations (généralement utilisées en algorithmique pour décrire une grammaire) sont les suivantes:

{ xxxxxx } veut dire 0 à n répétitions de xxxxxx

[ yyyyyyy ] veut dire yyyyyy est optionnel

| veut dire ou

::= veut dire défini par

upper_case_identifier_letter veut dire toutes les lettres majuscules de A à Z

lower_case_identifier_letter veut dire toutes les lettres Minuscules de a à z


Cette définition servira, dans un exercice, à illustrer la capacité du langage à exprimer directement un problème posé (illustration simple d'un automate à états finis contre des fonctions récursives avec test if imbriqués et boucles ) .


3.1 Les différents types de variables

Ada permet de représenter tous les objets que l'on peut rencontrer dans l'écriture d'un programme.

Certains types de variables sont déjà prédéfinis: les nombres, les tableaux et matrices, les caractères, les chaînes de caractères.

D'autres sont crées par l'utilisateur selon ses besoins.

Nous allons voir systématiquement comment effectuer ces déclarations.

Chaque type a des attributs qui lui sont associés et décrivent ses propriétés. C'est un point important du langage car ces ‘attributs' participent à l'écriture du code en facilitant sa compréhension et sa sûreté de fonctionnement

3.2 Les déclarations de type de variables et les déclarations de variables à partir de leur type


3.2.1 Les nombres constants


Dans ce cas on sait que la valeur ne changera pas (d'ailleurs le compilateur y veillera)


Charge_de_rupture : constant := 8.0 * 1024.0;

Max : constant := 500;

Taille_de_tableau : constant := Max / 6

memory : constant := 2 ** 16;

a, b ,c : constant := 1;


Le mot clé constant sera utilisé dans toutes les déclarations si le contenu de l'objet ne doit pas être modifié dans le programme.

3.2.2 Les entiers

Un type entier est prédéfini et s'appelle integer (ou long_integer)

3.2.2.1 Integer ou long_integer

Ce sont deux types prédéfinis avec les limites suivantes (peuvent varier d'un compilateur à l'autre et aussi en fonction du CPU)

Integer varie de -232 à 232 -1 (par exemple)

Long_integer varie de -264 à 264 -1 (par exemple);

L'instruction:


Z: integer;


Défini une variable dont le nom est Z pour stocker des valeurs de -232 à 232 -1 (par exemple). Cette variable n'a pas de valeur stockée connue (ATTENTION!!!!!!! selon les compilateurs elle peut contenir une valeur au hasard ou 0). La base mathématique utilisée pour représenter le nombre peut être différente de 10.


X : Long_integer := 15; -- Notation Décimale

Y : Long_integer := 2#1111#; -- Notation Binaire (base 2)

W : Long_integer := 8#77#; -- Notation Octale (base 8)

Z : Long_integer := 16#F#; -- Notation Hexadécimale (base 16)


Défini des variables dont le nom est X, Y et Z pour stocker des valeurs de -264 à 264 -1 (par exemple). X, Y, W et Z ont la même valeur 15. Observez bien la notation dans des bases autres que 10.

3.2.2.2 Range

On peut aussi définir un nouveau type d'entier, non compatible directement avec les deux types prédéfinis précédents.


Type my_integer_8 is range 1 .. 8;


Défini un NOUVEAU type contenant des entiers dont le nom est my_integer_8 pour stocker des valeurs de –1 à 8.


Ce type est différent du type integer prédéfini par le compilateur!!!!!!


A_1: my_integer_8:= my_integer_8'first;


La variable A_1 est du type my_integer_8 (entier différent de integer!!! car créé spécialement). Elle a comme valeur 1 noter l'utilisation de l'attribut FIRST qui équivaut à la plus petite valeur possible.

3.2.2.3 Modulo

C'est un type d'entier sans signe avec une arithmétique appropriée (qui comprend les opérateurs logiques or, and, et xor bit à bit):


Type my_modulo is mod 4;


Les variables de ce type peuvent avoir les valeurs 0, 1, 2 et 3. Avec les particularités suivantes:

3 + 1 donne 0

0 – 1 donne 3

de même pour * et /


mod_4: my_modulo:= my_modulo'last;


Cette instruction définit une variable dont le nom est Mod_4 pour stocker des valeurs de 0 à 3. Cette variable a la valeur 3, noter l'utilisation de l'attribut Last qui équivaut à la plus grande valeur possible pour les variables de type my_modulo.


Modular := 2 and 3; -- modular est égal à 2

Modular := 2 or 3; -- modular est égal à 3

Modular := 2 xor 3; -- modular est égal à 1

Modular := 3 + 1; -- modular est égal à 0

l'utilisation d'un masque permet de travailler au niveau des bits.

Modular := 2#10# and Mod_4 ; -- modular est égal à 2


Les opérations suivantes sont utilisées de façon courante:

Modular := Modular * 2**N;

Modular := Modular / 2**N;

Modular := Modular and 02#0110#;-- ici les bits 1 et 4 sont effacés (remplacés par des zéros).

Modular := Modular or 02#0110#;-- ici les bits 1 et 4 sont remplacés par des uns).

Modular := (Modular *2**N) or (Modular /2**(Modular'size-N));-- Modular'size = 4 étant le nombre de bits de modular


L'utilisation de l'hexadécimal permet une lecture plus simple si le nombre de bits est élevé:



Type modulo_64 is mod 2**64 ; - donne une variable avec 64 bits soit 16 chiffres hexadécimal.


Z: modulo_64;

.....

z:= z and 16#F000000000000000#;--ne garde que les 4 bits de poids le plus élevé de Z;


z := (z *2**N) or (z /2**(z'size-N));-- permutation circulaire

3.2.2.4 Positive

C'est un subtype (voir plus loin) prédéfini avec les limites suivantes (peuvent varier d'un compilateur à l'autre et aussi en fonction du CPU)

Positive varie de 1 à 232 -1 (par exemple)


A_M_0: Positive := Positive'First;


Cette instruction définit une variable dont le nom est A_M_0 pour stocker des valeurs de 1 à 232 -1 (par exemple). Cette variable a la valeur 1, noter l'utilisation de l'attribut First qui équivaut à la plus petite valeur possible pour les variables de type Positive.

3.2.2.5 Natural

C'est un subtype (voir plus loin) prédéfini avec les limites suivantes (peuvent varier d'un compilateur à l'autre et aussi en fonction du CPU)

Natural varie de 0 à 232 -1 (par exemple)


M_0: Natural := Natural'First;


Cette instruction définit une variable dont le nom est M_0 pour stocker des valeurs de 1 à 232 -1 (par exemple). Cette variable a la valeur 0, noter l'utilisation de l'attribut First qui équivaut à la plus petite valeur possible pour les variables de type Natural.

3.2.2.6 Les attributs applicables aux types entier ou dérivés

En plus des attributs first et last il existe aussi, entre autres, des attributs qui peuvent entre autre s'appliquer aux entiers :


Subtype test_type is integer range 1..5;

X: Test_Type:=2;

Y: Test_Type:=5;

Z: Test_Type;


Image


Transforme le contenu de la variable en un chaîne de caractères (principalement pour l'impression).

Test_type'image(x) renvoie le caractère 2 (avec un espace devant pour le signe +). Bien entendu, il existe dans le langage des méthodes permettant de contrôler le format des impressions.


Value


C'est l'inverse de la précédente, il transforme des caractères en un entier.


Z:= Test_type'Value(5);


Z contient maintenant 5.


Min


Permet de garder le minimum de deux variables


Z:= Test_type'Min(X,Y);


Z contient maintenant 2.


Max


Permet de garder le Maximum de deux variables

Z:= Test_type'Max(X,Y);

Z contient maintenant 5.


Range


C'est un attribut très utile qui équivaut à l'étendue des valeurs du type, il sert pour la logique, les tests et les boucles.


2 in Test_type'range renvoie vrai


3.2.3 Les options pour les types

Il est peu pratique (les types sont en effet incompatibles entre eux voir 3.2.3.2) de créer autant de types différents d'entiers que nécessaire pour couvrir les différences de nature des objets que l'on veux représenter. C'est pourquoi il existe un mécanisme pour limiter les bornes à partir d'un type (prédéfini ou créé).

3.2.3.1 Subtype

Subtype eee is my_integer_8 range 2 .. 5;


Cela donne un type dont le nom est eee compatible avec my_integer_8 mais limité à une plage de valeurs plus petite.


M_0: eee:= eee'last;


Cette instruction définit une variable de type eee dont le nom est M_0 pour stocker des valeurs de 2 à 5. Cette variable a la valeur 5, noter l'utilisation de l'attribut LAST qui équivaut à la plus grande valeur possible pour les variables de type eee.

3.2.3.2 New

Type fruit_number_type is range 1..100;


[RAPPEL]

Cette instruction défini un NOUVEAU type contenant des entiers dont le nom est fruit_number_type pour stocker des valeurs de 1 à 100

Ce type est différent du type integer prédéfini par le compilateur!!!!!!

Vous ne pouvez pas les mélanger dans une même instruction, le compilateur vous donne un message semblable à:

xxx.adb:12:18: expected type "fruit_number_type" defined at line …

xxx.adb:12:18: found type "Standard.Integer"

gnatmake: "premier.adb" compilation error


Ce type peut servir à définir des type dérivés:


Type apple_number_type is new fruit_number_type;

Type grapefruit_number_type is new fruit_number_type;


Ces instructions définissent DEUX NOUVEAU types contenant des entiers dont les nom sont apple_number_type et grapefruit_number_type pour stocker des valeurs de 1 à 100. Ces deux types sont différent du type fruit_number_type mais ont conservé ses limites de valeurs de 1 à 100.


apple_number: apple_number_type:= apple_number_type'first;


Cette instruction définit une variable de type apple_number_type dont le nom est apple_number pour stocker des valeurs de 1 à 100. Cette variable a la valeur 1, noter l'utilisation de l'attribut First qui équivaut à la plus petite valeur possible pour les variables de type apple_number_type.


grapefruit_number: grapefruit_number_type:= grapefruit_number_type;


Cette instruction définit une variable de type grapefruit_number_type dont le nom est grapefruit_number pour stocker des valeurs de 1 à 100. Cette variable n'a pas de valeur connue!!..

3.2.3.3 Private

Les types de variables définis dans un package (c'est une collection de fonctions et de procédures)

peuvent et sont utilisés dans les procédures et fonctions qui leur font référence dans la ZONE 1 (voir plus haut). Le concepteur du programme DOIT décider de l'utilisation par l'extérieur des variables des types qu'il définit.


Type example is private;

……

Private

……

Type example is integer range 1..2;


Les variables de ce type, déclarées à l'extérieur du «package» ne pourront PAS y être manipulées, seuls l'opérateur d'assignation (:=) est autorisé.

3.2.3.4 Limited private

Les types de variables définis dans un package (c'est une collection de fonctions et de procédures)

Peuvent et sont utilisés dans les procédures et fonction qui leur font référence dans la ZONE 1 (voir plus haut). Le concepteur du programme DOIT décider de l'utilisation par l'extérieur des variables des types qu'il définit.


Type example is limited private;

……

Private

……

Type example is integer range 1..2;


Les variables de ce type, déclarées à l'extérieur du «package» ne pourront PAS y être manipulées. L'utilisateur ne connaîtra pas les détails internes à ce type. Les objets de ce type sont en quelque sorte des mot de passe . Leur manipulation PASSERA OBLIGATOIREMENT par les procédures déclarées dans ce «package».

3.2.3.5 Aliased

type rr: aliased integer:=0;


Les variables de ce type pourront avoir leur adresse mémoire accessible par un pointeur.

3.2.4 Les réels

Les réels sont utilisée pour représenter les nombres avec décimales.

3.2.4.1 Digits

type Real is digits 2;


Cette instruction défini un NOUVEAU type contenant des réels dont le nom est real pour stocker des valeurs avec deux chiffres après la virgule la limite minimum et maximum ne sont pas précisées.

Le format de stockage des nombres dans la mémoire limite dans la réalité entre -3.40 10+38 et 3.40 10+38.


type Coefficient is digits 10 range –1.0 .. 1.0;


Cette instruction défini un NOUVEAU type contenant des réels dont le nom est real pour stocker des valeurs avec dix chiffres après la virgule. la limite minimum et maximum est -1.0000000000 et 1.0000000000 .


AAA: Real;

BBB: Coefficient := Coefficient'last;


Ces instruction déclarent deux variables correspondant aux type ci-dessus:

AAA peut représenter des nombres réels à deux décimales et n'est pas initialisée.

BBB peut représenter des nombres réels à dix décimales, est initialisée à 1.0000000000 et est limitée entre –1 et 1.

3.2.4.2 Float ou long_float

Trois type prédéfinis Float, Long_Float et Long_Long_Float existent avec les spécifications suivantes


X: float := 0.0;


X peut varier entre -3.40282E+38 et 3.40282E+38 avec 7 chiffres significatifs (stockage mémoire sur 32 bits).


Y: long_float := 0.0;


X peut varier entre -1.79769313486232E+308 et 1.79769313486232E+308 avec 16 chiffres significatifs (stockage mémoire sur 64 bits).

3.2.4.3 Delta

type Volt is delta 0.125;


Cette instruction défini un type contenant des réels dont le nom est volt pour stocker des valeurs arrondi à 0.125 prés la limite minimum et maximum ne sont pas précisées.

Par exemple 1 1.125 1.250 1.275 etc. …. Ce peut être utilisé pour stocker des valeurs de mesure physique pour lesquelles la précision de mesure est connue ( le voltmètre a une précision de 0.125 V dans cet exemple).

3.2.4.4 Delta et digits

type Money is delta 0.01 digits 15;


Cette instruction défini un type contenant des réels dont le nom est Money pour stocker des valeurs arrondi à 0.01 près la limite minimum et maximum ne sont pas précisées. Par exemple 1 1.125 1.250 1.275 etc. …. Ce peut être utilisé pour stocker des valeurs de physique pour lesquelles la précision de mesure est connue (le solde de votre compte en banque). 15 chiffres significatifs sont exigés pour les calcul (financiers dans cet exemple);


subtype Salary is Money digits 10;


C'est un exemple pour gérer les salaires des employés en modifiant une des caractéristiques.

3.2.4.5 Les attributs applicables aux types float ou dérivés

En plus des attributs applicables aux type entiers , il existe des attributs plus spécifiques:

3.2.5 Les booléens

C'est un type prédéfini qui peut avoir deux valeurs: True ou False.


D: Boolean:= False;

3.2.6 Les caractères

C'est un type prédéfini qui peut stocker un caractère;


A_char: character:= ' ';


A_char est initialisé avec un ESPACE!!!


Tous les caractères sont stockés en binaire par groupe de 8 bits selon un tableau. Ce tableau est prédéfini en ada . Par exemple:

A_char := Ascii.bs;



3.2.6.1 La table ASCII

Par exemple ^A signifie la clé ctrl et A en même temps

 

Dec  Hex  Char clavier Dec  Hex  Char clavier Dec  Hex  Char   Dec  Hex  Char 
---  ---  ----  ------ ---  ---  ---- ------- ---  ---  ----    ---  ---  ---- 
000  00   NUL    ^@    018  12   DC2   ^R     036  24    $      054  36    6
001  01   SOH    ^A    019  13   DC3   ^S     037  25    %      055  37    7
002  02   STX    ^B    020  14   DC4   ^T     038  26    &      056  38    8
003  03   ETX    ^C    021  15   NAK   ^U     039  27    '      057  39    9
004  04   EOT    ^D    022  16   SYN   ^V     040  28    (      058  3A    :
005  05   ENQ    ^E    023  17   ETB   ^W     041  29    )      059  3B    ;
006  06   ACK    ^F    024  18   CAN   ^X     042  2A    *      060  3C    <
007  07   BEL    ^G    025  19   EM    ^Y     043  2B    +      061  3D    =
008  08   BS     ^H    026  1A   SUB   ^Z     044  2C    ,      062  3E    >
009  09   HT     ^I    027  1B   ESC   ^[     045  2D    -      063  3F    ?
010  0A   LF     ^J    028  1C   FS    ^\     046  2E    .      064  40    @
011  0B   VT     ^K    029  1D   GS    ^]     047  2F    /      065  41    A
012  0C   FF     ^L    030  1E   RS    ^^     048  30    0      066  42    B
013  0D   CR     ^M    031  1F   US    ^_     049  31    1      067  43    C
014  0E   SO     ^N    032  20   SP           050  32    2      068  44    D
015  0F   SI     ^O    033  21   !            051  33    3      069  45    E
016  10   DLE    ^P    034  22   "            052  34    4      070  46    F
017  11   DC1    ^Q    035  23   #            053  35    5      071  47    G

Dec  Hex  Char       Dec  Hex  Char       Dec  Hex  Char       Dec  Hex  Char
---  ---  ----       ---  ---  ----       ---  ---  ----       ---  ---  ----
072  48    H         090  5A    Z         108  6C    l         126  7E    ~
073  49    I         091  5B    [         109  6D    m         127  7F
074  4A    J         092  5C    \         110  6E    n         128  80    €
075  4B    K         093  5D    ]         111  6F    o         129  81    
076  4C    L         094  5E    ^         112  70    p         130  82    ‚
077  4D    M         095  5F    _         113  71    q         131  83    ƒ
078  4E    N         096  60    `         114  72    r         132  84    „
079  4F    O         097  61    a         115  73    s         133  85    …
080  50    P         098  62    b         116  74    t         134  86    †
081  51    Q         099  63    c         117  75    u         135  87    ‡
082  52    R         100  64    d         118  76    v         136  88    ˆ
083  53    S         101  65    e         119  77    w         137  89    ‰
084  54    T         102  66    f         120  78    x         138  8A    Š
085  55    U         103  67    g         121  79    y         139  8B    ‹
086  56    V         104  68    h         122  7A    z         140  8C    Œ
087  57    W         105  69    i         123  7B    {         141  8D    
088  58    X         106  6A    j         124  7C    |         142  8E    Ž
089  59    Y         107  6B    k         125  7D    }         143  8F    

Dec  Hex  Char       Dec  Hex  Char       Dec  Hex  Char       Dec  Hex  Char
---  ---  ----       ---  ---  ----       ---  ---  ----       ---  ---  ----
144  90             162  A2    ¢         180  B4    Ž         198  C6    Æ
145  91    ‘         163  A3    £         181  B5    µ         199  C7    Ç
146  92    ’         164  A4    €         182  B6    ¶         200  C8    È
147  93    “         165  A5    ¥         183  B7    ·         201  C9    É
148  94    ”         166  A6    Š         184  B8    ž         202  CA    Ê
149  95    •         167  A7    §         185  B9    ¹         203  CB    Ë
150  96    –         168  A8    š         186  BA    º         204  CC    Ì
151  97    —         169  A9    ©         187  BB    »         205  CD    Í
152  98    ˜         170  AA    ª         188  BC    Œ         206  CE    Î
153  99    ™         171  AB    «         189  BD    œ         207  CF    Ï
154  9A    š         170  AA    ª         188  BC    Œ         206  CE    Î
153  99    ™         172  AC    ¬         190  BE    Ÿ         208  D0    Ð
155  9B    ›         173  AD    ­          191  BF    ¿         209  D1    Ñ
156  9C    œ         174  AE    ®         192  C0    À         210  D2    Ò
157  9D             175  AF    ¯         193  C1    Á         211  D3    Ó
158  9E    ž         176  B0    °         194  C2             212  D4    Ô
159  9F    Ÿ         177  B1    ±         195  C3    à         213  D5    Õ
160  A0              178  B2    ²         196  C4    Ä         214  D6    Ö
161  A1    ¡         179  B3    ³         197  C5    Å         215  D7    ×

Dec  Hex  Char       Dec  Hex  Char       Dec  Hex  Char       Dec  Hex  Char
---  ---  ----       ---  ---  ----       ---  ---  ----       ---  ---  ----
216  D8    Ø         234  EA    ê         252  FC    ü
217  D9    Ù         235  EB    ë         253  FD    ý
218  DA    Ú         236  EC    ì         254  FE    þ
219  DB    Û         237  ED    í         255  FF
220  DC    Ü         238  EE    î
221  DD    Ý         239  EF    ï
222  DE    Þ         240  F0    ð
223  DF    ß         241  F1    ñ
224  E0    à         242  F2    ò
225  E1    á         243  F3    ó
226  E2    â         244  F4    ô
227  E3    ã         245  F5    õ
228  E4    ä         246  F6    ö
229  E5    å         247  F7    ÷
230  E6    æ         248  F8    ø
231  E7    ç         249  F9    ù
232  E8    è         250  FA    ú
233  E9    é         251  FB    û

3.2.7 Les énumérations

Il arrive souvent que l'on désire représenter dans un projet, des objets définis par leur nom. Par exemple: des fruits peuvent être de oranges, des pommes, des poires, des cerises, etc. Dans les langages anciens, il fallait coder ces espèces de fruits par des nombres: c'est peu pratique, sujet à des erreurs et ne respecte pas les principes de la programmation orientée objet. Ada propose un type spécial:


Type fruit_type is (orange, apple, pea, cherry);

A_fruit:fruit_type :=fruit_type'last ;


A_fruit est une variable pouvant avoir seulement les valeurs déclarées { orange ou apple ou …} dans le type et initialisé à cherry.

3.2.8 Les tableaux et matrices

Les tableaux (les matrices étant une généralisation des tableaux) permettent de stocker de nombreuses données de nature identique (de même type).

Chaque donnée individuelle est affectée d'un indice qui permet de les différencier de toutes les autres.

La notation traditionnelle s'écrit comme suit: X(i) ou x est le nom du tableau et i l'indice affecté à la valeur représenté par X(i).

Il faut IMPÉRATIVEMENT distinguer :

3.2.8.1 L'index et le contenu

Le type de variable contenu dans le tableau et le type de l'indice utilisé peuvent (ou non) être les mêmes. La limitation pour les indices est que leur nombre soit limité (pas de flottants par exemple).


L'opérateur de concaténation noté & permet de nombreuses opérations sur des fragments de tableaux. Il faut donc décider lors de l'analyse intellectuelle si ces possibilités seront utilisées (uniquement possible sur plusieurs tableaux de même type) car la déclaration pourra être différente ;

A cet effet il existe plusieurs méthode de déclaration de type de tableau. Il faut TOUJOURS commencer par déclarer les types de contenu et d'indice (sauf emploi des types prédéfinis par le langage).

3.2.8.2 Index de limites définies par des nombres

Un tableau


Type U_Type is array (- 2 .. 3) of Integer range 1 .. 100;

U : U_Type := (others => 1);


C'est la plus directe: le type de tableau est déclaré de façon explicite. Le tableau: variable de type tableau_type initialisé a 0 pour toutes les valeurs des indices{ -2, -1, 0, 1, 2 et 3}. L'inconvénient est qu'aucun type ne correspond ni au contenu ni à l'indice! Il n'est donc pas possible de déclarer des variables pour les représenter sans courir le danger de dépasser les limites des valeurs.

3.2.8.3 Index de limites définies par type

Un tableau

Type indice_type is new integer range –2..3;

Type tableau_type is array(indice_type'range) of boolean;


Tableau : tableau_type := (others=>true);

Indice : indice_type;

Contenu : boolean;


On défini


On déclare le tableau: variable de type tableau_type initialisé à «true» pour toutes les valeurs des indices{ -2, -1, 0, 1, 2 et 3}.


Autre exemple:


Un tableau


Type fruit_type is (orange,apple,pear, cherry);

Type tableau_type is array(fruit_type'range) of boolean;


Tableau : tableau_type:=(others => true);

Indice : indice_type;

Contenu : boolean;


Autre exemple

Un tableau


Type fruit_type is (orange,apple,pear, cherry);

Type tableau_type is array (boolean) of fruit_type;


Tableau : tableau_type:= (others => apple);

Indice : boolean;

Contenu : fruit_type ;

3.2.8.4 Index de limites définies par les limites d'un subtype

Un tableau


Subtype contenu_type is integer range 1..2;

Subtype indice_type is integer range –2..3;

Type tableau_type is array(indice_type'range) of contenu_type;

Tableau : tableau_type:=(others => 1);

Indice : indice_type;

Contenu : contenu_type;


On défini le contenu, l'indice, le type de tableau , le tableau: variable de type tableau_type initialisé à 0 pour toutes les valeurs des indices{ -2, -1, 0, 1, 2 et 3}.

L'un des inconvénients est que la concaténation est limitée aux tableaux dont l'indice varie entre –2 et +3.


Autre exemple avec le même résultat

Un tableau


Subtype contenu_type is integer range 1..2;

Subtype indice_type_a is integer range –2..3;

Subtype indice_type_b is integer range 10..20

Type tableau_type is array(integer range <>) of contenu_type;


Tableau_a : tableau_type(indice_type_a'range) := (others => 1);

Tableau_b : tableau_type(indice_type_b'range) := (others => 1);


Maintenant tableau_a ET tableau_b sont de MÊME TYPE.

De cette façon on pourra écrire:


tableau_a(-2..0) := tableau_b(15..17);


Il y a aussi d'autres avantages que nous verrons plus loin.



3.2.8.5 Exemples de matrices

Dans la programmation avec des tableaux à N dimensions {matrices} il est particulièrement facile de mélanger lignes et colonnes si les deux indices sont de même type.

Les méthodes pour déclarer les tableaux se généralisent aux matrices.

Nous nous limiterons à quelques exemples:

Une matrice


Subtype contenu_type is integer range 1..200;

type indice_type_a is NEW integer range –20..39;

type indice_type_b is NEW integer range 10..20;

Type matrice_type is array(integer range <>,

integer range <>) of contenu_type;


Matrice:matrice_type(indice_type_a'range,indice_type_b'range):=(others =>(others => 1));


indice_a : indice_type_a;

indice_b : indice_type_b;


La généralisation des écritures permet d'écrire

x := matrice(indice_a,indice_b);

La ligne de code


x := matrice(indice_b,indice_a);


Sera REJETÉE par le compilateur.


Une matrice


Type fruit_type is (orange,apple,pear, cherry);

type indice_type is NEW integer range –20..39;

Type matrice_type is array(indice_type range <>,boolean range <>) of fruit_type;


Matrice: matrice_type(indice_type'range,boolean):= (others => (others => apple));

3.2.9 Les chaînes de caractères

Une chaîne de caractères est un type prédéfini par le langage: le type string. C'est un tableau de caractères avec un indice entier.

Sa définition POURRAIT s'écrire: array (positive range <>) of character;


Il possède toutes les caractéristiques des tableaux et en particulier, utilise l'opérateur &.

Toutes sortes de fonctions et procédures prédéfinies par le langage permettent de rechercher un mot, de transformer en minuscule, en majuscule, de traduire certaines lettres en d'autre lettres …….

Les bornes s'écrivent avec "


Chine: string (1..10);

R : constant string :="bonjour"

V : string (1..10) :="01234456789";

-- attention!!! le compilateur compte les caractères il en faut 10


Subtype my_string_type is string(1..50);

my_string : my_string_type := (others => ' ‘);--initialisée avec 50 espaces

A_string : my_string_type := (others => 'X‘);--initialisée avec 50 X

3.2.10 Les records

Décrivons un exemple de variables associées (par exemple appartenant au même objet). Le nom d'un article et son prix.


3.2.10.1 Les records simples

Type nom_type is (chaise,table,lampe,assiette);

Type prix_type is delta 0.10 digits 10 range 0.0 .. 1000.0;

Type article_type is record

Nom : nom_type := nom_type'first;

Prix : prix_type:= prix_type'first;

End record;


Article: article_type;


Le record 'capture' les propriétés de l'objet de l'exemple. La variable article a deux composants qui peuvent être d'un accès individuel:


article.Nom := 10.51;

article.article := Lampe;

ou collectif:

article := (nom => table, prix => 20.0);


Bien que pratique dans les cas simples, il n'est pas adapté à des problèmes plus sophistiqués.

3.2.10.2 Les records avec discriminants

Il est possible d'inclure un tableau et sa taille dans un record:


type Storage_Array_Type is array (Long_Integer range <>) of integer;


type Storage_Type(Size : Long_Integer := Initial_Array_Size)

is

record

Storage_Array : Storage_Array_Type(0 .. Size);

Current_Data_Position : Long_Integer := 0;

Current_Last_Position : Long_Integer := 0;

Bookmark_Position : Long_Integer := 0;

end record;


tableau: Storage_Type(Size => 10); -- initialisé avec un tableau d'indice 0 à 10;

3.2.10.3 Les records avec des parties variables et des choix discrets

Souvent les propriétés détaillées des articles sont différentes: il n'ont pas tous une couleur, se vendent au cageot, à la pièce ,….


Type nom_type is (chaise,table,pomme,poire,banane);

Type prix_type is delta 0.10 digits 10 range 0.0 .. 1000.0;

Subtype stock_type is integer range 1..100;

Type couleur_type is (blanc, brun, noir);

Type article_type (Article : nom_type := nom_type'first )

is

record

--c'est la partie commune à tous les articles :


stock: stock_type := stock_type'first;


-- partie spéciale pour table chaise et lampe qui sont compatibles : vente à l'unité et couleur


case Article

is

when chaise | Table | Lampe=>

prix_unitaire : prix_type := prix_type'first;

couleur : couleur_type := couleur_type'first;


when Pomme | poire =>

prix_au_kilo : prix_type := prix_type'first;

prix_pour_un_cageot : prix_type := prix_type'first;


when banane =>

prix_a_la_piece : prix_type := prix_type'first;

prix_pour_un_regime : prix_type := prix_type'first;


End case;


End article_type;


Type banana_type is article_type (Article=>banana);

Banana : banana_type;

.....

Banana. prix_pour_un_regime := …….;


Ici on distingue pour les différents articles la façon de les vendre: à l'unité, au kilo, par cageot ou par régime.

On se rapproche de la programmation ‘objet' mais il manque l'héritabilité (entre autres).

On peut aussi, comme illustré plus haut définir un «subtype» limité au bananes.

3.2.11 Les pointeurs

L'un des concepts utilisés lors de la création du langage ADA a été de garder une représentation statique du problème aussi longtemps que possible. La conséquence est que l'analyse de la robustesse et de la validité du code peut être faite par le compilateur: si un programme compile, et si l'analyse du problème a été bien faite il fonctionnera sans problème. De plus, pendant son exécution, les idées incorporées dans le code seront testées (valeur des variables, indice de tableau compris dans les limites déclarées …). En effet certains langages concurrents, basés sur une utilisation préalable importante de l'assembleur utilise les pointeurs et l'arithmétique sur ceux–ci à un très grand degré. Cela même si ce n'est pas utile.


Les pointeurs en ada permettent un accès indirect à un «objet» en représentant l'adresse de cet objet qui peut être une variable, une procédure, une fonction ou une tâche. Il permettent, et c'est leur fonction la plus importante, la création dynamique d'objets n'existant pas quant le programme commence son exécution. Par exemple:






Dés que l'objet n'est plus utile, il faut libérer la mémoire correspondante en utilisant l'instantiation d'un générique approprié !!!!

par exemple :


procedure Free is new Ada.Unchecked_Deallocation(Object => String,

Name => String_access_type);

3.2.11.1 Déclaration de base

Créons un exemple de type de pointeur à partir du type prédéfini string:


Type String_access_type is access all string;


Cet exemple permet d'illustrer quelques emplois possibles, créons une variable qui est le pointeur:


String_access: String _access_type := null;


Le mot clé null indique que le pointeur représenté par la variable string_access est vide et ne contient pas d'information valable. Le test d'un pointeur pour la valeur null est d'emploi courant (if null=string_access then ...).


Another_string_access : String _access_type:= new String'("bonjour");


--Ou alors

Another_string_access : String _access_type := null;

........

Another_string_access := new String'("bonjour");


C'est la création dynamique d'une chaîne de caractères, la variable Another_string_access pointe vers cette chaîne qui est accessible en utilisant l'opérateur de dé-référence .all :

Another_string_access.all est égal à "bonjour".

Ici, on ne défini pas la longueur de la chaîne de caractères à stocker, c'est un avantage primordial, le début et la fin sont accessibles par Another_string_access.all'first et Another_string_access.all'last:




Type String_array_type is arrray (1 .. 3) of String_access_type;


String_array : String_array_type := (1 => new'("01"),

2 => new'("01234"),

3 => new'("1"));


Cet autre exemple permet de construire un tableau de chaînes de caractères de longueurs différentes.


Il existe également la possibilité de gérer le stockage associé à ces pointeurs.


Par example:



with Ada.Unchecked_Deallocation;

procedure x …


Type String_access_type is access all string;

X : String_access_type := null;



procedure Free is new Ada.Unchecked_Deallocation(Object => String,

Name => String_access_type);

Begin

………

X := new string'("ee");

……

Free (x);

……

3.2.11.2 Déclarations incomplètes

L'une des applications les plus intéressantes des pointeurs est l'utilisation de records dont un des éléments est un pointeur sur ce même record. Cela pose le problème de l'œuf et de la poule: Chaque déclaration de l'un des deux types (le pointeur ou le record) dépend de l'autre déclaration qui est à la ligne suivante et donc encore inconnue du compilateur. Inverser les deux lignes ne change rien au problème: la poule précède l'œuf ou l'œuf précède la poule la question n'est pas résolue!!.


Le langage ADA résous le problème en ne précisant pas tout de suite la nature du type vers lequel pointeront les variables du type pointeur.


type a_record;


La nature exacte de ce type n'est pas encore définie …..


type record_access is access a_record;


Cette déclaration est incomplète!

3.2.11.3 Terminaison d'une déclaration incomplète

type A_record

is

record

Value : Integer;

Pointeur_to_next_record : record_access:=null;

end record;


La déclaration du record est complétée et contient un pointeur sur lui-même qui permettra d'accrocher dynamiquement des nouveaux records selon les besoins. Par exemple:


Record:A_Record;

..

Record := new A_Record'(Value => Data,

Pointeur_to_next_record => Record);

3.2.11.4 Pointeurs vers des objets composés (records et tableaux)

Examinons un exemple de déclaration:


type B is record

Plus : integer :=0;

Moins: integer :=0;

Egal : integer :=0;

end record;


type Access_To_B is access B;


X: Access_To_B;


Cela indique que tout nouvel objet de type Access_To_B créé par 'new B' sera initialisé tel que Plus, Moins et Egal seront à 0.

L'allocation peut aussi avoir une initialisation explicite:


X:= new B'(Plus => 2,

Moins => 3,

Egal => 5);


Supposons l'utilisation d'un tableau dynamique tel que :


type Tableau_Type is array (integer range <>) of integer;

type Access_To_Tableau is access Tableau_Type;


pendant la création aucune borne n'est nécessaire:


V: Access_To_Tableau;

W: Access_To_Tableau;


Au moment de stocker des valeurs, la longueur doit être précisée:


V:= new Tableau_Type(3..19);


V:= new Tableau_Type(1..7);


le dé-référencement s'écrit alors


V.all(i);

X.Plus.all


3.2.11.5 Assignation et test avec pointeurs

Attention!! les assignations n'ont pas le même sens et ne conduisent pas au résultat à priori évident:

les valeurs deviennent identiques

X.all:=Y.all;

et

les pointeurs vont au même endroit

X:=Y;


sont différentes!!!


Les test peuvent s'écrivent:


if X = null -- aucun objet

then

.....

end if;


if X.all = Y.all -- valeurs pointées égales

then

.....

end if;


3.2.11.6 Effacement d'un pointeur et des données associées


Quant le pointeur et son stockage associé ne sont plus nécessaires, il faut restituer la mémoire correspondante pour éviter les "fuites de mémoire". Par exemple:

déclaration du pointeur

type access_to_string is access all string;

instantiation de la procédure de restitution de la mémoire correspondante

procedure Free_Node is new Ada.Unchecked_Deallocation(Object => string,

Name => access_to_string);

déclaration du pointeur

A: access_to_string;

assignation du contenu du stockage associé

A:=new string'("abc");

restitution de la mémoire correspondante

Free_Node(A);

assignation à une nouvelle valeur

A:=new string'("cde");

3.2.12 Programmation objet

Il n'est pas possible d'écrire de grandes applications sans utiliser les techniques modernes de programmation. Nous allons prendre l'exemple du magasin qui vend:


Des tables, des chaises, des oranges et des bananes.


Plusieurs opérations s'appliquent à ces objets (au sens propre et programme) vendus dans ce magasin. Mais, leurs différences sont suffisante (durée de stockage, unité de vente, unité de stockage ….) pour justifier un traitement différent:


3.2.13 Abstract

Propriétés communes à tous ces objets:

Ils sont vendus dans le magasin et c'est tout !! on capture cette analyse (on dit abstraction) par une déclaration:


Type objet_vendus_dans_le magasin_type is abstract tagged with private;


L'utilisation du mot clé abstract indique que à ce stage, je ne désire pas de possibilité de traitement des données. Il sont vendus dans le magasin, ce qui peut se traduire par:


Procedure vendre(quoi: in out objet_vendus_dans_le magasin_type) is abstract;


A nouveau, a ce stade aucune action avec le mot clé abstract.


Private a son sens habituel de restriction d'usage.

3.2.14 Tagged

Bien sûr, je vais différencier par étapes successive entre les différents objets qui vont hériter des propriétés communes introduites dans les étapes précédentes .

3.2.15 Extension et héritabilité des types "tagged"

Tous ces objets sont stockés par unité de stockage (cageot, régime ou à la pièce)


Type unite_de stockage_type is (cageot, regime, par_piece);


Type objets_en_stock_type is new objet_vendus_dans_le magasin_type

With record

Unite_de_stokage: Unite_de_stokage_type:= Unite_de_stokage_type'first;

End record;

Et ainsi de suite pour les autres propriétés.

3.2.16 Le type task (tâche)

Ce type permet la création et l'exécution en parallèle de plusieurs parties du projet de manière indépendante et simultanée. Il possède de nombreuses possibilités telle que rendez-vous, délais variés.

L'accès simultané de plusieurs tâches aux mêmes données présente la possibilité d'erreurs. Ada a prévu ce problème grâce à un «type particulier de package» :


protected type Protected_Storage_Type

is

..

end Protected_Storage_Type;


Toutes ces possibilités seront discutées dans la suite de ce cours.

3.3 Domaine d'existence des variables

Il est très important de prévoir expressément :



Ces domaines peuvent être très variés:

3.3.1 Domaine d'existence limité à quelques lignes dans un code

C'est le cas, par exemple, pour l'indice d'une boucle for:



Dummy existe uniquement dans l'intervalle loop .. end loop

...

...

For Dummy in 1..Er'Last loop

...


z:=2*I;

...

end loop;

...


L'utilisation de "declare" permet aussi une limitation du domaine d'existence:


procedure r

is

....

begin

....

....

x existe entre sa déclaration et end

declare

X:Integer;

begin

X:=Z+X;

end;

...

...

....

end r;

...


3.3.2 Domaine d'existence limité à toutes les lignes d'une procédure / fonction

C'est le plus classique:

....

....

procedure z

is

x:integer;

y existe entre sa déclaration et end z

y:integer;

begin

....

....

y:=y+1;

....

end z;

....

...


3.3.3 Domaine d'existence limité à une partie des procédures / fonctions d'un package

Aucune garantie n'est donnée pour la conservation de la valeur stockée entre deux appels à une procédure / fonction du package (en général elle est conservée).



Package body e

is


procedure One (...)

is

begin

...


end one;

Str "existe" entre sa déclaration et end E

str: string (1..10);


procedure two (...)

is

begin

...


end two;

...

end E;

3.3.4 Domaine d'existence limité à toutes les lignes d'un package

Il y a plusieurs cas possibles:

3.3.4.1 Le domaine est limité à toutes les lignes du package avec impossibilité d'accès externe

3.3.4.1.1 Déclaration dans le "body"


Aucune garantie n'est donnée pour la conservation de la valeur stockée entre deux appels à une procédure / fonction du package (en général elle est conservée).


Package body e

is

Str "existe" entre sa déclaration et end E

str: string (1..10);


procedure One (...)

is

begin

...


end one;



procedure two (...)

is

begin

...


end two;

...

end E;


3.3.4.1.2 Déclaration dans la spécification

La conservation de la valeur (str) stockée entre deux appels à une procédure / fonction du package est garantie


Fichier e.ads (spécification):


Package e

is


procedure One (...) ;

procedure two (...) ;

après private aucune vue externe des variables

private

str: string (1..10);

...

end E;


Fichier e.adb (body):


Package body e

is

procedure One (...)

is

begin

...

end one;

...

procedure two (...)

is

begin

...

end two;

...

end E;

3.3.4.2 Le domaine est limité à toutes les lignes du package avec possibilité d'accès externe

Dans ce cas la conservation de la valeur stockée entre deux appels à une procédure / fonction du 'package' est garantie.


Fichier e.ads (spécification):


Package e

is


type xyz_type is ........;

xyz: xyz_type;

...

procedure One (...) ;

procedure two (...) ;

end E;


Fichier e.adb (body):


Package body e

is

procedure One (...)

is

begin

...

end one;

...

procedure two (...)

is

begin

...

end two;

...

end E;

3.3.5 Domaine d'existence limité à toutes les lignes de tous les packages en utilisant "with ..."

C'est une variable globale, chaque fois que "with e;" est présent cette variable est globale pour ce package. Attention: "with e;" n'importe pas les opérateurs associés à cette variable pour cela il faut mettre "use type e.xyz_type;"


with e;

Package body z

is

procedure One (...)

is

Accès aux opérateurs associés au type e.xyz_type

use type e.xyz_type;

begin

Accès à une variable globale associée au package e

my_xyz: e.xyz_type;

...

end one;

...

procedure two (...)

is

begin

...

end two;

...

end E;

3.3.6 Utilisation de "finalize" pour illustrer le domaine d'existence

Le langage ada à prévu la possibilité d'action à la création et à la destruction d'une variable: voici un exemple simpliste:


Le programme bien que vide donne le résultat suivant:


[dg@newdg miage_2005_2006]$ ./z

Initialize

Finalize



Fichier x.ads:


with Ada.Finalization;

package X

is

Le type example est vide dans ce cas simpliste mais ce n'est pas l'emploi le plus fréquent.


type Example

is new Ada.Finalization.Limited_Controlled

with null record;


procedure Initialize(Object : in out Example);

procedure Finalize(Object : in out Example);


end X;


Fichier x.adb:


with Ada.Text_Io;

with Ada.Finalization;


package body X

is

procédure appelée lors de la création

procedure Initialize(Object : in out Example)

is

begin

Ada.Text_Io.Put_Line("Initialize");

end Initialize;

procédure appelée lors de la destruction

procedure Finalize(Object : in out Example)

is

begin

Ada.Text_Io.Put_Line("Finalize");

end Finalize;

end X;


Fichier z.adb:


with X;

procedure Z

is

création de la variable, appel automatique de Initialize

Dummy : X.Example;

begin

null;

destruction de la variable: appel automatique de Finalize

end Z;

4 Le découpage des routines externes en Fichier ‘ADS' et ‘ADB'

Tout projet, même simple DOIT ÊTRE DÉCOUPÉ EN PLUSIEURS ROUTINES. L'exemple le plus simple est:

les fichiers se distinguent par leur nom, leur extension et le début de leur contenu. Tout projet ada contient un programme principal qui est une procédure sans paramètres. Le nom du fichier stocké est celui du nom de la procédure sans paramètre (cela oblige le nom du fichier à être un nom de procédure valide en ada). Par exemple, le fichier a.adb contiendra


-- des commentaires

with ……..;

procedure a

is

……

begin

……

end a;

4.1 Le choix entre une fonction et une procédure

Il existe 2 choix principaux pour découper un problème en routines indépendantes: la procédure et la fonction. Le choix se fait selon plusieurs critères définis ci-dessous.

4.1.1 Le passage de paramètres

Le passage de paramètres (variables, tableaux, pointeurs,…….) se fait selon trois modes différents.

Ces modes permettent de 'capturer votre analyse intellectuelle' du problème et d'assurer un programme conforme, écrit plus rapidement et avec moins d'erreurs.

4.1.1.1 Le mode in

Dans ce mode, la 'variable' sera en lecture seule dans cette routine (procédure ou fonction). C'est le mode par défaut si rien n'est précisé.


procedure Test(I : in Integer := 2;

A : in Integer;

B : Integer)

Is

begin

…..

end Test;


Remarquez la possibilité d'introduire une valeur par défaut pour la variable I. Toutes les variables I, A et B sont disponibles dans cette procédure avec les valeurs transférées lors de l'appel (pas de déclaration entre is et begin!!!). Par exemple, les trois instructions suivantes sont équivalentes:


Test(I => 1,

A => 2,

B => 3);


Test(1,

2,

3);


Test(1,

A => 2,

B => 3);

Elles appellent la procédure TEST avec les valeurs 1 pour I, 2 pour A et 3 pour B.


Les instructions suivantes appellent la procédure en utilisant la valeur par défaut.


Test(A => 2,

B => 3);


Test(2,

B => 3);


Test(2, 3);

4.1.1.2 Le mode out

Dans ce mode, la 'variable' sera en écriture seule (lecture permise après une écriture) dans cette routine (procédure ou fonction).


procedure Test(I : in Integer := 2;

A : out Integer;

B : out Integer)

Is

..

end Test;


Les appels ont la même syntaxe que pour le mode in.

4.1.1.3 Le mode in out

Dans ce mode, la 'variable' sera en lecture écriture dans cette routine (procédure ou fonction)


procedure Test(I : in Integer := 2;

A : in out Integer;

B : out Integer)

Is

…..

end Test;


Les appels ont la même syntaxe que pour le mode in.

4.1.1.4 Access

Dans cette possibilité la 'variable' sera un pointeur en lecture seule.


procedure Test(I : in Integer := 2;

A : in out Integer;

B : Access Object'Class)

Is

…..

end Test;

4.1.2 Les fonctions

La fonction prend plusieurs arguments (in par défaut), tous en lecture seule, et renvoie UNE SEULE VALEUR.

Elle s'apparente beaucoup à une variable dans sa syntaxe d'utilisation.


function A(A : Integer;

B : Float)

return Float

is

begin

return B**A;

end A;


Cette fonction très simple renvoie B puissance A. Notez la syntaxe.


La syntaxe d'appel est simple, il suffit de se souvenir que c'est la même utilisation qu'une variable.

Voici trois exemples équivalents (my_float est un réel déclaré avant):


My_Float:=A(2,3.0);


My_Float:=A(2,

B => 3.0);


My_Float:=A(A => 2,

B => 3.0);

4.1.3 Les procédures

Une procédure peut ne renvoyer aucune donnée (pas de paramètre, ou tous en mode in) mais ce n'est pas le cas général. Les paramètres en mode in peuvent avoir une valeur par défaut dans ce cas le paramètre peut être omis dans l'appel.

procedure A(I : in Integer := 2;

A : in out Integer;

B : out Integer)

is

begin

B := A / I * I;

A := A mod I;

end A;


La syntaxe d'appel à été explicitée auparavant. Voici deux exemples:


Utilisation de la valeur par défaut pour I

A(A =>1,

B =>2);


Appel normal sans utilisation de la valeur par défaut

A(I => 4,

A =>1,

B =>2);

5 La syntaxe du code

5.1 La syntaxe des affectations

L'opérateur := est utilisé pour l'affectation du résultat à une variable d'un type précis. La syntaxe dépend du type, voici quelques exemples:


x := 4.0;

x := Pi;

x := (1 .. 10 => 0);

x := Sum;

x := indice_type_a'Last;

x := Sine(X);

x := long_integer'(2);

x := Float(M * N);

x := Z * (X + 10);




x := Volume;

x := not Destroyed ;

x := 2 * Line_Count;

x := – 4.0;

x := – 4.0 + A;

x := B ** 2 – 4.0 * A * C;

x := Password(1 .. 3) = "Bwv";

x := Count in indice_type_a;

x := Count not in indice_type_a;

x := Index = 0 or over;

x := (Rouge and vert) or jaune; -- (parenthèses obligatoires)

x := A ** (B ** C); -- (parenthèses obligatoires)

x := (1 => 1,

others => 2);



x:= (un => 1,

deux | trois => 2,

fin => 35);

x.un := 1;

x.deux := 2;

x.trois:= 2;

x.fin := 35;

x := T(1..N) & S(3..5);


x:= Ma_Fonction(A => 2.0,

B => 5.0);


X:= new my_type'(x);


X := new Tagged_Data_Type'Class'(The_Record);


X := new Node'(Previous => null,

The_Item => From_Index.The_Item,

Next => null);


Variable : C.My_Type := C.My_Type'(Ada.Finalization.Controlled with I => 0);

5.1.1 Opérateurs logiques

Les opérateurs classiques and or xor sont définis comme d'habitude, ils s'appliquent aussi

A certains entiers.

A B (A and B) (A or B) (A xor B)


True True True True False

True False False True True

False True False True True

False False False False False



OR ELSE ou alors: le second terme n'est évalué qui si le premier terme est faux.

AND THEN et alors : le second terme n'est évalué qui si le premier terme est vrai.

IN compris dans l'intervalle

.. intervalle


Examples:


Rouge or jaune

A(1 .. 10) and B(15 .. 24)


pointeur /= null and then Age > 25

N = 0 or else X(N) = vert


z in 1..5 -- z compris entre 1 et 5


un petit programme:


with Ada.Text_Io;

procedure One

is

type Color_Type is(Yellow, Blue, Red, Cyan, Green, Magenta);

Color : Color_Type;

Test : Boolean;

begin

Color := Red;

Test := Color = Yellow or Color = Red;

Ada.Text_Io.Put("test is " & Boolean'Image(Test));

end One;


et sa sortie écran:


test is true

5.1.2 Opérateurs de comparaison

Ces opérateurs classiques sont définis comme d'habitude:



= égal

/= différent

< inférieur

<= inférieur ou égal

> supérieur à

>= supérieur ou égal


un exemple simple:


with Ada.Text_Io;

procedure Two

is

A : Integer;

B : Integer;

begin

A := 2;

B := 3;

Ada.Text_Io.Put(" 2 > 3 is " & Boolean'Image(2 > 3));

end Two;


Et sa sortie écran:


2 > 3 is true

5.1.3 Opérateurs d'addition

Ces opérateurs classiques sont définis comme d'habitude. L'opérateur & s'applique seulement au tableaux (dont les chaînes de caractères) et correspond au +.

+ plus

– moins

& concaténation

| ou dans les 'case' et les assignations


x:= (un => 1,

deux | trois => 2,

fin => 35);


case x is

when 1|2 => ....

....

end case;

5.1.4 Opérateurs de signe

Rien de spécial.

+ –

5.1.5 Opérateurs de multiplication

Ces opérateurs classiques sont définis comme d'habitude.

* Multiplication

/ Division

mod Modulo

rem Reste de la division


A B A/B A rem B A mod B A B A/B A rem B A mod B

10 5 2 0 0 –10 5 –2 0 0

11 5 2 1 1 –11 5 –2 –1 4

12 5 2 2 2 –12 5 –2 –2 3

13 5 2 3 3 –13 5 –2 –3 2

14 5 2 4 4 –14 5 –2 –4 1


A B A/B A rem B A mod B A B A/B A rem B A mod B


10 –5 –2 0 0 –10 –5 2 0 0

11 –5 –2 1 –4 –11 –5 2 –1 –1

12 –5 –2 2 –3 –12 –5 2 –2 –2

13 –5 –2 3 –2 –13 –5 2 –3 –3

14 –5 –2 4 –1 –14 –5 2 –4 –4

5.1.6 Opérateurs de rang le plus haut

Ces opérateurs classiques sont définis comme d'habitude.


** Élévation à une puissance

abs Valeur absolue

not Négation logique (voir plus haut)


5.1.7 Modification du sens des opérateurs classiques

Il est toujours possible, pour permettre une lecture plus facile d'un code, de renommer les opérateurs (ou les fonctions et procédures).


Function mult_plus_un (left : in integer;

right : in integer )

return integer

is

begin

return left*right+1;

end mult_plus_un;

.....

function "*" (left :in integer; right : in integer ) return integer renames mult_plus_un;

....

....

begin

x:= a*b; -- calcule a*b+1

...

5.1.8 Conversion entre types

Bien que peu utile, Il faut savoir l'utiliser

5.1.8.1 Entier vers réel

X := float (i);

5.1.8.2 Réel vers entier

I := integer(x);

5.1.8.3 Conversion par utilisation d'une adresse mémoire commune

Cette méthode permet l'accès à un niveau très bas. Elle permet de lire la même adresse mémoire de deux façons différentes si les deux type sont représentés par le même nombre de bits. Son utilisation, un peu complexe, est illustrée dans les tables de hashing.

5.2 La syntaxe des tests

Le langage permet deux types différents: if et case.

5.2.1 Le test if


La grammaire ada indique:


if condition then sequence_of_statements

{elsif condition then sequence_of_statements}

[else sequence_of_statements]

end if;


Les abréviations sont les suivantes:

{ xxxxxx } veut dire 0 à n répétitions de xxxxxx

[ yyyyyyy ] veut dire yyyyyy est optionnel

sequence_of_statements veut dire 1 à N instructions


exemples :


If my_test = 1

Then

X:=I;

End if;



If my_test = 1

Then

X:=I;

……

Elsif my_test = 0

Or else My_Test = 5

Then

Y:=I;

……

Elsif my_test in 2..4

Then

W:=I;

……

else –- optionnel!!

z:=I;

end if;

5.2.2 Le test case

Le test case permet beaucoup plus de possibilités et est plus lisible s'il y a beaucoup de 'elsif';

il oblige à traiter tous les cas, si tous les cas ne sont pas pris en compte on termine par others.

Pour le "else" final

Voici le même code que ci-dessus traduit en case:


Case My_Test

Is

when 1 =>

X:=I;

……

when 0 | 5 => -- 0 ou 5

Y:=I;

……

when 2 .. 4 => -- 2, 3 et 4

W:=I;

……

when others => -- doit être le dernier choix

z:=I;

end case;


voici un autre exemple


Type jour_type is (lundi,mardi,mercredi,jeudi,vendredi,samedi,dimanche);

Jour: Jour_type;

Begin

……

case jour

is

when lundi => nouvelle_semaine;

when mardi .. jeudi => travail;

when vendredi => vivement_ce_soir;

when samedi | dimanche => -- peut s'écrire samedi .. dimanche

repos;

end case;

5.3 La syntaxe des boucles

Les boucles sont des outils très importants dans la programmation. La sortie de boucle s'effectue:

Boucle «while» : condition de «while» fausse

Boucle «for» : indice supérieur à la borne

Toutes boucles: exit simple ou exit conditionnel

5.3.1 Boucle simple

Nom_de_boucle : -- optionnel mais utile si plusieurs boucles imbriquées

Loop


………

-- boucle infinie si pas de sortie

exit nom_de_boucle when a=0; -- exit conditionnel nom de boucle optionnel

exit nom_de_boucle; -- exit simple nom de boucle optionnel


………

end loop Nom_de_boucle;

5.3.2 Boucle while

While a>0 or else r <1 loop

…………

End loop;


La boucle se répète tant que la condition a>0 or else r <1 est vraie.

5.3.3 Boucle for

Ce type de boucle est souvent utilisé pour les indices de tableaux ou pour répéter le même code plusieurs fois.


Subtype contenu_type is integer range 1..2;

Subtype indice_type_a is integer range –2..3;

Subtype indice_type_b is integer range 10..20;

Type tableau_type is array(integer range <>) of contenu_type;

Tableau_a: tableau_type(indice_type_a'range):=(others=>1);

Tableau_b: tableau_type(indice_type_b'range):=(others=>1);

begin

x := 0;

for I in 1..2 loop

x:=x + Tableau_a(I);

end loop;


x := 0;

for I in tableau_a'range loop

x:= x + Tableau_a(I);

end loop;


nom_de_boucle :

for I in reverse tableau_a'range loop

for J in tableau_b'range loop

x:= x + Tableau_a(I)* tableau_b(j);

exit nom_de_boucle when 0 = Tableau_a(I);

end loop;

end loop_nom_de boucle;


I et J ne sont PLUS disponibles après la boucle. Si cela est nécessaire, il faut utiliser une boucle while,

et modifier les valeurs des indices par vous même.

………

I: integer ;

J : integer ;

………

Begin

…………

I:= indice_type_a'last;

J:= indice_type_b'first;


nom_de_boucle :


while I in tableau_a'range loop

while J in tableau_b'range loop


x:= x + Tableau_a(I)* tableau_b(j);

exit nom_de_boucle when 0 = Tableau_a(I);

J:=1 + J;

end loop;


I:= I - 1;

end loop_nom_de boucle;

5.4 La syntaxe d'appel des fonctions


Il suffit de se souvenir qu'une fonction s'utilise comme une variable.

Par exemple, une fonction de spécification:


Function abc(premier: in integer:=1;

Second : in integer) return float;


Peut s'appeler comme suit:


A: integer;

B : integer;

C: float;

...

...

--premier prends la valeur de a et second la valeur de b

c := 2.0 * Abc(a,b);

--premier prends la valeur de a et second la valeur de b


c:= abc(premier => a,

second => b);

--premier prends la valeur par défaut de 1 et second la valeur de b


c:= c + abc(second => b);



5.5 La syntaxe d'appel des procédures

Soit une procédure:


Procedure Prod (A_1: in out A_type;

A_2 : in A_Type;

A_3 : out A_type :=a_type'first);


L'appel pourrait se faire comme suit


X: A_Type;

Y: A_Type;

Z: A_Type;

....

.....

.....

prod(x,y,z);


prod(x,y);-- utilisation de la valeur par défault


prod (A_1=> 2 * X - 1,

A_2 => X * y,

A_3 => X * Y / z);



5.6 La segmentation en parties indépendantes par ‘declare' ou begin

Le programme peut (et doit) être séparé en sections indépendantes. Il en existe toujours une par défaut entre begin et end. Toute erreur pendant l'exécution à l'intérieur de ces parties DOIT être gérée, voir plus bas. Des variables peuvent éventuellement être déclarées dans un nouvelle section (qui peut avoir un nom) et n'être valable que dans cette section. Cette méthode permet de déclarer des tableaux (matrices) dynamiquement: leur longueur n'est pas connue du compilateur mais déterminée pendant le fonctionnement du programme:


Procedure X …..

is

size :integer;

type table_type is array (integer range <>) of integer;

begin

lecture de size ou affectation

size :=..........;


declare -- nécessaire si variable à déclarer

x: integer;

table: table_type(1..size);

begin – début d'une section supplémentaire

x:= .....;

table(x):=........;


end; -- fin de cette section supplémentaire

-- X et table n'existent plus !!!!


endX;


Le même exemple avec un nom de section


Procedure X …..

is

begin

interne : -- nom de la section

declare -- nécessaire si variable à déclarer

x: integer;

begin – début d'une section supplémentaire

x:= .....;


end interne; -- fin de cette section supplémentaire

-- X n'existe plus !!!!


endX;



5.7 Gestion des erreurs durant l'exécution du programme

Il faut toujours programmer en prenant en compte que l'utilisateur peut et fera des erreurs!

Pour le gérer on utilise la notion d'exceptions. C'est une réponse à une situation anormale.


5.7.1 La notion d'exception

Par exemple la racine carrée d'un nombre négatif n'est pas définie (sans nombres imaginaires!). On déclarera donc une exception:

Racine_imaginaire: exception;


Elle pourra servir plus loin dans le code par exemple

If x <=0.0

Then

Raise Racine_imaginaire;-- cette instruction renvoie à la gestion d'erreur et va

-- directement dans exception à la ligne correspondante

..

end if;

.......

......

exception

when Racine_imaginaire =>

...... traitement de l'exception

When ....=>

........

when others =>

... traitement des exceptions non prise en compte ci dessus

end ....; fin de la routines

5.7.2 Les exception intégrées au langage

Les fonctions déjà définies dans le langage ont très souvent des exceptions intégrées.

5.7.3 Définition d'une exception

On utilise le mot réservé exception:


Table_pleine, pointeur_null: exception;

5.7.4 Gestion des exceptions

Elle se fait à la fin d'un block défini entre begin et end après la dernière instruction et avant end.


..

begin

.

If x <=0.0

Then

Raise Racine_imaginaire;-- cette instruction renvoie après exception

else

X:= racine-carrée(y);

end if;


exception

when Racine_imaginaire =>

-- ici on gère les conséquences de l'erreur

when .... => .....


end;


5.7.5 Impression écran du type d'erreur rencontré


Si on désire imprimer le nom de l'erreur (avec le nom de la procédure):


with Ada.Exceptions;

with Ada.Text_Io;

....

procedure Initialize_Generator(......)

.....

begin

....

exception


when Programing_Error : others =>

Ada.Text_Io.Put("Initialize_Generator"

& Ada.Exceptions.Exception_Information(Programing_Error));

end Initialize_Generator;

....

6 Entrées et Sorties


6.1 entrée clavier

Principes généraux:


Il y a deux choix possibles: cacher tous les détails dans un package spécial (forcément limité dans ses possibilités voir le «package ou tout expliquer en détail au risque de paraître fastidieux. Des exemples tout prêts seront utilisés.



6.2 Utilisation de read_write

Ce programme déjà écrit pour vous vous permet de ne pas entrer dans les détails du fonctionnement des entrées sorties.

Voici les possibilités offertes ainsi qu'un exemple pour chaque


6.2.1 Entrée d'un entier

Vous pouvez aussi utiliser le code de Read_Write. (Voir Chapitre 14.1 )


with Read_Write;


procedure XX

is

x:Integer;

begin

....

Read_Write.Read(Header => "valeur de x ?",

Value => X);

....

end XX;


6.2.2 Sortie écran d'un entier

with Read_Write;


procedure XX

is

x:Integer;

begin

....

Read_Write.Write(Header => "La valeur de x est ",

Value => x);

....

end XX;

6.2.3 Entrée d'un entier long

with Read_Write;


procedure XX

is

x:Long_Integer;

begin

....

Read_Write.Read(Header => "valeur de x",

Value => x);

....

end XX;

6.2.4 Sortie écran d'un entier long

with Read_Write;


procedure XX

is

x:Long_Integer;

begin

....

Read_Write.Write(Header => "valeur de x",

Value => x);

....

end XX;

6.2.5 Entrée d'un réel

with Read_Write;


procedure XX

is

x:Float;

begin

....

Read_Write.Read(Header => "valeur de x",

Value => x);

....

end XX;

6.2.6 Sortie écran d'un réel



with Read_Write


procedure XX

is

x:Float;

begin

....

read_write.Write("valeur de x", x);

....

end XX;


6.2.7 Entrée d'un réel long

with Read_Write;


procedure XX

is

x:Long_Float;

begin

....

Read_Write.Read(Header => "valeur de x",

Value => x);

....

end XX;

6.2.8 Sortie écran d'un réel long



with Read_Write


procedure XX

is

x:Long_Float;

begin

....

read_write.Write("valeur de x", x);

....

end XX;

6.2.9 Entrée d'une chaîne de caractères

with Read_Write;


procedure XX

is

x : String(1..50) := (others => ' ');

begin

....

Read_Write.Read(Header => "valeur de x",

Value => x);

....

end XX;

6.2.10 Sortie écran d'une chaîne de caractères

with Read_Write;


procedure XX

is

x : String(1..50) := (others => ' ');

begin

....

Read_Write.Write(Header => "valeur de x",

Value => x);

....

end XX;


6.3 Utilisation de Ada.Text_Io

L'utilisation de ada.text_io pour la lecture est simple à quelques exceptions prés:


6.3.0.1 Lecture de nombre après instantiation:


6.3.0.1.1 Entier:

Si l'utilisateur entre 12 la valeur de I sera 12:


Package integer_io is new ada.text_io.integer_io(integer);

....

begin

integer_IO.get (I);


Si on entre 12X3 pendant l'utilisation du code précédent, l'exception data_error sera «générée» et le caractère X ne sera pas effacé du tampon d'entrée. Toute nouvelle lecture d'une nombre est devenue impossible! il faut donc purger les caractères restants avant tout nouvel essai:

Ada.text_io.Skip_Line;


6.3.0.1.2 Réel:


package My_Float_Io is new Ada.Text_Io.Float_Io(Float);

....

begin

My_float_IO.get(a_float);



6.3.0.1.3 Chaîne de caractères

Utilisation de ada_text_io.get_line

C'est la procédure de lecture d'une chaîne de caractères entrée par l'utilisateur, le code suivant peut paraître être à l'origine de DEUX entrées clavier successives, mais …………

Chaque get_line attend le «return» et renvoie: les caractères dans la chaîne et l'indice du dernier caractère dans la chaîne ( ce qui n'est égal au nombre de caractères entrés qui si le tableau commence à 1!!!).


String_1 : String (1..5);

String_2 : String (1..5);

Last_1 : Natural;

Last_2 : Natural;


Begin

.....

String_1 := (others => ' ‘);-- ne jamais oublier

String_2 := (others => ' ‘);-- ne jamais oublier


ada.text_io.Get_Line (String_1, Last_1);


ada.text_io.Get_Line (String_2, Last_2);


Tous les problèmes disparaissent si la longueur des chaînes est > au nombre de caractères entrés par l'utilisateur par ligne. C'EST CE QU'IL FAUT FAIRE sauf difficultés spéciales. Ici on utilise pour la démonstration des chaînes de 5 caractères


Si il y a moins de 5 caractères pour la première ligne par exemple ABC, string_1 contiendra «ABC »

NOTER bien les deux espaces à la fin!! et last_1 contiendra 3. le programme demandera ensuite la seconde ligne.


Si il y a 5 caractères pour la première ligne par exemple ABCDE, string_1 contiendra «ABCDE »

et last_1 contiendra 5. String_2 contiendra « » (5 espaces)

et last_2 contiendra 0 qui est le flag pour chaîne entrée vide (test facile pour «return» sans caractère avant).



Si il y a plus de 5 caractères pour la première ligne par exemple ABCDEFGH, string_1 contiendra «ABCDE » et last_1 contiendra 5. String_2 contiendra «FGH » NOTER bien les deux espaces a la fin!! et last_2 contiendra 3..


Pour purger entre les deux «get_line» utiliser la ligne de code suivante:


ada.text_io.Set_Col (ada.text_io.Current_Input, 1);



vous pouvez vérifier avec le programme w.adb


with Ada.Text_Io;


procedure W

is


String_1 : String(1 .. 5);

String_2 : String(1 .. 5);

Last_1 : Natural;

Last_2 : Natural;

begin


String_1 := (others => ' ');-- ne jamais oublier

String_2 := (others => ' ');-- ne jamais oublier


Ada.Text_Io.Put("string_1 ? ");


Ada.Text_Io.Get_Line(String_1, Last_1);


Ada.Text_Io.Put("string_2 ? ");


Ada.Text_Io.Get_Line(String_2, Last_2);


Ada.Text_Io.New_Line;


Ada.Text_Io.Put_Line('>'& String_1 & "< last_1 " & Integer'Image(Last_1));


Ada.Text_Io.Put_Line('>'& String_2 & "< last_2 " & Integer'Image(Last_2));


end W;


qui donne les résultats suivants:


2 entrées de moins de 5 caractères le programme demande les deux chaînes


string_1 ? ABC

string_2 ? DE


>ABC < last_1 3

>DE < last_2 2


1 entrée de 5 caractères => le programme demande une seule chaîne et se termine en sautant le second get_line:


string_1 ? ABCDE

string_2 ?

>ABCDE< last_1 5

> < last_2 0


1 entrée de plus de 5 caractères => le programme demande une seule chaîne et se termine en sautant le second get_line:



string_1 ? ABCDEFGH

string_2 ?

>ABCDE< last_1 5

>FGH < last_2 3



Essayez pour vous même en commentant la ligne qui initialise les chaînes avec des caractères. Que se passe-t-il?


6.3.1 Sortie écran

6.3.1.1 Principes généraux

La sortie écran d'une variable peut être simple si aucun format précis n'est nécessaire, Dans ce cas on utilise l'attribut image qui transforme en chaîne de caractères facile à utiliser

6.3.1.2 Chaîne de caractères

Chaine :string (1..12);

.....

begin

....

Ada.Text_Io.Put(Item => " La valeur est "

& chaine);


sur l'écran il apparaît:


La valeur est xyz

dans le cas ou vous voulez visualiser les espaces avant et après les autres c