PROGRAM_ERROR (ПРОГРАММНАЯ_ОШИБКА) Это исключение воз­буждается при попытке вызвать подпрограмму, активизировать задачу или предвыполнить конкретизацию настройки, если тело соответствующего мо­дуля еще не предвыполнено. Оно также возбуждается, если выполнение функции завершается через end (см. разд. 6.5); при выполнении оператора отбора с ожиданием, когда отсутствует раздел else, а все альтернативы за­крыты (см. разд. 9.7.1). Наконец, в зависимости от реализации исключение может возбуждаться при попытке выполнить ошибочное действие и при не­корректной зависимости от порядка (см. разд. 1.6).

STORAGE ERROR (ОШИБКА_ПАМЯТИ) Это исключение возбуждает­ся в одной из следующих ситуаций: при вычислении генератора, когда не хватает динамической памяти, выделенной для задачи; когда исчерпана па­мять для набора генерируемых объектов; при предвыполнении элемента описания или при вызове подпрограммы, если памяти недостаточно.

TASKING_ERROR (ОШИБКА_ЗАДАЧИ) Это исключение возбуждает­ся при возбуждении исключений во время взаимодействия задач (см. разд. 9 и 11.5).

Примечание. Описанные выше ситуации могут возникать, не возбуждая соответст­вующих исключений, если была использована Прагма SUPPRESS подавления проверок (см. разд. 11.7).

Примеры описанных пользователем исключений:

ВЫРОЖДЕННАЯ: exception;

ОШИБКА: exception;

ПЕРЕПОЛНЕНИЕ, ПОТЕРЯ_ТОЧНОСТИ: exception;

  1. Обработчики исключений

Ответная реакция на одно или несколько исключений определяется об­работчиком исключения.

обработчик..исключения : : =

when выбор_исключения {I выбор—исключения} => последовательность—операторов

выбор—Исключения : : = тля_исключения | others

Обработчик исключения помещается в операторе блока, в теле подпро­граммы, пакета, задачного модуля или настраиваемого модуля. Каждая из указанных конструкций называется в этой главе окружением. В любом слу­чае окружение обработчиков исключений синтаксически включает следую­щий раздел:

begin

последовательность—операторов

exception

обработчик—исключения

{обработчик—исключения }

end

Исключения, обозначенные именами исключений во всех выборах дан­ного окружения, должны быть все различны. Выбор исключения others до­пустим только в последнем обработчике исключения данного окружения, как единственный выбор; он задает все исключения, не перечисленные в предыдущих обработчиках окружения, включая исключения, имена кото­рых на месте данного обработчика исключения невидимы.

Обработчики исключений в окружении обрабатывают исключения, воз­буждаемые при выполнении последовательности операторов этого окруже- ния. Исключения обрабатываются тем обработчиком, в выборах которого заданы имена этих исключений.

Пример:

begin

- - последовательность операторов

exception

when ВЫРОЖДЕННАЯ | NUMERIC-ERROR =>

PUT (’’ВЫРОЖДЕННАЯ_МАТРИЦА”);

when others = >

PUT С’НЕИСПРАВИМАЯ-ОШИБКА”);

raise ОШИБКА;

end;

Примечание. В каждом обработчике исключений и в последовательностях опера­торов окружения допустимы одни и те же виды операторов. Например, оператор воз­врата допустим в обработчике, если окружение является телом функции.

  1. Операторы возбуждения

Оператор возбуждения возбуждает исключение.

оператор_возбуждения : : = raise [тля_исключения] ;

При выполнении оператора возбуждения с именем исключения возбуж­дается заданное исключение. Оператор возбуждения без имени исключения допустим только внутри обработчика исключения (но не в последователь­ности операторов подпрограммы, пакета, задачного модуля или настраивае­мого модуля, вложенной в данный обработчик); он снова возбуждает то же исключение, которое вызвало переход на обработчик, содержащий дан­ный оператор возбуждения.

Примеры:

raise ВЫРОЖДЕННАЯ;

raise NUMERIC-ERROR; - - явно возбуждается предопределенное исключение raise; - - только внутри обработчика исключения

  1. Обработка исключения

