Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

nC1DMY1V3A

.pdf
Скачиваний:
4
Добавлен:
15.04.2023
Размер:
1.71 Mб
Скачать

Важно указывать номер использованного правила как индекс к нетерминалу, соответствующему его правой части, иначе трудно будет определить, по какому правилу получена цепочка, так как тот же результат можно получить:

a<A>4<B>c a<A>b<B>c

Основным в теории формальных грамматик является понятие вывода цепочки. Оно позволяет сделать вывод о принадлежности той или иной цепочки заданному языку, а также лежит в основе алгоритмов синтаксического анализа.

Определение 3.2. Выводом называется последовательность правил грамматики, которые применяются для порождения цепочек языка, порождаемого этой грамматикой.

Цепочка acabac может иметь в грамматике G (см. пример) следующий вывод, стартующий с начального нетерминала:

<S>1 a<A>4<B>c a<A>3b<B>c ac<S><B>6b<B>c ac<S>2ab<B>c acab<B>6c acabac

Каждая цепочка терминалов и нетерминалов, встречающаяся в выво-

де, называется промежуточной цепочкой.

В указанном примере семь промежуточных цепочек, включая начальную и завершающую.

Промежуточную цепочку, выводимую из начального нетерминала также называют сентенциальной формой или выводимой цепочкой.

Если при определении вывода не указывается начальная цепочка, то предполагается, что начальной цепочкой является начальный нетерминал, в противном случае начальная цепочка должна указывается явно.

Существование вывода одной цепочки из другой обозначается: =>* Говорят «существует вывод цепочки acabac из цепочки <S>» или «из

цепочки <S> можно вывести цепочку acabac» и пишут:

<S> * acabac

Допускается нулевое число подстановок в выводе:

* ,

то есть цепочку можно получить из себя самой с помощью последовательности подстановок длины нуль.

Здесь « * » играет ту же роль, что и в итерациях, так как означает нуль или более применений отношений .

Можно исключить тривиальный вывод нулевой длины, тогда пишут

<S> + acabac

и говорят: «цепочку acabac можно получить из цепочки <S> с помощью вывода, длина которого больше нуля».

В приведенном выше примере цепочку acabac можно вывести из начального символа грамматики, и поэтому она принадлежит языку, зада-

20

ваемому грамматикой. С другой стороны, цепочка bb не выводится из <S>, следовательно, она не принадлежит языку, задаваемому грамматикой.

Более наглядным является представление структуры программы в виде дерева синтаксического разбора (дерева вывода).

Определение 3.3. Под деревом синтаксического разбора (деревом вывода) понимается конечный ориентированный граф, обладающий свойствами:

вершина, в которую не входит ни одна дуга, называется корнем дерева; в КС-грамматике ей соответствует начальный нетерминал грамматики – стартовый символ;

в остальные вершины дерева входит лишь одна дуга; вершины, не имеющие выходящих из них дуг, называются заключительными вершинами дерева или листьями, в КС-грамматике им соответствуют терминальные символы грамматики; внутренним вершинам дерева соответствуют нетерминальные символы грамматики;

он не содержит циклов.

Пример построения дерева вывода цепочки acabac из <S> по правилам грамматики G представлен на рис. 3.1.

1.<S>1

2.a<A>4<B>c

3.a<A>3b<B>c

4.ac<S><B>6b<B>c

5.ac<S>2ab<B>c

6.acab<B>6c

Рис. 3.1. Пример построения дерева вывода

Дерево синтаксического разбора показывает, какие правила применялись во время вывода к каким вхождениям нетерминалов. Но построенное дерево не отражает порядка применения правил грамматики. Поэтому

может быть много выводов, соответствующих одному и тому же дереву вывода.

Например, построенному дереву (рис. 3.1) соответствует еще и следующий вывод:

<S>1 a<A>4<B>c

a<A>3b<B>c ac<S>2<B>b<B>c

ac<B>6b<B>c

acab<B>6c acabac

 

21

