
- •Содержание
- •1.Рабочая программа
- •2.Модуль Вводный
- •3.Модуль Формальные грамматики и языки
- •3.1.Языки и цепочки символов. Способы задания языков
- •3.1.1.Цепочки символов. Операции над цепочками символов
- •3.1.2.Понятие языка. Формальное определение языка
- •3.1.3.Способы задания языков
- •3.1.4.Синтаксис и семантика языка
- •3.2.Определение грамматики
- •3.2.1.Особенности языков программирования
- •3.2.2.Определение грамматики. Форма Бэкуса—Наура
- •3.2.3.Принцип рекурсии в правилах грамматики
- •3.2.4.Другие способы задания грамматик
- •3.3.Классификация языков и грамматик
- •3.3.1.Классификация грамматик
- •3.3.2.Классификация языков
- •3.4.Контроль
- •4.Модуль Распознаватели, механизм вывода цепочек символов
- •4.1.Цепочки вывода. Сентенциальная форма.
- •4.1.1.Сентенциальная форма грамматики. Язык, заданный грамматикой
- •4.1.2.Левосторонний и правосторонний выводы
- •4.1.3.Однозначные и неоднозначные грамматики
- •4.1.4.Эквивалентность и преобразование грамматик
- •4.2.Распознаватели. Задача разбора
- •4.2.1.Общая схема распознавателя
- •4.2.2.Виды распознавателей
- •4.2.3.Классификация распознавателей по типам языков
- •4.3.Контроль
- •5.Модуль Регулярные грамматики и языки
- •5.1.Регулярные языки и грамматики
- •5.2.Леволинейные и праволинейные грамматики. Автоматные грамматики
- •5.3.Алгоритм преобразования регулярной грамматики к автоматному виду
- •5.4.Конечные автоматы
- •5.4.1.Определение конечного автомата
- •5.4.2.Детерминированные и недетерминированные конечные автоматы
- •5.4.3.Преобразование конечного автомата к детерминированному виду
- •5.5.Контроль
- •6.Модуль Контекстно-свободные грамматики и языки
- •6.1.Контекстно-свободные языки
- •6.1.1.Распознаватели кс-языков. Автоматы с магазинной памятью. Определение мп-автомата
- •6.2.Классы кс-языков и грамматик. Класс ll(k) грамматик.
- •6.3.Принципы построения распознавателей для ll(k)-грамматик
- •6.4.Левая факторизация
- •6.5.Удаление левой рекурсии
- •6.6.Алгоритм разбора для ll(1)-грамматик
- •6.7.Алгоритм построения множества first(1,a)
- •6.8.Алгоритм построения множества follow(1,a)
- •6.9.Восходящие распознаватели кс-языков без возвратов
- •6.9.1.Определение lr(k)-грамматики
- •6.10.Принципы построения распознавателей для lr(k)-грамматик
- •6.10.1.Грамматики простого предшествования
- •6.11.Распознаватели для lr(0) и lr(1) грамматик
- •6.11.1.Распознаватель для lr(0)-грамматики
- •6.11.2.Распознаватель для lr(1) грамматики
- •6.12.Контроль
- •7.Модуль Инструментальные средства для построения трансляторов
- •7.1.Инструментальные средства для построения компиляторов
- •7.1.1.Построитель лексических анализаторов Lex
- •7.2.Контроль
- •8.Модуль Особенности программирование трансляторов
- •8.1.Использование значений произвольных типов, алгоритм разбора
- •8.1.1.Алгоритм синтаксического разбора
- •8.1.2.Семантический стек
- •8.2.Неоднозначности и конфликты
- •8.3.Старшинство операций
- •8.4.Дополнительные возможности программ yacc и lex
- •8.4.1.Обработка ошибок
- •8.5.Совместное использование lex и yacc
- •8.5.1.Кодировка лексем и интерфейс
- •8.5.2.Сборка yacc-программ
- •8.6.Советы по подготовке спецификаций
- •8.6.1.Стиль
- •8.6.2.Использование левой рекурсии
- •8.6.3.Уловки анализа лексики
- •8.6.4.Входной синтаксис yacc'а
- •8.7.Контроль
- •9.Модуль Заключение
- •10.Обеспечение лабораторного практикума
- •11.Дополнительная информация. Примеры
- •11.4.Пример простейшего интерпретатора формул
- •11.5.Простой пример
- •11.6.Более сложный пример
- •11.7.Генераторы лексических и синтаксических анализаторов
- •11.8.Генераторы лексических и синтаксических анализаторов на java
- •11.9.Пакеты для разработки компиляторов
- •Список сокращений
- •Литература
- •Приложения Приложение 1. Учебно–методическая карта дисциплины “Системное программное обеспечение. Синтаксические анализаторы”
- •Приложение 2. Вопросы для зачета по дисциплине “Системное программное обеспечение. Синтаксические анализаторы”
- •Приложение 3. Методические указания к лабораторным работам по дисциплине «Системное программное обеспечение. Синтаксические анализаторы»
- •Порядок выполнения работы:
- •Контрольные вопросы
- •Лексический анализатор lex. Анализ структуры программ
- •Краткая теория:
- •Рассмотрим примеры:
- •Порядок выполнения работы:
- •Контрольные вопросы
- •Лексический анализатор lex, синтаксический анализатор yacc. Алгебраические вычисления
- •Краткая теория:
- •Порядок выполнения работы:
- •Контрольные вопросы
- •Лексический анализатор lex и синтаксический анализатор yacc. Изображение геометрических фигур
- •Краткая теория:
- •Создание метафайла и работа сним
- •Порядок выполнения работы:
- •Контрольные вопросы
- •Приложение 4. Организация рейтингового контроля по дисциплине «Системное программное обеспечение. Синтаксические анализаторы»
8.5.1.Кодировка лексем и интерфейс
Файл, порожденный YACC'ом в процессе работы, содержит таблицы разбора и функцию yyparse, содержащую интерпретатор таблиц и семантические действия. Для запуска парсера достаточно вызвать эту функцию. В случае успешного разбора она возвращает 0, в случае ошибки - 1.
По умолчанию имена лексем выбирает yacc. Для получения очередной лексемы парсер вызывает функцию yylex.
В процедуре лексического анализа кроме выделения лексем можно предусмотреть некоторую обработку лексем определенных типов, в частности, запоминание конкретных значений лексем.
Примером значения лексемы могут служить числовое значение символа - цифры, вычисленное значение константы, адрес идентификатора в таблице имен (построение таблицы имен осуществляет lex). Кроме того, эти значения обычно требуется передать грамматическому анализатору. С этой целью нужное значение должно быть присвоено внешней переменной целого типа с именем yylval. Функция yylex должна возвратить код лексемы и поместить ее значение в переменную yylval, которая имеет тип YYSTYPE. Если функция yylex находится в отдельном файле, то эта переменная должна быть объявлена:
extern int yylval;
Уточним, что значением_лексемы будем называть значение, присвоенное при ее распознавании переменной yylval. Заметим, что в yylval всегда должно находится значение последней выделенной лексемы.
Код лексемы - положительное целое число.
Лексемам, заданных в виде символьных констант, номер лексемы для литералов равен численному значению соответствующего символа в принятой кодировке символов, лежащий в диапазоне 0..255.
Код 256 зарезервирован для специальной лексемы error, которая служит для обработки ошибок.
Лексемам, имеющим имена, присваиваются коды начиная с 257.
Если пользователь предпочитает сам назначать имена лексем, сразу за первым вхождением имени лексемы или литерала в секции определений должно следовать неотрицательное целое число. Это число становится номером лексемы для имени или литерала. Не определенные таким способом имена и литералы доопределяет по умолчанию yacc. Данный механизм оставляет потенциальную возможность многократного использования одного номера. Необходимо обеспечить различие всех номеров лексем.
Процедуры синтаксического разбора и лексического анализа должны быть согласованы относительно номеров лексем. Номера может выбрать yacc или пользователь. В обоих случаях, чтобы дать возможность лексическому анализатору использовать символические обозначения номеров лексем, применяется механизм #define языка C.
Например, предположим, что имя лексемы DIGIT определено в секции определений файла yacc-спецификаций. Чтобы возвратить требуемый номер лексемы, соответствующий фрагмент лексического анализатора может выглядеть так:
int yylex ()
{
extern int yylval;
int c;
. . .
c = getchar ();
. . .
switch (c) {
. . .
case '0':
case '1':
. . .
case '9':
yylval = c - '0';
return (DIGIT);
. . .
}
. . .
}
Требуется возвратить номер лексемы DIGIT и значение, равное численному значению цифры. При условии, что процедура лексического анализа помещена в секцию подпрограмм файла спецификаций, идентификатор DIGIT определяется как номер, соответствующий лексеме DIGIT.
Такой механизм дает понятные, легко модифицируемые лексические анализаторы. Единственная неприятность, которую следует избегать, - это использование в грамматических правилах в качестве имен лексем слов, зарезервированных в языке C или в yacc'е. Например, использование имен лексем if или while почти наверняка приведет к серьезным трудностям при компиляции лексического анализатора. Имя лексемы error зарезервировано для обработки ошибок, не следует использовать его без нужды.
По историческим причинам маркер конца должен иметь нулевой или отрицательный номер лексемы. Данный номер лексемы не может быть переопределен пользователем. Поэтому все лексические анализаторы должны возвращать нуль или отрицательное число по достижении конца исходного текста.
Для каждого имени лексемы независимо от того, переопределен ли ее номер пользователем, yacc генерирует в выходном файле y.tab.c оператор препроцессора:
#define <имя_лексемы> <номер_типа>
Значение, возвращаемое функцией yylex, является номером типа лексемы. Таким образом, список лексем и номера их типов указываются в Yacc-программе, а определения этих лексем в Lex- программе. Возникает проблема соответствия номеров типов лексем в файлах y.tab.c и lex.yy.c, которая разрешается следующим образом:
при вызове yacc с флагом -d последовательность операторов #define помещается в файл y.tab.h.;
этот файл посредством оператора #include включается в Lex-программу.