Анимация
JavaScript


Главная  Библионтека 

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 [ 76 ] 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97

Основная идея состоит в том, чтобы отслеживать количество локальных параметров. Затем мы используем это число в инструкции LINK для корректировки указателя стека при выделения для них места. Формальные параметры адресуются как положительные смещения от указателя кадра а локальные как отрицательные смещения. С небольшой доработкой те же самые процедуры, которые мы уже создали, могут позаботиться обо всем этом.

Давайте начнем с создания новой переменной Base: var Base: integer;

Мы будем использовать эту переменную вместо NumParams для вычисления смещения стека. Это подразумевает изменение двух ссылок на NumParams в LoadParam и StoreParam:

{ Load a Parameter to the Primary Register } procedure LoadParam(N: integer); var Offset: integer; begin

Offset := 8 + 2 * (Base - N); EmitCMOVE ); WriteLn(Offset, (A6),D0);

end;

{ Store a Parameter from the Primary Register } procedure StoreParam(N: integer); var Offset: integer; begin

Offset := 8 + 2 * (Base - N); EmitCMOVE D0,); WriteLn(Offset, (A6));

end;

Идея состоит в том, что значение Base будет заморожено после того, как мы обработаем формальные параметры и не будет увеличиваться дальше когда новые, локальные, переменные будут вставлены в таблицу идентификаторов. Об этом позаботится код в конце FormalList:

{ Process the Formal Parameter List of a Procedure }

procedure FormalList;

begin

Match(();

if Look <> ) then begin FormalParam;

while Look = , do begin Match(,); FormalParam;

end;

end;

Match()); Fin;

Base := NumParams; NumParams := NumParams + 4;

end;

(Мы добавили четыре слова чтобы учесть адрес возврата и старый указатель кадра, который заканчивается между формальными параметрами и локальными переменными.)

Все что мы должны сделать дальше - это установить семантику объявления локальных переменных в синтаксическом анализаторе. Подпрограммы очень похожи на Decl и TopDecls:



{ Parse and Translate a Local Data Declaration } procedure LocDecl; var Name: char; begin

Match(v);

AddParam(GetName); Fin;

end;

{ Parse and Translate Local Declarations } function LocDecls: integer; var n: integer; begin

n := 0;

while Look = v do begin LocDecl; inc(n);

end;

LocDecls := n;

end;

Заметьте, что LocDecls является функцией, возвращающей число локальных переменных в DoProc. Затем мы изменим DoProc для использования этой информации:

{ Parse and Translate a Procedure Declaration } procedure DoProc; var N: char;

k: integer;

begin

Match(p);

N := GetName;

if InTable(N) then Duplicate(N);

ST[N] := p;

FormalList;

k := LocDecls;

ProcProlog(N, k);

BeginBlock;

ProcEpilog;

ClearParams;

end;

(Я сделал пару изменений, которые не были в действительности необходимы. Кроме небольшой реорганизации я переместил вызов Fin в FormalList а также в LocDecls. Не забудьте поместить его в конец FormalList.)

Обратите внимание на изменения при вызове ProcProlog. Новый параметр - это число слов (не байт) для распределения памяти. Вот новая версия ProcProlog:

{ Write the Prolog for a Procedure } procedure ProcProlog(N: char; k: integer); begin

PostLabel(N);

EmitCLINK A6,#); WriteLn(-2 * k)

end;

Сейчас должно работать. Добавьте эти изменения и посмотрите как они работают.



ЗАКЛЮЧЕНИЕ

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

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

Это будет следующая глава, которая появится ближе к Форуму.



0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 [ 76 ] 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97