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

5.3. Операторная грамматика предшествования

Алгоритм разбора Вирта–Вебера и отношения простого предшествования, лежащие в его основе, просты для понимания, безупречны и эффективны с теоретической точки и поэтому именно с них мы начали обсуждение детерминированных алгоритмов восходящего разбора. Но в практике построения компиляторов они не нашли широкого применения из–за причин, рассмотренных в разделе 5.2.3.

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

Операторной грамматикой называется КС–грамматика без аннулирующих правил, в которой правые части правил не содержат смежных нетерминалов. Иными словами в операторных грамматиках запрещены правила вида V UW, где U, W .

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

Введем вначале понятие множества самых левых (L) и самых правых (R) терминалов для нетерминала U:

L(U) = {x | x ( (U x) or (U U1x) or ( (U U2) (x L(U2)))},

где здесь и далее U, U1, U2 (нетерминалы) , а , ( ) (любые цепочки из терминалов и нетерминалов, возможно пустые).

R(U) = {x | x ( (U x) or (U xU1) or ( (U U2) (x R(U2)))}

Определим теперь отношения предшествования для терминалов грамматики x и y:

xy, если U xU1) (y L(U1) ;

xy, если (U U1y) (x R(U1) ;

xy, если U xy or U xU1y.

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

E ETT

T TMM

M (E)i

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

Для нахождения основ, состоящих из одного нетерминала, отношения операторного предшествования неприменимы, – для нетерминалов их просто не существует. Если рассмотреть, например, сентенциальную форму MM из арифметической грамматики примера 5.16, то основой здесь является М, а отношения есть только такие: # и # (как и в разделе 3.4 мы предполагаем, что сентенциальная форма заключена между ограничителями # и что #x и x# для всех терминалов x). На каждом шаге разбора при использовании операторного предшествования распознается и редуцируется не основа, а так называемая самая левая первичная фраза.

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

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

# N1T1N2T2 . . . NnTnNn+1 #

где Ni – нетерминалы, которые могут и отсутствовать, а Ti – терминальные символы. Иначе говоря, сентенциальная форма состоит их n терминалов, причем между каждыми двумя соседними терминалами находится не более чем один нетерминал.

Самой левой первичной фразой сентенциальной формы в операторных грамматиках предшествования является такая самая левая подцепочка NjTj ... NiTiNi+1 , что

Tj–1Tj , TjTj+1 , Ti–1Ti , TiTi+1 .

Это определение очень похоже на соответствующее определение для простого предшествования. Основное различие состоит в том, что здесь из отношений исключены нетерминальные символы. Тем не менее, нетерминалы, находящиеся слева от Tj и справа от Ti , а также все нетерминалы лежащие между ними всегда принадлежат первичной фразе.

Пример 5.17. Для иллюстрации этого определения проведем разбор цепочки i(ii), используя матрицу предшествования с рис. 5.19 б. На рис. 5.20 а представлено дерево разбора для этой цепочки, а в таблице на рис. 5.20 б показаны символы, к которым приводятся первичные фразы. 

Как видно из рис. 5.20 б, основываясь на интуиции, первое i мы свернули к T, а второе i – к E, хотя единственное, что очевидно из отношений и грамматики – это свертка от i к M. Заметим, что при поиске самой левой первичной фразы, которую нужно редуцировать, нетерминальные символы вообще не принимаются во внимание.

# i ( i i ) #

# E ( i i ) #

# E ( E i ) #

# E ( E E ) #

# E ( E ) #

# E E #

# E #

Рис. 5.21

В компиляторах с каждым нетерминалом или операндом связана масса семантической информации: тип операнда, его адрес, признак принадлежности операнда к формальным параметрам и т.п. Семантические программы, которые выполняются при редукции первичных фраз, нуждаются только в семантической информации, связанной с нетерминальными символами, а не в самих символах. Например, для семантической подпрограммы связанной с редукцией фразы TM, безразлично какая это фраза: TM, MT или MM. Она использует только семантику нетерминалов. Да и само появление в грамматике арифметических выражений нетерминалов T и M не связано с какими либо семантическими целями; они позволили сделать грамматику однозначной и определить необходимое предшествование операторов. После того как это выполнено, в грамматике достаточно оставить один нетерминал с тем, чтобы максимально упростить редукцию. Так арифметическая грамматика, которую можно получить из грамматики, представленной в примере 5.16, если оставить в грамматике единственный нетерминал E, имеет вид:

E EEEE(E)i

Рисунок 5.21 иллюстрирует свертку цепочки #i(ii)#, базирующуюся на полученной грамматике и отношениях операторного предшествования с рис. 5.19 б.

Конечно, семантические программы здесь могут стать более сложными, так как они должны будут проводить более подробную проверку операндов, чем в грамматиках простого предшествования. Но выигрыш здесь более существенен, так как распознаватель в целом становится значительно эффективнее. Отметим, что уменьшается объем памяти под матрицу предшествования, так как она содержит теперь отношения только для терминалов грамматики. Более того, распознаватель в явном виде не выполняет таких редукций, как E T или T M, поскольку T и M не первичные фразы и такого рода редукции не несут никакой семантической нагрузки.

Упражнения.

5.1. Построить отношения простого предшествования для грамматики с правилами S aSbcd.

5.2. Построить отношения простого предшествования и функцию предшествования, используя граф линеаризации, для грамматики с правилами S aSSbcd. Покажите этапы свертки фраз aacdbcb , ab , acb.

1

2

3

4

1







2





3





4

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

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

E E or TT

T T and MM

M a(E) not M

5.5. Постройте отношения простого предшествования для грамматики с правилами S 0S11011 и терминалами { 0, 1 }. Если данная грамматика не является грамматикой простого предшествования, то преобразуйте ее к такой грамматике.

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

5.7. Преобразуйте грамматику

S E

E TTBE(E)

T abz

B 

к грамматике простого предшествования. Покажите этапы свертки фразы a(b+c).

Упражнения на программирование.

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

5.9. Реализовать программу, которая по заданной грамматике строит отношения простого предшествования. Если грамматика не является грамматикой простого предшествования, то программа должна пытаться привести ее к такому виду. Визуализировать поэтапное построение отношений предшествования и работу алгоритма стратификации.

5.10. Реализовать программу, которая определяет, является ли заданная грамматика операторной, строит отношения операторного предшествования, функцию предшествования и реализует алгоритм синтаксического анализа с использованием этих отношений и функции. Визуализировать процесс построения отношений, функции и работу алгоритма разбора.