Изменения

Перейти к: навигация, поиск

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

86 байт убрано, 19:15, 4 сентября 2022
м
rollbackEdits.php mass rollback
==Синтаксически управляемая трансляция==
<wikitex>
{{Определение
|definition =
Данные правила циклические: невозможно вычислить ни $A.s$ в узле, ни $B.i$ в дочернем узле, не зная значение другого атрибута.
Далее будет рассмотрено два класса синтаксически управляемых грамматик, для которых можно однозначно определить порядок вычисления атрибутов.
</wikitex>
==Синтезируемые атрибуты==
<wikitex>
{{Определение
|definition =
Грамматика называется '''S-атрибутной''' ''(англ. S-attributed definition)'', если с атрибутами выполняются только операции присваивания значений других атрибутов, а внутри транслирующих символов происходят обращения только к атрибутам этого транслирующего символа. То есть в грамматике используются только синтезируемые атрибуты. Дерево разбора для такой грамматике всегда может быть аннотировано путем выполнения семантических правил снизу вверх, от листьев к корню.
}}
</wikitex>
===Пример S-атрибутной грамматики===
<wikitex>
Выпишем синтаксически управляемое определение для грамматики арифметических выражений с операторами $+$ и $*$ (здесь $\{ADD {{...}} \}$ и $\{MUL {{...}} \}$ {{---}} [[Атрибутные_транслирующие_грамматики#tr_char|транслирующие символы]]. Если в продукции несколько раз встречается одинаковый нетерминал, будем добавлять к нему индексы, считая от начала продукции.):
После такого разбора в $S.val$ будет лежать вычисленное значение выражения. Можно, например сразу напечатать его, добавив к нему правило $\{print(S.val)\}$.
 
</wikitex>
==Наследуемые атрибуты==
<wikitex>
{{Определение
|definition =
Грамматика называется '''L-атрибутной''' ''(англ. L-attributed definition)'', если значения наследуемых атрибутов зависят только от родителей и братьев слева (то есть не зависят от значений атрибутов братьев справа).
}}
</wikitex>
===Пример L-атрибутной грамматики===
<wikitex>
Для наглядности рассмотрим грамматику объявления переменных
(в начале строки идет тип, затем через запятую имена переменных. Примеры строк, разбираемых в ней: '''int a''' или '''real x,y,z''' и подобные):
[[Файл:Real_id1,_id2,_id3.png|600px|center|thumb|Аннотированное дерево разбора для '''$\mathbf{real}\ id1,\ id2,\ id3$'''|600px]]
</wikitex>
==Пример работы с атрибутами в нисходящем разборе==
<wikitex>Рассмотрим работы с атрибутами на примере $LL(1)$-грамматики арифметических выражений, которая уже была разобрана [[Построение FIRST и FOLLOW#Пример | ранее]] и расширим код [[Предиктивный_синтаксический_анализ | разборщика]] для нее:
$
$
В данной реализации рекурсивные функции от нетерминалов получают на вход (если необходимо) наследуемые атрибуты узла и возвращают вершины дерева разбора, в атрибутах которых записан результат вычислений соответствующего подвыражения. Однако этот код легко изменить, чтобы он только вычислял значение выражения и не строил дерево разбора. Как мы видим, $val$ {{- --}} синтезируемый атрибут, $acc$ {{--- }} наследуемый атрибут, $ADD$ {{--- }} транслирующий символ. Синим подсвечены строки, отвечающие за работу с атрибутами.
Здесь <tex>\mathtt{Node}</tex> {{---}} структура следующего вида:
'''struct''' Node
children : '''map<String, Node>'''
name: '''string'''
val : '''int''' <font color="green">// атрибут нетерминала</font>
'''function''' addChild('''Node''') <font color="green">// функция, подвешивающая поддерево к данному узлу</font>
[[Файл:2add3add7.png|600px|center|thumb| Дерево разбора для '''$2\ +\ 3\ +\ 7$''']]
</wikitex>
==Атрибуты в ANTLR==
Общедоступный генератора генератор разборщиков ANTLR<ref>[http://www.antlr.org/ ANTLR {{---}} Parser generator]</ref> поддерживает синтаксически управляемое определение.
Рассмотрим для той же грамматики арифметических выражений с операторами <tex>+ ,\ *</tex>, скобками и выводом результата выражениая выражения пример на ANTLR.
grammar Expression;
Естественным образом можно добавлять действия в продукции, где это нужно. Действия выполняются после предыдущего элемента грамматики и до следующего.
Стартовый нетерминал печатает резульатрезультат: s : expr { System.out.println($eexpr.valueval);}; В продукции для нетерминала <code>expr</code> определяется возвращаемое значение (<code>['''int''' val]</code>). Обращение к этому атрибуту имеет вид <code>$expr.value</code>. В фигурных скобках записаны семантические правила.
Разобранные нетерминалы возвращают результат, вычисленный в поддереве(<code>returns [int val]</code>) как свой синтезируемый атрибут, процесс вычисления которого описан в фигурных скобках <code>{ $val = $exprP.val; }</code>.
exprP['''int''' i] '''returns''' ['''int''' val]
: { $val = $i; } <font color="green"> // <tex>\varepsilon</tex>-правило</font> | '+' term e expr = exprP[$i + $term.val] { $val = $eexpr.val; }
;
term '''returns''' ['''int''' val]
: fact termP[$fact.val] { $val = $termpPtermP.val; }
;
termP['''int''' i] '''returns''' '''[int''' val]
: { $val = $i; } | '*' fact e expr = termP[$i * $fact.val] { $val = $eexpr.val; }
;
WS : [ \t \r \n]+ -> skip ;
NUM : [0-9]+ ;
 
 
В продукции для нетерминала <code>e</code> определяется возвращаемое значение (<code>[Integer value]</code>). Обращение к этому атрибуту имеет вид <code>$e.value</code>. В фигурных скобках записаны семантические правила.
== Примечания ==
1632
правки

Навигация