begin

Match('p');

Header;

TopDecls;

Main;

Match('.');

end;

{–}

Теперь добавьте две новые процедуры:

{–}

{ Process a Data Declaration }

procedure Decl;

begin

Match('v');

GetChar;

end;

{–}

{ Parse and Translate Global Declarations }

procedure TopDecls;

begin

while Look <> 'b' do

case Look of

'v': Decl;

else Abort('Unrecognized Keyword ''' + Look + '''');

end;

end;

{–}

Заметьте, что на данный момент Decl – просто заглушка. Она не генерирует никакого кода и не обрабатывает список... каждая переменная должна быть в отдельном утверждении VAR.

ОК, теперь у нас может быть любое число объявлений данных, каждое начинается с 'v' вместо VAR, перед блоком BEGIN. Попробуйте несколько вариантов и посмотрите, что происходит.

ОБЪЯВЛЕНИЯ И ИДЕНТИФИКАТОРЫ

Это выглядит довольно хорошо, но мы все еще генерируем только пустую программу. Настоящий ассемблер должен выдавать директивы ассемблера для распределения памяти под переменные. Пришло время действительно получить какой-нибудь код.

С небольшим дополнительным кодом это легко сделать в процедуре Decl. Измените ее следующим образом:

{–}

{ Parse and Translate a Data Declaration }

procedure Decl;

var Name: char;

begin

Match('v');

Alloc(GetName);

end;

{–}

Процедура Alloc просто выдает команду ассемблеру для распределения памяти:

{–}

{ Allocate Storage for a Variable }

procedure Alloc(N: char);

begin

WriteLn(N, ':', TAB, 'DC 0');

end;

{–}

Погоняйте программу. Попробуйте входную последовательность, которая объявляет какие-нибудь переменные, например:

pvxvyvzbe.

Видите, как распределяется память? Просто, да? Заметьте также, что точка входа «MAIN» появляется в правильном месте.

Кстати, «настоящий» компилятор имел бы также таблицу идентификаторов для записи используемых переменных. Обычно, таблица идентификаторов необходима для записи типа каждой переменной. Но так как в нашем случае все переменные имеют один и тот же тип, нам не нужна таблица идентификаторов. Оказывается, мы смогли бы находить идентификатор даже без различия типов, но давайте отложим это пока не возникнет такая необходимость.

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

БНФ для <var-list> следующая:

<var-list> ::= <ident> (, <ident>)*

Добавление этого синтаксиса в Decl дает новую версию:

{–}

{ Parse and Translate a Data Declaration }

procedure Decl;

var Name: char;

begin

Match('v');

Alloc(GetName);

while Look = ',' do begin

GetChar;

Alloc(GetName);

end;

end;

{–}

ОК, теперь откомпилируйте этот код и испытайте его. Попробуйте ряд строк с объявлениями VAR, попробуйте список из нескольких переменных в одной строке и комбинации этих двух. Работает?

ИНИЦИАЛИЗАТОРЫ

Пока мы работали с объявлениями данных, меня беспокоила одна вещь – то, что Pascal не позволяет инициализировать данные в объявлении. Эта возможность по общему признанию является своего рода излишеством, и ее может не быть в языке, который считается минимальным языком. Но ее также настолько просто добавить, что было бы позором не сделать этого. БНФ становится:

Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

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

Отметить Добавить цитату