Анимация
JavaScript
|
Главная Библионтека 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 |