При этом существует подход, при котором можно получить однозначность порождения цепочки по заданной грамматике, так как по дереву можно всегда определить то единственное правило, которое должно применяться при этой подстановке.

Утверждение 3.1. Для каждого дерева существует единственный ле-

вый вывод (или левосторонний), который получается, если всегда заменять самый левый нетерминал.

Утверждение 3.2. Для каждого дерева существует единственный правый вывод (или правосторонний), который получается, если всегда заменять самый правый нетерминал.

Для рассматриваемого примера правый вывод выглядит так:

<S>1 a<A><B>6c a<A>4ac a<A>3bac ac<S><B>6bac ac<S>2abac acabac

Многие методы обработки языков рассчитаны исключительно на левые или правые выводы, так как они удобны для синтаксического анализа.

Пишут

L

, если цепочка может быть получена из цепочки в

результате одной левой подстановки.

Аналогично,

R , если цепочка может быть получена из цепочки

врезультате одной правой подстановки.

Втаких случаях подстановку можно восстановить по двум промежуточным цепочкам.

Понятно, что a<A><B>c

La<A>b<B> cможет быть получено в ре-

зультате a<A>4<B>c a<A>b<B>c

 

И наоборот, a<A><B>c

Ra<A>b<B> может быть результатом только

a<A><B>5c a<A>b<B>c

 

 

Пишут, что существует левый вывод из , если

*

L , и, соответ-

ственно, правый вывод, если

*

 

R .

 

Цепочке языка также может соответствовать более, чем одно дерево, то есть она может иметь разные выводы, порождающие разные деревья. Иллюстрация такой ситуации для рассмотренного выше примера представлена на рис. 3.2.

Рис. 3.2. Пример построения деревьев вывода цепочки acabac

22

Когда одна цепочка может иметь несколько деревьев вывода, гово-

рят, что порождающая ее грамматика неоднозначна.

Эквивалентные преобразования КС-грамматик

Построение грамматики – творческий процесс. В результате разные разработчики для одного языка могут получить разные грамматики. Но, если построены правильные грамматики, то они являются эквивалентными друг другу, в том смысле, что они порождают один и тот же язык.

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

Первым этапом указанного приведения является удаление лишних нетерминалов. Лишними называются нетерминалы, которые не участвуют в порождении цепочек языка. Они бывают двух видов: непродуктивными и недостижимыми.

Определение 3.4. Нетерминалы, которые не порождают ни одной терминальной цепочки, называют непродуктивными.

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

Пример. Рассмотрим грамматику с начальным нетерминалом <S>:

1.<S> a<S>a

2.<S> b<A>d

3.<S> c

4.<A> c<B>d

5.<A> a<A>d

6.<B> d<A>f

Непродуктивными здесь являются нетерминалы <A> и <B>. Применив правило 4 к цепочке с символом <A>, можно получить цепочку, содержащую <B>, а применив к ней правило 6, можно снова получить цепочку, содержащую <A>. Таким образом, какие бы подстановки не делались, цепочка с <A> всегда переводится в цепочку с <B>, и наоборот.

Поэтому правила, содержащие <A> и <B>, можно исключить из грамматики, оставив лишь правила 1 и 3.

Грамматика, состоящая из правил 1 и 3, порождает те же терминальные цепочки, что и грамматика с правилами 1–6.

23

Определение 3.5. Нетерминалы, которые не появляются ни в одной цепочке, выводимой из начального символа, называются недостижимыми нетерминалами.

То есть в грамматике есть нетерминалы, которые невозможно достичь из начального нетерминала.

Пример. Рассмотрим грамматику с начальным нетерминалом <S>:

1.<S> a<S>b

2.<S> c

3.<A> b<S>

4.<A> a

Очевидно, что ни одна цепочка, выводимая из <S>, не может содержать <A>. Поэтому <A> не может участвовать в выводе цепочки из <S>, хотя сам по себе этот нетерминал не является непродуктивным. Следовательно, нетерминал <A> можно удалить из грамматики, оставив правила 1, 2, при этом грамматика будет порождать те же цепочки, что и первоначальная.

