- •Содержание
- •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.Совместное использование lex и yacc
В результате обработки пользовательской спецификации утилитой yacc создается содержащий C-подпрограммы файл y.tab.c. Основной в файле y.tab.c является функция yyparse, реализующая алгоритм грамматического разбора; это функция с целочисленным результатом. Когда она выполняется, то периодически запрашивает у yylex(), функции лексического анализа, заданной пользователем, входные лексемы. В конечном итоге либо обнаруживается ошибка, yyparse() возвращает значение 1 и восстановление после ошибки невозможно, либо лексический анализатор возвращает маркер конца и разбор успешно завершается. В этом случае yyparse() возвращает значение 0.
Чтобы получить работающую программу, пользователь должен сформировать для процедуры разбора определенное окружение. Например, как в любой программе на языке C, должна быть определена процедура с именем main(), вызывающая yyparse(). Кроме того, чтобы печатать сообщение об обнаруженной синтаксической ошибке, нужна процедура, называемая yyerror().
Эти две процедуры в той или иной форме должны быть заданы пользователем. Чтобы упростить на начальном этапе работу с yacc'ом, предоставляется библиотека с подразумеваемыми версиями функций main() и yyerror(). Библиотека задается при помощи аргумента ly команды cc(1) или редактора связей. Исходный текст
main ()
{
return (yyparse ());
}
и
#include
yyerror (s)
char *s;
{
(void) fprintf (stderr, "%s\n", s);
}
демонстрирует банальность этих предопределенных программ. Аргумент у функции yyerror() - текст, содержащий сообщение об ошибке, обычно syntax error. В реальных приложениях чаще выполняются более сложные действия. Обычно программа подсчитывает номер входной строки и печатает его вместе с сообщением об обнаружении синтаксической ошибки. Внешняя переменная целого типа yyc-har содержит номер предварительно просмотренной лексемы на момент обнаружения ошибки. Это может представлять некоторый интерес для формирования лучшей диагностики. Так как функция main() вероятнее всего задается пользователем (необходимо прочесть аргументы и т.п.), yacc-библиотека полезна только в маленьких проектах или на ранних этапах разработки больших.
Внешняя переменная целого типа yydebug обычно устанавливается равной 0. Если она имеет ненулевое значение, процедура разбора будет выдавать подробное описание действий, включающее сообщение о прочитанных входных символах и выполняемых операциях разбора. Значение этой переменной можно переустановить, используя отладчик sdb(1).
Для обеспечения корректной работы грамматического анализатора функция yylex должна быть согласована с конкретной спецификацией грамматики и удовлетворять определенным требованиям.
Пользователь при описании грамматики решает, какие конструкции целесообразнее непосредственно выделять из входного текста на этапе лексического анализа.
Сложность лексического анализатора зависит от того, какие структурные единицы взяты за основу при описании грамматических правил. Детализировав грамматику до отдельных символов, можно обойтись простейшим лексическим анализатором. Однако, в этом случае число правил растет, а грамматический разбор оказывается менее эффективным. Поэтому пользователь обычно должен найти некоторый компромисс при выборе набора лексем.
Заметим, что ключевые слова описываемого входного языка часто бывает удобно считать лексемами. Имена лексем могут совпадать с этими ключевыми словами, недопустимым является лишь совпадение имен лексем с зарезервированными словами языка Си.
Основная задача функции yylex состоит во вводе из входного потока ряда очередных символов до выявления конструкции, соответствующей одной из лексем, и возвращении номера типа этой лексемы и, когда это необходимо, значения этой лексемы.
Все виды лексем, кроме литералов, обозначаются некоторыми именами и под этими именами фигурируют в Yacc-программе, где объявление имен лексем осуществляется директивой token:
%token <список имен лексем>
Благодаря объявлению имен лексем в директиве token, yacc отличает имена лексем от имен нетерминальных символов.
Пример объявления имен лексем в Yacc-программе:
%token IDENT CONST ЗНАК IF THEN GOTO
При первом появлении лексемы или литерала в секции объявлений Yacc-программы за каждым из них может следовать неотрицательное целое число, рассматриваемое как номер_типа лексемы.