После возбуждения исключения нормальное выполнение программы прекращается и управление передается обработчику исключения. Выбор об­работчика зависит от места возбуждения: при выполнении операторов или при предвыполнении описаний.

  1. И с к л ю ч е н и я, возбуждаемые при выполне­нии операторов

Обработка исключения, возбуждаемого при выполнении последователь­ности операторов, зависит от того, вложена ли она в самое внутреннее окру­жение или в оператор принятия. Случай вложенности в оператор принятия описан в разд. 11.5.

Предпринимаемые действия зависят от того, содержит ли данное окру­жение обработчик этого исключения и возбуждено ли исключение в после­довательности операторов окружения или обработчика исключения.

Если некоторое исключение возбуждено в последовательности операто­ров окружения, содержащего нужный обработчик, то выполнение этой по­следовательности операторов прекращается и управление передается обра­ботчику данного исключения. Выполнение последовательности операторов обработчика заканчивает выполнение окружения (или предвыполнение, ес­ли окружение — тело пакета).

Если исключение возбуждено в последовательности операторов окру­жения, не содержащего обработчика этого исключения, то выполнение по­следовательности операторов прекращается. Дальнейшие действия зависят от природы окружения:

  1. Для тела подпрограммы — то же исключение возбуждается повторно в точке вызова этой подпрограммы, кроме случая, когда она является глав­ной программой. Тогда выполнение главной программы прекращается.

  2. Для оператора блока — то же исключение повторно возбуждается не­посредственно после оператора блока (т. е. в самом вложенном объемлю­щем окружении или в операторе принятия, содержащем этот оператор бло­ка) .

  3. Для тела пакета, являющегося дополнительным элементом описа­ния, — то же исключение возбуждается повторно непосредственно после этого элемента описания (в объемлющем разделе описаний). Если тело это­го пакета описано как субмодуль, то исключение возбуждается повторно на месте соответствующего следа тела. Если пакет является библиотечным модулем, то выполнение главной программы прекращается.

  4. Для тела задачи — задача становится законченной.

Говорят, что возбуждаемое повторно исключение (как это рассмотрено в подпунктах а, б и в) распространяется либо выполнением подпрограммы, либо выполнением оператора блока, либо предвыполнением тела пакета. В случае тела задачи распространения не происходит. Если окружение являет­ся подпрограммой или оператором блока, и если оно содержит зависимые задачи, то распространение исключения происходит только после заверше­ния зависимых задач.

Наконец, если исключение возбуждено в последовательности операто­ров обработчика исключения, то выполнение этой последовательности опе­раторов прекращается. Последующие действия (включая возможное рас­пространение) зависят от природы окружения и выполняются в соответст­вии с подпунктами от а до г.

Пример:

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. Если исключение ОШИБКА возбуждено при выполнении последователь­ности операторов внешней процедуры Р, то выполнение процедуры Р закан­чивает обработчик Е1, расположенный внутри Р.

  2. Если исключение ОШИБКА возбуждено при выполнении последователь­ности операторов процедуры Q, то обработчик Е2, расположенный внутри Q, закончит ее выполнение. По окончании выполнения этого обработчика управление будет возвращено в точку вызова процедуры Q.

  3. Если исключение ОШИБКА возбуждено в теле процедуры R, вызываемой из процедуры Q, то выполнение процедуры R прекращается, и то же самое исключение возбуждается в теле Q. Затем обработчик Е2 заканчивает вы­полнение процедуры Q, как и в случае 2.

Заметим, что в третьем случае возбуждение исключения в R приводит (косвенно) к передаче управления обработчику, являющемуся частью Q и, следовательно, не вложенному в R. Заметим также, что если бы внутри R был задан обработчик с выбором others, то в случае 3, вместо непосредст­венного завершения R, выполнился бы этот обработчик.

Наконец, если бы исключение ОШИБКА было описано в R, а не в Р, то обработчики Е1 и Е2 не могли бы обеспечивать обработку исключения ОШИБКА, так как этот идентификатор не был бы видимым внутри тел Р и Q. В случае 3, однако, это исключение могло бы быть обработано в Q с по­мощью обработчика с выбором исключения others.

Примечание. В языке не определено, что происходит после прекращения выполне­ния главной, программы в результате необработанного исключения.

