Синтаксический анализ Исходная программа Токен Лексический анализатор запрос следующего Синтаксический анализатор Таблица символов Дерево разбора Семантический разбор и т.п. Классы синтаксических анализаторов • Нисходящие анализаторы, которым соответствуют LL-грамматики • Восходящие анализаторы, которым соответствуют LR-грамматики • Переборные анализаторы – экспоненциальная трудоемкость. Синтаксический анализ КС-языков Стратегия 1. «Cверху-вниз» – нисходящий анализ. Основной принцип: Выводим из начального нетерминала все возможные цепочки методом «поиска в глубину». Поиск останавливается, если сгенерированная цепочка отличается от входной. Чтобы метод работал, желательно, чтобы «поиск в глубину» раскрывал самый левый из нераскрытых нетерминалов, иначе сложно проверять совпадение входной цепочки с уже сгенерированной. Недостаток метода: сложно выполнять атрибутные вычисления, т.к. при откате при поиске необходимо нейтрализовать возможные побочные эффекты атрибутивных вычислений. Преимущество: для определённых видов грамматик удаётся реализовать поиск без возвратов, а потом очень просто можно запрограммировать весь синтаксический анализ методом «рекурсивного спуска». Синтаксический анализ КС-языков Стратегия 2. «Снизу-вверх» – восходящий анализ. Основной принцип: Начиная с терминальной строки листьев дерева пытаемся найти т.н. «связку» – правую часть некоторой продукции грамматики, которую нужно заменить нетерминалом в левой части продукции, чтобы получить новый узел в дереве разбора. Формально: Связкой цепочки вывода называется самая левая цепочка β (возможно пустая) в µ, такая, что существует вывод S *A Недостаток метода: для реальной цепочки вывода достаточно сложно найти связку, а если её и нашли, то в дальнейшем связок может и не быть вообще, а потому придётся возвращаться и повторять поиск иной связки. Преимущество: для некоторых видов грамматики удаётся найти очень простые правила поиска связок, позволяющие создать очень быстрые алгоритмы синтаксического разбора. Подклассы КС-грамматик, допускающие эффективные методы синтаксического анализа КС-грамматики Грамматики простого предшествования LL(1)-грамматики s-грамматики LR(0)-грамматики LALR(k)-грамматики SLR(k)-грамматики ... ... Нисходящие методы синтаксического анализа Пусть у нас имеется некоторая грамматика и вывод S 1 2 3 4 ... abcdeabbaa dec В восходящем анализе вначале находится некоторая «связка» и, по сути, определяется, какое правило было применено на некотором этапе вывода: S ...i i 1... abcdeabbaadec В нисходящем анализе всегда восстанавливается самое первое правило, которое применено при выводе: S 1 ... abcdeabbaadec Пример. Дана грамматика: S aBDe | bCBD, … Пусть дана цепочка S ... abcdeabbaadec . Очевидно, что самым первым правилом, которое было применено для вывода цепочки abcdeabbaadec , было правило S aBDe, т.к. иначе первым символов выведенной цепочки был бы символ b. Грамматики, которые допускают последовательное восстановление всех этапов вывода i , i 1 , i 2 ,... на основании не более чем очередных k символов выведенной цепочки, называется LL(k)-грамматикой Автоматные грамматики Автоматными грамматиками являются такие грамматики, которые имеют правилами вывода типа A aB | a | . Пример автоматной грамматики. S aS | bA A aB | B bA | a Пример вывода в этой грамматике: S bA baB babA babaB bababA babab S A B A B A b a b a b LL-грамматика • Анализ без возвратов • Первая буква L означает просмотр входной цепочки слева направо (leftto-right scan) • Вторая буква L означает, что строится левый вывод цепочки (leftmost derivation). • k – количество очередных символов, необходимых восстановления вывода цепочки Метод рекурсивного спуска • Анализ методом рекурсивного спуска (recursive-descent parsing) – способ синтаксического анализа, при котором выполняется ряд рекурсивных процедур для обработки входного потока • Каждая процедура – связана с соответствующим нетерминалом • Вариант без возвратов можно использовать только для грамматик с правилами, в которых первого символа каждого правила должно быть достаточно для того, чтобы определить, какое правило применять Рекурсивный спуск с возвратами Для обхода трудностей, связанных с совпадением множеств FIRST, на практике зачастую используется следующий прием: – Перед началом разбора потенциально неоднозначного фрагмента запоминается текущее состояние лексического анализатора – Затем запускается разбор первой из возможных конструкций – В случае неудачного завершения разбора, мы восстанавливаем состояние лексического анализатора и переходим к следующему варианту разбора и т.д. – Если все варианты завершаются неудачно, то мы сообщаем об ошибке LL(k)-грамматика Определение. Грамматика G = (VT, VN, P, S) называется LL(k)-грамматикой, если для любых двух левых выводов S =>* wAv => wuv =>* wx S =>* wAv => wu1v =>* wy для которых FIRSTk (x) = FIRSTk (y) верно, что u=u1. Леворекурсивные грамматики • Грамматика называется леворекурсивной, если среди ее нетерминалов имеется по крайней мере один леворекурсивный нетерминал. • Нетерминал A называется леворекурсивным, если существует вывод A =>* Aw. • Леворекурсивные грамматики не обладают свойством LL(k) ни для какого k. Левая рекурсия Определение. КС-грамматика называется леворекурсивной, если в ней существует вывод A *A . Леворекурсивные грамматики достаточно неудобны на практике для синтаксического анализа. В частности нисходящие методы синтаксического анализа, восстанавливающие дерево вывода от его корня, не могут быть применены для таких грамматик. Рассмотрим пару продукций A A | . Эти правила порождают цепочки вида . Эти же цепочки можно также породить и эквивалентными правилами: A R ; R R | . Соответственно дерево вывода будет другое в этой грамматике: праворекурсивное, а не леворекурсивное: A A R A R A R A R Пример. Рассмотрим фрагмент правил классической грамматики арифметических выражений: E E T | T . Эквивалентная грамматика: E TE' ; E' TE'| .