- •1.2.1. Первичные понятия
- •1.2.2. Примеры, иллюстрирующие первичные понятия
- •1.2.3. Пустой язык
- •1.3.1. Грамматики типа 0
- •1.3.2. Грамматики типа 1
- •1.3.3. Грамматики типа 2
- •1.3.4. Грамматики типа 3
- •1.3.5. Вывод в кс-грамматиках и правила построения дерева вывода
- •1.3.7. Левый и правый выводы
- •1.5.1. Рекомендации по построению грамматик
- •Лексический анализатор должен читать символы из входного файла, строить записи, называемые токенами, и передавать их синтаксическому анализатору, как это показано на рисунке 6.1.
- •3.5. Функции перв, след и выбор.
- •5.4. Атрибутные преобразователи ( ап )
- •5.4.1. Представление правил lat-грамматики в магазине.
- •5.4.2. Построение инструкций ап.
5.4.2. Построение инструкций ап.
Итак, для построения левого вывода LАТ - грамматики в магазине при каждом применении правила необходимо построить фрагмент магазина, соответствующий правой части правила, и установить связи атрибутов правой части правила с атрибутами заменяемой левой части правила, которые в момент замены находятся непосредственно под вершиной магазина. В результате установки связи в элементы магазина, определяющие значения наследуемых атрибутов, должны быть записаны указатели на элементы магазина, в которые нужно поместить значения этих атрибутов, а в элементы, соответствующие синтезируемым атрибутам, должны быть занесены указатели на элементы магазина, в которых будут расположены значения этих атрибутов. При этом в магазине могут образовываться цепочки указателей, ссылающихся друг на друга, которые соответствуют отложенным присваиваниям и последовательностям стрелок в графическом представлении вывода. Вывод в атрибутных грамматиках совмещается с вычислением значений атрибутов. Если грамматика задана в форме простого присваивания, то вычисление значений атрибутов осуществляется при выполнении символов действия. Полученные в результате вычисления значения атрибутов должны заноситься в отведенные этим атрибутам элементы магазина, а также во все элементы, связанные с ними цепочкой указателей. Основываясь на описанной выше схеме выполнения левого вывода в атрибутной грамматике с использованием магазина, можно сделать вывод о том, что усложнение атрибутного преобразователя по сравнению с преобразователем, построенным по транслирующей грамматике, возникает за счет необходимости выделения памяти для атрибутов в магазине и работы с указателями. Действия, связанные с построением фрагмента магазина, АТ- преобразователь может выполнять при записи правой части правила в магазин. Предписания для установки указателей и определения значений атрибутов, необходимые для построения фрагмента, могут быть определены и описаны заранее на этапе построения АТ - преобразователя. Такие предписания зависят от вида атрибута и могут быть определены исходя из того, что при выводе с использованием магазина корень синтаксического дерева вывода находится на дне магазина, а конечные вершины дерева получаются на вершине. Кроме того, необходимо учесть, что значения синтезируемых атрибутов должны передаваться по направлению от конечных вершин дерева к корню, а значения наследуемых атрибутов наоборот - от корня к конечным вершинам. Отмеченные обстоятельства позволяют сформулировать правила вычисления значений атрибутов следующим образом.
1) Если источником копирующего правила является синтезируемый атрибут или атрибут терминального символа, то в поле, соответствующее источнику, записывается указатель на поле приемника, в которое нужно поместить значение источника после его определения.
2) Если источником копирующего правила является наследуемый атрибут, то в поле, соответствующее приемнику, записывается указатель на поле источника, из которого нужно взять значение.
3) Если источником копирующего правила является константа, то ее значение заносится в поле, соответствующее приемнику.
4) Если приемниками копирующего правила являются несколько атрибутов (множественное присваивание), то они связываются цепочкой указателей.
При построении фрагментов для правил грамматики следует помнить, что атрибуты левой части заменяемого правила должны находиться в магазине всегда непосредственно под первым атрибутом правой части правила, заносимого в магазин. Построим фрагмент магазина для правила
<A>/x1 {СЛЕДУК}%y1 a %z{f}/x2/x3/x4%y2 <B> /x5 %q !! ( x2,x5 ) = x1; x3 = y1; x4 = z; q = y2;
который можно изобразить в виде следующей диаграммы:
Процедуру построения этого фрагмента можно представить в виде инструкции АТ-преобразователя. Полагая, что смысл действий достаточно точно передается словами, используемыми для их обозначения, запишем инструкцию в виде:
{ 1. Записать в магазин цепочку %q/x5<B>%y2/x4/x3/x2{f}%z a%y1{СЛЕДУК} 2.В поле атрибута %y2 записать указатель на %q; 3.В поле атрибута %z записать указатель на /x4; 4.В поле атрибута %y1 записать указатель на /x3; 5.В поле атрибута /x2 записать указатель на /x5; 6.В поле атрибута /x5 записать указатель на /x1; }
Использование идентификаторов переменных в полученном описании противоречит принципам работы с адресуемой памятью. Чтобы избавиться от этого противоречия, воспользуемся программной реализацией магазина, расположенного в основной памяти. Обычно в этом случае расширяют возможности работы с магазином, разрешая обращения к элементам магазина, расположенным под его вершиной, и магазин называют стеком, а указатель на его вершину обозначают SP. Полагая, что указатели смежных элементов стека отличаются на единицу, в рассматриваемом случае элементы, находящиеся под вершиной, должны иметь указатели SP-1,SP-2,..., а элементы, расположенные над вершиной стека, - указатели SP+1,SP+2,... . Если в вершине стека расположен нетерминал, то указатель на него хранится в SP, а атрибуты этого нетерминала находятся в ячейках стека с указателями SP-1,SP-2,... . Заменяя нетерминал правой частью правила, состоящей из N символов, получим новое значение указателя стека SP'=SP+N-1. При этом указатели на атрибуты замененного нетерминала относительно нового значения указателя будут иметь следующие значения: SP'-N, SP'-N-1, SP'-N-2,... . В качестве иллюстрации использования адресации относительно указателя стека, найдем значение указателей для рассмотренного выше примера фрагмента стека, полагая, что стек представляет собой массив с именем STACK, а указатель SP является индексом этого массива.
Из приведенной схемы видно, что после записи 12 символов,образующих правую часть правила, указатель на первый атрибут удаленного нетерминального символа оказывается равным SP-12. Используя соглашение о представлении стека в памяти, инструкцию для построения фрагмента магазина запишем в следующем виде:
{ 1.Записать в стек цепочку %q/x5<B>%y2/x4/x3/x2{f}%z a%y1{СЛЕДУК} 2. STACK[SP-8] =SP-11; 3. STACK[SP-3] =SP-7; 4. STACK[SP-1] =SP-6; 5. STACK[SP-5] =SP-10; 6. STACK[SP-10] =SP-12; }
Приведенное описание инструкции преобразователя можно считать aлгоритмическим, поскольку описание действий в форме фразы естественного языка, использованное для краткости, может быть заменено последовательностью операций записи в магазин, сопровождающихся изменением указателя стека. Однако использо- вание адресации относительно вершины стека обеспечивает корректное значение указателей, если только вершина стека не изменяется. Чтобы получить возможность работы с указателями независимо от положения вершины в стеке, возьмем в качестве значения указателя приращение адреса стека относительно элемента, в который заносится указатель. Используя такой способ адресации, перепишем рассматриваемую инструкцию так:
{ 1. Записать в стек цепочку %q/x5<B>%y2/x4/x3/x2{f}%z a%y1{СЛЕДУК} 2. STACK[SP-1] =-5; 3. STACK[SP-3] =-4; 4. STACK[SP-5] =-5; 5. STACK[SP-8] =-3; 6.STACK[SP-10] =-2; }
43. Восходящие методы распознавания.
Построение восходящих атрибутных преобразователей
Детерминированные атрибутные преобразователи могут работать не только на основе нисходящего, но и на основе восходящего метода. Особенность процедуры построения восходящих атрибутных преобразователей заключается в том, что перевод, реализуемый такими преобразователями должен быть задан в форме S-атрибутной грамматики, которая определяется следующим образом. Определение. L-атрибутная грамматика в форме простого присваивания, у которой все атрибуты нетерминальных символов являются синтезируемыми атрибутами, называется S-атрибутной грамматикой.
Необходимость использования только синтезируемых атрибутов вытекает из способа работы восходящего преобразователя, соответствующего построению дерева вывода в направлению от листьев к корню дерева, при котором передача наследуемых атрибутов оказывается невозможной. Свойства L-атрибутной грамматики гарантируют, что в правилах вычисления синтезируемых атрибутов нетерминала <X> не используются другие синтезируемые атрибуты этого символа, и что в правилах вычисления наследуемых атрибутов, находящихся в правых частях правил грамматики, используются только атрибуты символов, расположенных в правилах грамматики слева от символа с рассматриваемым атрибутом. В качестве примера приведем S-атрибутную грамматику, построеннуую по грамматике Г 3. 14, которая имеет вид:
Г5.7:
<E>%a <E>%b+T%c{СЛЕДУК}%d{СЛОЖИТЬ/x /y %z} !! x = b; y = c; (a, z) = d; <E>%g <T>%h !! g = h; <T>%k (<E>%l) !! k = l; <T>%n i/m !! n = m;
Эта грамматика для выражения строит последовательность атомов, атрибутами которых являются указатели на элементы памяти, хранящие значения операндов и результата.Значения указателей операндов передаются от терминалов i через атрибуты нетерминальных символов на выход. Указатели на элементы памяти, выделяемые для промежуточных результатов, формируются символом действия с функцией СЛЕДУК. Если задана постфиксная транслирующая грамматика в виде S-атрибутной грамматики, и если входная грамматика заданной транслирующей грамматики относится к подклассу грамматик, порождающих детерминированные языки, например, к подклассу LR(0) или SLR(1), то для нее можно построить детерминированный восходящий атрибутный преобразователь. Такой преобразователь строится путем расширения восходящего распознавателя цепочки входной грамматики. Расширение заключается в том, что каждому грамматическому вхождению в стеке выделяются дополнительные элементы памяти для хранения атрибутов. К операциям свертки добавляются действия, связанные с вычислением значений атрибутов, их записью в стек и удалением из стека, а к операциям переноса добавляются действия записи атрибутов в стек. Например, для грамматики Г5.7 операции Свертка(4) и Свертка(2) должны заключаться в замене символа, находящегося в вершине стека. При выполнении операции Свертка(3) необходимо прочитать 4 элемента из стека и сохранить значение третьего элемента, соответствующего атрибуту l, затем записать в стек символ <T> с атрибутом n, присвоить этому атрибуту значение l. Выполнение операции Свертка(1) можно описать следующим образом: 1) выполнить действие {СЛЕДУК}%d и присвоить значение атрибута d атрибуту z, 2) прочитать из стека символ n, его атрибут, а затем присвоить значение этого атрибута атрибуту y, 3) удалить из стека один символ, 4) прочитать из стека символ и его атрибут, а затем присвоить этот атрибут атрибуту x, 5) записать в стек символ <E> с одним атрибутом и присвоить этому атрибуту значение атрибута с, 6) передать на выход атом {СЛОЖИТЬ/x /y %z}, атрибуты которого определены. Атрибутный преобразователь, построенный для грамматики Г5.7, должен работать в соответствии с таблицами переходов и действий распознавателя (Табл. 3.4 и Табл. 3.5). Последователь ность шагов, выполняемых атрибутным преобразователем при трансля ции входной цепочки i5 + i7+- можно изобразить в следующем виде. 1. В исходном состоянии в стеке находится маркер дна, а на входе - заданная цепочка. Стек Вход Выход
h0 i/5 + i/7 |-- -
2. По таблицам 3.4 и 3.5 находим, что необходимо выполнить операцию переноса. В результате имеем: Стек Вход Выход
h0 5 i + i/7 |-- -
3. По таблицам определяем, что следует выполнить операцию Свертка(4). Получаем: . Стек Вход Выход
h0 5 T2 + i/7 |-- -
4. Следующей должна выполняться операция Свертка(2). Стек Вход Выход
h0 5 Ex + i/7 |-- -
5. После выполнения операции переноса имеем: Стек Вход Выход
h0 5 Ex + i/7 |-- -
6. Выполняя операцию переноса в стек символа i с атрибутом получаем: . Стек Вход Выход
h0 5 Ex + 7 i |-- -
7. Согласно таблицам очередной операцией должна быть Свертка(4), после выполнения которой имеем: Стек Вход Выход
h0 5 Ex + 7 T1 |-- -
8. По таблицам находим, что следующей должна выполняться операция Свертка(1), поэтому, полагая, что функция СЛЕДУК возвращает значение 22, имеем: . Стек Вход Выход
h0 22 Ex |-- {СЛОЖ/5/7/22}
9. Входной символ, находящийся в вершине стека в соответствии с таблицами работы определяет выполнение операции Допустить, которая говорит об успешном завершении работы преобразователя.
