Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Pascal_Unkn.doc
Скачиваний:
8
Добавлен:
03.11.2018
Размер:
1.63 Mб
Скачать

Объявления

Очевидно на следующем шаге необходимо решить, что мы подразумеваем под объявлением. Я намереваюсь иметь два вида объявлений: переменных и процедур/функций. На верхнем уровне разрешены только глобальные объявления, точно как в C.

Сейчас здесь могут быть только объявления переменных, идентифицируемые по ключевому слову VAR (сокращенно "v").

     <top-level decls> ::= ( <data declaration> )*

     <data declaration> ::= VAR <var-list>

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

Процедура Prog становится:

{--------------------------------------------------------------}

{  Parse and Translate a Program }

procedure Prog; 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, попробуйте список из нескольких переменных в одной строке и комбинации этих двух.

Работает?

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]