Процедура обнаружения лишних нетерминалов состоит из двух частей: одна – для обнаружения непродуктивных нетерминалов, другая – для недостижимых нетерминалов [3].

Сначала нужно выполнить процедуру для непродуктивных нетерминалов, так как при их удалении из грамматики другие нетерминалы могут стать недостижимыми.

Назовем символ продуктивным, если из него выводится какаянибудь терминальная цепочка.

Процедура обнаружения непродуктивных нетерминалов основана на следующем свойстве продуктивных символов: если все символы правой части правила продуктивны, то продуктивен и символ, стоящий в левой части.

Шаги процедуры:

1.Составить список нетерминалов, для которых найдется хотя бы одно правило, правая часть которого не содержит нетерминальных символов.

2.Если найдено такое правило, что все нетерминалы, стоящие в его правой части, уже занесены в список, то добавить в список нетерминал, стоящий в его левой части.

3.Если на шаге 2 список больше не пополняется новыми нетерминалами, то получен список всех продуктивных нетерминалов грамматики, а все нетерминалы, не попавшие в него, являются непродуктивными.

Пример. Продемонстрируем описанную выше процедуру для следующей грамматики с начальным нетерминалом <S> (табл. 3.1).

24

Таблица 3.1

Процедура удаления непродуктивных нетерминалов

 

Исходное множество правил

 

 

Результат

 

 

 

 

 

 

1.

<S>

a<A><B><S>

 

 

 

2.

<S>

b<C><A><C>d

2.

<S>

b<C><A><C>d

3.

<A>

b<A><B>

 

 

 

4.

<A>

c<S><A>

4.

<A>

c<S><A>

5.

<A>

c<C><C>

5.

<A>

c<C><C>

6.

<B>

b<A><B>

 

 

 

7.

<B>

c<S><B>

 

 

 

8.

<C>

c<S>

8.

<C>

c<S>

 

 

 

9.

<C>

c

9.

<C>

c

 

 

 

 

 

 

 

 

 

Составим список нетерминалов, стоящих в левой части правил, у которых в правой части стоят только терминальные символы: {<C>}. Затем добавим в этот список терминалы, стоящие в левой части правил, у которых в правой части стоят терминалы и нетерминалы, уже включенные в

список: {<C>, <A>, <S>}.

 

 

Таким образом, нетерминалы <C>, <A> и

<S> –

продуктивны,

а <B> – непродуктивен, его можно удалить (вместе

с правилами,

где он присутствует). И в грамматике останутся

только

пять правил:

2, 4, 5, 8, 9.

Символ называется достижимым в грамматике, если он может появиться в какой-нибудь цепочке, выводимой из начального нетерминала.

Процедура обнаружения недостижимых символов грамматики основана на следующем свойстве достижимых символов: если нетерминал в левой части правила является достижимым, то достижимы и все символы правой части этого правила.

Шаги процедуры:

1.Образовать одноэлементный список, состоящий из начального нетерминала.

2.Если найдется правило, левая часть которого уже имеется в списке, то включить в список все нетерминалы, содержащиеся в его правой части.

3.Если на шаге 2 новые нетерминалы в список больше не поступают, то получен список всех достижимых нетерминалов, а нетерминалы, не попавшие в него, являются недоступными.

Пример. Продемонстрируем описанную выше процедуру для следующей грамматики с начальным нетерминалом <S> (табл. 3.2).

25

Таблица 3.2

Процедура удаления недостижимых нетерминалов

 

Исходное множество правил

 

 

 

Результат

1.

<S>

a<A><B>

1.

<S>

a<A><B>

2.

<S>

<E>

2.

<S>

<E>

3.

<A>

d<D><A>

3.

<A>

d<D><A>

4.

<A>

e

4.

<A>

e

5.

<B>

b<E>

5.

<B>

b<E>

6.

<B>

f

