
- •Введение
- •1 Предварительные математические сведения
- •1.1 Множества
- •1.2 Операции и отношения
- •1.2.1 Операции над множествами
- •1.2.2 Отношения на множествах
- •1.3.1 Цепочки
- •1.3.2 Операции над цепочками
- •1.4.2 Операции над языком
- •1.5 Алгоритмы
- •1.5.1 Частичные алгоритмы
- •1.5.2 Всюду определенные алгоритмы
- •1.5.3 Рекурсивные алгоритмы
- •1.5.4 Задание алгоритмов
- •1.5.5 Проблемы
- •1.6 Некоторые понятия теории графов
- •1.6.1 Ориентированные графы
- •1.6.2 Ориентированные ациклические графы
- •1.6.3 Деревья
- •1.6.4 Упорядоченные графы
- •2 Введение в компиляцию
- •2.1 Задание языков программирования
- •2.2 Синтаксис и семантика
- •2.3 Процесс компиляции
- •2.4 Лексический анализ
- •2.5 Работа с таблицами
- •2.6 Синтаксический анализ
- •2.7 Генератор кода
- •2.8 Оптимизация кода
- •2.9 Исправление ошибок
- •2.10 Резюме
- •3 Теория языков
- •3.1 Способы определения языков
- •3.2 Грамматики
- •3.3 Грамматики с ограничениями на правила
- •3.4 Распознаватели
- •3.5.1 Определения
- •3.8 Конечные автоматы и регулярные множества
- •3.9.1 Постановка задачи
- •3.10 Контекстно-свободные языки
- •3.10.2 Преобразование КС-грамматик
- •3.10.2.1. Алгоритм проверки пустоты языка
- •3.10.2.2. Алгоритм устранения недостижимых символов
- •3.10.2.3. Алгоритм устранения бесполезных символов
- •3.10.2.5. Алгоритм устранения цепных правил
- •3.10.3 Грамматика без циклов
- •3.10.4 Нормальная форма Хомского
- •3.10.5 Нормальная форма Грейбах
- •3.11 Автоматы с магазинной памятью
- •3.11.1 Основные определения
- •4.1 LL(k)-грамматики
- •4.2.2 Алгоритм поиска направляющих символов
- •4.2.2.1 Множество предшествующих символов
- •4.2.2.2 Множество последующих символов
- •4.2.2.3 Множество направляющих символов
- •4.3 LL(1)-таблица разбора
- •4.3.1 Построение таблицы
- •5 Синтаксический анализ снизу вверх
- •5.1 LR(k)-грамматики
- •5.2 LR(1)-грамматики
- •5.3 LR(1)-таблица разбора
- •5.3.1 Состояния анализатора
- •5.3.2 Построение таблицы
- •5.3.3 LR-конфликты
- •5.3.4 Разбор цепочки по таблице
- •5.4 Сравнение LL- и LR-методов разбора
- •6 Включение действий в синтаксис
- •6.2 Работа с таблицей символов
- •7 Проектирование компиляторов
- •7.1 Число проходов
- •7.2 Таблицы символов
- •7.2.2 Бинарное дерево
- •7.4.1 Стек времени прогона
- •7.4.2 Методы вызова параметров
- •7.4.3 Обстановка выполнения процедур
- •8 Генерация кода
- •8.1 Генерация промежуточного кода
- •8.2 Структура данных для генерации кода
- •8.3.1 Присвоение
- •8.3.2 Условные зависимости
- •8.3.3 Описание идентификаторов
- •8.3.4 Циклы
- •8.3.5 Вход и выход из блока
- •8.3.6 Прикладные реализации
- •8.4 Проблемы, связанные с типами
- •8.5 Время компиляции и время прогона
- •9 Исправление и диагностика ошибок
- •9.1 Типы ошибок
- •9.2 Лексические ошибки
- •9.3 Ошибки в употреблении скобок
- •9.4 Синтаксические ошибки
- •9.4.1 Методы исправления синтаксических ошибок
- •9.4.2 Предупреждения
- •9.4.3 Сообщения о синтаксических ошибках
- •9.5 Контекстно-зависимые ошибки
- •9.6 Ошибки, связанные с употреблением типов
- •9.7 Ошибки, допускаемые во время прогона
- •9.8 Ошибки, связанные с нарушением ограничений
- •Заключение
- •Список литературы
- •Глоссарий