Предопределенные исключения - это исключения, которые могут распространять­ся базовыми и предопределенными операциями.

Случай, когда окружением является настраиваемый модуль, уже был учтен в пра­вилах для тел подпрограмм и пакетов, так как последовательность операторов такого окружения не выполняется, а служит шаблоном для конкретизации настройки соот­ветствующей последовательности операторов подпрограммы или пакета.

  1. Исключения, возбуждаемые при предвыпол- ненииописаний

Если исключение возбуждено при предвыполнении раздела описаний данного окружения, то это предвыполнение прекращается. Дальнейшее дей­ствие зависит от природы окружения:

  1. Для тела подпрограммы - то же исключение повторно возбуждается в точке вызова подпрограммы, кроме случая, когда эта подпрограмма яв­ляется главной программой, тогда ее выполнение прекращается.

  2. Для оператора блока — то же исключение повторно возбуждается не­посредственно после оператора блока.

  3. Для тела пакета, являющегося дополнительным элементом описа­ния, — то же исключение повторно возбуждается непосредственно после этого элемента описания в объемлющем разделе описаний. Если тело пакета является субмодулем, то исключение возбуждается повторно на месте соот­ветствующего следа тела. Если пакет является библиотечным модулем, то выполнение главной программы прекращается.

  4. Для тела задачи — задача становится законченной, а в точке активиза­ции задачи возбуждается исключение TASKING_ERROR, как пояснено в разд. 9.3.

Если исключение возбуждается во время предвыполнения либо описа­ния пакета, либо описания задачи, то это предвыполнение прекращается; дальнейшее действие зависит от природы описания.

  1. Для описания пакета или задачи, являющегося элементом описания, то же исключение возбуждается повторно непосредственно после этого эле­мента описания в объемлющем разделе описаний или в спецификации паке­та. Для описания библиотечного пакета — выполнение главной программы прекращается.

Говорят, что возбуждаемое повторно исключение (как рассмотрено выше в подпунктах а, б, в и г) распространяется либо выполнением подпро­граммы или оператора блока, либо предвыполнением описания пакета, опи­сания задачи или тела пакета.

Пример исключения в разделе описания оператора блока (случай б):

procedure Р is

begin

declare

N: INTEGER: = F; - - функция F может возбуждать исключение ОШИБКА begin

exception

when ОШИБКА =>--обработчик El end;

' exception

when ОШИБКА => - - обработчик Е2

end Р;

  • - Если исключение ОШИБКА возбуждено в описании N,

  • - то оно обрабатывается обработчиком Е2.

  1. Исключения, возбуждаемые при взаимодействии задач

Исключение может распространяться на взаимодействие задач или на попытку начать взаимодействие одной задачи с другой. Исключение может также распространяться на вызывающую задачу, если оно было возбуждено в процессе рандеву.

Когда задача вызывает вход другой задачи, то в точке этого вызова в вызывающей задаче возбуждается исключение TASKING_ERROR,ecnn вы­званная задача закончена до принятия вызова входа или ко времени этого вызова.

Рандеву может иметь аварийное окончание в двух случаях:

  1. Если исключение возбуждено в операторе принятия и не обработано во внутреннем окружении. В этом случае выполнение оператора принятия прекращается, и то же исключение повторно возбуждается непосредственно после оператора принятия в вызванной задаче; исключение также распрост­раняется на вызывающую задачу в точку вызова входа.

  2. Если задача, содержащая оператор принятия, закончена аварийно в результате выполнения оператора прекращения. В этом случае исключе­ние TASKING_ERROR возбуждается в вызывающей задаче в точке вызова входа.

С другой стороны, если задача, вызывающая вход, аварийно прекраща­ет свое выполнение (в результате выполнения оператора прекращение), то в вызванной задаче исключение не возбуждается. Если рандеву еще не нача­лось, то вызов входа аннулируется. Если же рандеву началось, то оно закан­чивается нормально, и это никак не влияет на вызванную задачу.

  1. Исключения и оптимизация

В данном разделе описаны условия, при которых в реализации можно выполнять те или иные действия раньше или позже, чем это определено пра­вилами языка.