- •Глава 13 Основные
- •Определение компилятора. Отличие компилятора от транслятора
- •Определение интерпретатора. Разница между интерпретаторами и трансляторами
- •Назначение трансляторов, компиляторов и интерпретаторов. Примеры реализации
- •Этапы трансляции. Общая схема работы транслятора
- •Понятие прохода. Многопроходные и однопроходные компиляторы
- •Интерпретаторы. Особенности построения интерпретаторов
- •Трансляторы с языка ассемблера («ассемблеры»)
- •Реализация компиляторов с языка ассемблера
- •Макроопределения и макрокоманды
- •Простейшие методы построения таблиц идентификаторов
- •Построение таблиц идентификаторов по методу бинарного дерева
- •Построение таблиц идентификаторов на основе хэш-функций
- •Построение таблиц идентификаторов по методу цепочек
- •Комбинированные способы построения таблиц идентификаторов
- •Принципы построения лексических анализаторов
- •Определение границ лексем
- •Выполнение действий, связанных с лексемами
- •Построение лексических анализаторов
- •Автоматизация построения лексических анализаторов (программа lex)
- •Дерево разбора. Преобразование дерева разбора в дерево операций
- •1 Повтор того, что сказано до начала Шагов. — Примеч. Ред.
- •Автоматизация построения синтаксических анализаторов (программа yacc)
Автоматизация построения лексических анализаторов (программа lex)
Лексические распознаватели (сканеры) — это не только важная часть компиляторов. Лексический анализ применяется во многих других областях, связанных с обработкой текстовой информации на компьютере. Прежде всего, лексического анализа требуют все возможные командные процессоры и утилиты, требующие ввода командных строк и параметров пользователем. Кроме того, хотя бы самый примитивный лексический анализ вводимого текста применяют практически все современные текстовые редакторы и текстовые процессоры. Практически любой более-менее серьезный разработчик программного обеспечения рано или поздно сталкивается с необходимостью решать задачу лексического анализа (разбора)1.
C одной стороны, задачи лексического анализа имеют широкое распространение, а с другой — допускают четко формализованное решение на основе техники моделирования работы KA. Все это вместе предопределило возможность автоматизации решения данной задачи. И программы, ориентированные на ее решение,
C другой стороны, далеко не каждый разработчик, столкнувшись с этой задачей, понимает, что он имеет дело именно с лексическим анализом текста. Поэтому не всегда такие задачи решаются должным образом, в чем автор мог убедиться на собственном опыте.
не замедлили появиться. Причем поскольку математический аппарат KA известен уже длительное время, да и с задачами лексического анализа программисты столкнулись довольно давно, то и программам, их решающим, насчитывается не один десяток лет.
Для решения задач построения лексических анализаторов существуют различные программы. Наиболее известной среди них является программа LEX.
LEX — программа для генерации сканеров (лексических анализаторов). Входной язык содержит описания лексем в терминах регулярных выражений. Результатом работы LEX является программа на некотором языке программирования, которая читает входной файл (обычно это стандартный ввод) и выделяет из него последовательности символов (лексемы), соответствующие заданным регулярным выражениям.
История программы LEX тесно связана с историей операционных систем типа UNIX. Эта программа появилась в составе утилит OC UNIX и в настоящее время входит в поставку практически каждой OC этого типа. Однако сейчас существуют версии программы LEX практически для любой OC, в том числе для широко распространенной MS-DOS.
Поскольку LEX появилась в среде OC UNIX, то первоначально языком программирования, на котором строились порождаемые ею лексические анализаторы, был язык C. Ho со временем появились версии LEX, порождающие сканеры и на основе других языков программирования (например, известны версии для языка Pascal).
Принцип работы LEX достаточно прост: на вход ей подается текстовый файл, содержащий описания нужных лексем в терминах регулярных выражений, а на выходе получается файл с текстом исходной программы сканера на заданном языке программирования (обычно — на C). Текст исходной программы сканера может быть дополнен вызовами любых функций из любых библиотек, поддерживаемых данным языком и системой программирования. Таким образом, LEX позволяет значительно упростить разработку лексических анализаторов, практически сводя эту работу к описанию требуемых лексем в терминах регулярных выражений.
Более подробную информацию о работе с программой LEX можно получить в[5, 11,31,39,67,68].
Синтаксические анализаторы. Синтаксически управляемый перевод
Основные принципы работы синтаксического анализатора
Синтаксический анализатор (синтаксический разбор) — это часть компилятора, которая отвечает за выявление основных синтаксических конструкций входного языка. B задачу синтаксического анализа входит: найти и выделить основные синтаксические конструкции в тексте входной программы, установить тип и проверить правильность каждой синтаксической конструкции и, наконец, представить синтаксические конструкции в виде, удобном для дальнейшей генерации текста результирующей программы.
B основе синтаксического анализатора лежит распознаватель текста входной программы на основе грамматики входного языка. Как правило, синтаксические конструкции языков программирования могут быть описаны с помощью КС-грамматик (см. главу «Контекстно-свободные языки»), реже встречаются языки, которые могут быть описаны с помощью регулярных грамматик (см. главу «Регулярные языки»). Чаще всего регулярные грамматики применимы к языкам ассемблера, а языки высокого уровня построены на основе синтаксиса КС-языков.
Распознаватель дает ответ на вопрос о том, принадлежит или нет цепочка входных символов заданному языку. Однако, как и в случае лексического анализа, задача синтаксического разбора не ограничивается только проверкой принадлежности цепочки заданному языку. Необходимо выполнить все перечисленные выше задачи, которые должен решить синтаксический анализатор. B таком варианте анализатор уже не является разновидностью МП-автомата — его функции можно трактовать шире. Синтаксический анализатор должен иметь некий выходной язык, с помощью которого он передает следующим фазам компиляции всю информацию о найденных и разобранных синтаксических структурах. B таком случае он уже является преобразователем смагазинной памятью — МП-преобразователем1 [6, 23, 26, 40, 42].
Синтаксический разбор — это основная часть компилятора на этапе анализа. Без выполнения синтаксического разбора работа компилятора бессмысленна, в то время как лексический разбор в принципе является необязательной фазой. Все задачи по проверке синтаксиса входного языка могут быть решены на этапе синтаксического разбора. Сканер только позволяет избавить сложный по структуре синтаксический анализатор от решения примитивных задач по выявлению и запоминанию лексем входной программы.
Выходом лексического анализатора является таблица лексем (или цепочка лексем). Эта таблица образует вход синтаксического анализатора, который исследует только один компонент каждой лексемы — ее тип. Остальная информация о лексемах используется на более поздних фазах компиляции при семантическом анализе, подготовке к генерации и генерации кода результирующей программы. Синтаксический анализ (или разбор) — это процесс, в котором исследуется таблица лексем и устанавливается, удовлетворяет ли она структурным условиям, явно сформулированным в определении синтаксиса языка.
Bo всех разобранных выше в главах «Контекстно-свободные языки» и «Классы КС-языков и грамматик» примерах результатом работы МП-автомата являлся не только ответ на вопрос о принадлежности входной цепочки заданному языку («да» или «нет»), но и последовательность номеров правил грамматики, использованных для построения входной цепочки. Затем на основе этих правил строились цепочка вывода и дерево вывода. Поэтому, строго говоря, все рассмотренные ранее примеры МП-автоматов являлись не только МП-автоматами, но и МП-преобразователями.
Синтаксический анализатор воспринимает выход лексического анализатора и разбирает его в соответствии с грамматикой входного языка. Однако в грамматике входного языка программирования обычно не уточняется, какие конструкции следует считать лексемами. Примерами конструкций, которые обычно распознаются во время лексического анализа, служат ключевые слова, константы и идентификаторы. Ho эти же конструкции могут распознаваться и синтаксическим анализатором. Ha практике не существует жесткого правила, определяющего, какие конструкции должны распознаваться на лексическом уровне, а какие надо оставлять синтаксическому анализатору. Обычно это определяет разработчик компилятора исходя из технологических аспектов программирования, а также синтаксиса и семантики входного языка. Принципы взаимодействия лексического и синтаксического анализаторов были рассмотрены нами в разделе «Лексические анализаторы (сканеры). Принципы построения сканеров» этой главы.
Ниже рассмотрены технические аспекты, связанные с реализацией синтаксических анализаторов для использования результатов их работы на этапе генерации кода. Тем не менее основу любого синтаксического анализатора всегда составляет распознаватель, построенный на основе какого-либо класса КС-грамматик. Поэтому главную роль в том, как функционирует синтаксический анализатор и какой алгоритм лежит в его основе, играют принципы построения распознавателей КС-языков, рассмотренные в главе «Контекстно-свободные языки». Без применения этих принципов невозможно выполнить эффективный синтаксический разбор предложений входного языка.