247
Здесь пропущена закрывающая скобка. Это не обнаружится до тех пор,
пока не встретится fi. Однако неясно, где должна стоять эта скобка: после r,
после q, после p или 2. Выяснить, что предполагал программист, невозможно.
Поэтому самый легкий способ «исправления» – поставить закрывающую скобку непосредственно перед fi. Синтаксический анализатор продолжает работать, а на выход выдается сообщение о введенных изменениях.
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
9.4 СИНТАКСИЧЕСКИЕ ОШИБКИ
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Термин «синтаксическая ошибка» употребляется для обозначения ошибки, обнаруживаемой контекстно-свободным синтаксическим анализатором.
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Современные анализаторы обладают этим важным свойством – обна-
руживать синтаксически неправильную программу на первом недопустимом символе, т.е. они могут генерировать сообщения при чтении символа, кото-
рый не должен следовать за прочитанной к тому времени последовательно-
стью символов [2].
Ошибка в виде пропуска или неправильного употребления, допущен-
ная на более раннем этапе, может проявиться совсем в другом месте про-
граммы.
· · · · · · · · · · · · · · · · · · · · · · · · |
|
Пример · · · · · · · · · · · · · · · · · · · · · · · |
|
|
|
Это можно проиллюстрировать следующим примером. while x > y; begin <something> end.
248
Никакого сообщения об ошибке при встрече «;» на данной стадии син-
таксический анализатор не выдаст. Последствия ее могут появиться на более поздней фазе анализа.
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Сообщив о синтаксической ошибке, анализатор в большинстве случаев постарается продолжить разбор. Для этого ему понадобится исключить ка-
кие-либо символы, включить какие-либо символы или изменить их. Суще-
ствует ряд стратегий исправления ошибок. Практически все они хорошо сра-
батывают в одних случаях и плохо – в других. «Хорошая» стратегия заклю-
чается в том, чтобы обнаружить как можно больше синтаксических ошибок и генерировать как можно меньше сообщений в связи с каждой синтаксиче-
ской ошибкой. Обычно наилучшими методами являются методы, зависимые от языка, т.е. от знания исходного языка и от того, как он употребляется.
9.4.1 МЕТОДЫ ИСПРАВЛЕНИЯ СИНТАКСИЧЕСКИХ ОШИБОК
Режим переполоха. Один из наиболее распространенных методов ис-
правления синтаксических ошибок носит название «режим переполоха».
При появлении недопустимого символа весь последующий исходный текст, вплоть до соответствующего ограничителя (например, «;» или end),
игнорируется. Ограничитель заканчивает какую-то конструкцию языка, и
элементы удаляются из стека разбора до тех пор, пока не встретится адрес возврата. Этот элемент тоже удаляется из стека, а разбор продолжается,
начиная с адреса в таблице разбора, содержащего следующий входной сим-
вол. Такой метод довольно легко реализуется, но имеет серьезный недоста-
ток: длинные последовательности кода, соответствующие игнорируемым символам, не анализируются.
Исключение символов. Метод исключения символов также легко реа-
лизуется и не требует изменения степени разбора. Когда считывается недо-
пустимый символ, и он сам, и все последующие символы исключаются из

249
исходной строки до тех пор, пока не встретится допустимый символ. Хотя при таком методе могут исключаться длинные последовательности, в от-
дельных случаях он весьма эффективен.
· · · · · · · · · · · · · · · · · · · · · · · · |
|
Пример · · · · · · · · · · · · · · · · · · · · · · · |
|
|
|
Например, в записи
c := d+3; end,
где символ «;» является недопустимым, исправление ошибки – идеальное.
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Однако исключение скобок обычно разрушает блочную структуру и приводит к дальнейшим синтаксическим ошибкам.
Включение символов. Некоторые синтаксические анализаторы имеют наготове множество действительных символов продолжения. В некоторых случаях оправдано исправление программ путем включения символов – под-
становки одного из таких символов перед недопустимым символом, который вызвал ошибку.
· · · · · · · · · · · · · · · · · · · · · · · · |
|
Пример · · · · · · · · · · · · · · · · · · · · · · · |
|
|
|
Например, последовательность
end begin
никогда не будет допустимой. Однако включение «;» между end begin позво-
лит анализатору продолжить работу.
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Конечно, в таких ситуациях может иметь место неправильная подста-
новка, даже если анализатор продолжит работу.
Правила для ошибок. Один из способов исправления некоторых ти-
пов синтаксических ошибок заключается в расширении синтаксиса языка за

250
счет включения в него программ, содержащих типичные ошибки. Это не зна-
чит, что ошибки пройдут незамеченными, так как в грамматику могут быть включены сообщения о них. Но анализатор не будет считать такой вход не-
допустимым и не потребует никаких исправлений.
· · · · · · · · · · · · · · · · · · · · · · · · |
|
Пример · · · · · · · · · · · · · · · · · · · · · · · |
|
|
|
Так, можно обращаться, например, с ошибками типа «;» перед end или пропуск «;».
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Дополнительные правила, включенные в грамматику, обычно называ-
ются правилами для ошибок. Они неизбежно приводят к увеличению грамма-
тики, и поэтому включать их следует только для наиболее часто встречаю-
щихся ошибок программирования. При этом надо следить за тем, чтобы при включении этих правил грамматика не стала неоднозначной.
9.4.2 ПРЕДУПРЕЖДЕНИЯ
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Наряду с сообщениями о синтаксических ошибках, анали-
затор может выдавать предупреждения, когда ему встрети-
лась допустимая, но маловероятная последовательность симво-
лов.
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
· · · · · · · · · · · · · · · · · · · · · · · · |
|
Пример · · · · · · · · · · · · · · · · · · · · · · · |
|
|
|
Пример маловероятной последовательности символов:
;do
·· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·