Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Все_пособие_редактир.doc
Скачиваний:
175
Добавлен:
31.10.2018
Размер:
2.51 Mб
Скачать

5.5 Порождение

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

Рассмотрим, например, следующую грамматику арифметических выражений.

E->E+E | E*E | (E) | -E | id (5.3)

Продукция E-> -E означает, что выражение, которому предшествует знак минуса, также является выражением. Эта продукция может использоваться для порождения бо­лее сложных выражений из простых, позволяя заменять любой экземпляр E на –E. В простейшем случае можно заместить одно E на -E и описать это как Е=> -E. Такая запись читается, как "E порождает -E", или "из E выводится -E". Продукция E—>(E) го­ворит, что можно также заменить один экземпляр E в любой строке грамматики на (E), например E*E=>(E)*E или E*E=>E*(E).

Можно взять нетерминал E и неоднократно применять продукции в произ­вольном порядке для получения последовательности замещений, например, E => -E => -(E) => -(id). Такая последовательность замен представляет порождение (id) из E. ( Символ => означает "порождает за один шаг". Символ =*> означает "порождает за нуль или более шагов". Символ =+> используется для обозначения "порождает за один или более шагов". )

Предложение языка L(G), порождаемого грамматикой G, представляет собой сентенциальную форму без нетерминалов.

Например, строка -(id+id) является предложением грамматики (5.3) так как существует следующее порождение

Е => -E=> -(E) => -(Е + Е)=> -(id + Е) => -(id + id) (5.4)

Строки Е, -E, -(E),..., -(id+id), появляющиеся в процессе порождения, представляют собой сентенциальные формы данной грамматики. Для указания того, что -(id+id) мо­жет быть выведено из E, можно записать E=*>-(id + id).

На каждом шаге порождения осуществляется два выбора — во-первых, выбор за­меняемого нетерминала, во-вторых, его альтернативы. Например, порождение (5.4) из приме­ра 11 может продолжиться после -(E+E) следующим образом:

-(E+E) => -(E+id) => -(id+id) (5.5)

Каждый нетерминал в (5.5) замещается той же правой частью, что и в (5.4), но в дру­гом порядке.

    1. Деревья разбора и приведения.

Дерево разбора рассматривается как графическое представление порождения, из которого удалена информация о порядке замещения. Каждый внутренний узел дерева разбора помечается некоторым нетерминалом А, а узлы слева направо — символами из правой части продукции для этого нетерминала. Листья дерева разбора помечены нетерминалами или терминалами и, будучи прочитаны слева направо, образуют сентенциальную форму. Например, дерево разбора для -(id+id), полученное порождением (5.4), показано на рис. 22.

Рис. 22. Дерево разбора для -(id+id)

Пример 11

Рассмотрим порождение (5.4). Последовательность деревьев разбора, построенная на основе этого порождения, показана на рис. 23.

Первый шаг этого порождения – E => -E. Для моделирования этого шага добавляем к корню начального дерева два дочерних узла, помещенных как "-" и "E".

Второй шаг представляет собой -E=>-(E). Соответственно, добавляем три дочерних узла — "(", "Е" и ")" — к листу Е во втором дереве для получения третьего дерева, дающего -(Е). Продолжая построения получим шестое дерево в качестве полного дерева разбора.

Дерево разбора игнорирует порядок, в котором производилось замещение символов в сентенциальной форме. Например, если порождение (5.4) изменить в соответствии с (5.5), окончательное дерево разбора будет таким же, как на рис. 23.

Предложение может иметь не одно дерево разбора и даже не одно левое или правое порождение.

E

Рис. 23. Построение дерева разбора из порождения (5.4)

Пример 12

Обратимся вновь к грамматике арифметических выражений (5.3). Предложение id+id*id имеет два разных левых порождения

E=>E+E E=>E*E

=>id+ E E=>E+E*E

=>id + E*E => id + E * E

=> id + id * E => id + id * E

=> id + id*id => id + id*id

с двумя соответствующими им деревьями разбора, показанными на рис. 24.

a) 6)

Рис. 24. Два дерева разбора для id+id*id

Дерево разбора на рис. 24(а) отражает обычные приоритеты операций + и *, в отличие от дерева на рис. 24(6). Обычно приоритет умножения выше, и выражение типа а+b*с трактуется как а+(b*с), а не как (а+b)*с.