Лекции по построению компилятора на Pascal
компилятор Паскаля, разработанный для IBM PC должен выполняться на 64k машинах.
Компиляторы, разработанные на курсах Computer Science, должны были компилировать
широкий диапазон языков и следовательно требовали LALR синтаксических анализаторов.
В каждом из этих случаев эти предвзятые ограничения буквально доминировали над
проектом компилятора.
Хороший пример - компилятор Бринч Хансена, описанный в его превосходной книге "Brinch
Hansen on Pascal Compilers" (строго рекомендую). Хотя его компилятор один из самых ясных
и незатемненных реализаций компилятора, что я видел, одно решение, компилировать
большие файлы в небольшом ОЗУ, полностью управляло дизайном и он закончил не на
одном а многих промежуточных файлах, как и управляющими ими программах для их
записи и считывания.
Временами, архитектуры, возникающие из таких решений, находили свое место в учениях
компьютерной науки и принимались на веру. По мнению одного человека, пришло время
чтобы они были критически пересмотрены. Условия, требования, среды, которые вели к
классическим архитектурам не такие же, какие мы имеем сейчас. Нет никакой причины
полагать, что решения тоже должны быть те же самыми.
В этой обучающей серии мы следовали по шагам таких пионеров в мире маленьких
компиляторов для PC как Леор Золман, Рон Каин и Джеймс Хендрих, тех кто не знал
достаточно теорию компиляции чтобы знать, что они "не могли делать это таким способом".
Мы решительно отказались принимать произвольные ограничения, а скорее делали так, как
было проще В результате мы развили архитектуру, которая, хотя и совершенно отлична от
классической,] делает работу простым и прямым способом.
Я закончу эти философствования обзором понятия промежуточного языка. Хотя я отметил
перед этим, что мы не имеем его в нашем компиляторе, это не совсем точно; у] нас он есть,
или по крайней мере мы развиваем его, в том смысле, что мы определяем функции генерации
кода для вызова из парсера. В сущности, каждый вызов процедуры генерации кода можно
рассматривать как инструкцию на промежуточном языке. Если мы когда либо найдем
необходимым формализировать промежуточный язык, вот способ, которым бы мы сделали
это: выдать кода из синтаксического анализатора, представляющие собой вызовы процедур
генератора кода, а затем обработать каждый код вызывая эти процедуры в отдельном
проходе, реализованном в "back end". Откровенно говоря, я не вижу, что мы когда либо
найдем потребность в таком подходе, но это связь, если вы решите следовать ему, между
классическим и текущим подходами.
РАСШИРЕНИЕ СИНТАКСИЧЕСКОГО АНАЛИЗАТОРА
Хотя я обещал вам где-то в Главе 14, что мы никогда снова не будем переписывать каждую
одиночную функцию заново, я начал делать это с Главы 15. Единственная причина: эта
длинная пауз между двумя главами делала обзор кажущимся чрезвычайно оправданным...
даже необходимым и для вас и для меня. Более важно, решение собрать процедуры в модули
заставило нас взглянуть на каждую из них снова, хотели мы этого или нет. И, наконец,
откровенно говоря, за последние четыре года у меня появились некоторые новые идеи,
которые гарантировали свежий взгляд на некоторые старые вещи. Когда я с начала начал эту
серию я был искренне поражен и обрадован, узнав насколько простыми могут быть сделаны
подпрограммы анализа. Но в этот последний раз я удивил сам себя снова и был способен
делать их точно также, но даже немного проще.
Однако, из-за тотального переписывания модулей синтаксического анализа я не был только
способен включить многого в последнюю главу. Из-за этого наш герой, синтаксический
анализатор, когда мы последний раз его видели, был только тенью себя прежнего,
содержащий только код, достаточный для анализа и обработки показателя состоящего или из
переменной или константы. Основным достижением этой текущей главы должно стать
восстановление синтаксического анализатора в его прежней славе. В этом процессе, я