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

2.11 Атрибутные транслирующие грамматики

Синтезируемые атрибуты

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

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

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

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

Транслятор для S-атрибутного определения может быть реализован с помощью генератора LR-анализаторов типа YACC. По S-атрибутному определению генератор синтаксических анали-заторов может создать транслятор, вычисляющий атрибуты в процессе разбора входной строки.

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

Разбор

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

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

Анализатор может быть построен для любой грамматики, хотя используемые на практике грамматики имеют специальный вид. Для любой контекстно-свободной грамматики существует анализатор, который производит разбор строки, состоящей из n токенов, за время, не превышающее 0{n3}. Однако такое кубическое время разбора слишком велико. Для конкретного языка можно построить грамматику, которая будет анализироваться намного быстрее. Для разбора почти всех встречающихся на практике языков достаточно линейного алгоритма. Анализаторы языков программирования почти всегда делают один проход входного потока слева направо, заглядывая вперед на один токен.

Большинство методов разбора делится на два типа – нисходящие (сверху вниз) и восходящие (снизу вверх). Это связано с порядком, в котором строятся узлы дерева разбора. При первом методе построение начинается от корня по направлению к листьям, в то время как при втором методе – от листьев по направлению к корню. Популярность анализаторов "сверху вниз" обусловлена тем фактом, что построить эффективный анализатор вручную проще с использованием методов "сверху вниз". Однако разбор "снизу вверх" может работать с большим классом грамматик и схем трансляции, так что программный инструментарий для генерации анализаторов непосредственно по грамматикам тяготеет к восходящим методам.

Наследуемые атрибуты

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

Введем новый класс синтаксически управляемых определений, называемых L-атрибутными определениями, атрибуты которых всегда могут быть вычислены в порядке в глубину (здесь L означает left (левый), поскольку информация об атрибутах появляется слева направо). Большие классы L-атрибутных определений включают все синтаксически управляемые определения, основанные на LL(1)-грамматиках.

Синтаксически управляемое определение является L-атрибутным, если каждый наследуемый атрибут символа Xj, 1  j  n, из правой части продукции A →Х1Х2...Хn зависит только от атрибутов символов Х1, Х2, ...,X j-1, расположенных в продукции слева от Xj, и наследуемых атрибутов А.

Каждое S-атрибутное определение является L-атрибутным, так как ограничения относятся только к наследуемым атрибутам.

Схемы трансляции

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

Схемы трансляции имеют как наследуемые, так и синтезируемые атрибуты. В простых схемах трансляции атрибуты имеют строковый тип, у каждого символа грамматики был ровно один атрибут и для каждой продукции A → Х1Х2...Хn семантическое правило формировало строку атрибута для А конкатенацией строк для Х1, Х2, ..., Хn в приведенном порядке с некоторыми дополнительными строками между ними. Трансляция могла быть выполнена выводом строк в порядке их появления в семантических правилах.

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

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

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

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

Постфиксная запись

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

(а + b) * (c + d).

В постфиксной форме данное выражение имеет следующий вид:

ab + cd + *.

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

Постфиксная запись выражения Е может быть определена следующим образом.

1. Если Е является переменной или константой, то постфиксная запись Е представляет собой Е.

2. Если Е – выражение вида Е1 ор Е2, где ор – произвольный бинарный оператор, то постфиксная запись Е представляет собой Е1Е2 ор, где Е1 и Е2 – постфиксные записи для Е1 и Е2, соответственно.

3. Если Е – выражение вида (Е1), то постфиксная запись для Е1 представляет собой также и постфиксную запись для Е.

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

(9 – 5) + 2

является

95 – 2 +,

а для

9 – (5 + 2)

будет

952 + –.