- •1 Общая модель компилятора. Блоки компилятора и их функции
- •2 Общее понятие синтаксиса и семантики языка. Бнф и др. Методы описания синтаксиса и семантики языка.
- •3 Понятие языка. Способы задания языка. Операции над языком
- •4 Регулярные выражения. Способы задания регулярных выражений. Операции над регулярными выражениями.
- •5.Конечные автоматы. Способы задания. Методы построения конечных автоматов. Преобразование конечных автоматов.
- •6 Лексический анализ. Методы и средства построения лексического анализатора.
- •7 Распознавание цепочек символов с помощью конечных автоматов.
- •8 Распознавание цепочек символов с помощью автоматов с магазинной памятью.
- •9 Грамматики языков. Классификация языков по Хомскому.
- •11 Методы представления грамматики в памяти.
- •12 Нисходящий синтаксический анализ. Метод рекурсивного разбора.
- •14 Нисходящий синтаксический анализ. Методы восстановления после ошибок.
- •16 Синтаксический анализ приоритета операторов. Функция приоритета
- •18 Slr-анализаторы. Построение таблиц для slr-анализатора.
- •19 Методы анализа ошибок. Восстановление после ошибок.
- •20 Семантика языка, методы описания и анализа.
- •21 Понятие атрибутивные грамматики
- •22 Синтаксически управляемая трансляция.
- •23 Таблица символов, таблица меток и др. Методы построения, доступа и анализа.
- •24 Генерация промежуточного кода.
- •25 Методы оптимизация промежуточного кода.
- •29 Имена, связывание, проверка типов.
- •30 Область видимости имен. Способы реализации.
- •31 Типы данных. Способы реализации.
- •32 Выражения и операторы присваивания. Способы реализации.
- •36. Абстрактные типы данных. Способы реализации.
- •37 Объектно-ориентированные языки программирования. Способы реализации.
- •38 Обработка исключительных ситуаций. Способы реализации.
- •39 Языки параллельного программирования. Способы реализации.
- •40 Императивные языки программирования. Способы реализации.
- •41 Функциональные языки программирования. Способы реализации.
- •42 Языки логического программирования. Способы реализации.
- •43 Графовые грамматики. Назначение и основные понятия.
- •44 Antlr. Tree grammars.
- •46 Case-средства. Назначение, классификация и основные понятия.
- •47 Case-средства. Направления интеллектуализации.
11 Методы представления грамматики в памяти.
12 Нисходящий синтаксический анализ. Метод рекурсивного разбора.
Нисходящий разбор можно рассматривать как попытку найти левое порождение входной строки. Точно так же его можно рассматривать и как попытку построить дерево разбора для входной строки, начиная с корня и создавая вершины в прямом порядке. Мы рассмотрим нисходящий анализ в общем виде, а именно — анализ методом рекурсивного спуска, который может использовать откаты, т.е. производить повторное сканирование входного потока. Однако такие синтаксические анализаторы с откатом встречаются не очень часто. Одна из причин этого состоит в том, что для анализа конструкций реальных языков программирования откат требуется крайне редко. В ситуациях наподобие анализа естественных языков технология отката не очень эффективна, и предпочтительными являются табличные методы, вроде алгоритма динамического программирования.
Одним из наиболее простых и потому одним из наиболее популярных методов нисходящего синтаксического анализа является метод рекурсивного спуска.
Для объяснения принципов, лежащих в основе метода рекурсивного спуска, рассмотрим задачу вычисления значения арифметической формулы. Будем рассматривать формулы, состоящие из целочисленных значений, бинарных операций сложения (+), вычитания (–), умножения (*) и деления нацело (/), а также круглых скобок. Как обычно, приоритеты операций умножения и деления равны и их приоритет больше, чем приоритеты операций сложения и вычитания, причем приоритеты этих операций также равны. Будем называть операции + и – операциями типа сложения, а операции * и / – операциями типа умножения. Круглые скобки используются для изменения стандартного порядка выполнения операций. Наша задача заключается в написании программы, вычисляющей значение формулы.
13 Нисходящий синтаксический анализ. Предиктивный анализ.
Во многих случаях аккуратная разработка грамматики, устранение из нее левой рекурсии и ее левая факторизация позволяют получить грамматику, которая может быть проанализирована синтаксическим анализатором, работающим методом рекурсивного спуска и не требующим отката. Для построения предиктивного синтаксического анализатора мы должны знать, какая из альтернатив продукций А —>а1 | а2 | ... | аn данного анализируемого нетерминала А порождает строку, начинающуюся с полученного входного символа а. Иначе говоря, правильная альтернатива должна точно определяться по первому порождаемому ею символу. Обычно в языках программирования управляющие конструкции отвечают этому правилу. Например, если есть продукции
stmt —> if expr then stmt else stmt
| while expr do stmt
| begin stmt_/ist end
то ключевые слова if, while и begin однозначно определяют возможную альтернативу для рассматриваемой инструкции stmt.
В данном методе применяются 2 функции:FIRST (),FOLLOW ()
FIRST (T’) = {*, } – должна возвращать символы, которые находятся в начале всех цепочек вывода из аргумента этой функции.A => *a-
FOLLOW (F) = {+, *, (, $} – это множество символов, которые встречаются в цепочках вывода справа от символа
A => *Ba
Нерекурсивный предиктивный синтаксический анализатор можно построить с помощью явного использования стека (вместо неявного при рекурсивных вызовах). Ключевая проблема предиктивного анализа заключается в определении продукции, которую следует применить к нетерминалу.
Предиктивный синтаксический анализатор, управляемый таблицей, имеет входной буфер, стек, таблицу разбора и выходной поток. Входной буфер содержит анализируемую строку с маркером ее правого конца — специальным символом. Стек содержит последовательность символов грамматики с $ на дне. Изначально стек содержит стартовый символ грамматики непосредственно над символом $. Таблица разбора представляет собой двухмерный массив М[А, а], где А — нетерминал, а а — терминал или символ $.
Синтаксический анализатор управляется программой, которая работает следующим образом. Программа рассматривает X— символ на вершине стека, и а, текущий входной символ. Эти два символа определяют действия синтаксического анализатора. Имеется три варианта.
1. Если Х=а = $, синтаксический анализатор прекращает работу и сообщает об успешном завершении разбора.
2.Если Х= а $, синтаксический анализатор снимает со стека X и перемещает указатель входного потока к следующему символу.
3. Если X представляет собой нетерминал, программа рассматривает запись М[Х, а] из таблицы разбора M. Эта запись представляет собой либо .А'-продукцию грамматики, либо запись об ошибке. Если, например, М[Х, а] = {X—> UVW}, синтаксический анализатор замещает X на вершине стека на WVU (с U на вершине стека). Мы полагаем, что в качестве выхода синтаксический анализатор просто выводит использованную продукцию, но, конечно же, здесь может выполняться любой необходимый код. Если М[Х, а] = error, синтаксический анализатор вызывает программу восстановления после ошибки.
Если по одной входной строке можно построить несколько деревьев разбора, то такая грамматика называется неоднозначной.