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

СПО

.pdf
Скачиваний:
41
Добавлен:
31.05.2015
Размер:
2.9 Mб
Скачать

задаваемых символическими правилами, для списка получаем:

<L> <E> {<E>}*.

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

<I> #{x | y}* .

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

<A> <A>y<B>z и <A> x<B>z

могут быть записаны так:

<A> x[<A>y]<B>z.

8.4.4.3. Синтаксические диаграммы

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

1)Каждому правилу вида <A> a1 | a2 |...| ak ставится в соответствие диаграмма, структура которой определяется правой частью правила.

2)Каждое появление терминального символа x в цепочке

ai изображается на диаграмме дугой, помеченной этим символом x, заключенным в кружок.

3)Каждому появлению нетерминального символа <A> в

цепочке ai ставится в соответствие на диаграмме дуга, помеченная символом, заключѐнным в квадрат.

4) Порождающее правило, имеющее вид:

<A> a1a2...an

изображается на диаграмме следующим образом:

5) Порождающее правило, имеющее вид:

<A> a1 | a2 | ... | an

изображается на диаграмме так:

6) Если порождающее правило задано в виде итерации:

<A> {a}*,

то ему соответствует диаграмма:

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

Правила 3-6 предусматривают, что в качестве цепочки a1 на объединенной диаграмме могут быть использованы диаграммы построенные для этих цепочек. В качестве примера рассмотрим следующую грамматику с начальным символом

<A> :

Г1. 14: Vт = { x, +, (, ) }, Va = {<A>, <B>, <C>}, R = {<A> x | (<B>),

<B> <A><C>, <C> {+<A>}*}.

Синтаксические диаграммы для такой грамматики имеют вид (рис. 33):

Рис. 33. Синтаксические диаграммы для каждого правила грамматики

Заменяя нетерминальные символы, соответствующими диаграммами, получаем объединенную диаграмму в виде (рис.

34):

Рис. 34. Объединенная синтаксическая диаграмма для заданной грамматики

8.4.5. Построение грамматик и грамматики, описывающие основные конструкции языков программирования

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

Учитывая, что терминальный словарь грамматики должен включать все символы, используемые для построения цепочек, входящих в заданное множество, результатом реше-

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

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

8.4.5.1. Рекомендации по построению грамматик

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

вторяющиеся части цепочек и части, входящие во все це-

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

Для каждого выявленного элемента структуры введем обозначения. Множество таких обозначений составляет осно-

ву словаря нетерминальных символов некоторой граммати-

ки.

Следующим шагом построения является выявление последовательностей, в которых элементы структуры могут входить в заданные цепочки. Такие последовательности являются основой для построения правил грамматики.

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

1.Цепочке, состоящей из заданных символов abc, соответствует правило

<I> abc.

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

<I> a<A>.

3.Цепочке, заканчивающейся заданным символом a, со-

ответствует правило

<I> <A>a.

4.Цепочке, начинающейся и заканчивающейся заданными символами a, b, соответствует правило

<I> a<A>b.

5.Цепочке, содержащей в середине символ a, соответствует правило

<I> <A>a<B>.

6.Цепочке заданной длины l =2 соответствуют правила:

<A>a<B> и <B>a.

7.Цепочке, состоящей из повторяющихся символов a,

соответствуют правила

<A>a<A> и <A>a.

8. Цепочке, состоящей из чередующихся символов a и b, соответствуют правила:

<A>a<B> и <B>b<A>.

8.4.5.2.Описание списков

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

1) Обозначим элемент последовательности a. Простейшая последовательность может состоять из одного элемента a. Все другие последовательности могут быть получены путем приписывания к уже построенной последовательности еще одного элемента. Если обозначить построенную часть последовательности нетерминальным символом <R>, а последовательность символом <L>, то получим правила грамматики в виде:

Г1. 15: <L> a<R>, <R> a<R>,

<R>$.

2) В предыдущей задаче предполагалось, что список <L> должен содержать хотя бы один элемент. Если же допустить, что множество цепочек, порожденных правилами грамматики, может включать пустой символ, то к построенным правилам нужно добавить еще одно правило <L>$ . В этом случае набор правил имеет вид:

Г1. 16: <L> a<R>,

<R> a<R>, <R> $, <L> $.

3) Рассмотрим построение списка, между элементами которого должны стоять разделители. Выберем в качестве разделителя запятую. Простейший список, как и в предыдущем случае, состоит из одного элемента, а построение списка из нескольких элементов может быть выполнено приписыванием к уже построенной части списка разделителя с элементом списка. Правила, соответствующие этому построению, имеют вид:

Г1. 17: <L> a<R>, <R> ,a<R>, <R> $.

4) Если список с разделителями может быть пустым, то приведенный выше набор правил нужно дополнить еще одним правилом с пустой правой частью. В результате получим:

Г1. 18: <L> a<R>, <R> ,a<R>, <R> $, <L> $.

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

1)Выписать несколько примеров из заданного множества цепочек.

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

3)Ввести обозначения для сложных структур, состоящих из групп символов. Такие обозначения являются нетерми-

нальными символами искомой грамматики.

4)Построить правила для каждой из выделенных структур, используя для задания повторяющихся структур рекурсивные правила.

5)Объединить все правила.

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

8.4.5.3. Пример построения грамматик

Применение приведенных рекомендаций рассмотрим на следующем примере. Требуется построить грамматику для языка L, терминальный словарь которого Vт = {*, |}, а цепочки, образующие язык, имеют следующую структуру:

а) каждая цепочка начинается буквой * и заканчивается двумя буквами **.

b) между началом и концом цепочек могут быть: b1) либо непустая последовательность палочек

b2) либо несколько таких последовательностей, разделенных символами *.

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

* |||**,

* |*|*|**, * ||*||||*|||||** ,

* |||*|*||*||||||** .

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

начало цепочки (символ *),

конец цепочки (символы **),

непустая группа палочек,

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

3.Обозначим группу палочек символом <A>, а последовательность групп палочек символом <B>.

4.Выделенные структуры можно рассматривать как спи-

ски. Так последовательность палочек представляет собой список без разделителей, элементом которого является палочка. Правила грамматики, задающей такой список, имеют вид:

<A> | <B>,

<B> | <B>, <B> $.

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

<C> <A> <E>,

<E> *<A> <E>, <E> $.

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

<I> *<C>**.

5. Объединяя построенные правила, окончательно получаем схему искомой грамматики в виде:

Г1. 19: R = { <I> *<C>**, <C> <A> <E>,

<E> *<A> <E>, <E> $,

<A> | <B>,

<B> | <B>, <B> $ }

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

<I> *<C>** *<A> <E>** *<A>*<A> <E>** *<A>*<A>*<A> <E> *<A>*<A>*<A>**

*<A>*<A>* | <B>** *<A>*<A>* | ** *<A>* | <B>* | ** *<A>* | * | **

* | <B>* | * | ** * | * | * | **.

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

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

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

8.4.5.4. Грамматики, описывающие целые числа без знака и идентификаторы

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

Г1. 20: <N> <D> <R>,

<R> <D> <R>, <R> $, <D> 0 | 1 | ... | 9.

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

Г1. 21: R ={ <I> <C> <A>, <A> <C> <A> | <D> <A>,

<A> <C> | <D>,