- •Глава 12 Классы кс-языков
- •Алгоритм разбора по методу рекурсивного спуска
- •Пример реализации метода рекурсивного спуска
- •Расширенное применение распознавателей на основе метода рекурсивного спуска
- •Определение ll(k)-грамматики
- •Принципы построения распознавателей для ll(к)-грамматик
- •Алгоритм разбора для ll(1)-грамматик
- •Алгоритм построения множества first(1,a)
- •Алгоритм построения множества follow(1,a)
- •Пример построения распознавателя для ll(1)-грамматики
- •Принципы построения распознавателей для lr(k)-грамматик
- •Распознаватель для lr(0)-грамматики
- •Распознаватель для lr(1)-грамматики
- •Грамматики предшествования (основные принципы)
- •Грамматики простого предшествования
- •Алгоритм «сдвиг-свертка» для грамматики простого предшествования
- •Пример распознавателя для грамматики простого предшествования
- •Грамматики операторного предшествования
- •2. Различные порождающие правила имеют разные правые части, λ-правила отсутствуют.
- •Алгоритм «сдвиг-свертка» для грамматики операторного предшествования
- •Отношения между классами кс-грамматик
- •Отношения между классами кс-языков
Отношения между классами кс-языков
КС-язык называется языком некоторого класса КС-языков, если он может быть задан КС-грамматикой из данного класса КС-грамматик. Например, класс LL-языков составляют все языки, которые могут быть заданы с помощью LL-грамматик.
Соотношение классов КС-языков представляет определенный интерес, оно не совпадает с соотношением классов КС-грамматик. Это связано с многократно уже упоминавшейся проблемой преобразования грамматик. Например, выше уже говорилось о том, что любой LL-язык является и LL(1)-языком — то есть язык, заданный LL-грамматикой, может быть задан также и LR(1)-грамматикой. Однако не всякая LL-грамматика является при этом LR(1)-грамматикой и не всегда можно найти способ, как построить LR(1)-грамматику, задающую тот же самый язык, что и исходная LL-грамматика.
На рис. 12.12 приведено соотношение между некоторыми известными классами КС-языков [6, т. 2, 42, 47].
Следует обратить внимание прежде всего на то, что интересующий разработчиков компиляторов в первую очередь класс детерминированных КС-языков полностью совпадает с классом LR-языков и, более того, совпадает с классом LR(l)языков. To есть доказано, что для любого детерминированного КС-языка существует задающая его LR(l)-грамматика. Этот факт уже упоминался выше. Проблема состоит в том, что не всегда возможно найти такую грамматику и нет формализованного алгоритма, как ее построить в общем случае. То же самое относится к упоминавшимся здесь ОПК-грамматикам и ОПК(1,1)-грамматикам. Также уже упоминалось, что LL-языки являются собственным подмножеством LR-языков: всякий LL-язык является одновременно LR-языком, но существуют LR-языки, которые не являются LL-языками. Поэтому LL-языки образуют более узкий класс, чем LR-языки.
Языки простого предшествования, в свою очередь, также являются собственным подмножеством LR-языков, а языки операторного предшествования — собственным подмножеством языков простого предшествования. Интересно, что языки операторного предшествования представляют собой более узкий класс, чем языки простого предшествования.
В то же время языки простого предшествования и LL-языки несопоставимы между собой: существуют языки простого предшествования, которые не являются LL-языками, и в то же время существуют LL-языки, которые не являются языками простого предшествования. Однако существуют языки, которые одновременно являются и языками простого предшествования, и LL-языками. Аналогичное замечание относится также к соотношению между собой языков операторного предшествования и LL-языков.
Можно еще отметить, что язык арифметических выражений над символами а и Ь, заданный грамматикой G({+.-./,*,а,b},{S J,E},P,S), Р = (S-»S+T|S-T|T, Т-УГ*Е|Т/Е|Е, E->(S)|a|b}, который многократно использовался в примерах в данном учебном пособии, подпадает под все указанные выше классы языков. Из приведенных ранее по всей главе 3 примеров можно заключить, что этот язык является и LL-языком, и языком операторного предшествования, а следовательно, и языком простого предшествования и, конечно, LR(l)-языком. В то же время этот язык по мере изложения материала пособия описывался различными грамматиками, не все из которых могут быть отнесены в указанные классы. Более того, в главе 1 он был задан с помощью грамматики, которая не являлась даже однозначной. Таким образом, соотношение классов КС-языков не совпадает с соотношением задающих их классов КС-грамматик. Это связано с неразрешимостью проблем преобразования и эквивалентности грамматик, которые не имеют строго формализованного решения.
Контрольные вопросы и задачи
Вопросы
1. На алгоритме какого распознавателя основан метод рекурсивного спуска? В чем заключается принципиальное изменение, внесенное в алгоритм? Ведет ли это изменение к ограничению применимости данного алгоритма?
2. Какие преобразования возможно выполнить над грамматикой, чтобы к ней был применим метод рекурсивного спуска? Можно ли формализовать и автоматизировать выполнение этих преобразований?
3. За счет чего можно расширить применимость метода рекурсивного спуска? Как влияет рекурсия, присутствующая в грамматике, на применимость данного метода? Можно ли реализовать распознаватель по методу расширенного рекурсивного спуска для грамматики, содержащей левую рекурсию?
4. За счет чего класс LL(1)-грамматик является более широким, чем класс КС-грамматик, для которых можно построить распознаватель по методу рекурсивного спуска?
5. На каком алгоритме основана работа распознавателя для LL(k)-грамматики? Какие изменения внесены в алгоритм? Насколько они сузили применимость данного алгоритма?
6. Объясните работу алгоритмов построения множеств FIRST(1,A) и FOLLOW(1,A). Можно ли эти алгоритмы тривиально распространить на множества FIRST(k,A) и FOLLOW(k,A)? Если нет, то почему?
7. Почему класс языков, заданных LR-грамматиками, является более широким, чем класс языков, заданных LL-грамматиками?
8. На каком алгоритме основана работа распознавателя для LR(к)-грамматики? Какие изменения внесены в алгоритм? Насколько они сузили применимость данного алгоритма?
9. Почему не существует языков, заданных LL(0)-грамматиками, но существуют языки, заданные LR(0)-грамматиками?
10. Почему можно утверждать, что любая LL-грамматика и любая LR-грамматика являются однозначными?
11. В чем особенности реализации алгоритма типа «сдвиг-свертка» для грамматик простого и операторного предшествования? Какие ограничения эти особенности накладывают на правила грамматики?
12. Почему в грамматике простого предшествования не могут присутствовать цепные правила, а в грамматике операторного предшествования — могут? Почему в обоих классах грамматик не могут присутствовать λ-правила?
13. Распознаватели на основе грамматик операторного предшествования имеют массу преимуществ перед распознавателями на основе грамматик простого предшествования. Почему же тем не менее используются оба класса КС-грамматик?
14. Класс языков, заданных LR(1)-грамматиками, совпадает с классом детерминированных КС-языков. Зачем же тогда используются другие классы грамматик?
15. Как объяснить тот факт, что любой язык, заданный LL-грамматикой, может быть задан и LL(1)-грамматикой, но не всякая LL-грамматика при этом является LR(1)-грамматикой?
16. Почему любая LL-грамматика является LR-грамматикой?
Задачи
1. Постройте распознаватель, основанный на методе рекурсивного спуска для грамматики: G({a,b,с}, {S,A,B,C}, P, S)
выполните разбор цепочки символов «aabbabbcabbb».
2. Постройте распознаватель, основанный на расширенном методе рекурсивного спуска для грамматики: G({а,<,=,>,+,-,/,*}, {S,T,E}, P, S)
выполните разбор цепочки символов «а*а+а<а/а-а*а».
--- докажите, что она не является LL(l)- грамматикой;
--- преобразуйте данную грамматику к виду LL(l)-грамматики; О постройте распознаватель на основе полученной грамматики и выполните разбор цепочки символов: «ала&-а&(ал—а)».
4. Постройте распознаватель на основе грамматики простого предшествования для грамматики, заданной в задаче № 3. Выполните разбор цепочки символов, указанной в задаче № 3.
постройте для нее распознаватель на основе грамматики операторного предшествования. Выполните разбор цепочки символов, указанной в задаче № 3. 6. Придумайте функцию линеаризации матрицы предшествования для грамматики, заданной в задаче № 5.
постройте для нее распознаватель на основе грамматики операторного предшествования, считая «if», «then» и «else» едиными терминальными символами. Является ли данная грамматика однозначной? Выполните разбор цепочки символов «if b then if b then if b then a else а». К первому или к последнему «if» будет отнесено «else» в этой цепочке?
8. Перестройте правила грамматики, данной в задаче № 7 так, чтобы «else» всегда относилось к объемлющему «if», а не к ближайшему.
9. Придумайте функцию линеаризации матрицы предшествования для грамматики, заданной в задаче № 7.
