Анимация
JavaScript
|
Главная Библионтека Основная идея состоит в том, чтобы отслеживать количество локальных параметров. Затем мы используем это число в инструкции 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 |