
- •Алгоритмы и преобразования.
- •Преобразования формальных грамматик
- •Удаление бесполезных символов
- •Удаление e-правил (пустых правил)
- •Удаление цепных правил
- •Удаление левой рекурсии
- •Алгоритмы над формальными грамматиками
- •Построение множества укорачивающих символов
- •Получение множества перв (First).
- •Получение множества посл (Last).
- •Получение множества След (Follow).
- •Определение принадлежности к классу лл1
- •Алгоритм разбора для лл1 грамматик
- •Построение управляющей таблицы для лл1-анализатора
- •Грамматики предшествования
- •Вычисление матрицы предшествования
- •Определение принадлежности грамматики к классу простого предшествования
- •Определение принадлежности грамматики к классу слабого предшествования
Алгоритмы и преобразования.
Во многих приложениях формальных грамматик используются различные алгоритмы над формальными грамматиками и их преобразования. Для этих целей была разработана библиотека классов FGAlgoritms. Экземпляры классов этой библиотеки представляют собой функционалы или объекты функции. Т.е. у них перегружена операция (). Это позволяет использовать эти алгоритмы более широко, например мы можем использовать "побочные" результаты алгоритмов для различных нужд, или передавать алгоритм-преобразование, как параметр другого алгоритма.
Преобразования формальных грамматик
Формальные грамматики были разработаны для того, чтобы описывать некоторый язык. Основная их цель- давать формальной описание всем цепочкам, которые могут принадлежать некоторому языку. Однако, для одного языка могут существовать несколько формальных грамматик его описывающих. Причем их различие может заключаться на только в названиях термов или порядке правил, но и в самих правилах. Другими словами, грамматики могут "существенно" отличаться, т.е. никакая перестановка правил местами или переименование термов не приведут одну грамматику к другой. И несмотря на это языки, которые они порождают будут совпадать.
В качестве простого примера рассмотрим две язык, состоящий из всех цепочек из одной или более единиц. L={ (1)+ }. Для него можно написать две различные грамматики:
ФГ1:
( Vn={ "S" , "A" } Vt={ "1" } R={ "S::=1 A" , "A::=1 A" , "A::=" } S="S")
ФГ2:
( Vn={ "S" } Vt={ "1" } R={ "S::=1 S" , "S::=1 " } S="S")
Сразу видно, что эти две грамматики существенно отличаются. У них даже количество нетерминальных символов различно. Подобные различия грамматик порой очень сильно влияют на то, каким образом можно построить анализатор языка для данной грамматики. Для одного языка можно построить грамматики различных классов, с разным уровнем сложности разбора. Возникает задача- определить, порождают ли грамматики один и тот же язык, или нет. В общем случае эта задача не разрешима, однако есть некоторые преобразования грамматик, которые позволяют изменить грамматику, не изменив при этом язык, который она порождает.
Удаление бесполезных символов
Чтобы определить, что такое "бесполезный" символ, надо сначала дать два других определения:
Недостижимый символ- символ, который не может появится ни в одной сентенциальной форме.
Производящий нетерминал- символ, из которого можно вывести терминальную цепочку. Т.е. A=>+x
Теперь можно дать определение бесполезному символу. Символ называется бесполезным если он непроизводящий или недостижимый.
Алгоритм удаления бесполезных символов разбивается на четыре части: удаление непроизводящих символов, удаление правил, содержащих эти символы, удаление недостижимых символов, удаление правил, содержащих эти символы.
Удаление e-правил (пустых правил)
Пустое правило- это правило с пусто правой частью. Такие правила очень часто становятся большой проблемой для парсеров. Многие анализаторы не допускают использования в грамматиках таких правил. Для того, чтобы избавиться от таких правил можно применить алгоритм удаление пустых правил.
Для удаления этих пустых правил используется класс makeUnShorteningGrammar. Оператор () для этого класса преобразует формальную грамматику к форме без пустых правил.
FormalGrammar::ptr a_fg = new FormalGrammar(a_fileName); cout<<"FG до удаления пустых правил"<<a_fg->toString(); makeUnShorteningGrammar a_musg; a_fg = a_musg(a_fg); cout<<"FG после удаления пустых правил"<<a_fg->toString();