8.4. ВЫЗОВ ПРОЦЕДУРЫ
397
e) порождение и завершение экземпляров строго соответствует стековой дис-
циплине: “первым порожден — последним завершен”.
Возможности, соответствующие механизму рекурсивного вызова, у нашего
абстрактного вычислителя имеются: это запоминание всего локального кон-
текста на стеке и порождение нового контекста, которое можно трактовать
как порождение нового экземпляра рекурсивно запускаемой подпрограммы.
Возможность одновременного существования нескольких экземпляров од-
ной и той же процедуры или функции в динамике выполнения программы,
при условии выполнения только что перечисленных требований, можно рас-
сматривать в качестве определения рекурсивности этой процедуры или функ-
ции.
При определении абстрактных вычислений было бы неправильно тракто-
вать вызов процедуры как преобразование дерева абстрактного синтаксиса:
замена конструкции вызова процедуры деревом, представляющим ее тело.
Причина не в том, что при этом необходимо оперировать потенциально бес-
конечными графами (например, при раскрытии рекурсивных вызовов): это
вполне реализуемо, поскольку в семантически правильной программе рекур-
сия всегда конечна. Серьезным доводом против трактовки вызова как заме-
ны является растворение экземпляра процедуры в дереве программы и, как
следствие, невозможность оперирования с экземплярами. А оперирование с
экземплярами процедур, в том числе и не ограничивающее себя рамками сте-
ка, — исключительно важный момент
10
.
Однако,как всегда,нецелесообразность некоторого решения в общем слу-
чае не означает его нецелесообразности в частных. Например, в языке
C/C++
имеются встраиваемые процедуры (
inline
-процедуры), семантика вызова ко-
торых — именно прямая текстовая подстановка
11
тела процедуры вместо
конструкции вызова.
Осознав, что абстрактный вычислитель должен порождать именно экзем-
пляры процедур,необходимо далее ответить на вопрос,как запоминать экзем-
пляры, становящиеся временно пассивными, и как их активизировать, когда
10
Надо заметить, что в языке
Algol 60
было принято именно подстановочное определение
семантики вызова. Неудобства, связанные с таким определением, выявились в работах по
реализации
Algol 60
, и стимулировали осознание концепции контекста.
11
Как всегда, такое определение некорректно, и некорректность явно оговорена в семан-
тике, в частности, языка
C++
: правила локализации имен для встраиваемой и обычной про-
цедур одни и те же, и в этом главное отличие встраиваемых процедур от препроцессорных
определений.