Si vous détectez des erreurs ou si vous avez des suggestions, veuillez communiquer avec Pierre Bélisle
Généralités
·À qui s'adresse ce document?
·Pourquoi utiliser Ada dans les cours de programmation de base ?
Les types de base
·Qu'est-ce qu'un type ?
·Qu'est-ce qu'un intervalle ?
·Qu'est-ce qu'un sous-type ?
·Comment peut-on faire de la
conversion de type ?
Le type STRING
·Que peut-on faire avec le
type STRING ?
Le type CHARACTER
·Quels sont les codes ASCII associés aux caractères ?
Les types structurés
Les enregistrements ou articles (RECORD)
·Quelles sont les opérations permises sur les
articles ?
Les tableaux (ARRAY)
·Comment initialiser un tableau d'un seul
coup(aggrégats) ?
Les entrées/sorties
Les
affichages
·Comment fait-on pour afficher un entier sur moins de
11 colonnes ?
·Comment fait-on pour afficher un reel avec un autre
format que 1.00000E38 ?
·Pourquoi lorsque j'affiche une chaîne de caractères, il apparaît des caractères indésirables à l'écran ?
Entrés/sorties avec
les types énumératifs
·Comment saisir ou afficher une valeur de type énumératif(enumeration_io) ?
Le SKIP_LINE
·Comment "Skip_Line"
fonctionne-t-il ?
·Pourquoi "Skip_Line"
est conditionnel avec "Get_Line" ?
Quelques trucs
·Comment faire une pause pour que mon programme attende la touche <entrée> pour
continuer ?
·Comment positionner
le curseur à l'endroit que je désire ?
·Peut-on programmer en couleur en mode console ?
·Peut-on saisir une touche au clavier comme avec getch() en C ?
Les attributs de types
·Qu'est-ce qu'un attribut de type ?
Sur
les types de base
·Comment l'attribut 'POS fonctionne-t-il ?
·Comment l'attribut 'VAL fonctionne-t-il ?
·Comment l'attribut 'VALUE fonctionne-t-il ?
·Comment l'attribut 'IMAGE fonctionne-t-il ?
Sur
les tableaux
·Comment l'attribut 'FIRST fonctionne-t-il ?
·Comment l'attribut 'LAST fonctionne-t-il ?
·Comment l'attribut 'RANGE fonctionne-t-il ?
·Comment l'attribut 'LENGTH fonctionne-t-il ?
Les sous-programmes
·Qu'est-ce qu'un sous-programme ?
·Quelle est la différence entre IN, OUT
et IN OUT ?
·Quelles sont les règles sur les fonctions ?
·Quelle est la différence entre une variable globale et
une variable locale ?
·Quelles sont les règles de visibilité ?
Les Exceptions
·Pourquoi ma gestion d'exceptions ne se comporte pas comme je le voudrais ?
Les fichiers
·Qu'est-ce qu'un fichier ?
·Qu'est-ce qu'un fichier texte ou un fichier de texte ?
·Qu'est-ce qu'un fichier typé ou un fichier binaire ?
***Si vous ne trouvez pas la réponse à ce que vous cherchez ici, posez votre question
sur le forum de discussion.
Ce document s'adresse principalement aux étudiants du cours de programmation I, et tente de répondre aux questions les plus fréquemment posées dans ce cours.
Les cours de programmation de base servent à montrer aux étudiants à programmer. La résolution de problème par la programmation est tout le cheminement que l'on fait pour obtenir une solution à un problème en utilisant un outil qu'est l'ordinateur. Un langage de programmation est un outil qui permet à un programmeur de commander l'ordinateur pour qu'il effectue les différentes tâches qui sont nécessaires à résoudre le problème.
Ada est un langage de programmation qui est très peu permissif en ce qui a trait aux erreurs sur les types. Ce qui rend l'outil très intéressant dans un cadre pédagogique. Par exemple, Un langage comme le langage C est très déconseillé pour l'apprentissage de la programmation. La raison est qu'il est très permissif et permet à l'étudiant de faire beaucoup d'erreurs qui ne font pas nécessairement partie des objectifs à atteindre.
De plus, Ada est un langage structuré qui permet l'apprentissage de la programmation modulaire et encore une fois, il est très strict. Cela permet une fois de plus à l'étudiant de ne pas se mélanger en faisant des erreurs qui ne font pas parties des objectifs de ces cours.
Finalement, Ada est un langage orienté-objet, et permet le parallélisme. Ce qui permet d'apprendre de nouveaux concepts dès le deuxième cours de programmation, sans avoir à changer de langage.
Il est très clair que n'importe quel langage a ses avantages et ses inconvénients. Un langage comme Ada a plus d'avantages du côté pédagogique que du côté pratique, mail il permettra à l'étudiant de s'adapter à n'importe quel autre langage par la suite.
Ce qu'il faut se rappeler par-dessus tout, est que le langage de programmation n'est
qu'une façon de communiquer avec l'ordinateur. L'ordre des instructions et l'organisation
des données, c'est le programmeur qui en décide. C'est cela qu'on tente de montrer dans
les cours de programmation de base, et non seulement un langage de programmation.
Skip_Line est un sous-programme du module externe Ada.Text_IO. Cette procédure permet principalement de sauter par-dessus un symbole de fin de ligne(FL) dans un fichier de texte ouvert en lecture.
Le clavier est considéré comme un fichier de texte qui n'a qu'une ligne de texte possible à la fois. Donc, passer par-dessus le symbole de fin de ligne se résume à vider le tampon du clavier. Par contre dans un fichier de texte sur disque, on verra "skip_line" comme une instruction permettant de passer à la ligne suivante dans le fichier.
La stratégie employée est :
si le tampon est déjà vide lorsque skip_line est exécuté, l'ordinateur attendra qu'un utilisateur presse la touche <entrée>, pour continuer. Pour s'assurer du bon fonctionnement du Skip_line en ce qui regarde le clavier, nous dirons que chaque instruction de lecture "GET" qui provient du module externe Ada.Text_IO, sera préférablement suivie d'un Skip_Line. Ceci nous assurera de sauter par-dessus le symbole de fin de ligne et que le tampon est vide, si nous avons besoin de faire une pause.
ex: Es_Entiers.Get(Un_Nombre_Entier);
Ada.Text_IO.Skip_Line;
Es_Reels.Get(Un_Nombre_Reel);
Ada.Text_IO.Skip_Line;
Ada.Text_IO.Get(Un_Car);
Ada.Text_IO.Skip_Line;
--ceci fait
une pause, si le tampon du clavier est vide
Ada.Text_IO.Put("appuyer sur
<entrée> pour continuer");
Ada.Text_IO.Skip_Line;
Cette instruction permet de se positionner à l'écran, à une colonne en particulier de la ligne courante. Cependant, Set_Col ne permet pas de revenir en arrière sur la ligne. Si vous tentez de revenir sur une colonne qui vient avant la colonne courante, Set_Col fera un saut de ligne pour atteindre la colonne voulue de la ligne suivante.
ex: Ada.Text_IO.Set_Col(10); --va à la colonne 10 de la ligne courante
Ada.Text_IO.Put("Menu principal"); --affiche ce message à la ligne et la colonne courante
Ada.Text_IO.Set_Col(5); --va à la colonne 5 de la ligne suivante, parce qu'il ne revient pas en
--arrière
**Le nombre entre parenthèses doit être de type Positive_Count. Ce qui signifie que si vous mettez une variable comme paramètre, elle devra être de ce type ou bien il faudra faire une conversion de type.
ex: Ada.Text_IO.Set_Col(Ada.Text_IO.Positive_Count(Un_Nombre_Entier));
Un type est un concept essentiel en informatique. Chaque donnée à l'intérieur d'un programme Ada doit appartenir à un type.
Les types élémentaires utilisés pour ce cours sont :
Une des tâches du programmeur est d'apprendre pour chaque type qu'il connaît, quelles sont ces informations.
exemple : integer
Il est impossible de faire des opérations sur des types différents en Ada ou d'affecter une valeur à une variable avec une donnée d'un autre type. Il faut toujours s'assurer que les données sont de mêmes catégories. Donc il faudra convertir certaines données temporairement pour réussir à faire l'opération voulue. Pour convertir un type, il suffit de mettre entre parenthèses la donnée à convertir et de nommer le type voulu avant la parenthèse.
ex:
Dans le premier exemple, le nombre réel 2.75 sera converti en entier, ce qui signifie qu'il perdra sa partie décimale. Pour convertir un réel en entier, Ada arrondi selon le premier chiffre après le point. Ce qui donnera 3, après la conversion dans la variable Un_Nombre_Entier.
Dans le deuxième exemple le nombre entier sera converti en réel. Ce qui signifie qu'il aura une partie décimale. Ce qui donnera 2.000000 après la conversion dans la variable Un_Nombre_Reel.
***à noter que la conversion est comme une fonction qui retourne votre nombre dans un autre type, ce qui signifie que le nombre à convertir n'est pas modifié. Également, vous ne pouvez pas faire de conversion de type entre 2 types qui n'ont pas la même catégorie de base.
Vous ne pouvez pas faire une conversion du genre :
Car : Character := Character(3.78);
Autrement dit, les nombres avec les nombres, les caractères avec les caractères etc.
Un attribut de type est comme une fonction qui retourne de l'information sur un type. Soit un type quelconque T, il suffit de séparer le type de son attribut à l'aide d'une apostrophe. Il existe plusieurs attributs de type différents selon le type de données.
ex: 'IMAGE attribut pour le type string
'POS attribut pour les types énumératifs
Chaque caractère a une correspondance numérique qu'on appelle le code ASCII. Pour faire référence au code ASCII d'un caractère, à l'intérieur d'un programme ADA, on peut utiliser l'attribut de type 'POS. Cet attribut est comme une fonction qui retourne un entier qui correspond au code ASCII du caractère voulu.
exemple : --le code correspondant au caractère 'A' est 65
...
Car : Character := 'A';
BEGIN
Es_Entiers.Put(Character'POS(Car)); --ceci affichera 65 à l'écran
END;
Chaque caractère a une correspondance numérique qu'on appelle le code ASCII. Pour faire référence à un caractère à partir du code ASCII à l'intérieur d'un programme ADA, on peut utiliser l'attribut de type 'VAL. Cet attribut est comme une fonction qui retourne un caractère qui correspond à la valeur demandée, c'est l'attribut contraire de l'attribut 'POS.
exemple : --le code correspondant au caractère 'A' est 65
...
BEGIN
Es_Entiers.Put(Character'VAL(65)); --ceci affichera le caractère 'A' à l'écran
END;
Cet attribut de type sert avec les données de type STRING. Il est impossible de convertir par la conversion de type habituelle, les données qui sont d'ancêtres différents. L'attribut 'VALUE permettra d'obtenir l'équivalent numérique d'une chaîne de caractères.
Ex: nombre : Integer := Integer'VALUE("12345");
l'attribut 'VALUE retournera sous forme d'entier, la chaîne de caractères entre parenthèses. ATTENTION, il faut absolument que le contenu de la chaîne puisse se transformer en entier. On ne pourrait pas faire :
Ex: Nombre : Integer := Integer'VALUE("abcde");
Cet attribut de type sert avec les données de type STRING. Il est impossible de convertir par la conversion de type habituelle, les données qui sont d'ancêtres différents. L'attribut 'IMAGE permettra d'obtenir l'équivalent chaîne de caractères d'une valeur numérique.
Ex: Chaine : String := Integer'IMAGE(12345);
l'attribut 'IMAGE retournera sous forme de chaîne de caractères, le nombre entre
parenthèses.
Cet attribut de type retourne le nombre de caractères maximum possibles de la définition d'une variable de type chaîne de caractères. La formule pour trouver l'intervalle c'est : valeur maximum - valeur minimum + 1.
Ex:
Chaine : String(5..180);
Es_Entiers.Put(Chaine'LENGTH) --affichera
le nombre 176 à l'écran (180-5+1).
Pour afficher un entier avec Ada.Text_IO, il faut faire une instanciation de paquetage générique dans la partie déclarative du programme. Ensuite, on peut utiliser l'instruction "put" dans le corps du programme en préfixant avec le nom du paquetage.
PACKAGE Es_Entiers IS NEW Ada.Text_IO.Integer_IO(Integer);
Un_Nombre_Entier : Integer := 12;
BEGIN
Ada.Text_IO.Put("Votre nombre est : ")
Es_Entiers.Put(Un_Nombre_Entier);
END;
Le problème est qu'un entier par défaut est affiché sur 11 colonnes. Ce qui fait que le nombre est affiché à l'écran de la façon suivante :
Votre nombre est : 12
On peut régler ce problème en ajoutant une information à l'instruction "put". On peut lui dire sur combien de colonnes au minimum afficher le nombre. Ce qui donnera ce qui suit :
PACKAGE Es_Entiers IS NEW Ada.Text_IO.Integer_IO(Integer);
Un_Nombre_Entier : Integer := 12;
BEGIN
Ada.Text_IO.Put("Votre nombre est : ")
Es_Entiers.Put(Un_Nombre_Entier,1); --la deuxième valeur est le nombre de colonnes minimum
END;
--Le nouveau résultat sera :
Votre nombre est : 12
***à noter qu'il n'y a jamais de valeur qui ne sont pas affichée parce que le nombre
de colonne est plus petit que le nombre à afficher.
Pour afficher un réel avec Ada.Text_IO, il faut faire une instanciation de paquetage générique dans la partie déclarative du programme. Ensuite, on peut utiliser l'instruction "put" dans le corps du programme en préfixant avec le nom du paquetage.
PACKAGE Es_Reels IS NEW Ada.Text_IO.Float_IO(Float);
Un_Nombre_Reel : Float := 12.;
BEGIN
Ada.Text_IO.Put("Votre nombre est : ")
Es_Reels.Put(Un_Nombre_Reel);
END;
Le problème est qu'un réel par défaut est affiché de la façon suivante :
Votre nombre est : 12.575000E+00
On peut régler ce problème en ajoutant une information à l'instruction "put". On peut lui dire combien de nombre pour la partie entière, combien de nombre pour la partie décimale et combien de nombre pour la partie exposant. Ce qui donnera ce qui suit :
PACKAGE Es_Reels IS NEW Ada.Text_IO.Float_IO(Float);
Un_Nombre_Reel : Float := 12.575;
BEGIN
Ada.Text_IO.Put("Votre nombre est : ")
Es_Reels.Put(Un_Nombre_Reel,4,2,0); --le
format sera 4 entiers avant le point, 2 chiffres après le
--point et pas de chiffre pour l'exposant.
END;
--Le nouveau résultat sera :
Votre nombre est : 12.58
***à noter qu'il y aura arrondissement si le nombre de colonne de la partie décimale
est plus petit que la partie décimale à afficher.
Un type énumératif, est un type dont on définit toutes les valeurs possibles. Le type "Boolean" et le type "character" en font parties. Pour définir nous même un type énumératif, il suffit de faire l'énumération des valeurs permises pour ce type.
ex: TYPE T_Jour_Semaine IS (dimanche, lundi, mardi, mercredi, jeudi, vendredi, samedi);
Les opérations permises sur les données d'un type énumératif, sont : l'affectation et les opérateurs de relations (<, >, >=, <=, =, /=, :=). Il faut comprendre que les valeurs fournies lors de la définition du type sont utilisables tel quel. Ce qui signifie que les valeurs ne doivent pas être entre guillemets lors de leur utilisation.
ex: Jour : T_Jour_Semaine := lundi;
Le compilateur ne fait pas de différence entre les majuscules et les minuscules pour
les valeurs d'un type énumératif( à l'exception du type
"character"). Finalement, pour faire des entrées/sorties sur une
donnée d'un type énumératif, il faut instancier le paquetage enumeration_io
ou utiliser l'attribut de type 'image.
Pour pouvoir utiliser directement les instruction "put" et "get" sur des types énumératifs, il faut instancier le module externe enumeration_io avec le type pour lequel on veut faire des entrées/sorties.
ex: TYPE T_Jour_Semaine IS (dimanche, lundi, mardi, mercredi, jeudi, vendredi, samedi);
PACKAGE ES_Jour IS NEW
Ada.Text_IO.Enumeration_IO(T_Jour_Semaine);
Par la suite il suffit d'utiliser le nom du paquetage comme préfixe pour afficher ou saisir une donnée de ce type.
ex: ES_Jour.Put(lundi);
**l'affichage se fera toujours en majuscule et la saisie ne fera pas de différence
entre majuscules et minuscules.
Get_Line est l'instruction de Ada.Text_IO qui permet de lire une donnée de type chaîne de caractères en provenance du clavier. Get_Line nécessite 2 informations, la chaîne à lire et une variable de type entier pour recevoir la longueur de la chaîne lue.
ex: Chaine : String(1..20);
Longueur : Natural;
Get_Line(Chaine,Longueur);
La variable "Chaine" contiendra la chaîne que l'utilisateur a entré et "Get_Line" mettra dans la variable "Longueur", la longueur de cette chaîne. "Longueur" ne dépassera jamais le nombre de caractères maximum possibles de la chaîne(20 dans le dernier exemple). Cette instruction retourne une chaîne lorsque l'une ou l'autre des conditions suivantes sera remplies. Soit la touche <entrée> a été pressée ou le nombre de caractères maximum possibles de la chaîne à été lu. Si le premier cas est atteint un "Skip_Line" est fait automatiquement. Dans le deuxième cas, il n'est pas fait, il faudra alors en faire un. Donc la seule information que nous possédons pour savoir si un "Skip_Line" a été fait, c'est "Longueur", Si elle est égale au nombre de caractères maximum possibles, on fera un "Skip_Line".
IF Longueur = Chaine'LENGTH THEN
Skip_Line;
END IF;
Voici les affectations légales avec le type STRING. La seule vrai contrainte est
que lors de l'affectation, la longueur des chaînes doivent être égales.
ex: Chaine1 : String(1..40);
Chaine2 : String(1..150);
Chaine1 := Chaine2(25..64); --pour compter le nombre de cases, la valeur max - la valeur min + 1.
--Ce qui donne ici 64-25+1 = 40 et c'est légal. Si aucun intervalle n'est donné, --c'est de toute la chaîne dont on parle.
--C'est aussi légal de prendre une portion d'une chaîne de la déplacer dans la même chaîne
ex: Chaine2(20..30) := Chaine2(1..11);
Un fichier est une façon de conserver de façon permanente sur un support physique, des données qui sont en mémoire. Cela permet de communiquer des informations d'un programme à un autre et/ou de communiquer des informations à un utilisateur, et/ou de faire une sauvegarde des données.
Les 2 grandes catégories de fichiers sont les fichiers de
texte et les fichiers binaires. Peu importe la
catégorie, il existe certaines généralités pour l'utilisation de fichier, en voici
quelques unes :
Un fichier de texte est comme un grand tableau de caractères sur un support physique(disque dur, disquette ...). Chaque ligne de texte est séparée par un symbole qu'on appelle "fin de ligne" (FL). Un fichier de texte se termine par un symbole appelé "fin de fichier"(FF).
Pour une question d'efficacité, l'ordinateur a besoin d'un espace mémoire pour chaque fichier qu'on appelle "tampon" ou en anglais "buffer". Ce tampon peut contenir plusieurs caractères et est rempli chaque fois qu'il est vide. Le mécanisme est que si une instruction de lecture est faite dans un fichier de texte et que le tampon est vide, il sera rempli par les caractères du fichier et ensuite l'affectation se fera à partir du tampon. Si par contre lors d'une lecture il y a déjà des caractères dans le tampon, il n'y aura pas de lecture dans le fichier, l'affectation se fera quand même, mais à partir du tampon.
L'ordinateur s'occupe de savoir où il est rendu à lire dans le tampon et dans le fichier. Vous n'avez pas à vous en préoccuper avec Ada. Pour associer un tampon avec un fichier, il faut déclarer une variable qui servira de tampon.
ex: fichier_texte : Ada.Text_IO.File_Type;
C'est lors de l'ouverture du fichier que le lien se fera entre le fichier réel et le tampon en mémoire.
ex: Ada.Text_IO.Create(Fichier_Texte,Ada.Text_IO.Out_File,"a:toto.txt");
Cette dernière instruction, créera un fichier appelé "toto.txt" sur l'unité de disquette "a:", et associera un tampon appelé "fichier_texte". Dorénavant, toutes les instructions dans ce fichier se feront via le tampon.
ex: Ada.Text_IO.Put(Fichier_Texte,"salut vous autres");
À la fin du programme il faut couper le lien entre le fichier et le tampon. Pour ce faire il faut utiliser la procédure close:
ex: Ada.Text_IO.Close(Fichier_Texte);
Un fichier binaire (ou typé) est un grand tableau sur un support physique(disque dur, disquette ...), mais dont le contenu peut être de tout type(élémentaire, tableau, article, tableau d'articles...). Il n'y a que 2 instructions qui permettent de manipuler le contenu d'un fichier binaire en Ada et c'est READ(lecture) et WRITE(écriture).
Pour pouvoir utiliser un fichier binaire, il faut déterminer si on l'accède en mode séquentiel ou direct. Si on veut accéder aux données séquentiellement, nous devons importer ADA.SEQUENTIAL_IO. Par contre en accès direct, on doit importer ADA.DIRECT_IO. Par la suite, nous devons spécifier de quel type est le fichier et cela se fait par l'instanciation de paquetage.
ex; PACKAGE ES_Fic_Etud IS NEW ADA.SEQUENTIAL_IO(T_Etud);
Cette dernière instruction nous donne tous les outils pour pouvoir utiliser un fichier binaire de type "T_Etud" en accès séquentiel. Naturellement, le type "T_Etud" doit avoir préalablement été défini.
À partir du moment où le paquetage est défini, n'importe quel référence à un type, une procédure ou une fonction qui provient de ADA.SEQUENTIAL_IO doit être utiliser avec le nom du paquetage en préfixe.
ex:
Un sous-programme a les mêmes droits qu'un programme principal, mais il peut recevoir
des informations sous forme de ce qu'on appelle des paramètres. Les
paramètres qui sont dans la définition du sous-programme sont dits paramètres formels
et ceux lors de l'appel du sous-programme sont dits paramètres effectifs.
Exemple de définition d'un sous-programme avec paramètres formels :
--Cette procédure valide n'importe quel entier pour qu'il soit entre les bornes
minimum et maximum
--reçus également en paramètre. L'entier est retourné via son canal de
sortie(OUT).
PROCEDURE Valider_Entier(Msg_Sollic : IN String; --message de sollicitation à afficher
Entier : OUTInteger; --l'entier à lire et à valider
Min : IN Integer; --la valeur minimum permise
Max : IN Integer; --la valeur maximum permise
Msg_Erreur : IN String) IS --message à afficher en cas de non
--respect des bornes
BEGIN --Valider_Entier
LOOP
Put(Msg_Sollic);
Es_Entiers.Get(Entier);
Ada.Text_IO.Skip_Line;
EXIT WHEN Entier IN Min..Max;
Put(Msg_Erreur);
END LOOP;
END
Valider_Entier;
Différence entre IN, OUT et IN OUT
En Ada tout les paramètres sont passés par références(adresses). Cependant, il est nécessaire de connaître les règles de passages de paramètres selon les différents modes possibles. On peut imaginer le fonctionnement de la façon suivante :
IN : Le contenu du paramètre effectif est copié dans le paramètre formel. À la fin du sous-programme, le paramètre effectif est inchangé. Le paramètre formel ne peut servir que comme une constante à l'intérieur du sous-programme.
OUT : Le contenu du paramètre effectif n'est pas copié dans le paramètre formel. À la fin du sous-programme, le paramètre effectif est modifié. Le paramètre formel est utilisable comme une variable locale à l'intérieur du sous-programme. Il est impératif de mettre une valeur dans le paramètre formel avant la fin du sous-programme pour éviter des erreurs à l'exécution.
IN OUT : Le contenu du paramètre effectif est copié dans le paramètre formel. À la fin du sous-programme, le paramètre effectif est modifié. Le paramètre formel est utilisable comme une variable locale à l'intérieur du sous-programme.
Ce qui implique qu'aussitôt que l'on voit qu'un paramètre formel est OUT ou IN OUT,
il faut absolument que le paramètre effectif soit une variable. Dans le cas d'un
paramètre IN, le paramètre effectif peut être aussi une constante ou un
littéral.
Il peut y avoir de 0 à plusieurs paramètres pour une fonction. S'il y en a, ils doivent tous être en mode IN. Une fonction doit minimalement avoir une instruction RETURN dans sa partie exécutive(entre begin..end;), pour que le programme compile. De plus, lors de l'exécution de la fonction, il est impératif qu'il y ait une instruction RETURN d'exécutée. Si ce n'est pas le cas, une exception PROGRAM_ERROR sera levée. Il est préférable de mettre les valeurs de retour dans une variable temporaire, locale à la fonction(du même type que la valeur de retour), et de faire le RETURN juste avant le END de la fonction, pour éviter ce genre d'erreur.
Ex:
FUNCTION Bissextile(Annee : IN Integer)
RETURN Boolean IS
--retourne vrai si l'année reçue en
paramètre est bissextile et faux sinon
BEGIN -- Bissextile
RETURN (Annee mod 400 = 0) OR (Annee mod 4 = 0 AND Annee mod 100 /= 0);
END Bissextile;
FUNCTION Nombre_Jour_Max(Mois : IN
Integer; Annee : IN Integer) RETURN Integer IS
--Retourne le nombre de jours maximum permis
pour le mois de l'année reçu en paramètre.
--variable
Nombre_Jour : Integer; --nécessaire pour n'avoir qu'un seul RETURN
BEGIN --Nombre_Jour_Max
--Dans cet exemple, nous présumons que le mois a été validé avant l'appel de la
fonction.
CASE Mois IS
WHEN 2 => Nombre_Jour := 28 + Boolean'POS(Bissextile(Annee));
WHEN 4|6|9|11 => Nombre_Jour := 30;
WHEN others => Nombre_Jour := 31;
END CASE;
RETURN Nombre_Jour;
END Nombre_Jour_Max;
**Boolean'POS(Bissextile(Annee)) retourne 1 si l'année est bissextile et 0
sinon.
Il est possible de programmer en couleur en mode console. Pour pouvoir le faire,
il faut importer des fichiers et suivre les indications qui sont fournies à cette page.
Peut-on saisir une touche au clavier comme avec getch() en C?
Il est possible de récupérer un caractère sans avoir à presser la touche
<entrée>. Pour ce faire, il faut utiliser le sous-programme
"get_immediate", du module Ada.text_io. Il y a cependant un inconvénient
si l'utilisateur utilise la touche <entrée>, il devra le faire 2 fois. Il est
possible également avec PRAGMA et le langage C, mais cela déborde du cadre de ce cours.
Initialiser un tableau d'un coup
Vous pouvez initilialiser un tableau ou un article en une seule instruction grâce à ce qu'on appelle des aggrégats. Il existe 2 sortes d'aggrégats : par nom ou par position.
Par nom :
Soit le tableau suivant :
TYPE T_Tab IS ARRAY(1..10) OF Integer;
Tableau : T_Tab;
Il est possible de mettre des valeurs dans chaque case du tableau en nommant les cases dans lesquelles on veut mettre une valeur et cela pendant l'affectation. Pour ce faire, il suffit de mettre entre parenthèses le nom de la case suivi du symbole "=>" suivi de la valeur à mettre dans cette case.
ex: Tableau := (1=>3,5=>4,7=>5,others=>0);
Cette dernière instruction met dans la case 1 la valeur 3, dans la case 5 la valeur 4, dans la case 7 la valeur 5 et dans toutes les autres cases(others) la valeur 0. Donc si on veut mettre toutes les cases d'un tableau à une même valeur...
ex: Tableau := (others => 1).
Ceci met la valeur 1 dans toutes les cases du tableau qui n'ont pas été
nommées. Comme il n'y en a eu aucune de nommée, toutes les cases du tableau
seront affectées.
Par position :
Cette méthode ne demande pas de nommer les cases, alors c'est l'ordre dans lequel les valeurs sont mises qui détermine dans quelle case ira la valeur.
ex: Tableau :=(0,0,3,0,4,0,5,0,0,0); ou Tableau :=(0,0,3,0,4,0,5,others=>0);
Ces 2 instructions d'affectation sont équivalentes au premier exemple que nous avons donné plus haut pour la méthode par nom. Il n'est pas permis de mélanger les 2 méthodes. La seule chose qui peut être utilisé dans les 2 cas est le "others".
Les caractères indésirables lors de l'affichage d'une chaîne
Vous avez probablement omis d'utiliser la longueur de la chaîne à afficher.
ex: Put(chaine(1..lng));
Quelles sont les opérations permises sur les articles(RECORD)?
Les seules opérations qui sont permises sont l'affectation(:=) et la comparaison
d'égalité(=, /=). Toutes les autres opérations doivent être définies par le
programmeur.
Quelle est la différence entre une variable globale et une variable locale?
Pour bien comprendre la différence, il faut connaître les règles de visibilité du compilateur. Si
une variable est utilisée dans une région déclarative autre que celle où elle a été
définie, on dira qu'elle est utilisée globalement et que c'est une variable
globale. En résumé, à l'intérieur d'un sous-programme, les seules choses
qu'on devrait utiliser sont les variables définies dans ce sous-programme et les
paramètres formels de ce sous-programme.
Une région déclarative est une portion de texte qui est d'une des formes suivantes :
Cet attribut de type se comporte différemment selon le type de données avec lequel il est utilisé. Si c'est un type énumératif, cet attribut retournera la première valeur dans la définition du type. Si c'est un type tableau, l'attribut 'FIRST retournera la valeur de l'indice de la première case.
Soit: TYPE T_Jour_Semaine IS (dimanche, lundi, mardi, mercredi, jeudi, vendredi, samedi);
TYPE T_Tab IS ARRAY(50..225) OF Integer;
Tableau : T_Tab;
ex:
T_Jour_Semaine'FIRST retournera dimanche
Tableau'First retournera 50
***L'erreur la plus fréquente est de penser que T_Tab'First retournera le contenu de
la première case du tableau. Si ce qu'on désire est le contenu de la case, il
faudra faire utiliser plutôt Tableau(Tableau'FIRST). On peut utiliser
aussi bien le nom du type qu'une variable avec cet attribut Tableau(T_Tab'FIRST).
Tout comme l'attribut 'FIRST, cet attribut donne de
l'information sur les valeurs d'un type de données et se comporte
différemment selon le type. Si c'est un type énumératif,
cet attribut retournera la dernière valeur dans la définition du type. Si c'est un
type tableau, l'attribut 'LAST retournera la valeur de l'indice de la dernière case.
Soit: TYPE T_Jour_Semaine IS (dimanche, lundi, mardi, mercredi, jeudi, vendredi, samedi);
TYPE T_Tab IS ARRAY(50..225) OF Integer;
Tableau : T_Tab;
ex:
T_Jour_Semaine 'LAST retournera samedi
Tableau'Last retournera 225
***L'erreur la plus fréquente est de penser que T_Tab'Last retournera le contenu de la
dernière case du tableau. Si ce qu'on désire est le contenu de la case, il faudra
faire utiliser plutôt Tableau(Tableau'LAST). On peut utiliser aussi
bien le nom du type qu'une variable avec cet attribut Tableau(T_Tab'LAST).
Cet attribut de type retourne une valeur de type intervalle. L'intervalle qui est retourné est celui qui a été utilisé lors de la définition d'un tableau.
Soit::
TYPE T_Tab IS ARRAY(50..225) OF Integer;
Tableau : T_Tab;
ex: Tableau'RANGE retournera 50..225
Un sous-type est un sous-ensemble d'un type existant. Il est totalement compatible et hérite de toutes les opérations permises de son type parent. Par exemple le type "natural" est un sous-type du type "integer". Pour définir un sous-type, il faut utiliser le mot réservé SUBTYPE, donner le type parent et une contrainte d'intervalle si nécessaire avec le mot réservé RANGE.
ex: SUBTYPE Natural IS Integer RANGE 0..Integer'Last
ex:
TYPE T_Jour_Semaine IS (dimanche, lundi, mardi, mercredi, jeudi, vendredi, samedi);
TYPE T_Tab IS ARRAY (T_Jour_Semaine) OF Integer;
Tableau : T_Tab;
Tableau est un tableau de 7 cases dont le nom des cases est représenté par les valeurs du type T_Jour_Semaine. Il est donc légal de faire :
FOR Jour IN T_Jour_Semaine LOOP
Tableau(Jour) := 0;
END LOOP;
Dans le langage Ada, un intervalle c'est 2 valeurs séparées par deux points consécutifs(..). Ceci signifie les valeurs comprises entre les valeurs nommées, incluant ces valeurs.
ex: 10..100 signifie toutes les valeurs de 10 jusqu'à 100 inclusivement.
On peut définir des types et des sous-types de la catégorie des intervalles en utilisant le mot réservé RANGE. Dès lors, toutes les variables ou constantes définies comme faisant partie de cette catégorie, ne pourront pas avoir de valeur ne faisant pas partie de l'intervalle défini. Si cette contrainte n'est pas respectée, une exception CONSTRAINT_ERROR est levée.
ex: TYPE T_Inter IS NEW Integer RANGE 10..100; OU
SUBTYPE T_Inter IS Integer RANGE 10..100;
Une exception est levée lorsqu'une erreur survient lors de l'exécution d'un programme. Ce genre d'erreurs n'est pas détectables comme une erreur de compilation, il faut absolument que le programme soit en cours d'exécution pour que ces problèmes puissent. survenir.
Voici quelques remarques pour la gestion des exceptions :
Les erreurs classiques :
***REMARQUE
Toutes les erreurs ne se règlent pas nécessairement avec les exceptions et si on peut, vaut mieux éviter de s'en servir. La gestion des exceptions ajoute du traitement à votre programme et ralentit l'exécution.