Ада-95. Компилятор GNAT

       

Код элаборации


Стандарт Ada95 предусматривает общие правила выполнения кода в процессе элаборации (иначе, кода элаборации).

Обработка кода элаборации осуществляется в трех контекстах:

Инициализация переменных - Переменные, описанные на уровне библиотеки в спецификациях или телах пакетов, могут требовать инициализацию, которая выполняется в процессе элаборации:

Sqrt_Half : Float := Sqrt (0.5);

Инициализация пакетов - Код в секции begin - end, на внешнем уровне тела пакета, является кодом инициализации пакета, и выполняется как часть кода элаборации тела пакета.

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

Любой из этих контекстов допускает вызов подпрограмм.

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

Более того, существует возможность написания программы, вся работа которой осуществляется в процессе элаборации, при этом, головная прорамма - пуста.

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

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

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

Следовательно, важна правильность последовательности, в которой осуществляется выполнение этих секций.

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

Порядок элаборации не вызывает проблем, когда соблюдается следующее правило: элаборация спецификации и тела, каждого указанного в спецификаторе with модуля, осуществляется перед элаборацией модуля, который содержит такой спецификатор with.




Например:

with Unit_1; package Unit_2 is ...

В данном случае необходимо, чтобы элаборация спецификации и тела модуля Unit_1

осуществлялась перед спецификацией модуля Unit_2.

Однако, такое правило накладывает достаточно жесткие ограничения.

В частности, это делает невозможным наличие взаимно рекурсивных подпрограмм, которые распологаются в разных пакетах.

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

Рассмотрим следующий пример.

Тело модуля Unit_1

содержит подпрограмму Func_1, которая использует переменную Sqrt_1

описанную в коде элаборации тела Unit_1:

Sqrt_1 : Float := Sqrt (0.1);

Код элаборации тела модуля Unit_1 также содержит:

if expression_1 = 1 then

Q := Unit_2.Func_2; end if;

Существует также модуль Unit_2, структура которого аналогична: он содержит подпрограмму Func_2, которая использует переменную Sqrt_2

описанную в коде элаборации тела Unit_2:

Sqrt_2 : Float := Sqrt (0.1);

Код элаборации тела модуля Unit_2 также содержит:

if expression_2 = 2 then

Q := Unit_1.Func_1; end if;

Для показанных фрагментов кода суть вопроса заключена в выборе правильного порядка элаборации, то есть выбрать последовательность вида:

Spec of Unit_1 Spec of Unit_2 Body of Unit_1 Body of Unit_2

или последовательность вида:

Spec of Unit_2 Spec of Unit_1 Body of Unit_2 Body of Unit_1

При внимательном рассмотрении можно обнаружить, что ответить на этот вопрос во время компиляции не возможно.

Если выражение expression_1 не равно 1, а выражение expression_2 не равно 2, то можно использовать любую из показанных выше последовательностей элаборации, поскольку отсутствуют вызовы функций.

В случае, когда результаты обеих проверок истинны (true), не может быть использована ни одна из показанных последовательностей элаборации.

Если результат проверки одного условия истина (true), а другого - ложь (false), то одна из показанных последовательностей элаборации будет справедлива, а другая - нет.

Например, если expression_1 = 1 и expression_2 /= 2, то присутствует вызов Func_2, но нет вызова Func_1.

Это подразумевает, справедливость выполнения элаборации тела модуля Unit_1

перед элаборацией тела Unit_2, то есть первая последовательность элаборации правильна, а вторая - нет.

Если выражения expression_1 и expression_2

зависят от вводимых данных, то компилятор и/или редактор связей будут не в состоянии определить какое из условий будет истинным.

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


Содержание раздела