Les instructions
Une instruction définit une action à effectuer; le processus par lequel une instruction accomplit son action est appelé exécution de l'instruction.
Cette page décrit les règles générales applicables à toutes les instructions. Certaines instructions spécifiques sont abordées dans les pages suivants. Les autres formes d'instructions sont présentées dans cette page.
Énoncés simples et composés - Séquences d'énoncés
Un énoncé est soit simple, soit composé. Un énoncé simple n'englobe aucun autre énoncé. Un énoncé composé peut englober des énoncés simples et d'autres énoncés composés.
séquence_d_instructions ::= instruction (instruction) instruction ::= [etiquette] instruction_simple | [etiquette] instruction_composee instruction_simple ::= instruction_nulle | instruction_d_affectation | instruction_d_appel_de_procédure | instruction_exit | instruction_return | instruction_goto | instruction_d_appel_d_entree | instruction_delay | instruction_d_abandon | instruction_raise | instruction_code instruction_composee ::= instruction_if | instruction_de_cas | instruction_boucle | instruction_de_bloc | instruiction_accept | instruction_de_select etiquette ::= <<label_simple_name>> instruction_nulle ::= null; |
On dit qu'une instruction est étiquetée par le nom d'étiquette de n'importe quelle étiquette de l'instruction. Un nom d'étiquette, et de même un nom de boucle ou de bloc, est implicitement déclaré à la fin de la partie déclarative de l'instruction de bloc la plus interne, du corps du sous-programme, du corps du paquet, du corps de la tâche ou du corps générique entourant l'instruction étiquetée, l'instruction de boucle nommée ou l'instruction de bloc nommée, selon le cas. Pour une instruction de bloc sans partie déclarative, une partie déclarative implicite (et une instruction la précédant) est supposée.
Les déclarations implicites pour les différents noms d'étiquettes, noms de boucles et noms de blocs apparaissent dans le même ordre que les débuts des instructions étiquetées, instructions de boucle et instructions de bloc correspondantes. Des identifiants distincts doivent être utilisés pour tous les noms d'étiquettes, de boucles et de blocs étant implicitement déclarés dans le corps d'une unité de programme, y compris dans les instructions de bloc incluses dans ce corps, mais excluant les autres unités de programme incluses (une unité de programme est soit un sous-programme, un paquet, une unité de tâche ou une unité générique).
L'exécution d'une instruction null n'a d'autre effet que de passer à l'action suivante. L'exécution d'une séquence d'instructions consiste en l'exécution successive des instructions individuelles jusqu'à ce que la séquence soit terminée ou qu'un transfert de contrôle ait lieu. Un transfert de contrôle est provoqué soit par l'exécution d'une instruction exit, return ou goto ; par la sélection d'une alternative terminate ; par la levée d'une exception ; ou (indirectement) par l'exécution d'une instruction abort.
Exemples d'instructions étiquetées&nbps;:
- <<HERE>> <<ICI>> <<AQUI>> <<HIER>> null;
- <<AFTER>> X := 1;
Remarque : La portée d'une déclaration commence à l'endroit de la déclaration elle-même. Dans le cas d'un nom d'étiquette, de boucle ou de bloc, il résulte de cette règle que la portée de la déclaration implicite commence avant la première occurrence explicite du nom correspondant, puisque cette occurrence se trouve soit dans une étiquette d'instruction, une instruction de boucle, une instruction de bloc ou une instruction goto. Une déclaration implicite dans une instruction de bloc peut masquer une déclaration donnée dans une unité de programme externe ou une instruction de bloc (conformément aux règles habituelles de masquage).
Instruction d'affectation
Une instruction d'affectation remplace la valeur actuelle d'une variable par une nouvelle valeur spécifiée par une expression. La variable nommée et l'expression de droite doivent être du même type; ce type ne doit pas être un type limité.
instruction_d_affectation ::= nom_variable := expression; |
Pour l'exécution d'une instruction d'affectation, le nom de la variable et l'expression sont d'abord évalués, dans un ordre n'étant pas défini par le langage de programmation. On vérifie ensuite que la valeur de l'expression appartient au sous-type de la variable, sauf dans le cas d'une variable étant un tableau (l'affectation implique alors une conversion de sous-type). Enfin, la valeur de l'expression devient la nouvelle valeur de la variable.
L'exception CONSTRAINT_ERROR est générée si la vérification du sous-type mentionnée ci-dessus échoue; dans ce cas, la valeur actuelle de la variable reste inchangée. Si la variable est une sous-composante dépendant des discriminants d'une variable d'enregistrement non contrainte, l'exécution de l'affectation est erronée si la valeur de l'un de ces discriminants est modifiée par cette exécution.
Exemples :
- VALUE := MAX_VALUE - 1;
- SHADE := BLUE;
-
- NEXT_FRAME(F)(M, N) := 2.5;
- U := DOT_PRODUCT(V, W);
-
- WRITER := (STATUS => OPEN, UNIT => PRINTER, LINE_COUNT => 60);
- NEXT_CAR.all := (72074, null);
Exemples de contrôles de contraintes :
Remarques : Les valeurs des discriminants d'un objet désigné par une valeur d'accès ne peuvent pas être modifiées (même pas en attribuant une valeur complète à l'objet lui-même) puisque de tels objets, créés par des allocateurs, sont toujours contraints; cependant, les sous-composantes de tels objets peuvent ne pas être contraints. Si l'expression du côté droit est soit un littéral numérique, soit un nombre nommé, soit un attribut produisant un résultat de type universal_integer ou universal_real, alors une conversion de type implicite est effectuée.
La détermination du type de la variable d'une instruction d'affectation peut nécessiter la prise en compte de l'expression si le nom de la variable peut être interprété comme le nom d'une variable désignée par la valeur d'accès renvoyée par un appel de fonction, et de même, comme une composante ou une tranche d'une telle variable.
Affectations de tableau
Si la variable d'une instruction d'affectation est une variable de tableau (y compris une variable de tranche), la valeur de l'expression est implicitement convertie en sous-type de la variable de tableau; le résultat de cette conversion de sous-type devient la nouvelle valeur de la variable de tableau.
Cela signifie que la nouvelle valeur de chaque composante de la variable de tableau est spécifiée par le composant correspondant dans la valeur de tableau obtenue par l'évaluation de l'expression. La conversion de sous-type vérifie que pour chaque composant de la variable de tableau, il existe une composante correspondant dans la valeur de tableau, et vice versa. L'exception CONSTRAINT_ERROR est levée si cette vérification échoue ; dans un tel cas, la valeur de chaque composant de la variable de tableau reste inchangée.
Exemples :
Remarques : l'affectation de tableau est définie même dans le cas de tranches superposées, car l'expression du côté droit est évaluée avant d'effectuer toute affectation de composant. Dans l'exemple ci-dessus, une implémentation produisant A(1 .. 12) = "tartartartar" serait incorrecte.
La conversion de sous-type implicite décrite ci-dessus pour l'affectation à une variable de tableau est effectuée uniquement pour la valeur de l'expression du côté droit dans son ensemble ; elle n'est pas effectuée pour les sous-composantes étant des valeurs de tableau.
Instructions If
Une instruction if sélectionne pour exécution une ou aucune des séquences d'instructions incluses, en fonction de la valeur (vraie) d'une ou plusieurs conditions correspondantes :
instruction_if ::= if condition then sequence_d_instructions | elsif condition then sequence_d_instructions| | else sequence_d_instructions] end if; condition ::= expression_booleenne |
Une expression spécifiant une condition doit être de type booléen.
Pour l'exécution d'une instruction if, la condition spécifiée après if et toutes les conditions spécifiées après elsif sont évaluées successivement (en traitant un else final comme elsif TRUE then), jusqu'à ce que l'une d'elles soit évaluée à TRUE ou que toutes les conditions soient évaluées et donnent FALSE. Si une condition est évaluée à TRUE, alors la séquence d'instructions correspondante est exécutée; sinon, aucune des séquences d'instructions n'est exécutée.
Exemples :
Instructions case
Une instruction case sélectionne pour exécution l'une des nombreuses séquences alternatives d'instructions; l'alternative choisie est définie par la valeur d'une expression :
instruction_case ::= case expression is instruction_case_alternative | instruction_case_alternative] end case; instruction_case_alternative ::= when choix (| choix ( => sequence_d_instructions |
L'expression doit être d'un type discret devant pouvoir être déterminé indépendamment du contexte dans lequel l'expression apparaît, mais en utilisant le fait que l'expression doit être d'un type discret. De plus, le type de cette expression ne doit pas être un type formel générique. Chaque choix dans une alternative d'instruction case doit être du même type que l'expression ; la liste de choix spécifie pour quelles valeurs de l'expression l'alternative est choisie.
Si l'expression est le nom d'un objet dont le sous-type est static, alors chaque valeur de ce sous-type doit être représentée une et une seule fois dans l'ensemble des choix de l'instruction case, et aucune autre valeur n'est autorisée ; cette règle s'applique également si l'expression est une expression qualifiée ou une conversion de type dont la marque de type désigne un sous-type static. Sinon, pour d'autres formes d'expression, chaque valeur du type (de base) de l'expression doit être représentée une et une seule fois dans l'ensemble des choix, et aucune autre valeur n'est autorisée.
Les expressions simples et les intervalles discrets données comme choix dans une instruction case doivent être statiques. Un choix défini par un intervalle discret représente toutes les valeurs de l'intervalle correspondante (aucune si l'intervalle est nulle). Le choix autres n'est autorisé que pour la dernière alternative et comme seul choix; il représente toutes les valeurs (éventuellement aucune) non données dans les choix des alternatives précédentes. Un nom simple de composante n'est pas autorisé comme choix d'alternative d'instruction case.
L'exécution d'une instruction case consiste en l'évaluation de l'expression suivie de l'exécution de la séquence d'instructions choisie.
Exemples :
- case SENSOR is
- when ELEVATION => RECORD_ELEVATION (SENSOR_VALUE);
- when AZIMUTH => RECORD_AZIMUTH (SENSOR_VALUE);
- when DISTANCE => RECORD_DISTANCE (SENSOR_VALUE);
- when others => null;
- end case;
-
- case TODAY is
- when MON => COMPUTE_INITIAL_BALANCE;
- when FRI => COMPUTE_CLOSING_BALANCE;
- when TUE .. THU => GENERATE_REPORT(TODAY);
- when SAT .. SUN => null;
- end case;
-
- case BIN_NUMBER(CQUNT) is
- when 1 => UPDATE_BIN(1);
- when 2 => UPDATE_.BIN(2);
- when 3 | 4 =>
- EMPTY_BIN(1);
- EMPTY_BIN(2);
- when others => raise ERROR;
- end case
Remarques : L'exécution d'une instruction case choisit une et une seule alternative, car les choix sont exhaustifs et mutuellement exclusifs. La qualification de l'expression d'une instruction case par un sous-type statique peut souvent être utilisée pour limiter le nombre de choix devant être donnés explicitement.
Un autre choix est requis dans une instruction case si le type de l'expression est le type universal_integer (par exemple, si l'expression est un littéral entier), car c'est la seule façon de couvrir toutes les valeurs du type universal_integer.
L'instruction Loop
Une instruction de boucle comprend une séquence d'instructions devant être exécutée de manière répétée, zéro ou plusieurs fois :
instruction_boucle ::= [boucle_simple_nom:] [ schema_d_iteration] loop sequence_d_instructions end loop [boucle_simple_nom]; schema_d_iteration ::= while condition | for specification_des_parametres_de_boucle specification_des_parametres_de_boucle ::= identifiant in [reverse] intervalle_discret |
Si une instruction de boucle possède un nom simple de boucle, ce nom simple doit être donné au début et à la fin.
Une instruction de boucle sans schéma d'itération spécifie l'exécution répétée de la séquence d'instructions. L'exécution de l'instruction de boucle est terminée lorsque la boucle est quittée suite à l'exécution d'une instruction de sortie ou suite à un autre transfert de contrôle. Pour une instruction de boucle avec un schéma d'itération while, la condition est évaluée avant chaque exécution de la séquence d'instructions; si la valeur de la condition est TRUE, la séquence d'instructions est exécutée, si FALSE l'exécution de l'instruction de boucle est terminée.
Pour une instruction de boucle avec un schéma d'itération for, la spécification du paramètre de boucle est la déclaration du paramètre de boucle avec l'identifiant donné. Le paramètre de boucle est un objet dont le type est le type de base de l'intervalle discret. Dans la séquence d'instructions, le paramètre de boucle est une constante. Par conséquent, un paramètre de boucle n'est pas autorisé comme variable (côté gauche) d'une instruction d'affectation. De même, le paramètre de boucle ne doit pas être donné comme paramètre out ou in out d'une instruction d'appel de procédure ou d'entrée, ou comme paramètre in out d'une instanciation générique.
Pour l'exécution d'une instruction de boucle avec un schéma d'itération for, la spécification du paramètre de boucle est d'abord élaborée. Cette élaboration crée le paramètre de boucle et évalue l'intervalle discret. Si l'intervalle discret est un intervalle nulle, l'exécution de l'instruction de boucle est terminée. Sinon, la séquence d'instructions est exécutée une fois pour chaque valeur de l'intervalle discret (à condition que la boucle ne soit pas quittée à la suite de l'exécution d'une instruction exit ou à la suite d'un autre transfert de contrôle). Avant chaque itération de ce type, la valeur correspondante de la plage discrète est affectée au paramètre de boucle. Ces valeurs sont affectées par ordre croissant, sauf si le mot réservé reverse est présent, auquel cas les valeurs sont affectées par ordre décroissant.
Exemple d'instruction de boucle sans schéma d'itération :
- loop
- GET(CURRENT_CHARACTER);
- exit when CURRENT_CHARACTER = '*';
- end loop;
Exemple d'une instruction de boucle avec un schéma d'itération while :
Exemple d'une instruction de boucle avec un schéma d'itération for :
Exemple d'une instruction de boucle avec un nom de boucle simple :
Remarques : La portée d'un paramètre de boucle s'étend de la spécification du paramètre de boucle jusqu'à la fin de l'instruction de boucle, et les règles de visibilité sont telles qu'un paramètre de boucle n'est visible que dans la séquence d'instructions de la boucle.
L'intervalle discret d'une boucle for n'est évaluée qu'une seule fois. L'utilisation du mot réservé reverse ne modifie pas l'intervalle discrète, de sorte que les schémas d'itération suivants ne sont pas équivalents; le premier a un intervalle nulle :
Les noms de boucle sont également utilisés dans les instructions de sortie et dans les noms développés (dans un préfixe du paramètre de boucle).
Instructions de bloc
Une instruction de bloc renferme une séquence d'instructions éventuellement précédée d'une partie déclarative et éventuellement suivie de gestionnaires d'exceptions :
instruction_bloc ::= [bloc_simple_nom:] [ declare partie_declarative] begin sequence_d_instructions [ exception gestionnaire_d_exceptions [ gestionnaire_d_exceptions|] end [bloc_simple_nom] |
Si une instruction de bloc a un nom simple de bloc, ce nom simple doit être donné au début et à la fin.
L'exécution d'une instruction de bloc consiste en l'élaboration de sa partie déclarative (le cas échéant) suivie de l'exécution de la séquence d'instructions. Si l'instruction de bloc a des gestionnaires d'exceptions, ceux-ci gèrent les exceptions correspondantes étant levées pendant l'exécution de la séquence d'instructions.
Exemple :
Remarques : Si des objets de tâche sont déclarés dans une instruction de bloc dont l'exécution est terminée, l'instruction de bloc n'est pas abandonnée tant que toutes les tâches en dépendant ne sont pas terminées. Cette règle s'applique également à une complétion provoquée par une instruction exit, return ou goto ; ou par la levée d'une exception.
Dans une instruction de bloc, le nom du bloc peut être utilisé dans des noms développés désignant des entités locales telles que SWAP.TEMP dans l'exemple ci-dessus.
L'instruction Exit
Une instruction de sortie est utilisée pour terminer l'exécution d'une instruction de boucle englobante (appelée boucle dans ce qui suit); l'achèvement est conditionnel si l'instruction de sortie inclut une condition :
instruction_exit ::= exit [nom_boucle] [when condition]; |
Une instruction de sortie avec un nom de boucle n'est autorisée que dans la boucle nommée et s'applique à cette boucle; une instruction de sortie sans nom de boucle n'est autorisée que dans une boucle et s'applique à la boucle la plus interne (qu'elle soit nommée ou non). De plus, une instruction de sortie s'appliquant à une boucle donnée ne doit pas apparaître dans un corps de sous-programme, un corps de paquet, un corps de tâche, un corps générique ou une instruction d'acceptation, si cette construction est elle-même entourée par la boucle donnée.
Pour l'exécution d'une instruction de sortie, la condition, si elle est présente, est d'abord évaluée. La sortie de la boucle a alors lieu si la valeur est TRUE ou s'il n'y a pas de condition.
Exemples :
Remarque : plusieurs boucles imbriquées peuvent être quittées par une instruction de sortie nommant la boucle externe.
L'instruction return
Une instruction de retour est utilisée pour terminer l'exécution de la fonction, de la procédure ou de l'instruction d'acceptation la plus interne :
instruction_return ::= return [expression] |
Une instruction return n'est autorisée que dans le corps d'un sous-programme ou d'un sous-programme générique, ou dans une instruction accept, et s'applique à la construction la plus interne (englobante) de ce type; une instruction return n'est pas autorisée dans le corps d'une unité de tâche, d'un paquet ou d'un paquet générique entouré par cette construction (en revanche, elle est autorisée dans une instruction composée entourée par cette construction et, en particulier, dans une instruction de bloc).
Une instruction de retour pour une instruction accept ou pour le corps d'une procédure ou d'une procédure générique ne doit pas contenir d'expression. Une instruction de retour pour le corps d'une fonction ou d'une fonction générique doit contenir une expression.
La valeur de l'expression définit le résultat renvoyé par la fonction. Le type de cette expression doit être le type de base de la marque de type donnée après le mot réservé return dans la spécification de la fonction ou de la fonction générique (cette marque de type définit le sous-type de résultat).
Pour l'exécution d'une instruction return, l'expression (le cas échéant) est d'abord évaluée et une vérification est effectuée pour savoir si la valeur appartient au sous-type de résultat. L'exécution de l'instruction de retour est ainsi terminée si la vérification réussit ; il en va de même pour l'exécution du sous-programme ou de l'instruction accept. L'exception CONSTRAINT_ERROR est levée à la place de l'instruction de retour si la vérification échoue.
Exemples :
Remarque : si l'expression est un littéral numérique ou un nombre nommé, ou un attribut qui génère un résultat de type universal_integer ou universal_real, une conversion implicite du résultat est effectuée.
L'instruction Goto
Une instruction goto spécifie un transfert explicite du contrôle de cette instruction vers une instruction cible nommée par une étiquette :
instruction_goto ::= goto nom_etiquette |
La séquence d'instructions la plus interne entourant l'instruction cible doit également entourer l'instruction goto (notez que l'instruction goto peut être une instruction d'une séquence interne). De plus, si une instruction goto est entourée par une instruction accept ou le corps d'une unité de programme, alors l'instruction cible ne doit pas être en dehors de cette construction englobante; à l'inverse, il résulte de la règle précédente que si l'instruction cible est entourée par une telle construction, alors l'instruction goto ne peut pas être en dehors.
L'exécution d'une instruction goto transfère le contrôle à l'instruction cible nommée.
Remarque : les règles ci-dessus autorisent le transfert de contrôle vers une instruction d'une séquence d'instructions englobante, mais pas l'inverse. De même, elles interdisent les transferts de contrôle entre les alternatives d'une instruction case, if ou select, entre les gestionnaires d'exceptions ou depuis un gestionnaire d'exceptions d'une trame vers la séquence d'instructions de cette trame.
Exemple :