Выбрать главу

27. Мал золотник,

или...

КОМПИЛЯТОР ДЛЯ АЛГЕБРАИЧЕСКОГО ЯЗЫКА

Компилятор — это всегда большая программа. Написать его, практически на пустом месте, даже под опекой преподавателей вовсе не просто. И хотя при создании Мини ставилась цель свести все муки к минимуму, во всяком случае, в той мере, в какой это позволяло его просветительское назначение, предлагаемая задача все же оказалась самой трудной в книге. Если вы (и ваши верные друзья) не обладаете достаточной энергией и временем, то не стоит за нее и браться.

Язык Мини

Мини — универсальный, процедурный, алгебраический язык программирования. Он уходит своими корнями в Алгол, Алгол 68 и Паскаль. Подобно этим языкам, Мини предназначен для компиляции, загрузки и выполнения на обычных ЭВМ (хорошим примером такой машины служит УМ-1, см. гл. 25). Синтаксис задается контекстно-свободной грамматикой, пригодной для разбора методами LRA). Семантика аналогична алгольной и паскалевой, и нам кажется достаточным ее неформальное описание. Квалификация читателя позволит ему домыслить все недосказанное[54]. Ниже приведены логически связанные части грамматики и их семантика.

Единицы компиляции

<единица компиляции>::=<программный сегмент>

| <единица компиляции> <программный сегмент>

<программный сегмент>::= <главная программа>

| <внешняя процедура>

<Единица компиляции> — это цепочка замкнутых <программных сегментов>[55]. Каждый <программный сегмент> есть либо <главная программа>, либо <внешняя процедура>. Все сегменты <единицы компиляции> свяжет друг с другом загрузчик, однако не обязательно, чтобы все сегменты, нужные для полной загрузки, компилировались вместе. При загрузке должна присутствовать ровно одна <главная программа>.

Программы

<главная программа> ::= <заголовокпрограммы><тело программы> <конец программы>

<заголовок программы>::= PROGRAM <идентификатор>

<тело программы>::= <тело сегмента>

<конец программы>::= END PROGRAM <идентификатор>;

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

Внешние процедуры

 <внешняя процедура> ::= <внешняя подпрограмма>

| <внешняя функция>

<внешняя подпрограмма> ::= <заголовок внешней подпрограммы>:

<тело внешней подпрограммы>

<конец внешней подпрограммы>

<внешняя функция> ::= <заголовок внешней функции>:

<тело внешней функции> <конец внешней функции>

<заголовок внешней подпрограммы> ::= EXTERNAL PROCEDURE <имя внешней процедуры>

<заголовок внешней функции>::= EXTERNAL FUNCTION <имя внешней процедуры>

<внешний тип>

<имя внешней процедуры> ::= <идентификатор>

| <идентификатор> <список внешних параметров>

<список внешних параметров>::= <заголовок внешних параметров>)

<заголовок внешних параметров>::= (<внешний параметр>

| <заголовок внешних параметров>, <внешний параметр>

<внешний параметр>::= <идентификатор> <внешний тип>

| <идентификатор> <внешний тип> NAME

<внешний тип>::= <базовый тип>

<тело внешней подпрограммы>::= <тело сегмента>

<тело внешней функции>::= <тело сегмента>

<конец внешней подпрограммы>::= END EXTERNAL PROCEDURE <идентификатор>;

<конец внешней функции>::= END EXTERNAL FUNCTION <идентификатор>;

<Внешние процедуры> позволяют компилировать модули раздельно и собирать их вместе во время загрузки. При загрузке допускается лишь одна <внешняя процедура> с данным именем. <Внешние параметры> и возвращаемые <внешними функциями> значения должны иметь <базовый тип>. <Внешние параметры> передаются по значению, если они не помечены резервированным словом NAME; при наличии этого слова параметры передаются по имени. Перед <концом внешней подпрограммы> неявно располагается <инструкция возврата>, однако <внешние функции> должны завершать работу явной <инструкцией возврата> с возвращаемым значением; попытка выхода из <внешней функции> через <конец внешней функции> является семантической ошибкой, которую иногда можно обнаружить при компиляции. Единственной связью между переменными <внешней процедуры> и переменными вызывающей процедуры служит механизм передачи параметров. Однако во время сборки сегментов (например, с помощью загрузчика, подобного описанному в гл. 26) будет проверено совпадение типов формальных и фактических параметров, функций и возвращаемых значений.

вернуться

54

Стиль последующего изложения показывает, сколь высоко оценивает автор квалификацию своих читателей. — Прим. перев.

вернуться

55

В русском переводе приходится склонять нетерминальные символы грамматики. — Прим. перев.