Les paquets
Les paquets sont l'une des quatre formes d'unités de programme dont les programmes peuvent être composés. Les autres formes sont les sous-programmes, les unités de tâches et les unités génériques.
Les paquets permettent de spécifier des groupes d'entités logiquement liées. Dans leur forme la plus simple, les paquets spécifient des bassins d'objets et de déclarations de types communs. Plus généralement, les paquets peuvent être utilisés pour spécifier des groupes d'entités liées, y compris des sous-programmes pouvant être appelés depuis l'extérieur du paquet, tandis que leur fonctionnement interne reste caché et protégé des utilisateurs extérieurs.
Structure du paquet
Un paquet est généralement fourni en deux parties : une spécification de paquet et un corps de paquet. Chaque paquet possède une spécification de paquet, mais tous les paquets n'ont pas de corps de paquet :
declaration_de_paquet ::= specification_du_paquet; specification_du_paquet ::= package identifier is |element_declaratif_de_base| [ private |element_declaratif_de_base|] end [nom_simple_du_paquet] corps_du_paquet ::= package body nom_simple_du_paquet is [ partie_declarative] [ begin séquence_d_instructions [ exception gestionnaire_d_exceptions | gestionnaire_d_exceptions(]] end [nom_simple_du_paquet] |
Le nom simple au début du corps d'un paquet doit répéter l'identifiant du paquet. De même, si un nom simple apparaît à la fin de la spécification ou du corps du paquet, il doit répéter l'identifiant du paquet.
Si une déclaration de sous-programme, une déclaration de paquet, une déclaration de tâche ou une déclaration générique est un élément déclaratif d'une spécification de paquet donnée, alors le corps (s'il y en a un) de l'unité de programme déclarée par l'élément déclaratif doit lui-même être un élément déclaratif de la partie déclarative du corps du paquet donné.
Remarques : Une forme simple de paquet, spécifiant un bassin d'objets et de types, ne nécessite pas de corps de paquet. L'une des utilisations possibles de la séquence d'instructions d'un corps de paquet est d'initialiser de tels objets. Pour chaque déclaration de sous-programme, il doit y avoir un corps correspondant (sauf pour un sous-programme écrit dans un autre langage). Si le corps d'une unité de programme est un stub de corps, alors une sous-unité compilée séparément contenant le corps approprié correspondant est requise pour l'unité de programme. Un corps n'est pas un élément déclaratif de base et ne peut donc pas apparaître dans une spécification de paquet.
Une déclaration de paquet est soit un paquet de bibliothèque, soit un élément déclaratif déclaré dans une autre unité de programme.
Spécifications et déclarations de paquets
La première liste d'éléments déclaratifs d'une spécification de paquet est appelée la partie visible du paquet. La liste facultative d'éléments déclaratifs après le mot réservé private est appelée la partie privée du paquet.
Une entité déclarée dans la partie privée d'un paquet n'est pas visible en dehors du paquet lui-même (un nom désignant une telle entité n'est possible qu'à l'intérieur du paquet). En revanche, les noms étendus désignant des entités déclarées dans la partie visible peuvent être utilisés même en dehors du paquet; de plus, la visibilité directe de telles entités peut être obtenue au moyen de clauses use.
L'élaboration d'une déclaration de paquet consiste à élaborer ses éléments déclaratifs de base dans l'ordre donné.
Remarques : La partie visible d'un paquet contient toutes les informations qu'une autre unité de programme est en mesure de connaître sur le paquet. Un paquet constitué uniquement d'une spécification de paquet (c'est-à-dire sans corps de paquet) peut être utilisé pour représenter un groupe de constantes ou de variables communes, ou un pool commun d'objets et de types, comme dans les exemples ci-dessous.
Exemple de paquet décrivant un groupe de variables communes :
Exemple d'un paquet décrivant un bassin commun d'objets et de types :
Corps de paquet
Contrairement aux entités déclarées dans la partie visible d'une spécification de paquet, les entités déclarées dans le corps du paquet ne sont visibles qu'à l'intérieur du corps du paquet lui-même. Par conséquent, un paquet avec un corps de paquet peut être utilisé pour la construction d'un groupe de sous-programmes liés (un paquet au sens habituel), dans lequel les opérations logiques disponibles pour les utilisateurs sont clairement isolées des entités internes.
Pour l'élaboration d'un corps de paquet, sa partie déclarative est d'abord élaborée, puis sa séquence d'instructions (le cas échéant) est exécutée. Les gestionnaires d'exceptions facultatifs à la fin d'un corps de paquet traitent les exceptions levées pendant l'exécution de la séquence d'instructions du corps du paquet.
Remarques : une variable déclarée dans le corps d'un paquet n'est visible qu'à l'intérieur de ce corps et, par conséquent, sa valeur ne peut être modifiée qu'à l'intérieur du corps du paquet. En l'absence de tâches locales, la valeur d'une telle variable reste inchangée entre les appels émis depuis l'extérieur du paquet vers des sous-programmes déclarés dans la partie visible. Les propriétés d'une telle variable sont similaires à celles d'une variable "propre" d'Algol 60.
L'élaboration du corps d'un sous-programme déclaré dans la partie visible d'un paquet est provoquée par l'élaboration du corps du paquet. Ainsi, un appel d'un tel sous-programme par une unité de programme extérieure lève l'exception PROGRAM_ERROR si l'appel a lieu avant l'élaboration du corps du paquet.
Exemple de paquet :
- package RATIONAL_NUMBERS is
-
- type RATIONAL is
- record
- NUMERATOR : INTEGER;
- DENOMINATOR : POSITIVE;
- end record;
-
- function EQUAL (X,Y : RATIONAL) return BOOLEAN;
-
- function "/" (X,Y : INTEGER) return RATIONAL; -- construire un nombre rationnel
-
- function "+" (X,Y : RATIONAL) return RATIONAL;
- function "-" (X,Y : RATIONAL) return RATIONAL;
- function "*" (X,Y RATIONAL) return RATIONAL;
- function "/" (X,Y RATIONAL) return RATIONAL;
- end;
-
- package body RATIQNAI_NUMBERS is
-
- procedure SAME_DENOMINATOR (X,Y : in out RATIONAL) is begin
- -- réduit X et Y au même dénominateur :
- --
- end;
-
- function EQUAL(X,Y : RATIONAL) return BOOLEAN is
- U,V : RATIONAL;
- begin
- U := X;
- V := Y;
- SAME_DENOMINATOR (U,V);
- return U.NUMERATOR - V.NUMERATOR;
- end EQUAL;
-
- function "/" (X,Y : INTEGER) return RATIONAL is begin
- if Y > 0 then
- return (NUMERATOR => X, DENOMINATOR => Y);
- else
- return (NUMERATOR => -X, DENOMINATOR => -Y);
- end if;
- end "/";
-
- function "+" (X,Y RATIONAL) return RATIONAL is .. end "+";
- function "-" (X,Y RATIONAL) return RATIONAL is .. end "-";
- function "*" (X,Y RATIONAL) return RATIONAL is .. end "*";
- function "/" (X,Y RATIONAL) return RATIONAL is .. end "/"
-
- end RATIONAL_NUMBERS;
Déclarations de types privés et de constantes différées
La déclaration d'un type en tant que type privé dans la partie visible d'un paquet sert à séparer les caractéristiques pouvant être utilisées directement par des unités de programme externes (c'est-à-dire les propriétés logiques) des autres caractéristiques dont l'utilisation directe est limitée au paquet (les détails de la définition du type lui-même). Les déclarations de constantes différées déclarent des constantes de types privés :
declaration_de_type_prive ::= type identifiant [discriminant_part] is [limited] private; declaration_constante_differee ::= liste_identifiant : constant marque_type; |
Une déclaration de type privé n'est autorisée qu'en tant qu'élément déclaratif de la partie visible d'un paquet, ou en tant que déclaration de paramètre générique pour un type formel générique dans une partie formelle générique.
La marque de type d'une déclaration de constante différée doit désigner un type privé ou un sous-type d'un type privé; une déclaration de constante différée et la déclaration du type privé correspondant doivent toutes deux être des éléments déclaratifs de la partie visible du même paquet. Une déclaration de constante différée avec plusieurs identifiants est équivalente à une séquence de déclarations de constantes différées uniques.
Exemples de déclarations de type privé :
- type KEY is private;
- type FILE_NAME is limited private;
Exemple de déclaration de constante différée :
- NULL_KEY : constant KEY;
Types privés
Si une déclaration de type privé est donnée dans la partie visible d'un paquet, une déclaration correspondante d'un type avec le même identifiant doit alors apparaître comme un élément déclaratif de la partie privée du paquet. La déclaration correspondante doit être soit une déclaration de type complète, soit la déclaration d'un type de tâche. Dans le reste de cette section, les explications sont données en termes de déclarations de type complètes ; les mêmes règles s'appliquent également aux déclarations de types de tâches.
Une déclaration de type privé et la déclaration de type complète correspondante définissent un seul type. La déclaration de type privé, ainsi que la partie visible, définissent les opérations disponibles pour les unités de programme externes. D'autre part, la déclaration de type complète définit d'autres opérations dont l'utilisation directe n'est possible qu'au sein du paquet lui-même.
Si la déclaration de type privé comprend une partie discriminante, la déclaration complète doit inclure une partie discriminante conforme et sa définition de type doit être une définition de type d'enregistrement. Inversement, si la déclaration de type privé n'inclut pas de partie discriminante, le type déclaré par la déclaration de type complète (le type complet) ne doit pas être un type sans contrainte avec des discriminants. Le type complet ne doit pas être un type de tableau sans contrainte. Un type limité (en particulier un type de tâche) n'est autorisé pour le type complet que si le mot réservé limited apparaît dans la déclaration de type private.
Dans la spécification du paquet déclarant un type private et avant la fin de la déclaration de type complète correspondante, une restriction s'applique à l'utilisation d'un nom qui désigne le type private ou un sous-type du type private et, de même, à l'utilisation d'un nom désignant tout type ou sous-type ayant une sous-composante du type private. Les seules occurrences autorisées d'un tel nom sont dans une déclaration de constante différée, une déclaration de type ou de sous-type, une spécification de sous-programme ou une déclaration d'entrée ; de plus, les occurrences dans des définitions de type dérivées ou dans des expressions simples ne sont pas autorisées.
L'élaboration d'une déclaration de type private crée un type private. Si la déclaration de type private comporte une partie discriminante, cette élaboration inclut celle de la partie discriminante. L'élaboration de la déclaration de type complète consiste en l'élaboration de la définition de type; la partie discriminante, le cas échéant, n'est pas élaborée (puisque la partie discriminante conforme de la déclaration de type privé a déjà été élaborée).
Remarques : Il résulte des règles données que ni la déclaration d'une variable d'un type private, ni la création par un allocateur d'un objet du type privé ne sont autorisées avant la déclaration complète du type. De même, avant la déclaration complète, le nom du type privé ne peut pas être utilisé dans une instanciation générique ou dans une clause de représentation.
Les opérations d'un type privé
Les opérations implicitement déclarées par une déclaration de type privé incluent les opérations de base. Il s'agit des opérations d'affectation (sauf si le mot réservé limited apparaît dans la déclaration), des tests d'appartenance, des composants sélectionnés pour la sélection de tout discriminant, de la qualification et des conversions explicites.
Pour un type privé T, les opérations de base incluent également les attributs T'BASE et T'SIZE. Pour un objet A de type privé, les opérations de base incluent l'attribut A'CONSTRAINED si le type privé possède des discriminants, et dans tous les cas les attributs A SIZE et A'ADDRESS.
Enfin, les opérations implicitement déclarées par une déclaration de type privé incluent la comparaison prédéfinie pour l'égalité et l'inégalité sauf si le mot réservé limited apparaît dans la déclaration de type private.
Les opérations ci-dessus, ainsi que les sous-programmes ayant un paramètre ou un résultat du type privé et étant déclarés dans la partie visible du paquet, sont les seules opérations du paquetage étant disponibles en dehors du paquetage pour le type private.
Au sein du paquet déclarant le type private, les opérations supplémentaires implicitement déclarées par la déclaration de type complète sont également disponibles. Cependant, la redéfinition de ces opérations implicitement déclarées est autorisée au sein de la même région déclarative, y compris entre la déclaration de type private et la déclaration complète correspondante. Un sous-programme explicitement déclaré cache une opération implicitement déclarée possédant le même profil de type de paramètre et de résultat (cela n'est possible que si l'opération implicitement déclarée est un sous-programme dérivé ou un opérateur prédéfini).
Si un type composite a des sous-composantes d'un type privé et est déclaré en dehors du paquet déclarant le type private, alors les opérations implicitement déclarées par la déclaration du type composite incluent toutes les opérations ne dépendant que des caractéristiques résultant de la déclaration de type privé seule. (Par exemple, l'opérateur < n'est pas inclus pour un type de tableau unidimensionnel.)
Si le type composite est lui-même déclaré dans le paquet déclarant le type privé (y compris dans un paquet interne ou un paquet générique), alors les opérations supplémentaires qui dépendent des caractéristiques du type complet sont implicitement déclarées, comme l'exigent les règles applicables au type composite (par exemple, l'opérateur < est déclaré pour un type de tableau unidimensionnel si le type complet est discret). Ces opérations supplémentaires sont implicitement déclarées au premier endroit dans la portée immédiate du type composite et après la déclaration complète du type.
Les mêmes règles s'appliquent aux opérations implicitement déclarées pour un type d'accès dont le type désigné est un type privé ou un type déclaré par une déclaration de type incomplète.
Pour chaque type ou sous-type privé T, l'attribut suivant est défini :
Attribut | Description |
---|---|
T'CONSTRAINED | Renvoie la valeur FALSE si T désigne un type privé non formel sans contrainte avec des discriminants ; renvoie également la valeur FALSE si T désigne un type privé formel générique et que le sous-type réel associé est soit un type sans contrainte avec des discriminants, soit un type de tableau sans contrainte; renvoie la valeur TRUE dans le cas contraire. La valeur de cet attribut est du type prédéfini BOOLEAN. |
Remarque : Une déclaration de type privé et la déclaration de type complète correspondante définissent deux vues différentes d'un même type. En dehors du paquet de définition, les caractéristiques du type sont celles définies par la partie visible. Dans ces unités de programme extérieures, le type est simplement un type privé et toute règle de langage qui s'applique uniquement à une autre classe de types ne s'applique pas. Le fait que la déclaration complète puisse implémenter le type privé avec un type d'une classe particulière (par exemple, en tant que type de tableau) n'est pertinent qu'au sein du paquet lui-même.
Les conséquences de cette implémentation réelle sont cependant valables partout. Par exemple : toute initialisation par défaut des composantes a lieu; l'attribut SIZE fournit la taille du type complet ; les règles de dépendance des tâches s'appliquent toujours aux composantes étant des objets de tâches.
Exemple :
- package KEY_MANAGER is
- type KEY is private;
- NULLKEY : constant KEY;
- procedure GET_KEY(K : out KEY);
- function "<(" (X, Y : KEY) return BOOLEAN;
- private
- type KEY is new NATURAL;
- NULI_KEY : constant KEY := 0;
- end;
-
- package body KEY_MANAGER is
- LAST_KEY : KEY := 0;
- procedure GET_KEY(K : out KEY) is begin
- LAST_KEY := LAST_KEY + 1;
- K := LAST_KEY;
- end GET_KEY;
-
- function "<(" (X, Y : KEY) return BOOLEAN is begin
- return INTEGER(X) < INTEGER(Y);
- end "<";
- end KEY_MANAGER;
Notes sur l'exemple : En dehors du paquet KEY_MANAGER, les opérations disponibles pour les objets de type KEY incluent l'affectation, la comparaison pour l'égalité ou l'inégalité, la procédure GET_KEY et l'opérateur "<" ; elles n'incluent pas d'autres opérateurs relationnels tels que ">=", ni les opérateurs arithmétiques.
L'opérateur "<" explicitement déclaré cache l'opérateur prédéfini "<" implicitement déclaré par la déclaration de type complète. Dans le corps de la fonction, une conversion explicite de X et Y vers le type INTEGER est nécessaire pour appeler l'opérateur "<" de ce type. Alternativement, le résultat de la fonction pourrait être écrit comme not (X >= Y), puisque l'opérateur ">=" n'est pas redéfini.
La valeur de la variable LAST_KEY, déclarée dans le corps du paquet, reste inchangée entre les appels de la procédure GET_KEY.
Constantes différées
Si une déclaration de constante différée est donnée dans la partie visible d'un paquet, alors une déclaration de constante (c'est-à-dire une déclaration d'objet déclarant un objet constant, avec une initialisation explicite) avec le même identifiant doit apparaître comme un élément déclaratif de la partie privée du paquet. Cette déclaration d'objet est appelée la déclaration complète de la constante différée. La marque de type donnée dans la déclaration complète doit être conforme à celle donnée dans la déclaration de constante différée. Des déclarations multiples ou uniques sont autorisées pour les déclarations différées et complètes, à condition que les déclarations uniques équivalentes soient conformes.
Dans la spécification du paquet déclarant une constante différée et avant la fin de la déclaration complète correspondante, l'utilisation d'un nom désignant la constante différée n'est autorisée que dans l'expression par défaut pour une composante d'enregistrement ou pour un paramètre formel (pas pour un paramètre formel générique).
L'élaboration d'une déclaration de constante différée n'a aucun autre effet. L'exécution d'un programme est erronée si celui-ci tente d'utiliser la valeur d'une constante différée avant l'élaboration de la déclaration complète correspondante.
Remarque : la déclaration complète d'une constante différée ayant un type privé donné ne doit pas apparaître avant la déclaration complète du type correspondant. Ceci est une conséquence des règles définissant les utilisations autorisées d'un nom désignant un type privé.
Types limités
Un type limité est un type pour lequel ni l'affectation ni la comparaison prédéfinie pour l'égalité et l'inégalité ne sont déclarées implicitement.
Une déclaration de type privé incluant le mot réservé limited déclare un type limité. Un type de tâche est un type limité. Un type dérivé d'un type limité est lui-même un type limité. Enfin, un type composite est limité si le type de l'un de ses sous-composants est limité.
Pour un paramètre formel dont le type est limité et dont la déclaration intervient dans une déclaration explicite de sous-programme, le mode out n'est autorisé que si ce type est privé et que la déclaration de sous-programme intervient dans la partie visible du paquet déclarant le type privé. Il en va de même pour les paramètres formels des déclarations d'entrée et des déclarations de procédures génériques. Le type complet correspondant ne doit pas être limité si le mode out est utilisé pour un tel paramètre formel. Dans le cas contraire, le type complet correspondant est autorisé (mais pas obligatoire) à être un type limité (en particulier, il est autorisé à être un type de tâche). Si le type complet correspondant à un type privé limité n'est pas lui-même limité, alors l'affectation pour le type est disponible dans le paquet, mais pas en dehors.
Voici les conséquences des règles pour les types limités :
- Une initialisation explicite n'est pas autorisée dans une déclaration d'objet si le type de l'objet est limité.
- Une expression par défaut n'est pas autorisée dans une déclaration de composant si le type du composant d'enregistrement est limité.
- Une valeur initiale explicite n'est pas autorisée dans un allocateur si le type désigné est limité.
- Un paramètre formel générique de mode in ne doit pas être de type limité.
Remarques : Les règles ci-dessus n'excluent pas une expression par défaut pour un paramètre formel d'un type limité; elles n'excluent pas une constante différée d'un type limité si le type complet n'est pas limité. Une déclaration explicite d'un opérateur d'égalité est autorisée pour un type limité.
Les agrégats ne sont pas disponibles pour un type composite limité. La concaténation n'est pas disponible pour un type de tableau limité.
Exemple :
- package I_O_PACKAGE is
- type FILE_NAME is limited private;
-
- procedure OPEN (F : in out FILE_NAME);
- procedure CLOSE (F : in out FILE_NAME);
- procedure READ (F : in FILE.NAME; ITEM; out INTEGER);
- procedure WRITE (F : in FILE_NAME; ITEM; in INTEGER);
- private
- type FILE_NAME is
- record
- INTERNAL_NAME : INTEGER := 0;
- end record;
- end LO_PACKAGE;
-
- package body I_O_PACKAGE is
- LIMIT : constant := 200;
- type FILE_DESCRIPTOR is record ... end record;
- DIRECTORY : array (1 .. LIMIT) of FILE_DESCRIPTOR;
- ...
- procedure OPEN (F : in out FILE_NAME) is ... end;
- procedure CLOSE (F : in out FILE_NAME) is ... end;
- procedure READ (F : in FILE_NAME; ITEM : out INTEGER) is ... end;
- procedure WRITE (F : in FILEJMAME; ITEM : in INTEGER) is ... end;
- begin
- end I_O_PACKAGE;
Remarques sur l'exemple : Dans l'exemple ci-dessus, un sous-programme externe utilisant I_OI_PACKAGE peut obtenir un nom de fichier en appelant OPEN et l'utiliser ultérieurement dans des appels à READ et WRITE. Ainsi, en dehors du paquet, un nom de fichier obtenu à partir d'OPEN agit comme une sorte de mot de passe ; ses propriétés internes (comme le fait de contenir une valeur numérique) ne sont pas connues et aucune autre opération (comme l'ajout ou la comparaison de noms internes) ne peut être effectuée sur un nom de fichier.
Cet exemple est caractéristique de tout cas où un contrôle complet sur les opérations d'un type est souhaité. De tels paquets ont un double objectif. Ils empêchent un utilisateur d'utiliser la structure interne du type. Ils implémentent également la notion de type de données encapsulé où les seules opérations sur le type sont celles indiquées dans la spécification du paquet.
Exemple d'un paquet de gestion de table
L'exemple suivant illustre l'utilisation de paquets pour fournir des procédures de haut niveau avec une interface simple à l'utilisateur. Le problème consiste à définir un paquet de gestion de table pour l'insertion et la récupération d'éléments. Les éléments sont insérés dans la table au fur et à mesure qu'ils sont fournis. Chaque élément inséré possède un numéro d'ordre. Les éléments sont récupérés en fonction de leur numéro d'ordre, l'élément avec le numéro d'ordre le plus bas étant récupéré en premier.
Du point de vue de l'utilisateur, le paquet est assez simple. Il existe un type appelé ITEM désignant les éléments de la table, une procédure INSERT pour l'insertion d'éléments et une procédure RETRIEVE pour obtenir l'élément avec le numéro d'ordre le plus bas. Il existe un élément spécial NULLITEM étant renvoyé lorsque la table est vide et une exception TABLE_FULL étant levée par INSERT si la table est déjà pleine. Un schéma d'un tel paquet est donné ci-dessous. Seule la spécification du paquet est exposée à l'utilisateur.
- package TABLE_MANAGER is
-
- type ITEM is
- record
- ORDER_NUM : INTEGER;
- ITEM_CODE : INTEGER;
- QUANTITY : INTEGER;
- ITEM_TYPE : CHARACTER;
- end record;
-
- NULL_ITEM : constant ITEM :=
- (ORDER_NUM | ITEM_CODE | QUANTITY => 0, ITEM_TYPE => ' ');
-
- procedure INSERT (NEW_ITEM ; in ITEM);
- procedure RETRIEVE (FIRST_ITEM : out ITEM);
-
- TABLE_FULL : exception; -- déclenché par INSERT lorsque la table est pleine
- end;
Les détails de la mise en ouvre de tels paquets peuvent être assez complexes; dans ce cas, ils impliquent une table bidirectionnelle d'éléments internes. Une procédure de gestion locale EXCHANGE est utilisée pour déplacer un élément interne entre les listes occupées et libres. Les liens de table initiaux sont établis par la partie d'initialisation. Le corps du paquet n'a pas besoin d'être montré aux utilisateurs du paquet :
- package body TABLE_MANAGER is
- SIZE : constant := 2000;
- subtype INDEX is INTEGER range 0 .. SIZE;
-
- type INTERNAL_ITEM is
- record
- CONTENT : ITEM;
- SUCC : INDEX;
- PRED : INDEX;
- end record;
-
- TABLE : array (INDEX) of INTERNAL_ITEM;
- FIRST_BUSY_ITEM : INDEX := 0;
- FIRST_FREE_ITEM : INDEX := 1;
-
- function FREE_LIST_EMPTY return BOOLEAN is ... end;
- function BUSY__LIST_EMPTY return BOOLEAN is ... end;
- procedure EXCHANGE (FROM : in INDEX; TO : in INDEX) is ... end;
-
- procedure INSERT (NEW_ITEM : in ITEM) is begin
- if FREE_LIST_EMPTY then
- raise TABLE_FULL;
- end if;
- -- code restant pour INSERT
- end INSERT;
-
- procedure RETRIEVE (FIRST_ITEM : out ITEM) is ... end;
-
- begin
- -- initialisation des liens de table
- end TABLE_MANAGER;
Exemple d'un paquet de gestion de texte
Cet exemple illustre un paquet de gestion de texte simple. Les utilisateurs n'ont accès qu'à la partie visible ; l'implémentation leur est cachée dans la partie privée et le corps du paquet (non affiché).
Du point de vue de l'utilisateur, un TEXT est une chaîne de caractères de longueur variable. Chaque objet texte a une longueur maximale, devant être indiquée lors de la déclaration de l'objet, et une valeur courante, étant une chaîne de caractères d'une longueur comprise entre zéro et le maximum. La longueur maximale possible d'un objet texte est une constante définie par l'implémentation.
Le paquet définit d'abord les types nécessaires, puis les fonctions qui renvoient certaines caractéristiques des objets du type, puis les fonctions de conversion entre les textes et les types prédéfinis CHARACTER et STRING, et enfin certaines des opérations standard sur des chaînes de caractères variables. La plupart des opérations sont surchargées sur les chaînes et les caractères ainsi que sur le type TEXT, afin de minimiser le nombre de conversions explicites que l'utilisateur doit écrire.
- package TEXT_HANDLER is
- MAXIMUM : constant := SOME_VALUE; -- défini par l'implémentation
- subtype INDEX is INTEGER range 0 .. MAXIMUM;
-
- type TEXT(MAXIMUM_LENGTH : INDEX) is limited private;
-
- function LENGTH (T : TEXT) return INDEX;
- function VALUE (T : TEXT) return STRING;
- function EMPTY (T : TEXT) return BOOLEAN;
-
- function TO_TEXT (S : STRING; MAX : INDEX) return TEXT; -- longueur maximale
- function TO_TEXT (C : CHARACTER; MAX : INDEX) return TEXT;
- function TO_TEXT (S : STRING) return TEXT; -- longueur maximale S'LENGTH
- function TO_TEXT (C : CHARACTER) return TEXT;
-
- function "&" (LEFT : TEXT; RIGHT : TEXT) return TEXT
- function "&" (LEFT : TEXT; RIGHT : STRING) return TEXT
- function "&" (LEFT : STRING; RIGHT : TEXT) return TEXT
- function "&" (LEFT : TEXT; RIGHT : CHARACTER) return TEXT
- function "&" (LEFT : CHARACTER; RIGHT : TEXT) return TEXT
-
- function "=" (LEFT : TEXT; RIGHT : TEXT) return BOOLEAN
- function "<" (LEFT : TEXT; RIGHT : TEXT) return BOOLEAN
- function "<=" (LEFT : TEXT; RIGHT : TEXT) return BOOLEAN
- function ">" (LEFT : TEXT; RIGHT : TEXT) return BOOLEAN
- function ">=" (LEFT : TEXT; RIGHT : TEXT) return BOOLEAN
-
- procedure SET (OBJECT : in out TEXT; VALUE : in TEXT);
- procedure SET (OBJECT : in out TEXT; VALUE : in STRING);
- procedure SET (OBJECT : in out TEXT; VALUE : in CHARACTER);
-
- procedure APPEND (TAIL : in TEXT; TO in out TEXT);
- procedure APPEND (TAIL : in STRING; TO in out TEXT);
- procedure APPEND (TAIL : in CHARACTER; TO in out TEXT);
-
- procedure AMEND (OBJECT : in out TEXT; BY in TEXT; POSITION : in INDEX);
- procedure AMEND (OBJECT : in out TEXT; BY in STRING; POSITION : in INDEX);
- procedure AMEND (OBJECT : in out TEXT; BY in CHARACTER; POSITION : in INDEX);
-
- -- amender remplace une partie de l'objet par le texte, la chaîne ou le caractère donné
- -- en commençant à la position donnée dans l'objet
-
- function LOCATE (FRAGMENT : TEXT; WITHIN : TEXT) return INDEX;
- function LOCATE (FRAGMENT : STRING; WITHIN : TEXT) return INDEX;
- function LOCATE (FRAGMENT : CHARACTER; WITHIN : TEXT) return INDEX;
-
- -- tous renvoient 0 si le fragment n'est pas localisé
-
- private
- type TEXT(MAXIMUM_LENGTH : INDEX) is
- record
- POS : INDEX := 0;
- VALUE : STRING(1 .. MAXIMUM.LENGTH);
- end record;
- end TEXT_HANDLER;
Exemple d'utilisation du paquet de traitement de texte :
Un programme ouvre un fichier de sortie dont le nom est fourni par la chaîne de caractères NAME. Cette chaîne de caractères a la forme :
[DEVICE :] [FILENAME [.EXTENSION]] |
Il existe des valeurs par défaut standard pour le périphérique, le nom de fichier et l'extension. Le nom fourni par l'utilisateur est transmis à EXPAND_FILE_NAME en tant que paramètre, et le résultat est la version étendue, avec les valeurs par défaut nécessaires ajoutées :
- function EXPAND_FILE_NAME (NAME : STRING) return STRING is
- use TEXTJHANDLER;
-
- DEFAULT_DEVICE : constant STRING := "SY:";
- DEFAULT_FILE_NAME : constant STRING := "RESULTS";
- DEFAULT_EXTENSION : constant STRING := ".DAT";
-
- MAXIMUM_FILE_NAME_LENGTH : constant INDEX := SOME_j4PPROPRIATE_VALUE;
- FILE_NAME : TEXT(MAXIMUM_FILE_NAME_LENGTH);
-
- begin
- SET(FILE_NAME, NAME);
-
- if EMPTY(FILE_NAME) then
- SET(FILE_NAME, DEFAULT_FILE_NAME);
- end if;
-
- if LOCATE(':', FILE_NAME) = 0 then
- SET(FILE_NAME, DEFAULT-DEVICE & FILEJMAME);
- end if;
-
- if LOCATE('.', FILE_NAME) = 0 then
- APPEND(DEFAULT_EXTENSION, TO => FILE_NAME);
- end if;
-
- return VALUE(FILE_NAME);
- end EXPAND_FILE_NAME;