
111
9. Вид сверху
ВВЕДЕНИЕ
В предыдущих главах мы изучили многие из методов, необходимых для создания
полноценного компилятора. Мы разработали операции присваивания (с булевыми и
арифметическими выражениями), операторы отношений и управляющие конструкции. Мы
все еще не обращались к вопросу вызова процедур и функций, но даже без них мы могли
бы в принципе создать мини-язык. Я всегда думал, что было бы забавно просто
посмотреть, насколько маленьким можно было бы построить язык, чтобы он все еще
оставался полезным. Теперь мы уже почти готовы сделать это. Существует проблема:
хотя мы знаем, как анализировать и транслировать конструкции, мы все еще совершенно
не знаем, как сложить их все вместе в язык.
В этих ранних главах разработка наших программ имела явно восходящий характер. В
случае с синтаксическим анализом выражений, например, мы начали с самых
низкоуровневых конструкций, индивидуальных констант и переменных и прошли свой
путь до более сложных выражений.
Большинство людей считают, что нисходящий способ разработки лучше, чем
восходящий. Я тоже так думаю, но способ, который мы использовали, казался
естественно достаточным для тех вещей, которые мы анализировали.
Тем не менее вы не должны думать, что последовательный подход, который мы
применяли во всех этих главах, является принципиально восходящим. В этой главе я
хотел бы показать вам, что этот подход может работать точно также, когда применяется
сверху вниз... может быть даже лучше. Мы рассмотрим языки типа C и Pascal и увидим
как могут быть построены законченные компиляторы начиная сверху.
В следующей главе мы применим ту же самую методику для создания законченного
транслятора подмножества языка KISS, который я буду называть TINY. Но одна из моих
целей в этой серии состоит в том, чтобы вы не только могли увидеть как работает
компилятор для TINY или KISS, но чтобы вы также могли разрабатывать и создавать
компиляторы своих собственных языков. Примеры Си и Паскаля помогут вам в этом.
Одна вещь, которую я хотел чтобы вы увидели, состоит в том, что естественная структура
компилятора очень сильно зависит от транслируемого языка, поэтому простота и легкость
конструирования компилятора очень сильно зависит от того, позволите ли вы языку
определять структуру программы.
Немного сложнее получить полный компилятор C или Pascal, да мы и не будем. Но мы
можем расчистить верхние уровни так, чтобы вы увидели как это делается.
Давайте начнем.
ВЕРХНИЙ УРОВЕНЬ
Одна из самых больших ошибок людей при нисходящем проектировании заключается
в неправильном выборе истинной вершины. Они думают, что знают какой должна быть
общая структура проекта и поэтому они продолжают и записывают ее.
Всякий раз, когда я начинаю новый проект, я всегда хочу сделать это в самом начале.
На языке разработки программ (program design language - PDL) этот верхний уровень
походит на что-нибудь вроде:
begin
solve the problem
end
Конечно, я соглашусь с вами, что это не слишком большая подсказка о том, что
расположено на следующем уровене, но я все равно запишу это просто для того, чтобы
почувствовать, что я действительно начинаю с вершины.
В нашем случае, общая функция компилятора заключается в компиляции законченной
программы. С этого начинается любое определение языка, записанное в БНФ. На что