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

Реализации предоставляется дополнительная свобода для переупорядо- чивания действий, включающих предопределенные или базовые операции, за исключением присваивания. Эта свобода предоставляется даже в том слу­чае, если при выполнении предопределенных операций может распростра­няться (предопределенное) исключение с учетом следующих правил:

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

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

Также дополнительная свобода предоставляется реализации при вычис­лении простых числовых выражений. При выполнении предопределенных операций в реализации допускается использование операций над типами, ко­торые имеют более широкий диапазон результата, чем базовый тип операн­дов, при условии, что это приводит к точному результату (или результату с заданной точностью для вещественного типа), даже если промежуточные результаты выходят за границы базового типа. В таком случае нет необхо­димости возбуждать исключение NUMERIC_ERROR. В частности, если чис­ловое выражение является операндом предопределенной операции отноше­ния и может быть получен правильный результат типа BOOLEAN, то в про­цессе вычисления можно не возбуждать исключение NUMERIC-ERROR.

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

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

Выражение СКОРОСТЬ < 300_000.0 может быть заменено на TRUE, если значе­ние 300_000.0 находится вне границ базового типа для СКОРОСТЬ, даже если неявное преобразование этого числового литерала может возбудить исключение NUMERIC_ ERROR.

Пример:

declare

N: INTEGER;

begin

N: = 0; --(1)

for J in 1. .10 loop

N: = N + J ** A (K); - - А и К являются

- - глобальными переменными

end loop;

PUT(N);

exception

when others => PUT (”ОБНАРУЖЕННАЯ_ОШИБКА”); PUT(N);

end;

Вычисление А (К) может быть выполнено до цикла и, возможно, непо­средственно перед оператором присваивания (1), даже если в нем может возбудиться исключение. Следовательно, внутри обработчика исключения значение N будет либо неопределенным, либо результатом последнего при­сваивания. С другой стороны, вычисление А (К) не может быть выполнено до begin, поскольку в этом случае исключение будет обрабатываться дру­гим обработчиком. По этой причине инициализация N в описании будет ис­ключать возможность наличия неопределенного начального значения N в обработчике.

11.7. Подавление проверок

Присутствие прагмы SUPPRESS позволяет реализации опускать некото­рые проверки во время выполнения программы. Эта прагма имеет следую­щий вид:

pragma SUPPRESS (идентификатор [, [ON =>] имя] );

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

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

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

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

ACCESS-CHECK (ПРОВЕРКА_ССЫЛКИ) Проверяется именуемый компонент, индексируемый компонент, отрезок или атрибут объекта, ука­занный ссылочным значением, на неравенство значению null этого ссылочно­го значения.

DISCRIMINANT-CHECK (ПРОВЕРКА_ДИСКРИМИНАНТА) Проверя­ется, что дискриминант составного значения удовлетворяет ограничению дискриминанта. Также при ссылке на компоненты записи проверяется их существование для текущих значений дискриминанта.

INDEX_CHECK (ПРОВЕРКА..ИНДЕКСА) Проверяется, что границы значений индексов массива равны соответствующим границам ограничения индекса. Также при ссылке на компонент массива по каждой размерности проверяется, что данное значение индекса находится в диапазоне, опреде­ленном границами индекса массива; при ссылке на отрезок массива прове­ряется, что заданный дискретный диапазон совместим с диапазоном, опре­деленным границами индексов массива.

LENGTH_CHECK (ПРОВЕРКА_ДЛИНЫ) Проверяется, что каждому компоненту массива соответствует подходящий компонент при выполне­нии присваивания массиву, преобразовании типа и выполнении логических операций над массивами логических компонентов.

RANGE_CHECK (ПРОВЕРКА_ДИАПАЗОНА) Проверяется, что неко­торое значение удовлетворяет ограничению диапазона. Также при предвы- полнении указания подтипа проверяется совместимость ограничения (если оно имеется) с обозначением типа. Для агрегата проверяется принадлеж­ность индекса или дискриминанта соответствующему подтипу. Наконец, осуществляются проверки любых ограничений, создаваемых при конкрети­зации настройки.

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

DIVISION-CHECK (ПРОВЕРКА—ДЕЛЕНИЯ) Проверяется, что второй операнд операций /, rem и mod не равен нулю.

OVERFLOW-CHECK (ПРОВЕРКА_ПЕРЕПОЛНЕНИЯ) Проверяется, что в результате выполнения числовой операции не возникает переполнения.

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

ELABORATION_CHECK (ПРОВЕРКА_ПРЕДВЫПОЛНЕНИЯ) Когда вызывается подпрограмма, выполняется активизация задачи или предвы- полняется конкретизация настройки, то проверяется, что тело соответству­ющего программного модуля уже предвыполнено.

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

STORAGE_CHECK (ПРОВЕРКА_ПАМЯТИ) Проверяется, что выполне­ние генератора не потребует объем памяти, больший необходимого для на­бора, или что требуемый под задачу или для подпрограммы объем памяти достаточен.

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

Примеры:

pragma SUPPRESS (RANGE_CHECK);

pragma SUPPRESS (INDEX_CHECK, ON => ТАБЛИЦА);

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

12. НАСТРАИВАЕМЫЕ МОДУЛИ

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

Настраиваемый модуль задается описанием настройки, которое имеет раздел формальных параметров настройки, описывающий эти параметры. Конкретный экземпляр настраиваемого модуля получается в результате конкретизации настройки путем сопоставления формальным параметрам фактических. Экземпляр настраиваемой подпрограммы — это подпрограм­ма. Экземпляр настраиваемого пакета — пакет.

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

12.1. Описание настройки <

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

описание_настройки : : = спецификация—настройки;

спецификация_настройки : : =

раздел_формальных_параметров_настройки спецификация—подпрограммы

I раздел_формальных_параметров—настройки спецификация _пак era

раздел_формальных_параметров_настройки : : = generic { описание_параметра_настройки )■

описание_параметра_настройки : : =

список_идентификаторов :

[in [out]] обозначение_типа [:= выражение];

I type идентификатор is определение—настраиваемого-типа;

I описание—личного—типа

I with спецификации-подпрограммы [is имя];

I with спецификация-подпрограммы [is < >];

определение—настраиваемого—типа : : =

(< >) I range < >| digits <> I delta <>

I определение—индексируемого_типа

I определение—ссылочного—типа

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

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

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

Предвыполнение описания настройки не имеет другого эффекта.

Примеры разделов формальных параметров:

generic - - без параметров

generic

РАЗМЕР: NATURAL; - - формальный объект

generic

ДЛИНА: INTEGER: = 200; --формальный объект с выражением по умолчанию

ПЛОЩАДЬ: INTEGER: = ДЛИНА * ДЛИНА;

- - формальный объект с выражением по умолчанию generic

type ЭЛЕМЕНТ is private; - - формальный тип

type ИНДЕКС is (< >); - - формальный тип

type РЯД is array (ИНДЕКС range < >) of ЭЛЕМЕНТ; - - формальный тип

with function (X, Y: ЭЛЕМЕНТ) return BOOLEAN;

формальная подпрограмма

Примеры описаний настройки с настраиваемыми подпрограммами:

generic

type ЭЛЕМ is private;