<<
>>

Передача по значению

Давайте просто попробуем некоторые нехитрые вещи и посмотрим, куда они нас приведут. Давайте начнем со случая передачи по значению. Рассмотрим вызов процедуры:

FOO(X, Y)

Почти единственным приемлемым способом передачи данных является передача через стек ЦПУ.

Поэтому, код который мы бы хотели видеть сгенерированным мог бы выглядеть так:

MOVE X(PC),-(SP) ; Push X

MOVE Y(PC),-(SP) ; Push Y

BSR FOO ; Call FOO

Это конечно не выглядит слишком сложным!

Когда BSR выполнен центральный процессор помещает адрес возврата в стек и переходит к FOO. В этой точке стек будет выглядеть следующим образом:

.

.

Значение X (2 bytes)

Значение Y (2 bytes)

SP –> Адрес возврата (4 bytes)

Так что значения параметров имеют адреса с фиксированными смещениями от указателя стека. В этом примере адреса такие:

X: 6(SP)

Y: 4(SP)

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

PROCEDURE FOO(A, B)

BEGIN

A = B

END

(Помните, что имена формальных параметров произвольные...

учитываются только позиции).

Желаемый код мог бы выглядеть так:

FOO: MOVE 4(SP),D0

MOVE D0,6(SP)

RTS

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

Давайте начнем с объявления новой таблицы:

var Params: Array['A'..'Z'] of integer;

Нам также необходимо отслеживать, сколько параметров имеет данная процедура:

var NumParams: integer;

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

Вот инициализатор:

{–}

{ Initialize Parameter Table to Null }

procedure ClearParams;

var i: char;

begin

for i := 'A' to 'Z' do

Params[i] := 0;

NumParams := 0;

end;

{–}

Мы поместим обращение к этой процедуре в Init и также в конец DoProc:

{–}

{ Initialize }

procedure Init;

var i: char;

begin

GetChar;

SkipWhite;

for i := 'A' to 'Z' do

ST[i] := ' ';

ClearParams;

end;

{–}

.

.

.

{–}

{ Parse and Translate a Procedure Declaration }

procedure DoProc;

var N: char;

begin

Match('p');

N := GetName;

FormalList;

Fin;

if InTable(N) then Duplicate(N);

ST[N] := 'p';

PostLabel(N);

BeginBlock;

Return;

ClearParams;

end;

{–}

Обратите внимание, что вызов внутри DoProc гарантирует, что таблица будет чиста, когда мы в основной программе.

Хорошо, теперь нам нужны несколько процедур для работы с таблицей. Следующие несколько функций являются по существу копиями InTable, TypeOf и т.д.:

{–}

{ Find the Parameter Number }

function ParamNumber(N: char): integer;

begin

ParamNumber := Params[N];

end;

{–}

{ See if an Identifier is a Parameter }

function IsParam(N: char): boolean;

begin

IsParam := Params[N] 0;

end;

{–}

{ Add a New Parameter to Table }

procedure AddParam(Name: char);

begin

if IsParam(Name) then Duplicate(Name);

Inc(NumParams);

Params[Name] := NumParams;

end;

{–}

Наконец, нам понадобятся некоторые подпрограммы генерации кода:

{–}

{ Load a Parameter to the Primary Register }

procedure LoadParam(N: integer);

var Offset: integer;

begin

Offset := 4 + 2 * (NumParams – N);

Emit('MOVE ');

WriteLn(Offset, '(SP),D0');

end;

{–}

{ Store a Parameter from the Primary Register }

procedure StoreParam(N: integer);

var Offset: integer;

begin

Offset := 4 + 2 * (NumParams – N);

Emit('MOVE D0,');

WriteLn(Offset, '(SP)');

end;

{–}

{ Push The Primary Register to the Stack }

procedure Push;

begin

EmitLn('MOVE D0,-(SP)');

end;

{–}

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

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

Давайте начнем с обработки формальных параметров.

Все что мы должны сделать – добавить каждый параметр в таблицу идентификаторов параметров:

{–}

{ Process a Formal Parameter }

procedure FormalParam;

begin

AddParam(GetName);

end;

{–}

Теперь, что делать с формальными параметрами, когда они появляются в теле процедуры? Это требует немного больше работы. Мы должны сначала определить, что это формальный параметр. Чтобы сделать это, я написал модифицированную версию TypeOf:

{–}

{ Get Type of Symbol }

function TypeOf(n: char): char;

begin

if IsParam(n) then

TypeOf := 'f'

else

TypeOf := ST[n];

end;

{–}

(Обратите внимание, что так как TypeOf теперь вызывает IsParam, возможно будет необходимо изменить ее местоположение в программе.)

Мы также должны изменить AssignOrProc для работы с этим новым типом:

{–}

{ Decide if a Statement is an Assignment or Procedure Call }

procedure AssignOrProc;

var Name: char;

begin

Name := GetName;

case TypeOf(Name) of

' ': Undefined(Name);

'v', 'f': Assignment(Name);

'p': CallProc(Name);

else Abort('Identifier ' + Name + ' Cannot Be Used Here');

end;

end;

{–}

Наконец, код для обработки операции присваивания и выражения должен быть расширен:

{–}

{ Parse and Translate an Expression }

{ Vestigial Version }

procedure Expression;

var Name: char;

begin

Name := GetName;

if IsParam(Name) then

LoadParam(ParamNumber(Name))

else

LoadVar(Name);

end;

{–}

{ Parse and Translate an Assignment Statement }

procedure Assignment(Name: char);

begin

