Компилятор пишется так...М. Черкашин Журнал "Монитор" № 4 1992 год Писать компилятор приходится чаще, чем обычно
думают. Практически всякая большая система включает
в себя входной язык -
от
Чтобы писать сложные, эффективные и быстрые компиляторы,
есть много рецептов. Но здесь речь пойдет
не о них. Как написать компилятор
Оптимизацию и генерацию кода мы рассматривать не будем.
Оптимизация - тема для отдельной статьи,
а генерация кода - занятие для
|
|
Так
и делаем. Время компиляции, конечно, увеличивается, но зато мы избавляемся от большого количества неприятной возни. Модельный компилятор Лучший способ понять, как писать компилятор - написать
его самому. Лучший способ объяснить это - предъявить
текст программы. Вот мы и
Наш модельный компилятор состоит из четырех частей:
сканер, блок таблиц имен, основная часть
компилятора и
И, наконец, основная часть компилятора
...компилирует. Точнее, следит за ходом компиляции.
Как только становится ясно, с какой
Сканер Среди всех конструкций,
воспринимаемых компилятором, есть минимальные,
и которые уже не исеет смысла делить на части. Например:
|
|
В языке SIMPLE существуют пять
видов лексем (pис.2): ключевые слова, идентификаторы,
числа, спецсимволы и нечто в
квадратных
Посмотрим на текст программы (Пример 1. Сканер). Основная
процедура сканера - Scan. Вызывая ее, мы получаем очередную
лексему. Мы можем
Обратим внимание на вспомогательные
процедуры GetCh и UngetCh. Процедура GetCh заменяет сиволы
перевода строки и табуляции на пробелы
|
Таблица имен Когда человек пишет свою программу
или разбирается в чужой, ему нужно держать в голове кое-какую информацию.
Но машина железная, у нее
С записями будет посложнее. Даже в голове
у нас они хранятся не целиком, а как нечто,
сложенное из кусочков. А к чему должно быть ближе то, что хранится
в таблице
Но в одну ячейку таблицы имен может поместиться информация
максимум об одной переменной. Поэтому сейчас
наша задача - "раскидать" по
|
|
В данном случае ссылка - просто номер ячейки таблицы имен, содержащей заголовок этого описания. Описание структуры записи представляет
собой заголовок и еще несколько - по одной на каждое поле -
ячеек. Каждая из этих ячеек
Первые MaxKey записей таблицы имен
на самом деле не имена, а ключевые слова. Имена и
ключевые слова вообще очень легко перепутать.
Для обращения к таблице имен
(Пример 2) предусмотрено всего трипроцедуры: поиск имени
в таблице, помещение имени в таблицу
и
|
Основной блок компилятора. К моменту, когда вы уже готовы сесть
и начать писать текст этого блока, вы должны знать,
что у вас делают остальные части (сканер,
Посмотрите на текст программы (Пример
3). Что должна делать основная часть? Читать
описания переменных и заполнать таблицу имен.
В описаниях основная проблема - это описания записей.
"Разобраться" с ними - значит поместить их в таблицу имен.
В данной программе это
Есть также определенные проблемы
и с трансляцией описаний. Оператор присваивания
или печати мы всегда можем считать целиком в
|
|
Куда идти дальше? У тех, кто дошел до этого места, возможно, возникнут вопросы. Я не берусь предугадать их все, но на некоторые можно ответить заранее. - Что еще нужно сделать, если с компилятором будут работать часто? - Необходимо вставить диагностику ошибок. На
практике компилятор в большинстве случаев выдает не
скомпилированный текст, а сообщение
- Как вставлять новые конструкции в язык? - Если речь идет о структурах данных, то лучше добавить
новое поле в запись таблицы имен, чем ломать
голову над тем, как сэкономить
- А если хочется все-таки сделать компилятор более эффективным? - Ради Бога! Только сначала пусть он заработает.
А потом его можно оптимизировать по вкусу.
Кроме того, прежде чем
применить
- Как отлаживать компилятор? - Компилятор - очень коварная программа.
И выловить все ошибки из него обычно не удается.
Не полагайтесь на свою интуицию. Сделайте
И напоследок еще один совет. Больше простоты! Если
бы программисты всегда ему следовали, то работающих
программ было бы несомненно
|
|
Пример 1. Сканер
procedure IniScan;
(*
(*
procedure KeyOrNames;
(* Считать число *)
(* Установить переменные LexType и LexVal
( Нечто в квадратных скобках **)
(* Вспомогательные подпрограммы для сканера *)
procedure UngetCh;
procedure NewLine;
Пример 2. Таблица имен. (**************************************)
procedure IniTab;
(* Найти переменную с данным именем *)
(* Создать новую запись таблицы имен
(* Если номер записи не больше MaxKey,
Пример 3. Основной блок компилдятора. Type EnumKey = (KeyProc, KeyMain, KeyEnd, KeyInt,
(* Скомпилировать одну процедуру *)
(* Обработать одно описание *)
(* Считать список имен переменных после описателя
(* Обработать поля записи *)
(* Dcl1 делает почти тоже, что и Declare,
(* Разница между NameList и NameList1 в том,
(* Скомпилировать все операторы в процедуре *)
(* Скомпилировать один оператор *)
(* Семантические подпрограммы *) (* If...then *)
(* Else *)
(* Print...*)
(* По первой лексеме нельзя отличить
(* While...do *)
(* Close *)
Краткий обзор языка SIMPLE Программа на языке SIMPLE есть:
Одна из процедур носит имя main.
Описание int список переменных через запятую;
Описание Присваивание: Имя := [....];
Ключевые слова
procedure then
Имена
Например:
Числа
Например:
Спецсимволы
:=
"Нечто в []"
Например:
|