Structure du programme et problèmes de compilation
La structure générale des programmes et les fonctionnalités de compilation séparée sont décrites dans cette page. Un programme est un ensemble d'une ou plusieurs unités de compilation soumises à un compilateur dans une ou plusieurs compilations. Chaque unité de compilation spécifie la compilation séparée d'une construction pouvant être une déclaration ou un corps de sous-programme, une déclaration ou un corps de paquetage, une déclaration ou un corps générique ou une instanciation générique. Alternativement, cette construction peut être une sous-unité, auquel cas elle inclut le corps d'un sous-programme, d'un paquetage, d'une unité de tâche ou d'une unité générique déclarée dans une autre unité de compilation.
Unités de compilation - Unités de bibliothèque
Le texte d'un programme peut être soumis au compilateur en une ou plusieurs compilations. Chaque compilation est une succession d'unités de compilation.
compilation ::= {unite_de_compilation} unite_de_compilation ::= clause_contextuelle unite_bibliotheque | clause_contextuelle unite_secondaire unite_bibliotheque ::= declaration_sous-programme | declaration_de_paquet | declaration_generique | instantiation_generique | sous_programme_corps unite_secondaire ::= unite_bibliotheque_corps | sous_unite unite_bibliotheque_corps ::= sous_programme_corps | corps_du_paquet |
Les unités de compilation d'un programme sont dites appartenir à une bibliothèque de programmes. Une unité de compilation définit soit une unité de bibliothèque, soit une unité secondaire. Une unité secondaire est soit le corps propre compilé séparément d'une unité de bibliothèque, soit une sous-unité d'une autre unité de compilation. Le désignateur d'un sous-programme compilé séparément (qu'il s'agisse d'une unité de bibliothèque ou d'une sous-unité) doit être un identifiant. Dans une bibliothèque de programmes, les noms simples de toutes les unités de bibliothèque doivent être des identifiants distincts.
L'effet de la compilation d'une unité de bibliothèque est de définir (ou de redéfinir) cette unité comme appartenant à la bibliothèque de programmes. Pour les règles de visibilité, chaque unité de bibliothèque agit comme une déclaration apparaissant immédiatement dans le paquet STANDARD.
L'effet de la compilation d'une unité secondaire est de définir le corps d'une unité de bibliothèque, ou dans le cas d'une sous-unité, de définir le corps propre d'une unité de programme qui est déclarée dans une autre unité de compilation.
Un corps de sous-programme donné dans une unité de compilation est interprété comme une unité secondaire si la bibliothèque de programmes contient déjà une unité de bibliothèque étant un sous-programme portant le même nom; dans le cas contraire, il est interprété à la fois comme une unité de bibliothèque et comme le corps de l'unité de bibliothèque correspondante (c'est-à-dire comme une unité secondaire).
Les unités de compilation d'une compilation sont compilées dans l'ordre donné. Un pragma s'appliquant à l'ensemble d'une compilation doit apparaître avant la première unité de compilation de cette compilation. Un sous-programme étant une unité de bibliothèque peut être utilisé comme programme principal au sens habituel. Chaque programme principal agit comme s'il était appelé par une tâche d'environnement; les moyens par lesquels cette exécution est initiée ne sont pas prescrits par la définition du langage. Une implémentation peut imposer certaines exigences sur les paramètres et sur le résultat, le cas échéant, d'un programme principal. Dans tous les cas, chaque implémentation doit autoriser, au moins, des programmes principaux qui sont des procédures sans paramètres, et chaque programme principal doit être un sous-programme qui est une unité de bibliothèque.
Remarques : Un programme simple peut être constitué d'une seule unité de compilation. Une compilation n'a pas besoin d'avoir d'unités de compilation ; par exemple, son texte peut être constitué de pragmas.
Le désignateur d'une fonction de bibliothèque ne peut pas être un symbole d'opérateur, mais une déclaration de renommage est autorisée pour renommer une fonction de bibliothèque en tant qu'opérateur. Deux sous-programmes de bibliothèque doivent avoir des noms simples distincts et ne peuvent donc pas se surcharger l'un l'autre. Cependant, les déclarations de renommage sont autorisées à définir des noms surchargés pour de tels sous-programmes, et un sous-programme déclaré localement est autorisé à surcharger un sous-programme de bibliothèque. Le nom étendu STANDARD.L peut être utilisé pour une unité de bibliothèque L (à moins que le nom STANDARD ne soit masqué) puisque les unités de bibliothèque agissent comme des déclarations qui se produisent immédiatement dans le paquet STANDARD.
Clauses de contexte - Clauses with
Une clause de contexte est utilisée pour spécifier les unités de bibliothèque dont les noms sont nécessaires dans une unité de compilation.
clause_contextuelle ::= {clause_with {clause_d_utilisation}} clause_with ::= with nom_simple_de_l_unite {, nom_simple_de_l_unite}; |
Les noms apparaissant dans une clause de contexte doivent être les noms simples des unités de bibliothèque. Le nom simple de toute unité de bibliothèque est autorisé dans une clause with. Les seuls noms autorisés dans une clause use d'une clause context sont les noms simples des paquets de bibliothèque mentionnés par les clauses with précédentes de la clause context. Un nom simple déclaré par une déclaration de renommage n'est pas autorisé dans une clause context.
Les clauses with et use de la clause context d'une unité de bibliothèque s'appliquent à cette unité de bibliothèque et également à l'unité secondaire définissant le corps correspondant (qu'une telle clause soit répétée ou non pour cette unité). De même, les clauses with et use de la clause context d'une unité de compilation s'appliquent à cette unité et également à ses sous-unités, le cas échéant.
Si une unité de bibliothèque est nommée par une clause with s'appliquant à une unité de compilation, alors cette unité de bibliothèque est directement visible dans l'unité de compilation, sauf si elle est masquée ; l'unité de bibliothèque est visible comme si elle était déclarée immédiatement dans le paquet STANDARD.
Les dépendances entre les unités de compilation sont définies par des clauses with; c'est-à-dire qu'une unité de compilation mentionnant d'autres unités de bibliothèque dans ses clauses with dépend de ces unités de bibliothèque. Ces dépendances entre unités sont prises en compte pour la détermination de l'ordre autorisé de compilation (et de recompilation) des unités de compilation, et pour la détermination de l'ordre autorisé d'élaboration des unités de compilation.
Remarques : Une unité de bibliothèque nommée par une clause with d'une unité de compilation est visible (sauf si elle est masquée) dans l'unité de compilation et peut donc être utilisée comme unité de programme correspondante. Ainsi, dans l'unité de compilation, le nom d'un paquet de bibliothèque peut être donné dans les clauses use et peut être utilisé pour former des noms étendus; un sous-programme de bibliothèque peut être appelé ; et des instances d'une unité générique de bibliothèque peuvent être déclarées.
Les règles données pour les clauses with sont telles que le même effet est obtenu que le nom d'une unité de bibliothèque soit mentionné une ou plusieurs fois par les clauses with applicables, ou même dans une clause with donnée.
Exemple 1 : Un programme principal : Voici un exemple de programme principal constitué d'une seule unité de compilation : une procédure d'impression des racines réelles d'une équation quadratique. Le paquet prédéfini TEXT_IO et un paquet défini par l'utilisateur REAL.OPERATIONS (contenant la définition du type REAL et des paquets REAL_IO et REAL_FUNCTIONS) sont supposés déjà présents dans la bibliothèque de programmes. De tels paquets peuvent être utilisés par d'autres programmes principaux.
- with TEXT_IO, REAL_OPERATIONS; use REAL_OPERATIONS;
- procedure QUADRATIC_EQUATION is
- A, B, C, D : REAL;
- use REAL_IO, -- permet d'obtenir une visibilité directe de GET et PUT pour REAL
- TEXT_IO, -- permet d'obtenir une visibilité directe de PUT pour les chaînes et de NEW_LINE
- REAL_FUNCTIONS; -- permet d'obtenir une visibilité directe de SORT
- begin
- GET(A); GET(B); GET(C);
- D := B**2 - 4.0*A*C;
- if D < 0.0 then
- PUT("Racines imaginaires.");
- else
- PUT("Racines réelles : X1 = ");
- PUT((-B - SQRT(D))/(2.Q*A)); PUT(" X2 = ");
- PUT((-B + SQRT(D))/(2.0*A));
- end if;
- NEW_LINE;
- end QUADRATIC_EQUATION;
Notes sur l'exemple : Les clauses with d'une unité de compilation ne doivent mentionner que les noms des sous-programmes et paquets de bibliothèque dont la visibilité est réellement nécessaire au sein de l'unité. Elles n'ont pas besoin (et ne devraient pas) mentionner d'autres unités de bibliothèque étant utilisées à leur tour par certaines des unités nommées dans les clauses with, à moins que ces autres unités de bibliothèque ne soient également utilisées directement par l'unité de compilation actuelle. Par exemple, le corps du paquet REAL_OPERATIONS peut nécessiter des opérations élémentaires fournies par d'autres paquets. Ces derniers paquets ne doivent pas être nommés par la clause with de QUADRATIC_EQUATION puisque ces opérations élémentaires ne sont pas directement appelées au sein de son corps.
Exemples d'unités de compilation
Une unité de compilation peut être divisée en plusieurs unités de compilation. Prenons par exemple le programme suivant :
- procedure PROCESSOR is
-
- SMALL : constant := 20;
- TOTAL : INTEGER := 0;
-
- package STOCK is
- LIMIT : constant := 1000;
- TABLE : array (1 .. LIMIT) of INTEGER;
- procedure RESTART;
- end STOCK;
-
- package body STOCK is
- procedure RESTART is begin
- for N in 1 .. LIMIT loop
- TABLE(N) := N;
- end loop;
- end;
- begin
- RESTART;
- end STOCK;
-
- procedure UPDATE(X : INTEGER) is
- use STOCK;
- begin
- ...
- TABLE(X) := TABLE(X) + SMALL;
- ...
- end UPDATE;
-
- begin
- ...
- STOCK.RESTART; -- réinitialise TABLE
- ...
- end PROCESSOR;
Les trois unités de compilation suivantes définissent un programme avec un effet équivalent à l'exemple ci-dessus (les lignes brisées entre les unités de compilation servent à rappeler au lecteur que ces unités ne doivent pas nécessairement être des textes contigus).
Exemple 2 : Plusieurs unités de compilation :
- package STOCK is
- LIMIT : constant := 1000;
- TABLE : array (1 .. LIMIT) of INTEGER;
- procedure RESTART;
- end STOCK;
-
- ----------------------------
-
- package body STOCK is
- procedure RESTART is
- begin
- for N in 1 .. LIMIT loop
- TABLE(N) := N;
- end loop;
- end;
- begin
- RESTART;
- end STOCK;
-
- ----------------------------
-
- with STOCK;
- procedure PROCESSOR is
-
- SMALL : constant := 20;
- TOTAL : INTEGER := 0;
-
- procedure UPDATE(X ; INTEGER) is
- use STOCK;
- begin
- ...
- TABLE(X) := TABLE(X) + SMALL;
- ...
- end UPDATE;
- begin
- STOCK.RESTART; -- réinitialise TABLE
- end PROCESSOR;
Notez que dans cette dernière version, le paquet STOCK n'a aucune visibilité sur les identifiants externes autres que les identifiants prédéfinis (du paquet STANDARD). En particulier, STOCK n'utilise aucun identifiant déclaré dans PROCESSOR tel que SMALL ou TOTAL ; sinon STOCK n'aurait pas pu être extrait de PROCESSOR de la manière ci-dessus. La procédure PROCESSOR, en revanche, dépend de STOCK et mentionne ce paquet dans une clause with. Cela permet les occurrences internes de STOCK dans le nom étendu STOCK .RESTART et dans la clause use.
Ces trois unités de compilation peuvent être soumises dans une ou plusieurs compilations. Par exemple, il est possible de soumettre la spécification du paquet et le corps du paquet ensemble et dans cet ordre dans une seule compilation.
Sous-unités des unités de compilation
Une sous-unité est utilisée pour la compilation séparée du corps propre d'une unité de programme déclarée dans une autre unité de compilation. Cette méthode de division d'un programme permet un développement de programme hiérarchique :
corps_stub ::= specification_du_sous_programme is separate; | package body nom_simple_du_paquet is separate; | task body tache_simple_nom is separate; sous_unite ::= separate (nom_unite_parent) corps_propre |
Un stub de corps n'est autorisé comme corps d'une unité de programme (un sous-programme, un paquet, une unité de tâche ou une unité générique) que si le stub de corps apparaît immédiatement dans la spécification d'un paquet de bibliothèque ou dans la partie déclarative d'une autre unité de compilation.
Si le corps d'une unité de programme est un stub de corps, une sous-unité compilée séparément contenant le corps approprié correspondant est requise. Dans le cas d'un sous-programme, les spécifications de sous-programme données dans le corps approprié et dans le stub de corps doivent être conformes.
Chaque sous-unité mentionne le nom de son unité parente, c'est-à-dire l'unité de compilation où le stub de corps correspondant est donné. Si l'unité parente est une unité de bibliothèque, elle est appelée unité de bibliothèque ancêtre. Si l'unité parente est elle-même une sous-unité, le nom de l'unité parente doit être donné en entier sous forme de nom développé, en commençant par le nom simple de l'unité de bibliothèque ancêtre. Les noms simples de toutes les sous-unités ayant la même unité de bibliothèque ancêtre doivent être des identifiants distincts.
La visibilité au sein du corps propre d'une sous-unité est la visibilité étant obtenue à la place du corps correspondant (au sein de l'unité parente) si les clauses with et use de la sous-unité étaient ajoutées à la clause context de l'unité parente. Si l'unité parente est elle-même une sous-unité, la même règle est alors utilisée pour définir la visibilité au sein du corps propre de l'unité parente.
L'élaboration d'un corps de référence a pour effet d'élaborer le corps propre de la sous-unité.
Remarques : Deux sous-unités de différentes unités de bibliothèque dans la même bibliothèque de programmes n'ont pas besoin d'avoir des identifiants distincts. Dans tous les cas, leurs noms complets développés sont distincts, car les noms simples des unités de bibliothèque sont distincts et les noms simples de toutes les sous-unités qui ont une unité de bibliothèque donnée comme unité ancêtre sont également distincts. Au moyen de déclarations de renommage, des noms de sous-programmes surchargés qui renomment des sous-unités (distinctes) peuvent être introduits.
Une unité de bibliothèque nommée par la clause with d'une sous-unité peut être masquée par une déclaration (avec le même identifiant) donnée dans le corps propre de la sous-unité. De plus, une telle unité de bibliothèque peut même être masquée par une déclaration donnée dans une unité parente puisqu'une unité de bibliothèque agit comme si elle était déclarée dans STANDARD ; cela n'affecte cependant pas l'interprétation des clauses with elles-mêmes, car seuls les noms des unités de bibliothèque peuvent apparaître dans les clauses with.
Exemples de sous-unités
La procédure TOP est d'abord écrite comme une unité de compilation sans sous-unités :
- with TEXT_IO;
- procedure TOP is
-
- type REAL is digits 10;
- R, S : REAL := 1.0;
-
- package FACILITY is
- PI : constant 3.14159_26536;
- function F (X : REAL) return REAL;
- procedure G (Y, Z : REAL);
- end FACILITY;
-
- package body FACILITY is
- -- quelques déclarations locales suivies de
-
- function F(X : REAL) return REAL is
- begin
- -- séquence d'instructions de F
- end F;
-
- procedure G(Y, Z : REAL) is
- -- procédures locales utilisant TEXT_IO
- ...
- begin
- -- séquence d'instructions de G
- end G;
- end FACILITY;
-
- procedure TRANSFORM(U : in out REAL) is
- use FACILITY;
- begin
- U := F(U);
- ...
- end TRANSFORM;
- begin -- TOP
- TRANSFORM(R);
- ...
- FACILITY.G(R, S);
- end TOP;
Le corps du paquet FACILITY et celui de la procédure TRANSFORM peuvent être transformés en sous-unités séparées de TOP. De même, le corps de la procédure G peut être transformé en sous-unité de FACILITY comme suit.
Exemple 3 :
- procedure TOP is
-
- type REAL is digits 10;
- R, S : REAL := 1.0;
-
- package FACILITY is
- PI : constant := 3.14159_26536;
- function F (X : REAL) return REAL;
- procedure G (Y, Z : REAL);
- end FACILITY;
-
- package body FACILITY is separate; -- bout de FACILITY
- procedure TRANSFORMS(U : in out REAL) is separate; -- bout de TRANSFORM
-
- begin -- TOP
- TRANSFORM(R);
- ...
- FACILITY.G(R, S);
- end TOP;
- ---------------------------
-
- separate (TOP)
- procedure TRANSFORM(U : in out REAL) is
- use FACILITY;
- begin
- U := F(U);
- ...
- end TRANSFORM;
-
- ---------------------------
-
- separate (TOP)
- package body FACILITY is
- -- quelques déclarations locales suivies de
-
- function F(X : REAL) return REAL is
- begin
- -- séquence d'instructions de F
- end F;
-
- procedure G(Y, Z : REAL) is separate; -- bout de G
- end FACILITY;
-
- ---------------------------
-
- with TEXT_IO;
- separate (TOP.FACILITY) - full name of FACILITY
- procedure G(Y, Z : REAL) is
- -- procédures locales utilisant TEXT_IO
- ...
- begin
- -- séquence d'instructions de G
- ...
- end G;
Dans l'exemple ci-dessus, TRANSFORM et FACILITY sont des sous-unités de TOP, et G est une sous-unité de FACILITY. La visibilité dans la version divisée est la même que dans la version initiale, à l'exception d'un changement : comme TEXT_IO n'est utilisé que dans G, la clause with correspondante est écrite pour G au lieu de TOP. Hormis ce changement, les mêmes identifiants sont visibles aux points de programme correspondants dans les deux versions. Par exemple, tous les éléments suivants sont (directement) visibles dans le corps propre de la sous-unité G : la procédure TOP, le type REAL, les variables R et S, le paquet FACILITY et le numéro nommé PI contenu et les sous-programmes F et G.
Ordre de compilation
Les règles définissant l'ordre dans lequel les unités peuvent être compilées sont des conséquences directes des règles de visibilité et, en particulier, du fait que toute unité de bibliothèque mentionnée par la clause de contexte d'une unité de compilation est visible dans l'unité de compilation.
Une unité de compilation doit être compilée après toutes les unités de bibliothèque nommées par sa clause de contexte. Une unité secondaire étant un sous-programme ou un corps de paquet doit être compilée après l'unité de bibliothèque correspondante. Toute sous-unité d'une unité de compilation parent doit être compilée après l'unité de compilation parent. Si une erreur est détectée lors de la tentative de compilation d'une unité de compilation, la tentative de compilation est rejetée et n'a aucun effet sur la bibliothèque du programme ; il en va de même pour les recompilations (aucune unité de compilation ne peut devenir obsolète à cause d'une telle recompilation).
L'ordre dans lequel les unités de compilation d'un programme sont compilées doit être cohérent avec l'ordre partiel défini par les règles ci-dessus.
Des règles similaires s'appliquent aux recompilations. Une unité de compilation est potentiellement affectée par un changement dans toute unité de bibliothèque nommée par sa clause de contexte. Une unité secondaire est potentiellement affectée par un changement dans l'unité de bibliothèque correspondante. Les sous-unités d'une unité de compilation parent sont potentiellement affectées par un changement de l'unité de compilation parent. Si une unité de compilation est recompilée avec succès, les unités de compilation potentiellement affectées par ce changement sont obsolètes et doivent être recompilées à moins qu'elles ne soient plus nécessaires. Une implémentation peut être en mesure de réduire les coûts de compilation si elle peut déduire que certaines des unités potentiellement affectées ne sont pas réellement affectées par le changement.
Les sous-unités d'une unité peuvent être recompilées sans affecter l'unité elle-même. De même, les modifications apportées à un sous-programme ou au corps d'un paquet n'affectent pas les autres unités de compilation (à l'exception des sous-unités du corps) puisque ces unités de compilation n'ont accès qu'au sous-programme ou à la spécification du paquet. Une implémentation n'est autorisée à déroger à cette règle que pour les inclusions en ligne, pour certaines optimisations du compilateur et pour certaines implémentations d'unités de programme génériques, comme décrit ci-dessous.
- Si un pragma INLINE est appliqué à une déclaration de sous-programme donnée dans une spécification de paquet, l'inclusion en ligne ne sera réalisée que si le corps du paquet est compilé avant les unités appelant le sous-programme. Dans un tel cas, l'inclusion en ligne crée une dépendance de l'unité appelante sur le corps du paquet, et le compilateur doit reconnaître cette dépendance lorsqu'il décide de la nécessité d'une recompilation. Si une unité appelante est compilée avant le corps du paquet, le pragma peut être ignoré par le compilateur pour de tels appels (un avertissement indiquant que l'inclusion en ligne n'a pas été réalisée peut être émis). Des considérations similaires s'appliquent à un sous-programme compilé séparément pour lequel un pragma INLINE est spécifié.
- À des fins d'optimisation, une implémentation peut compiler plusieurs unités d'une compilation donnée de manière à créer des dépendances supplémentaires entre ces unités de compilation. Le compilateur doit alors prendre en compte ces dépendances lorsqu'il décide de la nécessité de recompilations.
- Une implémentation peut exiger qu'une déclaration générique et le corps approprié correspondant fassent partie de la même compilation, que l'unité générique soit elle-même compilée séparément ou qu'elle soit locale à une autre unité de compilation. Une implémentation peut également exiger que les sous-unités d'une unité générique fassent partie de la même compilation.
Exemples d'ordre de compilation :
- Dans l'exemple 1 : la procédure QUADRATIC_EQUATION doit être compilée après les paquetages de bibliothèque TEXT_IO et REAL_OPERATIONS puisqu'ils apparaissent dans sa clause with.
- Dans l'exemple 2 : le corps du paquetage STOCK doit être compilé après la spécification du paquetage correspondant.
- Dans l'exemple 2 : la spécification du paquet STOCK doit être compilée avant la procédure PROCESSOR. D'autre part, la procédure PROCESSOR peut être compilée avant ou après le corps du paquet STOCK.
- Dans l'exemple 3 : la procédure G doit être compilée après le paquet TEXT_IO puisque ce paquet est nommé par la clause with de G. D'autre part, TEXT_IO peut être compilé avant ou après TOP.
- Dans l'exemple 3 : les sous-unités TRANSFORM et FACILITY doivent être compilées après le programme principal TOP. De même, la sous-unité G doit être compilée après son unité parente FACILITY.
Remarques : Pour les paquets de bibliothèque, il résulte des règles de recompilation qu'un corps de paquet est rendu obsolète par la recompilation de la spécification correspondante. Si la nouvelle spécification de paquet est telle qu'un corps de paquet n'est pas nécessaire (c'est-à-dire si la spécification de paquet ne contient pas la déclaration d'une unité de programme), alors la recompilation d'un corps pour ce paquet n'est pas nécessaire. Dans tous les cas, le corps de paquet obsolète ne doit pas être utilisé et peut donc être supprimé de la bibliothèque de programmes.
La bibliothèque de programmes
Les compilateurs doivent appliquer les règles du langage de la même manière pour un programme constitué de plusieurs unités de compilation (et sous-unités) que pour un programme soumis sous forme de compilation unique. Par conséquent, un fichier de bibliothèque contenant des informations sur les unités de compilation de la bibliothèque de programmes doit être maintenu par le compilateur ou l'environnement de compilation. Ces informations peuvent inclure des tables de symboles et d'autres informations relatives à l'ordre des compilations précédentes.
Une soumission normale au compilateur comprend les unités de compilation et le fichier de bibliothèque. Ce dernier est utilisé pour les contrôles et est mis à jour pour chaque unité de compilation compilée avec succès.
Remarques : une seule bibliothèque de programmes est implicite pour les unités de compilation d'une compilation. L'existence possible de différentes bibliothèques de programmes et les moyens par lesquels elles sont nommées ne sont pas des préoccupations de la définition du langage ; elles sont des préoccupations de l'environnement de programmation.
Il devrait y avoir des commandes pour créer la bibliothèque de programmes d'un programme donné ou d'une famille de programmes donnée. Ces commandes peuvent permettre la réutilisation d'unités d'autres bibliothèques de programmes. Enfin, il devrait y avoir des commandes pour interroger l'état des unités d'une bibliothèque de programmes. La forme de ces commandes n'est pas spécifiée par la définition du langage.
Élaboration des unités de bibliothèque
Avant l'exécution d'un programme principal, toutes les unités de bibliothèque nécessaires au programme principal sont élaborées, ainsi que les corps d'unités de bibliothèque correspondants, s'il y en a. Les unités de bibliothèque nécessaires au programme principal sont : celles nommées par des clauses with applicables au programme principal, à son corps et à ses sous-unités; celles nommées par des clauses with applicables à ces unités de bibliothèque elles-mêmes, aux corps d'unités de bibliothèque correspondants et à leurs sous-unités ; et ainsi de suite, de manière transitive. L'élaboration de ces unités de bibliothèque et des corps d'unités de bibliothèque correspondants est effectuée dans un ordre cohérent avec l'ordre partiel défini par les clauses with. De plus, une unité de bibliothèque mentionnée par la clause de contexte d'une sous-unité doit être élaborée avant le corps de l'unité de bibliothèque ancêtre de la sous-unité.
Un ordre d'élaboration cohérent avec cet ordre partiel ne garantit pas toujours que chaque corps d'unité de bibliothèque soit élaboré avant toute autre unité de compilation dont l'élaboration nécessite que le corps d'unité de bibliothèque soit déjà élaboré. Si l'élaboration préalable des corps d'unités de bibliothèque est nécessaire, cela peut être demandé par un pragma ELABORATE. La forme de ce pragma est la suivante :
pragma ELABORATE (nom_simple_de_l_unité_de_bibliotheque |, nom_simple_de_l_unité_de_bibliotheque}); |
Ces pragmes ne sont autorisés qu'immédiatement après la clause de contexte d'une unité de compilation (avant l'unité de bibliothèque suivante ou l'unité secondaire). Chaque argument d'un tel pragma doit être le nom simple d'une unité de bibliothèque mentionnée par la clause de contexte, et cette unité de bibliothèque doit avoir un corps d'unité de bibliothèque. Un tel pragma spécifie que le corps de l'unité de bibliothèque doit être élaboré avant l'unité de compilation donnée. Si l'unité de compilation donnée est une sous-unité, le corps de l'unité de bibliothèque doit être élaboré avant le corps de l'unité de bibliothèque ancêtre de la sous-unité.
Le programme est illégal si aucun ordre cohérent ne peut être trouvé (c'est-à-dire si une circularité existe). L'élaboration des unités de compilation du programme est effectuée dans un ordre n'étant pas défini par ailleurs par le langage.
Optimisation du programme
L'optimisation de l'élaboration des déclarations et de l'exécution des instructions peut être effectuée par les compilateurs. En particulier, un compilateur peut être capable d'optimiser un programme en évaluant certaines expressions, en plus de celles qui sont des expressions statiques. Si l'une de ces expressions, statique ou non, est telle qu'une exception serait levée par son évaluation, alors le code dans ce chemin du programme peut être remplacé par du code pour lever l'exception ; il en va de même pour les exceptions levées par l'évaluation des noms et des expressions simples.
Un compilateur peut constater que certaines instructions ou sous-programmes ne seront jamais exécutés, par exemple, si leur exécution dépend d'une condition connue pour être FALSE. Le code machine objet correspondant peut alors être omis. Cette règle permet l'effet de compilation conditionnelle au sein du langage.
Remarque : une expression dont l'évaluation est connue pour lever une exception ne doit pas nécessairement représenter une erreur si elle se produit dans une instruction ou un sous-programme n'étant jamais exécuté. Le compilateur peut avertir le programmeur d'une erreur potentielle.