PROGRAM_ERROR (ПРОГРАММНАЯ_ОШИБКА) Это исключение возбуждается при попытке вызвать подпрограмму, активизировать задачу или предвыполнить конкретизацию настройки, если тело соответствующего модуля еще не предвыполнено. Оно также возбуждается, если выполнение функции завершается через end (см. разд. 6.5); при выполнении оператора отбора с ожиданием, когда отсутствует раздел else, а все альтернативы закрыты (см. разд. 9.7.1). Наконец, в зависимости от реализации исключение может возбуждаться при попытке выполнить ошибочное действие и при некорректной зависимости от порядка (см. разд. 1.6).
STORAGE ERROR (ОШИБКА_ПАМЯТИ) Это исключение возбуждается в одной из следующих ситуаций: при вычислении генератора, когда не хватает динамической памяти, выделенной для задачи; когда исчерпана память для набора генерируемых объектов; при предвыполнении элемента описания или при вызове подпрограммы, если памяти недостаточно.
TASKING_ERROR (ОШИБКА_ЗАДАЧИ) Это исключение возбуждается при возбуждении исключений во время взаимодействия задач (см. разд. 9 и 11.5).
Примечание. Описанные выше ситуации могут возникать, не возбуждая соответствующих исключений, если была использована Прагма SUPPRESS подавления проверок (см. разд. 11.7).
Примеры описанных пользователем исключений:
ВЫРОЖДЕННАЯ: exception;
ОШИБКА: exception;
ПЕРЕПОЛНЕНИЕ, ПОТЕРЯ_ТОЧНОСТИ: exception;
Обработчики исключений
Ответная реакция на одно или несколько исключений определяется обработчиком исключения.
обработчик..исключения : : =
when выбор_исключения {I выбор—исключения} => последовательность—операторов
выбор—Исключения : : = тля_исключения | others
Обработчик исключения помещается в операторе блока, в теле подпрограммы, пакета, задачного модуля или настраиваемого модуля. Каждая из указанных конструкций называется в этой главе окружением. В любом случае окружение обработчиков исключений синтаксически включает следующий раздел:
begin
последовательность—операторов
exception
обработчик—исключения
{обработчик—исключения }
end
Исключения, обозначенные именами исключений во всех выборах данного окружения, должны быть все различны. Выбор исключения others допустим только в последнем обработчике исключения данного окружения, как единственный выбор; он задает все исключения, не перечисленные в предыдущих обработчиках окружения, включая исключения, имена которых на месте данного обработчика исключения невидимы.
Обработчики исключений в окружении обрабатывают исключения, возбуждаемые при выполнении последовательности операторов этого окруже- ния. Исключения обрабатываются тем обработчиком, в выборах которого заданы имена этих исключений.
Пример:
begin
- - последовательность операторов
exception
when ВЫРОЖДЕННАЯ | NUMERIC-ERROR =>
PUT (’’ВЫРОЖДЕННАЯ_МАТРИЦА”);
when others = >
PUT С’НЕИСПРАВИМАЯ-ОШИБКА”);
raise ОШИБКА;
end;
Примечание. В каждом обработчике исключений и в последовательностях операторов окружения допустимы одни и те же виды операторов. Например, оператор возврата допустим в обработчике, если окружение является телом функции.
Операторы возбуждения
Оператор возбуждения возбуждает исключение.
оператор_возбуждения : : = raise [тля_исключения] ;
При выполнении оператора возбуждения с именем исключения возбуждается заданное исключение. Оператор возбуждения без имени исключения допустим только внутри обработчика исключения (но не в последовательности операторов подпрограммы, пакета, задачного модуля или настраиваемого модуля, вложенной в данный обработчик); он снова возбуждает то же исключение, которое вызвало переход на обработчик, содержащий данный оператор возбуждения.
Примеры:
raise ВЫРОЖДЕННАЯ;
raise NUMERIC-ERROR; - - явно возбуждается предопределенное исключение raise; - - только внутри обработчика исключения
Обработка исключения
После возбуждения исключения нормальное выполнение программы прекращается и управление передается обработчику исключения. Выбор обработчика зависит от места возбуждения: при выполнении операторов или при предвыполнении описаний.
И с к л ю ч е н и я, возбуждаемые при выполнении операторов
Обработка исключения, возбуждаемого при выполнении последовательности операторов, зависит от того, вложена ли она в самое внутреннее окружение или в оператор принятия. Случай вложенности в оператор принятия описан в разд. 11.5.
Предпринимаемые действия зависят от того, содержит ли данное окружение обработчик этого исключения и возбуждено ли исключение в последовательности операторов окружения или обработчика исключения.
Если некоторое исключение возбуждено в последовательности операторов окружения, содержащего нужный обработчик, то выполнение этой последовательности операторов прекращается и управление передается обработчику данного исключения. Выполнение последовательности операторов обработчика заканчивает выполнение окружения (или предвыполнение, если окружение — тело пакета).
Если исключение возбуждено в последовательности операторов окружения, не содержащего обработчика этого исключения, то выполнение последовательности операторов прекращается. Дальнейшие действия зависят от природы окружения:
Для тела подпрограммы — то же исключение возбуждается повторно в точке вызова этой подпрограммы, кроме случая, когда она является главной программой. Тогда выполнение главной программы прекращается.
Для оператора блока — то же исключение повторно возбуждается непосредственно после оператора блока (т. е. в самом вложенном объемлющем окружении или в операторе принятия, содержащем этот оператор блока) .
Для тела пакета, являющегося дополнительным элементом описания, — то же исключение возбуждается повторно непосредственно после этого элемента описания (в объемлющем разделе описаний). Если тело этого пакета описано как субмодуль, то исключение возбуждается повторно на месте соответствующего следа тела. Если пакет является библиотечным модулем, то выполнение главной программы прекращается.
Для тела задачи — задача становится законченной.
Говорят, что возбуждаемое повторно исключение (как это рассмотрено в подпунктах а, б и в) распространяется либо выполнением подпрограммы, либо выполнением оператора блока, либо предвыполнением тела пакета. В случае тела задачи распространения не происходит. Если окружение является подпрограммой или оператором блока, и если оно содержит зависимые задачи, то распространение исключения происходит только после завершения зависимых задач.
Наконец, если исключение возбуждено в последовательности операторов обработчика исключения, то выполнение этой последовательности операторов прекращается. Последующие действия (включая возможное распространение) зависят от природы окружения и выполняются в соответствии с подпунктами от а до г.
Пример:
function ФАКТОРИАЛ (N: POSITIVE) return FLOAT is
begin
if N = 1 then
return 1.0;
else
return FLOAT (N) * ФАКТОРИАЛ (N-l) ;
end if;
exception
when NUMERIC_ERROR => return FLOAT'SAFE_LARGE;
end ФАКТОРИАЛ;
Если при умножении возбуждается исключение NUMERIC_ERROR, то значение FLOAT'SAFE—LARGE возвращается обработчиком исключения. Это значение будет вызывать возбуждение исключения NUMERIC_ERROR при вычислении выражения в каждом из оставшихся обращений к этой функции. Таким образом, для больших значений N эта функция всегда будет возвращать значение FLOAT' SAFE_LARGE.
Пример:
procedure Р is
ОШИБКА: exception;
procedure R;
procedure Q is
begin
R;
... - - ошибочная ситуация 2 exception
when ОШИБКА = > - - обработчик E2
end Q;
procedure R is
begin
... - - ошибочная ситуация З end R;
begin
... - - ошибочная ситуация 1 Q;
exception
when ОШИБКА => - - обработчик El end P;
Могут возникнуть следующие случаи.
Если исключение ОШИБКА возбуждено при выполнении последовательности операторов внешней процедуры Р, то выполнение процедуры Р заканчивает обработчик Е1, расположенный внутри Р.
Если исключение ОШИБКА возбуждено при выполнении последовательности операторов процедуры Q, то обработчик Е2, расположенный внутри Q, закончит ее выполнение. По окончании выполнения этого обработчика управление будет возвращено в точку вызова процедуры Q.
Если исключение ОШИБКА возбуждено в теле процедуры R, вызываемой из процедуры Q, то выполнение процедуры R прекращается, и то же самое исключение возбуждается в теле Q. Затем обработчик Е2 заканчивает выполнение процедуры Q, как и в случае 2.
Заметим, что в третьем случае возбуждение исключения в R приводит (косвенно) к передаче управления обработчику, являющемуся частью Q и, следовательно, не вложенному в R. Заметим также, что если бы внутри R был задан обработчик с выбором others, то в случае 3, вместо непосредственного завершения R, выполнился бы этот обработчик.
Наконец, если бы исключение ОШИБКА было описано в R, а не в Р, то обработчики Е1 и Е2 не могли бы обеспечивать обработку исключения ОШИБКА, так как этот идентификатор не был бы видимым внутри тел Р и Q. В случае 3, однако, это исключение могло бы быть обработано в Q с помощью обработчика с выбором исключения others.
Примечание. В языке не определено, что происходит после прекращения выполнения главной, программы в результате необработанного исключения.
Предопределенные исключения - это исключения, которые могут распространяться базовыми и предопределенными операциями.
Случай, когда окружением является настраиваемый модуль, уже был учтен в правилах для тел подпрограмм и пакетов, так как последовательность операторов такого окружения не выполняется, а служит шаблоном для конкретизации настройки соответствующей последовательности операторов подпрограммы или пакета.
Исключения, возбуждаемые при предвыпол- ненииописаний
Если исключение возбуждено при предвыполнении раздела описаний данного окружения, то это предвыполнение прекращается. Дальнейшее действие зависит от природы окружения:
Для тела подпрограммы - то же исключение повторно возбуждается в точке вызова подпрограммы, кроме случая, когда эта подпрограмма является главной программой, тогда ее выполнение прекращается.
Для оператора блока — то же исключение повторно возбуждается непосредственно после оператора блока.
Для тела пакета, являющегося дополнительным элементом описания, — то же исключение повторно возбуждается непосредственно после этого элемента описания в объемлющем разделе описаний. Если тело пакета является субмодулем, то исключение возбуждается повторно на месте соответствующего следа тела. Если пакет является библиотечным модулем, то выполнение главной программы прекращается.
Для тела задачи — задача становится законченной, а в точке активизации задачи возбуждается исключение TASKING_ERROR, как пояснено в разд. 9.3.
Если исключение возбуждается во время предвыполнения либо описания пакета, либо описания задачи, то это предвыполнение прекращается; дальнейшее действие зависит от природы описания.
Для описания пакета или задачи, являющегося элементом описания, то же исключение возбуждается повторно непосредственно после этого элемента описания в объемлющем разделе описаний или в спецификации пакета. Для описания библиотечного пакета — выполнение главной программы прекращается.
Говорят, что возбуждаемое повторно исключение (как рассмотрено выше в подпунктах а, б, в и г) распространяется либо выполнением подпрограммы или оператора блока, либо предвыполнением описания пакета, описания задачи или тела пакета.
Пример исключения в разделе описания оператора блока (случай б):
procedure Р is
begin
declare
N: INTEGER: = F; - - функция F может возбуждать исключение ОШИБКА begin
exception
when ОШИБКА =>--обработчик El end;
' exception
when ОШИБКА => - - обработчик Е2
end Р;
- Если исключение ОШИБКА возбуждено в описании N,
- то оно обрабатывается обработчиком Е2.
Исключения, возбуждаемые при взаимодействии задач
Исключение может распространяться на взаимодействие задач или на попытку начать взаимодействие одной задачи с другой. Исключение может также распространяться на вызывающую задачу, если оно было возбуждено в процессе рандеву.
Когда задача вызывает вход другой задачи, то в точке этого вызова в вызывающей задаче возбуждается исключение TASKING_ERROR,ecnn вызванная задача закончена до принятия вызова входа или ко времени этого вызова.
Рандеву может иметь аварийное окончание в двух случаях:
Если исключение возбуждено в операторе принятия и не обработано во внутреннем окружении. В этом случае выполнение оператора принятия прекращается, и то же исключение повторно возбуждается непосредственно после оператора принятия в вызванной задаче; исключение также распространяется на вызывающую задачу в точку вызова входа.
Если задача, содержащая оператор принятия, закончена аварийно в результате выполнения оператора прекращения. В этом случае исключение TASKING_ERROR возбуждается в вызывающей задаче в точке вызова входа.
С другой стороны, если задача, вызывающая вход, аварийно прекращает свое выполнение (в результате выполнения оператора прекращение), то в вызванной задаче исключение не возбуждается. Если рандеву еще не началось, то вызов входа аннулируется. Если же рандеву началось, то оно заканчивается нормально, и это никак не влияет на вызванную задачу.
Исключения и оптимизация
В данном разделе описаны условия, при которых в реализации можно выполнять те или иные действия раньше или позже, чем это определено правилами языка.