Match('=');

Expression;

if IsParam(Name) then

StoreParam(ParamNumber(Name))

else

StoreVar(Name);

end;

{–}

Как вы можете видеть, эти процедуры обработают каждое встретившееся имя переменной или как формальный параметр или как глобальную переменную, в зависимости от того, появляется ли оно в таблице идентификаторов параметров. Запомните, что мы используем только остаточную форму Expression. В конечной программе изменения, показанные здесь, должны быть добавлены в Factor а не Expression.

Осталось самое простое. Мы должны только добавить семантику в фактический вызов процедуры, что мы можем сделать с помощъю одной новой строки кода:

{–}

{ Process an Actual Parameter }

procedure Param;

begin

Expression;

Push;

end;

{–}

Так вот. Добавьте эти изменения в вашу программу и испытайте ее. Попробуйте объявить одну или две процедуры, каждая со списком формальных параметров. Затем сделайте какие-нибудь присваивания, используя комбинации глобальных и формальных параметров. Вы можете вызывать одну процедуру из другой, но вы не можете объявлять вложенные процедуры. Вы можете даже передавать формальные параметры из одной процедуры в другую. Если бы мы имели здесь полный синтаксис языка, вы могли бы также читать и выводить формальные параметры или использовать их в сложных выражениях.

<< | >>
Источник: Креншоу Джек. Давайте создадим компилятор!. 1999

Еще по теме Передача по значению:

  1. § 29 Передача и переход прав по обязательствам. – Римская конструкция права передачи. – Облегчение передачи новейшим законодательством. – Передаточная надпись. – Ограничения передачи. – Действие передачи. – Ответственность передатчика и права приобретателя. – Вступление в право кредитора или суброгация. – Русский закон передачи. – Передача заемных писем. – Переход требований к кредиторам.
  2. § 24 Особое значение целого семейства в торгующем купечестве и в бывших податных сословиях. – Финансовое и хозяйственное значение семейного раздела. – Особое значение семейства в отправлении рекрутской повинности. – Семейная община у Индусов.
  3. Интервью с официальными лицами или представителями их пресс-служб чреваты двумя проблемами: опасностью невольного искажения информации при передаче, интерпретации фактов, а также передачей намеренно дозированных сведений.
  4. § 8 Значение формы в договоре. – Римская стипуляция и правила иностранных законодательств. – Историческое значение формы в русском законодательстве. – Правила о совершении актов. – Отсутствие руководящего начала. – Колебания судебной прак- тики и наклонность ее к формализму. – Значение явки в актах договора. – Домашние акты. – Словесные соглашения. – Можно ли доказывать их свидетелями? – Гербовый сбор.
  5. § 77 Предмет авторского права. – Литературное произведение. – Речи и чтение. – Журнальные статьи. – Художественное про- изведение. – Особенное значение формы. – Воспроизведение. – Музыкальное, драматическое, архитектурное произведение. – Удостоверение художественной собственности. – Владетель авторского права. – Совокупное право. – Аноним и псевдоним. – Передача авторского права. – Договор об уступке. – Издание журнальных статей и частной корреспонденции. – Издание художественных произведений
  6. § 40 Условия об очистках. – Понятие об очистке (garantie). – Практическое значение иска об очистке. Особенное значение вотчинной очистки (gar. reelle)
  7. § 3 Содержание обязательства. – Положительное и отрицательное. – Обязательство дать или исполнить. – Взаимное обязательство. – Нераздельные и делимые обязательства. – Действие возможное и невозможное; известное и неизвестное. – Разделительное обязательство и значение выбора. – Определение предмета родом, видом и особью. – Значение денег.
  8. § 45 Договор о найме имуществ. – Предмет его. – Плата. – Отношение сторон. – Обязанность хозяина. – Передача. – Поддержание имущества. – Обязанности наемщика и права его. – Сублокация. – Эмфитевтическое пользование и бессрочный наем. – Право отказа. – Значение владения в найме и отношение его к праву собственности. – Действие давности. – Возобновление найма. – Ограждение наемщика и хозяина особым процессом. – Отношение найма к узуфрукту. – Наем земельный. – Правила арендных договоров. – Наем изп
  9. § 37 История вотчинной записки в России. – Явка актов в приказах. – Справка. – Юридическое и финансовое ее значение. – Аналогия нашей формы с западными. – Изменение старой формы при Петре I. – Новый крепостной порядок и новое значение справки и отказа. – Форма нового отказа и ввода во владение
  10. § 84 Значение писцовых книг и межевых актов по делам специального межевания и отношение их к вотчинному праву. – Может ли разрешенный по межевым правилам вопрос о владении внутри общей дачи служить к предосужде- нию вотчинного права? – Случаи, в коих требуются доводы от перводачников. – Нынешнее значение писцовых книг как доказательства в делах вотчинных
  11. Замысел передачи
  12. § 83 Историческое значение писцовых книг. – Писцовые книги как доказательство по межевым делам. – Отношение межевых доказательств к вотчинным. – Могут ли межевые акты служить к предосуждению вотчинных прав? Значение межевых актов и планов в спорных вотчинных делах. – Общее замечание об отношении вотчинного права к межевому
  13. ПЕРЕДАЧА СЦЕНАРИЯ
  14. ПЕРЕДАЧА СЦЕНАРИЯ
  15. ПЕРЕДАЧА СВЕТА.
  16. Музыкальные концертно-постановочные передачи
  17. Корреспонденция («передача»)
  18. § 3. Направленность на передачу имущества в собственность
  19. Получение Передачи