Читаем Давайте создадим компилятор! полностью

(Помните, что имена формальных параметров произвольные... учитываются только позиции).

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

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;

{–}

Перейти на страницу:

Похожие книги

Разработка приложений в среде Linux. Второе издание
Разработка приложений в среде Linux. Второе издание

Книга известных профессионалов в области разработки коммерческих приложений в Linux представляет СЃРѕР±РѕР№ отличный справочник для широкого круга программистов в Linux, а также тех разработчиков на языке С, которые перешли в среду Linux из РґСЂСѓРіРёС… операционных систем. РџРѕРґСЂРѕР±но рассматриваются концепции, лежащие в основе процесса создания системных приложений, а также разнообразные доступные инструменты и библиотеки. Среди рассматриваемых в книге вопросов можно выделить анализ особенностей применения лицензий GNU, использование СЃРІРѕР±одно распространяемых компиляторов и библиотек, системное программирование для Linux, а также написание и отладка собственных переносимых библиотек. Р

Майкл К. Джонсон , Эрик В. Троан

Программирование, программы, базы данных