Процедура или функция считается вложенной, когда она описы-
вается внутри другой процедуры или функции. По умолчанию вложен-
ные процедуры и функции всегда используют ближний тип вызова
(NEAR), поскольку они доступны только внутри определенной проце-
дуры или функции в том же сегменте кода. Однако в оверлейных за-
дачах обычно для того, чтобы обеспечить для всех процедур и функ-
ций дальний тип вызова (FAR), используется директива {$F+}.
При вызове вложенной процедуры или функции компилятор непос-
редственно перед инструкцией CALL генерирует инструкцию PUSH BP,
фактически передавая регистр BP вызывающей программы в качестве
дополнительного параметра. После того, как вызываемая процедура
установит свой собственный регистр BP, регистр ВР вызывающей про-
цедуры доступен, как слово, сохраненное в [BP+4] или в [BP+6]
(если процедура имеет дальний тип вызова). Используя связь через
[BP+4] и [BP+6], вызываемая процедура может получить доступ к ло-
B.Pascal 7 & Objects/LR - 392 -
кальным переменным в границах стека вызывающей процедуры. Следую-
щий пример показывает, как можно получить доступ к локальным пе-
ременным из оператора inline во вложенной процедуре:
procedure A; near;
var IntA: integer;
procedure B; far;
var IntB: integer;
procedure C; near;
var IntC: integer;
begin
inline(
$8B/$46// { MOV AX,[BP+IntC] ;AX = IntC }
$8B/$5E/$04/ { MOV BX,[BP+4] ;BX = стек В }
$36/$8b/$47// { MOV AX,SS:[BX+IntB] ;AX = IntB }
$8B/$5E/$04/ { MOV BX,[BP+4] ;BX = стек B }
$36/8B/$5F/$06/ { MOV BX,SS:[BX+6] ;BX = стек A }
$36/$8B/$47/); { MOV AX,SS:[BX+IntA] ;AX =IntA }
end;
begin C end;
begin B end;
Примечание: Вложенные процедуры и функции нельзя описы-
вать с помощью директивы external, и они не могут иметь па-
раметры процедурного типа.
Примечание: Блок inline в приведенном примере можно записать
также в виде:
begin
asm
MOV AX,[BP+IntC] { AX = IntC }
MOV BX,[BP+4] { BX = стек В }
MOV AX,SS:[BX+IntB] { AX = IntB }
MOV BX,[BP+4] { BX = кадр стек B }
MOV BX,SS:[BX+6] { BX = кадр стек A }
MOV AX,SS:[BX+IntA] { AX =IntA }
end;
end;