Чтение онлайн

на главную - закладки

Жанры

Давайте создадим компилятор!
Шрифт:

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

BEGIN { of MAIN }

Это всегда казалось мне немного клуджем. Возникает вопрос: Почему обработка основной программы должна так отличаться от обработки процедур? Теперь, когда мы осознали, что объявление процедур это просто... часть глобальных объявлений... не является ли основная программа также просто еще одним объявлением?

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

более ортогональным. Я предлагаю использовать для идентификации основной программы явное ключевое слово PROGRAM (Заметьте, что это означает, что мы не можем начать с него файл, как в Паскале). В этом случае наша БНФ становится:

<declaration> ::= <data decl> | <procedure> | <main program>

<procedure> ::= PROCEDURE <ident> <begin-block>

<main program> ::= PROGRAM <ident> <begin-block>

Код также смотрится намного лучше, по крайней мере в том смысле, что DoMain и DoProc выглядят более похоже:

{–}

{ Parse and Translate a Main Program }

procedure DoMain;

var N: char;

begin

Match('P');

N := GetName;

Fin;

if InTable(N) then Duplicate(N);

Prolog;

BeginBlock;

end;

{–}

.

.

.

{–}

{ Parse and Translate Global Declarations }

procedure TopDecls;

begin

while Look <> '.' do begin

case Look of

'v': Decl;

'p': DoProc;

'P': DoMain;

else Abort('Unrecognized Keyword ' + Look);

end;

Fin;

end;

end;

{–}

{ Main Program }

begin

Init;

TopDecls;

Epilog;

end.

{–}

Так как объявление основной программы теперь внутри цикла TopDecl, возникают некоторые трудности. Как мы можем гарантировать, что она – последняя в файле? И выйдем ли мы когда либо из цикла? Мой ответ на второй вопрос, как вы можете видеть, – в том, чтобы вернуть нашего старого друга точку. Как только синтаксический анализатор увидит ее дело сделано.

Ответ на первый вопрос: он зависит от того, насколько мы хотим защищать программиста от глупых ошибок. В коде, который я показал, нет ничего, предохраняющего программиста от добавления кода после основной программы... даже другой основной программы. Код просто не будет доступен. Однако, мы могли бы обращаться к нему через утверждение FORWARD, которое мы предоставим позже. Фактически, многие программисты на ассемблере любят использовать область сразу после программы для объявления больших, неинициализированных блоков данных, так что действительно может быть некоторый смысл не требовать, чтобы основная программа была последней. Мы оставим все как есть.

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

Вызов процедуры

Если вы удовлетворены работой программы, давайте обратимся ко второй половине уравнения... вызову.

Рассмотрим БНФ для вызова процедуры:

<proc_call> ::= <identifier>

с другой стороны БНФ для операции присваивания:

<assignment> ::= <identifier> '=' <expression>

Кажется у нас проблема.

Оба БНФ утверждения с правой стороны начинаются с токена <identifier>. Как мы предполагаем узнать, когда мы видим идентификатор, имеем ли мы вызов процедуры или операцию присваивания? Это похоже на случай, когда наш синтаксический анализатор перестает быть предсказывающим и действительно это точно такой случай. Однако, оказывается эту проблему легко решить, так как все, что мы должны сделать – посмотреть на тип идентификатора записанный в таблице идентификаторов. Как мы обнаружили раньше, небольшое локальное нарушение правила предсказывающего синтаксического анализа может быть легко обработано как специальный случай.

Вот как это делается:

{–}

{ Parse and Translate an Assignment Statement }

procedure Assignment(Name: char);

begin

Match('=');

Expression;

StoreVar(Name);

end;

{–}