6.

<B>

f

7.

<C>

c<A><B>

 

 

 

 

8.

<C>

d<S><D>

 

 

 

 

9.

<C>

a

 

 

 

 

10.

<D>

e<A>

10.

<D>

e<A>

11.

<E>

f<A>

11.

<E>

f<A>

12.

<E>

g

12.

<E>

g

Составим одноэлементный список: {<S>}. Добавим в этот список нетерминалы, стоящие в правой части правил, в левой части которых стоят нетерминалы уже включенные в список: {<S>, <A>, <B>, <E>, <D>}.

Таким образом, достижимые нетерминалы: <S>, <A>, <B>, <D>, <E>, недостижимые: <C>. Удаляем все правила, содержащие <C>, в результате получаем грамматику, состоящую из 9 правил.

Пример. Продемонстрируем результат применения обеих процедур к одной грамматике (таблица 3.3).

 

 

 

 

 

 

Таблица 3.3

 

 

Процедура удаления лишних нетерминалов

 

 

 

 

 

 

 

 

Грамматика

 

Процедура 1

Процедура 2

1.

<S>

1.

<S>

1. <S> aс

2.

<S>

b<A>

 

 

 

 

3.

<A>

c<B><C>

 

 

 

 

4.

<B>

a<S><A>

 

 

 

 

5.

<C>

b<C>

5.

<C>

b<C>

 

6.

<C>

d

6.

<C>

d

 

 

 

 

 

Таким образом, язык, порождаемый этой грамматикой, содержит только одну цепочку ac.

Можно заметить, что нетерминал <C> стал недостижимым лишь после удаления правила 3. Поэтому, если бы процедуры использовались в другом порядке: сначала устранялись недостижимые, а потом – непродуктивные, грамматику не удалось бы до конца упростить.

26

Следующий этап приведения грамматики – эквивалентные преобразования КС-грамматики для облегчения создания анализаторов языка. В результате таких преобразований изменяется вид и состав правил грамматики.

Примерами таких преобразований грамматик могут служить: удаление -правил; удаление цепных правил.

Определение 3.6. -правилами называются правила грамматики вида

<A>

, где <A> N, – пустая цепочка.

Наличие -правил в множестве правил формальной грамматики оз-

начает,

что возможна пустая подстановка вместо нетерминала <А>, то

есть грамматика является укорачивающей КС-грамматикой (УКСграмматика). Удаление -правил позволяет преобразовать укорачивающую грамматику к стандартному виду правил грамматики класса 2 по классификации по Холмскому – КС-грамматике.

Определение 3.7. Грамматика G называется грамматикой без -

правил, если в ней не существует правил <A>

, где <A> – не начальный

нетерминал,

 

 

или существует только одно правило <S>

, где <S> – начальный

нетерминал, в том случае, когда

L(G), и при этом <S> не встречается в

правой части ни одного правила грамматики G.

 

Шаги процедуры исключения

-правил:

 

1.Составить список нетерминалов, для которых имеются -правила.

2.Дополнить полученный список нетерминалами, для которых в правилах правая часть содержит только нетерминалы уже включенные в список.

3.

Удалить из набора правил

грамматики правила определенные в

 

п. 1, 2.

 

4.

Оставшиеся правила преобразовать следующим образом:

 

Если имеется правило <A>

и в цепочку входят нетерминалы

из списка, тогда на основе цепочки

