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

Удаление цепных правил

Цепные правила- это правила вида : A::=B, где A и B- нетерминалы. Такие правила удлиняют вывод, замедляя работу анализаторов. Удаление подобных правил из формальной грамматики позволяет ускорить разбор цепочек.

Для удаления цепных правил используется класс delChainRules. Оператор () для этого класса преобразует формальную грамматику к форме без цепных правил.

FormalGrammar::ptr a_fg = new FormalGrammar(a_fileName); cout<<"FG до удаления цепных правил"<<a_fg->toString(); delChainRules a_dcr; a_fg = a_dcr(a_fg); cout<<"FG после удаления цепных правил"<<a_fg->toString();

Удаление левой рекурсии

Этот алгоритм крайне важен, поскольку целый класс формальных грамматик не может содержать левую рекурсию. Это класс ЛЛ1-грамматик. Разбор этих грамматик крайне прост и в то же время многие конструкции могут быть представлены в виде ЛЛ1-грамматик. Сначала дадим определение прямой левой рекурсии.

Грамматика называется грамматикой с прямой левой рекурсией, если содержит хотя бы одно правило вида A::=A w.

Грамматика называется грамматикой с левой рекурсией, если в ней возможен вывод A=>*Aw, для некоторого нетерминала A.

Удаление левой рекурсии часто приводит к тому, что грамматика становится ЛЛ1-грамматикой. Однако у этого алгоритма есть один недостаток- несмотря на то, что язык, который описывает грамматика остается прежним, сама грамматика может стать неузнаваемой. Появляется много новых правил, нетерминалов, исчезает много старых правил.

Для удаления левой рекурсии используется класс delLeftRecursion. Оператор () для этого класса преобразует формальную грамматику к форме без левой рекурсии.

FormalGrammar::ptr a_fg = new FormalGrammar(a_fileName); cout<<"FG до удаления левой рекурсии"<<a_fg->toString(); delLeftRecursion a_dlr; a_fg = p_dlr(a_fg); cout<<"FG после удаления левой рекурсии"<<a_fg->toString();

Алгоритмы над формальными грамматиками

Формальные грамматики сами по себе не представляют практического интереса. Интересны анализаторы построенные на их основе. Для построения этих алгоритмов необходимы некоторые вспомогательные результаты, которые могут быть получены с помощью алгоритмов, которые рассматриваются в этом разделе.

Построение множества укорачивающих символов

Укорачивающим символом называют такой символ для, которого верно: A=>*e. Множество таких символов используется во многих других алгоритмах, например для построения множеств ПЕРВ, ПОСЛ, СЛЕД.

Для получения этого множества используются объекты класса makeUnshortening. Его метод getShorteningTerms возвращает искомое множество термов.

FormalGrammar::ptr a_fg = new FormalGrammar(a_fileName); cout<<"FG\n"<<a_fg->toString(); makeUnShortening a_gs(); SetOfTerms::ptr a_st = p_gs.getShorteningTerms(a_fg); cout<<"Shortening terms :\n"<<a_gs->toString();

Получение множества перв (First).

Множество ПЕРВ рассматривается для термов и правил. Неформально это множество представляет собой набор терминалов, которыми могут начинаться все сентенциальные формы, выводимые их терма A (для терма). Для правила это множество термов, которыми может начинаться цепочка выводимая из правой части правила.

Формально множество ПЕРВ(A) для терма определяется так:

ПЕРВ(A) = { a | a in Vt, A=>aw }

Для правила множество ПЕРВ(R) определяется похожим образом:

ПЕРВ(R) = { a | a in Vt, R=>aw }

Для получения этого множества используются объекты класса getFirst.

FormalGrammar::ptr a_fg = new FormalGrammar(a_fileName); cout<<"FG "<<a_fg->toString(); getFirst a_gf(a_fg); SetOfTerms::ptr a_st = p_gf(a_fg->getStartSymbol()); cout<<"First(S)="<<a_st->toString();