Анимация
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

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); EmitCMOVE ); 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); EmitCMOVE DO,); WriteLn(Offset, (SP));

end;

{ Push The Primary Register to the Stack }

procedure Push;

begin

EmitLn(MOVE D0,-(SP));



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

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

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

{ 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;

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

ЧТО НЕПРАВИЛЬНО?

Тут вы могли бы подумать: Уверен, здесь должно быть что-то большее чем несколько сохранений и восстановлений из стека. Для передачи параметров здесь должно быть что-то большее чем тут есть.

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



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