{ 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': Assignment(Name);

'p': CallProc(Name);

else Abort('Identifier ' + Name +

' Cannot Be Used Here');

end;

end;

{–}

{ Parse and Translate a Block of Statements }

procedure DoBlock;

begin

while not(Look in ['e']) do begin

AssignOrProc;

Fin;

end;

end;

{–}

Как вы можете видеть, процедура Block сейчас вызывает AssignOrProc вместо Assignment. Назначение этой новой процедуры просто считать идентификатор, определить его тип и затем вызвать процедуру, соответствующую этому типу. Так как имя уже прочитано, мы должны передать его в эти две процедуры и соответственно изменить Assignment. Процедура CallProc – это просто подпрограмма генерации кода:

{–}

{ Call a Procedure }

procedure CallProc(N: char);

begin

EmitLn('BSR ' + N);

end;

{–}

Хорошо, к этому моменту у нас есть компилятор, который может работать с процедурами. Стоить отметить, что процедуры могут вызывать процедуры с любой степенью вложенности. Так что, даже хотя мы и не разрешаем вложенные объявления, нет ничего, чтобы удерживало нас от вложенных вызовов, точно так, как мы ожидали бы на любом языке. Мы получили это и это было не слишом сложно, не так ли?

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

Передача параметров

Снова, все мы знаем основную идею передачи параметров, но давайте просто для надежности разберем ее заново.

Вообще, процедуре предоставляется список параметров, например:

PROCEDURE FOO(X, Y, Z)

В объявлении процедуры параметры называются формальными параметрами и могут упоминаться в теле процедуры по своим именам. Имена, используемые для формальных параметров в действительности произвольны. Учитывается только позиция. В примере выше имя 'X' просто означает «первый параметр» везде, где он используется.

Поделиться:
Популярные книги

Любовь Носорога

Зайцева Мария
Любовные романы:
современные любовные романы
9.11
рейтинг книги
Любовь Носорога

Лекарь для захватчика

Романова Елена
Фантастика:
попаданцы
историческое фэнтези
фэнтези
5.00
рейтинг книги
Лекарь для захватчика

Кротовский, не начинайте

Парсиев Дмитрий
2. РОС: Изнанка Империи
Фантастика:
городское фэнтези
попаданцы
альтернативная история
5.00
рейтинг книги
Кротовский, не начинайте

Новый Рал 3

Северный Лис
3. Рал!
Фантастика:
попаданцы
5.88
рейтинг книги
Новый Рал 3

Сердце Дракона. Том 10

Клеванский Кирилл Сергеевич
10. Сердце дракона
Фантастика:
фэнтези
героическая фантастика
боевая фантастика
7.14
рейтинг книги
Сердце Дракона. Том 10

Я – Стрела. Трилогия

Суббота Светлана
Я - Стрела
Любовные романы:
любовно-фантастические романы
эро литература
6.82
рейтинг книги
Я – Стрела. Трилогия

Имперец. Земли Итреи

Игнатов Михаил Павлович
11. Путь
Фантастика:
героическая фантастика
боевая фантастика
5.25
рейтинг книги
Имперец. Земли Итреи

Блуждающие огни 4

Панченко Андрей Алексеевич
4. Блуждающие огни
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Блуждающие огни 4

Книга 4. Игра Кота

Прокофьев Роман Юрьевич
4. ОДИН ИЗ СЕМИ
Фантастика:
фэнтези
боевая фантастика
рпг
6.68
рейтинг книги
Книга 4. Игра Кота

Наследник 2

Шимохин Дмитрий
2. Старицкий
Фантастика:
попаданцы
альтернативная история
фэнтези
5.75
рейтинг книги
Наследник 2

Расческа для лысого

Зайцева Мария
Любовные романы:
современные любовные романы
эро литература
8.52
рейтинг книги
Расческа для лысого

Кодекс Крови. Книга VI

Борзых М.
6. РОС: Кодекс Крови
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Кодекс Крови. Книга VI

Клан

Русич Антон
2. Долгий путь домой
Фантастика:
боевая фантастика
космическая фантастика
5.60
рейтинг книги
Клан

Истинная со скидкой для дракона

Жарова Анита
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Истинная со скидкой для дракона