Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Алгоритмы и преобразования.doc
Скачиваний:
0
Добавлен:
01.04.2025
Размер:
89.6 Кб
Скачать

Алгоритмы и преобразования.

Во многих приложениях формальных грамматик используются различные алгоритмы над формальными грамматиками и их преобразования. Для этих целей была разработана библиотека классов 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();