В целом, если правила языка задают порядок некоторых действий (канонический порядок), реализация может использовать альтернативный порядок при гарантиях, что такое переупорядочивание не скажется на результате выполнения программы. В частности, если при выполнении программы в каноническом порядке не возбуждается никакое исключение, то также никакие исключения не должны возбуждаться при выполнении переупорядоченной программы. С другой стороны, если порядок некоторых действий не определен языком, то реализация может использовать любой порядок. (Например, аргументы предопределенной операции могут вычисляться в любом порядке, так как правила из разд. 4.5 не требуют определенного порядка выполнения.)
Реализации предоставляется дополнительная свобода для переупорядо- чивания действий, включающих предопределенные или базовые операции, за исключением присваивания. Эта свобода предоставляется даже в том случае, если при выполнении предопределенных операций может распространяться (предопределенное) исключение с учетом следующих правил:
С целью установления, одинаков ли результат выполнения некоторых действий в каноническом или в альтернативном порядках, можно предположить, что ни одна из вызванных этими действиями предопределенных операций не распространяет (предопределенное) исключение, и при этом выполняются два следующих требования к реализации альтернативного порядка: во-первых, операция не должна вызываться в альтернативном порядке, если она не вызывается в каноническом порядке; во-вторых, самое внутреннее объемлющее окружение или оцератор принятия для каждой операции должны быть одинаковы для канонического и альтернативного порядков с теми же самыми обработчиками исключений.
Связь знаков операций с операндами в выражении определена синтаксисом. Однако для последовательности предопределенных операций с одним и тем же приоритетом (при отсутствии скобок, вводящих особые связи) эти связи могут быть изменены (и это допускается) при выполнении следующего требования: результат целого типа должен быть эквивалентен результату вычислений в каноническом порядке слева направо; результат вещественного типа должен принадлежать модельному интервалу результата, полученного после выполнения в каноническом порядке слева направо (см. 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 => ТАБЛИЦА);
Примечание. Для некоторых реализаций может оказаться невозможным или слишком, дорогим подавление некоторых проверок, тогда соответствующая прагма SUPPRESS может быть проигнорирована. Следовательно, наличие такой прагмы внутри данного модуля не гарантирует, что соответствующее исключение не будет возбуждено; эти исключения также могут распространяться вызванными модулями.
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;