стоится множество цепочек { '} пу-

тем исключения из всех возможных комбинаций нетерминальных символов из списка и все новые правила добавляются к правилам грамматики.

Если начальный нетерминал попал в список, следовательно L(G), то тогда в множество нетерминальных символов добавляется новый символ <S'>, который становится начальным нетерминалом грамматики, а в набор правил добавляются два новых правила:

<S'>

<S>, <S'> .

Пример. Рассмотрим грамматику G:

1. <S>

a<S>b<S>

2. <S>

 

Построим грамматику G' без -правил, эквивалентную грамматике G.

27

В данной грамматике -правилом является правило 2. Его необходимо исключить из грамматики, а первое преобразовать, заменив его на набор правил, реализующих использование пустой цепочки:

<S> a<S>b<S> <S> a<S>b <S> ab<S> <S> ab

Так как в исходной грамматике начальный нетерминал входил в - правило, то для сохранения пустой цепочки в порождаемом языке необходимо ввести новый начальный нетерминал и два специальных правила:

<S'> , <S'> <S>

Таким образом, в новой грамматике G' получаем 6 правил и N' = {<S'>, <S>}; причем <S'> – начальный нетерминал (таблица 3.4).

 

 

 

 

Таблица 3.4

Процедура исключения

-правил

 

 

 

 

 

Исходное множество правил

 

 

 

Результат

1. <S> a<S>b<S>

 

1.

<S'>

 

2. <S>

 

2.

<S'>

<S>

 

 

3.

<S>

a<S>b<S>

 

 

4.

<S>

a<S>b

 

 

5.

<S>

ab<S>

 

 

6.

<S>

ab

Эквивалентные преобразования

грамматики с целью устранения

цепных правил позволяет сократить количество шагов работы алгоритма распознавания, то есть повысить быстродействие анализатора.

Определение 3.8. Цепные правила грамматики – это правила вида

<A> <B>.

Цепные правила могут привести к бесполезным циклам в грамматике. Определение 3.9. Циклом (циклическим выводом) в грамматике G

называется вывод вида <A> * <A>.

Процедура исключения цепных правил применяется для всех нетерминалов грамматики в отдельности.

Шаги процедуры:

1.Создать одноэлементный список, состоящий из исследуемого нетерминала, например <A>.

2.Если найдено правило, левая часть которого уже имеется в списке, а правая представлена одним нетерминалом, то включить в список нетерминал, стоящий в правой части.

3.Если после шага 2 в списке больше, чем один нетерминал, то исклю-

чить из набора правил найденные цепные правила вида <A> <B>.

28

4.Для всех правил вида <В> , где <B> – нетерминал, включенный в список нетерминала <A>, добавить в набор правил правила вида

<А> .

Пример. Пусть задана грамматика с начальным нетерминалом <S>:

1.<S> <S>a<S>

2.<S> <A>

3.<A> <A>b<B>

4.<A> <B>

5.<B> c<S>d

6.<B> m

В данной грамматике имеются три нетерминала: <S>, <A>, <B>. Построим список для нетерминала {<S>}. Так как в грамматике при-

сутствуют цепные правила: <S>

<A>, <A> <B>, то в список внесем не-

терминалы <A> и <B>, а грамматику дополним правилами:

<S>

<A>b<B>

 

<S>

c<S>d

 

<S>

m

 

Построим список для нетерминала {<A>}. Так как в грамматике при-

сутствует цепное правило: <A>

<B>, то в список внесем нетерминал <B>,

а грамматику дополним правилами:

<A>

c<S>d

 

<A>

m

 

Нетерминал <B> не находится в левой части цепного правила, поэтому процедуру можно закончить, предварительно удалив все цепные правила. В результате получаем грамматику, состоящую из девяти правил

(табл. 3.5).

Таблица 3.5

Процедура исключения цепных правил

 

Исходное множество правил

 

 

Результат

1.

<S>

<S>a<А>

1.

<S>

<S>a<A>

2.

<S>

<A>

2.

<S>

<A>b<B>

3.

<A>

<A>b<B>

3.

<S>

c<S>d

4.

<A>

<B>

4.

<S>

m

5.

<B>

c<S>d

5.

<A>

<A>b<B>

6.

<B>

m

6.

<A>

c<S>d

 

 

 

7.

<A>

m

 

 

 

8.

<B>

c<S>d

 

 

 

9.

<B>

m

Определение 3.10. Грамматика G = <N, T, S, P> называется приведенной, если в ней отсутствуют лишние нетерминалы и исключены цепные и -правила.

29

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]