Section courante

A propos

Section administrative du site

 Langage  Elément  Tutoriel  Programmation  IDE  Annexe  Aide 
ABAP/4
Ada
Assembleur
Assembly & bytecode
ASP (Active Server Pages)
Basic
C
C++
C# (C Sharp)
Cobol
ColdFusion
Fortran
HTML
Java
JavaScript
LISP
Logo
LotusScript
Oberon
Pascal
Perl
PHP
PL/1
Prolog
Python
Rebol
REXX
Ruby
Rust
SAS
NoSQL
SQL
Swift
X++ (Axapta)
GNAT
SMALLAda
VHDL
Assembleur 370
Assembleur 1802
Assembleur 4004
Assembleur 6502
Assembleur 6800
Assembleur 68000
Assembleur 8080 et 8085
Assembleur 8089
Assembleur 80x86
Assembleur AGC4
Assembleur ARM
Assembleur DPS 8000
Assembleur i860
Assembleur Itanium
Assembleur MIPS
Assembleur PDP-11
Assembleur PowerPC
Assembleur RISC-V
Assembleur SPARC
Assembleur SuperH
Assembleur UNIVAC I
Assembleur VAX
Assembleur Z80
Assembleur Z8000
Assembleur z/Architecture
ASSEMBLER/MONITOR 64
Micol Assembler
GFA Assembler
A86
MASM (Macro Assembler)
TASM (Turbo Assembler)
CIL
Jasmin
LLVM
MSIL
Parrot
P-Code (PCode)
SWEET16
G-Pascal
ASP 1.0
ASP 2.0
ASP 3.0
ASP.NET
ASP.NET Core
ABasiC (Amiga)
Adam SmartBASIC
Altair BASIC
AmigaBASIC (Amiga)
AMOS Basic (Amiga)
Atari Basic (Atari 400, 600 XL, 800, 800XL)
Basic Apple II (Integer BASIC/APPLESOFT)
Basic Commodore 64 (CBM-BASIC)
Basic Commodore 128 (BASIC 7.0)
Basic Commodore VIC-20 (CBM-BASIC 2.0)
Basic Coco 1 (Color Basic)
Basic Coco 2 (Extended Color Basic)
Basic Coco 3 (Extended Color Basic 2.0)
BASICA (PC DOS)
Basic Pro
BBC BASIC
Blitz BASIC (Amiga)
DarkBASIC
Dartmouth BASIC
GFA-Basic (Atari ST/Amiga)
GWBASIC (MS-DOS)
Liberty BASIC
Locomotive BASIC (Amstrad CPC)
MSX-Basic
Omikron Basic (Atari ST)
Oric Extended Basic
Power Basic
Quick Basic/QBasic (MS-DOS)
Sinclair BASIC (ZX80, ZX81, ZX Spectrum)
ST BASIC (Atari ST)
Turbo Basic
Vintage BASIC
VBScript
Visual Basic (VB)
Visual Basic .NET (VB .NET)
Visual Basic pour DOS
Yabasic
BeckerBASIC
SIMONS' BASIC
Basic09 d'OS-9
Disk Extended Color Basic
Basic09 d'OS-9
Disk Extended Color Basic
Access
Excel
Visual Basic pour Windows
Visual Basic .NET pour Windows
C Shell Unix (csh)
C pour Amiga
C pour Atari ST
C pour DOS
C pour Falcon030
C pour GEMDOS (Atari ST)
C pour Linux
C pour PowerTV OS
C pour OS/2
C pour Unix
C pour Windows
Aztec C
CoCo-C
GNU C
HiSoft C
IBM C/2
Introl-C
Lattice C
Microsoft C
MinGW C
MSX-C
Open Watcom C
OS-9 C Compiler
Pure C
Quick C
Turbo C
HiSoft C for Atari ST
HiSoft C for CP/M (Amstrad CPC)
C++ pour OS/2
C++ pour Windows
Borland C++
C++Builder
IBM VisualAge C++
Intel C++
MinGW C++
Open Watcom C++
Symantec C++
Turbo C++
Visual C++
Visual C++ .NET
Watcom C++
Zortech C++
C# (C Sharp) pour Windows
Apple III Cobol
Microsoft Cobol
BlueDragon
Lucee
OpenBD
Railo
Smith Project
Microsoft Fortran
WATFOR-77
CSS
FBML
Open Graph
SVG
XML
XSL/XSLT
LESS
SASS
GCJ (GNU)
JSP
Jython
Visual J++
Node.js
TypeScript
AutoLISP
ACSLogo
LotusScript pour Windows
Amiga Oberon
Oberon .NET
Apple Pascal
Delphi/Kylix/Lazarus
Free Pascal
GNU Pascal
HighSpeed Pascal
IBM Personal Computer Pascal
Lisa Pascal
Maxon Pascal
MPW Pascal
OS-9 Pascal
OSS Personal Pascal
Pascal-86
Pascal du Cray Research
Pascal/VS
Pascal-XT
PURE Pascal
QuickPascal
RemObjets Chrome
Sun Pascal
THINK Pascal
Tiny Pascal (TRS-80)
Turbo Pascal
UCSD Pascal
VAX Pascal
Virtual Pascal
Turbo Pascal for CP/M-80
Turbo Pascal for DOS
Turbo Pascal for Macintosh
Turbo Pascal for Windows
CodeIgniter (Cadre d'application)
Drupal (Projet)
Joomla! (Projet)
Phalanger (PHP .NET)
phpBB (Projet)
Smarty (balise)
Twig (balise)
Symfony (Cadre d'application)
WordPress (Projet)
Zend (Cadre d'application)
PL360
PL/M-80
PL/M-86
Turbo Prolog
CPython
IronPython
Jython
PyPy
AREXX
Regina REXX
JMP
Btrieve
Cassandra
Clipper
CouchDB
dBASE
Hbase
Hypertable
MongoDB
Redis
Access
BigQuery
DB2
H2
Interbase
MySQL
Oracle
PostgreSQL
SAP HANA
SQL Server
Sybase
U-SQL
Introduction
Les remarques
Les opérateurs
Les instruction conditionnelles
Les instructions de boucles
Type de données
Définition de fonction
Référence de mots réservés (mots clefs)
Référence de procédures et fonctions
Les modules (Packages)
Les premiers pas
Les éléments lexicaux
Les déclarations et types
Les noms et les expressions
Les instructions
Les sous-programmes
Les paquets
Les règles de visibilité
Les tâches
Structure du programme et problèmes de compilation
Les exceptions
Les unités génériques
Clauses de représentation et fonctionnalités dépendantes de la mise en oeuvre
Les entrées-sorties
Bonjour
Biochimie
Géographie
Géométrie
Histoire
Mathématique
Médicale
Météorologie
Océanographie
Sport
Temps
Trigonométrie
Validation
Calcul du calcium corrigé
Distance en Km entre deux longitudes et latitudes
Aire d'un cercle
Aire d'une surface de prisme rectangulaire
Aire d'un triangle
Distance entre deux points
Chiffre romain
Ackermann
Exp
Factoriel
Fibonacci
Log
Nombre premier
Odd
Random
Sqrt
Triangle Pascal
Hauteur utérine
Unité de mesure
Fréquence des vagues
Hockey
Année bissextile
Date de la Pâque
Atn/ATan/ArcTan
Courriel
AdaGIDE
GNAT Programming Studio
SET's Editor
Attributs de langages prédéfinis
Les pragma de langage prédéfinis
Environnement de langage prédéfini
Référence de termes et du vocabulaire
Téléchargement
Préface
Notes légal
Dictionnaire
Recherche

Les exceptions

Cette page définit les fonctionnalités permettant de gérer les erreurs ou autres situations exceptionnelles survenant pendant l'exécution d'un programme. Une telle situation est appelée une exception. Déclencher une exception revient à abandonner l'exécution normale du programme afin d'attirer l'attention sur le fait que la situation correspondante s'est produite. L'exécution de certaines actions, en réponse à la survenue d'une exception, est appelée gestion de l'exception.

Une déclaration d'exception déclare un nom pour une exception. Une exception peut être déclenchée par une instruction raise, ou par une autre instruction ou opération propageant l'exception. Lorsqu'une exception survient, le contrôle peut être transféré à un gestionnaire d'exceptions fourni par l'utilisateur à la fin d'une instruction de bloc ou à la fin du corps d'un sous-programme, d'un paquet ou d'une unité de tâche.

Déclarations d'exception

Une déclaration d'exception déclare un nom pour une exception. Le nom d'une exception ne peut être utilisé que dans les instructions raise, les gestionnaires d'exceptions et les déclarations de renommage.

declaration_d_exception ::= liste_identifiant : exception

Une déclaration d'exception avec plusieurs identifiants est équivalente à une séquence de déclarations d'exceptions simples. Chaque déclaration d'exception simple déclare un nom pour une exception différente. En particulier, si une unité générique inclut une déclaration d'exception, les déclarations d'exception générées implicitement par différentes instanciations de l'unité générique font référence à des exceptions distinctes (mais ont toutes le même identifiant). L'exception particulière désignée par un nom d'exception est déterminée au moment de la compilation et est la même quel que soit le nombre de fois que la déclaration d'exception est élaborée. Par conséquent, si une déclaration d'exception se produit dans un sous-programme récursif, le nom de l'exception désigne la même exception pour toutes les invocations du sous-programme récursif.

Les exceptions suivantes sont prédéfinies dans le langage; elles sont levées lorsque les situations décrites sont détectées :

Exception Description
CONSTRAINT_ERROR Cette exception est levée dans l'une des situations suivantes : lors d'une tentative de violation d'une contrainte d'intervalle, d'une contrainte d'index ou d'une contrainte discriminante; lors d'une tentative d'utilisation d'une composante d'enregistrement n'existant pas pour les valeurs discriminantes actuelles; et lors d'une tentative d'utilisation d'un composant sélectionné, d'un composant indexé, d'une tranche ou d'un attribut d'un objet désigné par une valeur d'accès, si l'objet n'existe pas parce que la valeur d'accès est nulle.
NUMERIC_ERROR Cette exception est levée par l'exécution d'une opération numérique prédéfinie qui ne peut pas fournir un résultat correct (dans les limites de précision déclarées pour les types réels); cela inclut le cas où une implémentation utilise une opération numérique prédéfinie pour l'exécution, l'évaluation ou l'élaboration d'une construction.
PROGRAM_ERROR Cette exception est levée lors d'une tentative d'appel d'un sous-programme, d'activation d'une tâche ou d'élaboration d'une instanciation générique, si le corps de l'unité correspondante n'a pas encore été élaboré. Cette exception est également levée si la fin d'une fonction est atteinte; ou lors de l'exécution d'une attente sélective n'ayant pas de partie else, si cette exécution détermine que toutes les alternatives sont fermées. Enfin, selon l'implémentation, cette exception peut être levée lors d'une tentative d'exécution d'une action erronée, et pour des dépendances d'ordre incorrectes.
STORAGE_ERROR Cette exception est levée dans l'une des situations suivantes : lorsque l'entreposage dynamique alloué à une tâche est dépassé; lors de l'évaluation d'un allocateur, si l'espace disponible pour la collecte des objets alloués est épuisé; ou lors de l'élaboration d'un élément déclaratif, ou lors de l'exécution d'un appel de sous-programme, si l'entreposage n'est pas suffisant.
TASKING_ERROR Cette exception est levée lorsque des exceptions surviennent lors de la communication intertâche.

Remarque : les situations décrites ci-dessus peuvent survenir sans déclencher les exceptions correspondantes, si le pragma SUPPRESS a été utilisé pour donner la permission d'omettre les vérifications correspondantes.

Exemples de déclarations d'exceptions définies par l'utilisateur :

  1. SINGULAR            : exception;
  2. ERROR               : exception;
  3. OVERFLOW, UNDERFLOW : exception;

Gestionnaires d'exceptions

La réponse à une ou plusieurs exceptions est spécifiée par un gestionnaire d'exceptions :

gestionnaire_d_exceptions ::=
  when choix_exception || choix_exception| =>
    sequence_d_instructions

choix_exception ::= nom_exception | others

Un gestionnaire d'exceptions apparaît dans une construction étant soit une instruction de bloc, soit le corps d'un sous-programme, d'un paquet, d'une unité de tâche ou d'une unité générique. Une telle construction sera appelée un cadre dans cette page. Dans chaque cas, la syntaxe d'un cadre possédant des gestionnaires d'exceptions comprend la partie suivante :

begin
  sequence_d_instructions
exception
  gestionnaire_d_exceptions
 {gestionnaire_d_exceptions}
end

Les exceptions désignées par les noms d'exception donnés comme choix d'exception d'une trame doivent toutes être distinctes. Le choix d'exception autres n'est autorisé que pour le dernier gestionnaire d'exception d'une trame et comme seul choix d'exception; il représente toutes les exceptions non répertoriées dans les gestionnaires précédents de la trame, y compris les exceptions dont les noms ne sont pas visibles à la place du gestionnaire d'exception.

Les gestionnaires d'exception d'une trame gèrent les exceptions étant déclenchées par l'exécution de la séquence d'instructions de la trame. Les exceptions gérées par un gestionnaire d'exception donné sont celles nommées par les choix d'exception correspondants.

Exemple :

  1. begin
  2.  -- séquence d'instructions
  3. exception
  4.  when SINGULAR | NUMERIC_ERROR =>
  5.    PUT(" LA MATRICE EST SINGULIÈRE ");
  6.  when others =>
  7.    PUT(" ERREUR FATALE ");
  8.    raise ERROR;
  9. end;

Remarque : les mêmes types d'instructions sont autorisés dans la séquence d'instructions de chaque gestionnaire d'exceptions que dans la séquence d'instructions de la trame. Par exemple, une instruction return est autorisée dans un gestionnaire au sein d'un corps de fonction.

Instructions raise

Une instruction raise lève une exception :

instruction_raise ::= raise [nom_de_l_exception];

Pour l'exécution d'une instruction raise avec un nom d'exception, l'exception nommée est levée. Une instruction raise sans nom d'exception n'est autorisée que dans un gestionnaire d'exceptions (mais pas dans la séquence d'instructions d'un sous-programme, d'un paquet, d'une unité de tâche ou d'une unité générique, délimitée par le gestionnaire); elle lève à nouveau l'exception ayant provoqué le transfert vers le gestionnaire englobant le plus interne.

Exemples :

  1. raise SINGULAR;
  2. raise NUMERIC_ERROR;  -- déclencher explicitement une exception prédéfinie
  3. raise;                -- uniquement dans un gestionnaire d'exceptions

Gestion des exceptions

Lorsqu'une exception est déclenchée, l'exécution normale du programme est abandonnée et le contrôle est transféré à un gestionnaire d'exceptions. Le choix de ce gestionnaire dépend du fait que l'exception est déclenchée pendant l'exécution des instructions ou pendant l'élaboration des déclarations.

Exceptions levées lors de l'exécution d'instructions

La gestion d'une exception levée par l'exécution d'une séquence d'instructions dépend du fait que le cadre le plus interne ou l'instruction accept entourant la séquence d'instructions est un cadre ou une instruction accept. Le cas où une instruction accept est la plus interne est décrit dans dans les prochaines sections. Le cas où un cadre est le plus interne est présenté ici.

Différentes actions ont lieu, selon que cette trame possède ou non un gestionnaire pour l'exception, et selon que l'exception est levée dans la séquence d'instructions de la trame ou dans celle d'un gestionnaire d'exceptions.

Si une exception est levée dans la séquence d'instructions d'une trame possédant un gestionnaire pour l'exception, l'exécution de la séquence d'instructions de la trame est abandonnée et le contrôle est transféré au gestionnaire d'exceptions. L'exécution de la séquence d'instructions du gestionnaire termine l'exécution de la trame (ou son élaboration si la trame est un corps de paquet).

Si une exception est levée dans la séquence d'instructions d'une trame ne possédant pas de gestionnaire pour l'exception, l'exécution de cette séquence d'instructions est abandonnée. L'action suivante dépend de la nature de la trame :

  1. Pour un corps de sous-programme, la même exception est levée à nouveau au point d'appel du sous-programme, sauf si le sous-programme est le programme principal lui-même, auquel cas l'exécution du programme principal est abandonnée.
  2. Pour une instruction de bloc, la même exception est à nouveau levée immédiatement après l'instruction de bloc (c'est-à-dire dans le cadre englobant le plus interne ou dans l'instruction accept).
  3. Pour un corps de paquet étant un élément déclaratif, la même exception est à nouveau levée immédiatement après cet élément déclaratif (dans la partie déclarative englobante). Si le corps du paquet est celui d'une sous-unité, l'exception est à nouveau levée à la place du stub de corps correspondant. Si le paquet est une unité de bibliothèque, l'exécution du programme principal est abandonnée.
  4. Pour un corps de tâche, la tâche devient terminée.

Une exception étant levée à nouveau (comme dans les cas (a), (b) et (c) ci-dessus) est dite propagée, soit par l'exécution du sous-programme, soit par l'exécution de l'instruction de bloc, soit par l'élaboration du corps du paquet. Aucune propagation n'a lieu dans le cas d'un corps de tâche. Si le cadre est un sous-programme ou une instruction de bloc et s'il a des tâches dépendantes, la propagation d'une exception n'a lieu qu'après la fin des tâches dépendantes.

Enfin, si une exception est levée dans la séquence d'instructions d'un gestionnaire d'exceptions, l'exécution de cette séquence d'instructions est abandonnée. Les actions ultérieures (y compris la propagation, le cas échéant) sont comme dans les cas (a) à (d) ci-dessus, selon la nature du cadre.

Exemple :

  1. function FACTORIAL (N : POSITIVE) return FLOAT is begin
  2.  if N = 1 then
  3.   return 1.0;
  4.  else
  5.   return FLOAT(N) * FACTORIAL(N-1);
  6.  end if;
  7. exception
  8.  when NUMERIC_ERROR => return FLOAT'SAFE_LARGE;
  9. end FACTORIAL;

Si la multiplication génère une erreur NUMERIC_ERROR, le gestionnaire renvoie alors la valeur FLOAT'SAFE_LARGE. Cette valeur entraînera la génération d'autres exceptions NUMERIC_ERROR par l'évaluation de l'expression dans chacune des invocations restantes de la fonction, de sorte que pour les valeurs N élevées, la fonction renverra finalement la valeur FLOAT'SAFE-LARGE.

Exemple :

  1. procedure P is
  2.   ERROR : exception;
  3.   procedure R;
  4.  
  5.   procedure Q is
  6.   begin
  7.     R;
  8.     ...               -- situation d'erreur (2)
  9.   exception
  10.     ...
  11.     when ERROR =>     -- gestionnaire E2
  12.   end Q;
  13.  
  14.   procedure R is
  15.   begin
  16.     ...               -- situation d'erreur (3)
  17.   end R;
  18.  
  19. begin
  20.   ...                 -- situation d'erreur (1)
  21.   Q;
  22.   ...
  23. exception
  24.   ...
  25. when ERROR =>         -- gestionnaire E1
  26.   ...
  27. end P;

Les situations suivantes peuvent se produire :

  1. Si l'exception ERROR est levée dans la séquence d'instructions de la procédure externe P, le gestionnaire E1 fourni dans P est utilisé pour terminer l'exécution de P.
  2. Si l'exception ERROR est levée dans la séquence d'instructions de Q, le gestionnaire E2 fourni dans Q est utilisé pour terminer l'exécution de Q. Le contrôle sera rendu au point d'appel de Q une fois le gestionnaire terminé.
  3. Si l'exception ERROR est levée dans le corps de R, appelé par Q, l'exécution de R est abandonnée et la même exception est levée dans le corps de Q. Le gestionnaire E2 est alors utilisé pour terminer l'exécution de Q, comme dans la situation (2).

Notez que dans la troisième situation, l'exception levée dans R entraîne le transfert (indirect) du contrôle à un gestionnaire faisant partie de Q et n'est donc pas inclus dans R. Notez également que si un gestionnaire était fourni dans R pour le choix d'exception others, la situation (3) provoquerait l'exécution de ce gestionnaire, plutôt que l'arrêt direct de R.

Enfin, si ERROR avait été déclaré dans R, plutôt que dans P, les gestionnaires E1 et E2 ne pourraient pas fournir de gestionnaire explicite pour ERROR puisque cet identifiant ne serait pas visible dans les corps de P et Q. Dans la situation (3), l'exception pourrait cependant être gérée dans Q en fournissant un gestionnaire pour le choix d'exception others.

Remarques : Le langage ne définit pas ce qui se passe lorsque l'exécution du programme principal est abandonnée après une exception non gérée.

Les exceptions prédéfinies sont celles qui peuvent être propagées par les opérations de base et les opérateurs prédéfinis.

Le cas d'une trame étant une unité générique est déjà couvert par les règles pour les corps de sous-programmes et de paquets, puisque la séquence d'instructions d'une telle trame n'est pas exécutée mais est le modèle pour les séquences d'instructions correspondantes des sous-programmes ou des paquets obtenus par instanciation générique.

Exceptions levées lors de l'élaboration des déclarations

Si une exception est levée lors de l'élaboration de la partie déclarative d'un cadre donné, cette élaboration est abandonnée. L'action suivante dépend de la nature du cadre :

  1. Pour un corps de sous-programme, la même exception est levée à nouveau au point d'appel du sous-programme, à moins que le sous-programme ne soit le programme principal lui-même, auquel cas l'exécution du programme principal est abandonnée.
  2. Pour une instruction de bloc, la même exception est levée à nouveau immédiatement après l'instruction de bloc.
  3. Pour un corps de paquet étant un élément déclaratif, la même exception est levée à nouveau immédiatement après cet élément déclaratif, dans la partie déclarative englobante. Si le corps du paquet est celui d'une sous-unité, l'exception est levée à nouveau à la place du stub de corps correspondant. Si le paquet est une unité de bibliothèque, l'exécution du programme principal est abandonnée.
  4. Pour un corps de tâche, la tâche devient terminée et l'exception TASKING_ERROR est levée au point d'activation de la tâche.

De même, si une exception est levée pendant l'élaboration d'une déclaration de paquet ou d'une déclaration de tâche, cette élaboration est abandonnée; l'action suivante dépend de la nature de la déclaration.

  1. Pour une déclaration de paquet ou une déclaration de tâche, c'est-à-dire un élément déclaratif, l'exception est levée à nouveau immédiatement après l'élément déclaratif dans la partie déclarative ou la spécification de paquet englobante. Pour la déclaration d'un paquet de bibliothèque, l'exécution du programme principal est abandonnée.

Une exception étant levée à nouveau (comme dans les cas ci-dessus (a), (b), (c) et (e)) est dite propagée, soit par l'exécution du sous-programme ou de l'instruction de bloc, soit par l'élaboration de la déclaration de paquet, de la déclaration de tâche ou du corps du paquet.

Exemple d'exception dans la partie déclarative d'une instruction de bloc (cas (b)) :

  1. procedure P is
  2.   ...
  3. begin
  4.   declare
  5.      N : INTEGER := F;  -- la fonction F peut générer une erreur ERROR
  6.   begin
  7.      ...
  8.   exception
  9.      when ERROR =>      -- gestionnaire E1
  10.   end;
  11.    ...
  12. exception
  13.   when ERROR =>         -- gestionnaire E2
  14. end P;
  15.  
  16. -- si l'exception ERROR est levée dans la déclaration de N, elle est gérée par E2

Exceptions levées pendant la communication des tâches

Une exception peut être propagée à une tâche communiquant ou tentant de communiquer avec une autre tâche. Une exception peut également être propagée à une tâche appelante si l'exception est levée pendant un rendez-vous.

Lorsqu'une tâche appelle une entrée d'une autre tâche, l'exception TASKING_ERROR est levée dans la tâche appelante, à l'endroit de l'appel, si la tâche appelée est terminée avant d'accepter l'appel d'entrée ou est déjà terminée au moment de l'appel.

Un rendez-vous peut être terminé anormalement dans deux cas :

  1. Lorsqu'une exception est levée dans une instruction accept, mais n'est pas gérée dans un cadre interne. Dans ce cas, l'exécution de l'instruction accept est abandonnée et la même exception est levée à nouveau immédiatement après l'instruction accept dans la tâche appelée ; l'exception est également propagée à la tâche appelante au point d'appel de l'entrée.
  2. Lorsque la tâche contenant l'instruction accept est terminée anormalement à la suite d'une instruction abort. Dans ce cas, l'exception TASKING_ERROR est levée dans la tâche appelante au moment de l'appel d'entrée.

En revanche, si une tâche émettant un appel d'entrée devient anormale (suite à une instruction d'abandon), aucune exception n'est levée dans la tâche appelée. Si le rendez-vous n'a pas encore commencé, l'appel d'entrée est annulé. Si le rendez-vous est en cours, il se termine normalement et la tâche appelée n'est pas affectée.

Exceptions et optimisation

L'objectif de cette section est de spécifier les conditions dans lesquelles une implémentation est autorisée à effectuer certaines actions plus tôt ou plus tard que ce qui est spécifié par d'autres règles du langage.

En général, lorsque les règles du langage spécifient un ordre pour certaines actions (l'ordre canonique), une implémentation ne peut utiliser un ordre alternatif que si elle peut garantir que l'effet du programme n'est pas modifié par le réordonnancement. En particulier, aucune exception ne doit survenir pour l'exécution du programme réordonné si aucune exception ne survient pour l'exécution du programme dans l'ordre canonique. Lorsque, en revanche, l'ordre de certaines actions n'est pas défini par le langage, n'importe quel ordre peut être utilisé par l'implémentation. (Par exemple, les paramètres d'un opérateur prédéfini peuvent être évalués dans n'importe quel ordre puisque les règles ne nécessitent pas d'ordre d'évaluation spécifique.

Une liberté supplémentaire est laissée à une implémentation pour réorganiser les actions impliquant des opérations prédéfinies étant soit des opérateurs prédéfinis, soit des opérations de base autres que des affectations. Cette liberté est laissée, comme défini ci-dessous, même dans le cas où l'exécution de ces opérations prédéfinies peut propager une exception (prédéfinie) :

  1. Pour établir si le même effet est obtenu par l'exécution de certaines actions dans l'ordre canonique et dans un ordre alternatif, on peut supposer qu'aucune des opérations prédéfinies invoquées par ces actions ne propage une exception (prédéfinie), à ??condition que les deux exigences suivantes soient remplies par l'ordre alternatif : premièrement, une opération ne doit pas être invoquée dans l'ordre alternatif si elle n'est pas invoquée dans l'ordre canonique ; deuxièmement, pour chaque opération, le cadre englobant le plus interne ou l'instruction accept doit être le même dans l'ordre alternatif que dans l'ordre canonique, et les mêmes gestionnaires d'exceptions doivent s'appliquer.
  2. Dans une expression, l'association des opérateurs avec les opérandes est spécifiée par la syntaxe. Cependant, pour une séquence d'opérateurs prédéfinis de même niveau de priorité (et en l'absence de parenthèses imposant une association spécifique), toute association d'opérateurs avec les opérandes est autorisée si elle satisfait l'exigence suivante : un résultat entier doit être égal à celui donné par l'ordre canonique de gauche à droite; un résultat réel doit appartenir à l'intervalle de modèle de résultat défini pour l'ordre canonique de gauche à droite. Un tel réordonnancement est autorisé même s'il peut supprimer une exception, ou introduire une autre exception prédéfinie.

De même, une liberté supplémentaire est laissée à une implémentation pour l'évaluation d'expressions numériques simples. Pour l'évaluation d'une opération prédéfinie, une implémentation est autorisée à utiliser l'opération d'un type dont la plage est plus large que celle du type de base des opérandes, à condition que cela fournisse le résultat exact (ou un résultat dans la précision déclarée, dans le cas d'un type réel), même si certains résultats intermédiaires se situent en dehors de l'intervalle du type de base. L'exception NUMERIC_ERROR n'a pas besoin d'être levée dans un tel cas. En particulier, si l'expression numérique est un opérande d'un opérateur relationnel prédéfini, l'exception NUMERIC_ERROR n'a pas besoin d'être levée par l'évaluation de la relation, à condition que le résultat BOOLEAN correct soit obtenu.

Une opération prédéfinie n'a pas besoin d'être invoquée du tout, si son seul effet possible est de propager une exception prédéfinie. De même, une opération prédéfinie n'a pas besoin d'être invoquée si la suppression des opérations suivantes par la règle ci-dessus rend cette invocation inefficace.

Remarques : La règle (b) s'applique aux opérateurs prédéfinis mais pas aux formes de contrôle de court-circuit.

L'expression SPEED < 300_000.0 peut être remplacée par TRUE si la valeur 300_000.0 se situe en dehors du type de base de SPEED, même si la conversion implicite du littéral numérique déclencherait l'exception NUMERIC_ERROR.

Exemple :

  1. declare
  2.   N : INTEGER;
  3. begin
  4.   N := 0;                    -- (1)
  5.   for J in 1 .. 10 loop
  6.      N := N + J**A(K);       -- A et K sont des variables globales
  7.   end loop;
  8.   PUT(N);
  9. exception
  10.   when others => PUT("Une erreur est survenue"); PUT(N);
  11. end;

L'évaluation de A(K) peut être effectuée avant la boucle, et éventuellement immédiatement avant l'instruction d'affectation (1) même si cette évaluation peut déclencher une exception. Par conséquent, dans le gestionnaire d'exceptions, la valeur de N est soit la valeur initiale indéfinie, soit une valeur assignée ultérieurement. En revanche, l'évaluation de A(K) ne peut pas être déplacée avant le début de la boucle car une exception serait alors gérée par un gestionnaire différent. Pour cette raison, l'initialisation de N dans la déclaration elle-même exclurait la possibilité d'avoir une valeur initiale indéfinie de N dans le gestionnaire.

Suppression des vérifications

La présence d'un pragma SUPPRESS donne la permission à une implémentation d'omettre certaines vérifications d'exécution. La forme de ce pragma est la suivante :

pragma SUPPRESS (identifiant [, [ON =>] nom])

L'identifiant est celui du contrôle pouvant être omis. Le nom (s'il est présent) doit être soit un nom simple, soit un nom développé et doit désigner soit un objet, un type ou un sous-type, une unité de tâche ou une unité générique ; le nom peut également être un nom de sous-programme, auquel cas il peut représenter plusieurs sous-programmes surchargés visibles.

Un pragma SUPPRESS n'est autorisé qu'immédiatement dans une partie déclarative ou immédiatement dans une spécification de paquet. Dans ce dernier cas, la seule forme autorisée est avec un nom qui désigne une entité (ou plusieurs sous-programmes surchargés) déclarée immédiatement dans la spécification de paquet. L'autorisation d'omettre la vérification donnée s'étend de l'emplacement du pragma jusqu'à la fin de la région déclarative associée à l'instruction de bloc ou à l'unité de programme la plus interne. Pour un pragma donné dans une spécification de paquet, l'autorisation s'étend jusqu'à la fin de la portée de l'entité nommée.

Si le pragma inclut un nom, l'autorisation d'omettre la vérification donnée est encore plus restreinte : elle est donnée uniquement pour les opérations sur l'objet nommé ou sur tous les objets du type de base d'un type ou sous-type nommé; pour les appels d'un sous-programme nommé; pour les activations de tâches du type de tâche nommé ; ou pour les instanciations de l'unité générique donnée.

Les vérifications suivantes correspondent aux situations dans lesquelles l'exception CONSTRAINT_ERROR peut être levée ; pour ces vérifications, le nom (s'il est présent) doit désigner soit un objet, soit un type.

Vérification Description
ACCESS_CHECK Lors de l'accès à un composant sélectionné, à un composant indexé, à une tranche ou à un attribut d'un objet désigné par une valeur d'accès, vérifiez que la valeur d'accès n'est pas nulle.
DISCRIMINANT_CHECK Vérifiez qu'un discriminant d'une valeur composite possède la valeur imposée par une contrainte discriminante. De plus, lors de l'accès à une composante d'enregistrement, vérifiez qu'il existe pour les valeurs discriminantes actuelles.
INDEX_CHECK Vérifiez que les limites d'une valeur de tableau sont égales aux limites correspondantes d'une contrainte d'index. De même, lors de l'accès à un composant d'un objet tableau, vérifiez pour chaque dimension que la valeur d'index donnée appartient à l'intervalle définie par les limites de l'objet tableau. De même, lors de l'accès à une tranche d'un objet tableau, vérifiez que l'intervalle discrète donnée est compatible avec l'intervalle définie par les limites de l'objet tableau.
LENGTH_CHECK Vérifiez qu'il existe un composant correspondant pour chaque composante d'un tableau, dans le cas d'affectations de tableau, de conversions de type et d'opérateurs logiques pour les tableaux de composantes booléens.
RANGE_CHECK Vérifiez qu'une valeur satisfait une contrainte d'intervalle. De même, pour l'élaboration d'une indication de sous-type, vérifiez que la contrainte (si présente) est compatible avec la marque de type. De même, pour un agrégat, vérifiez qu'un index ou une valeur discriminante appartient au sous-type correspondant. Enfin, vérifiez les éventuelles vérifications de contrainte effectuées par une instanciation générique.

Les vérifications suivantes correspondent aux situations dans lesquelles l'exception NUMERIC_ERROR est levée. Les seuls noms autorisés dans les pragmas correspondants sont les noms de types numériques :

Vérification Description
DIVISION_CHECK Vérifiez que le deuxième opérande n'est pas nul pour les opérations /, rem et mod.
OVERFLOW_CHECK Vérifiez que le résultat d'une opération numérique ne déborde pas.

La vérification suivante correspond aux situations dans lesquelles l'exception PROGRAM_ERROR est levée. Les seuls noms autorisés dans les pragmas correspondants sont les noms désignant des unités de tâches, des unités génériques ou des sous-programmes.

Vérification Description
ELABORATION_CHECK Lorsqu'un sous-programme est appelé, qu'une activation de tâche est réalisée ou qu'une instanciation générique est élaborée, vérifiez que le corps de l'unité correspondante a déjà été élaboré.

La vérification suivante correspond aux situations dans lesquelles l'exception STORAGE_ERROR est levée. Les seuls noms autorisés dans les pragmas correspondants sont les noms désignant des types d'accès, des unités de tâches ou des sous-programmes :

Vérification Description
STORAGE_CHECK Vérifiez que l'exécution d'un allocateur ne nécessite pas plus d'espace que celui disponible pour une collection. Vérifiez que l'espace disponible pour une tâche ou un sous-programme n'a pas été dépassé.

Si une situation d'erreur survient en l'absence des contrôles d'exécution correspondants, l'exécution du programme est erronée (les résultats ne sont pas définis par le langage).

Exemples :

  1. pragma SUPPRESS(RANGE_CHECK);
  2. pragma SUPPRESS(INDEX_CHECK, ON => TABLE);

Remarques : Pour certaines implémentations, il peut être impossible ou trop coûteux de supprimer certains contrôles. Le pragma SUPPRESS correspondant peut être ignoré. Par conséquent, l'occurrence d'un tel pragma dans une unité donnée ne garantit pas que l'exception correspondante ne se produira pas ; les exceptions peuvent également être propagées par les unités appelées.



PARTAGER CETTE PAGE SUR
Dernière mise à jour : Mardi, le 7 janvier 2025