<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
		<id>http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=95.161.221.199&amp;*</id>
		<title>Викиконспекты - Вклад участника [ru]</title>
		<link rel="self" type="application/atom+xml" href="http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=95.161.221.199&amp;*"/>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BB%D1%83%D0%B6%D0%B5%D0%B1%D0%BD%D0%B0%D1%8F:%D0%92%D0%BA%D0%BB%D0%B0%D0%B4/95.161.221.199"/>
		<updated>2026-04-17T20:03:50Z</updated>
		<subtitle>Вклад участника</subtitle>
		<generator>MediaWiki 1.30.0</generator>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D1%82%D1%80%D0%B8%D0%B1%D1%83%D1%82%D0%BD%D1%8B%D0%B5_%D1%82%D1%80%D0%B0%D0%BD%D1%81%D0%BB%D0%B8%D1%80%D1%83%D1%8E%D1%89%D0%B8%D0%B5_%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B0%D1%82%D0%B8%D0%BA%D0%B8&amp;diff=82177</id>
		<title>Атрибутные транслирующие грамматики</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D1%82%D1%80%D0%B8%D0%B1%D1%83%D1%82%D0%BD%D1%8B%D0%B5_%D1%82%D1%80%D0%B0%D0%BD%D1%81%D0%BB%D0%B8%D1%80%D1%83%D1%8E%D1%89%D0%B8%D0%B5_%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B0%D1%82%D0%B8%D0%BA%D0%B8&amp;diff=82177"/>
				<updated>2022-01-25T18:20:32Z</updated>
		
		<summary type="html">&lt;p&gt;95.161.221.199: ещё меньше ненужных тегов&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
Часто, осуществляя разбор, мы хотим извлечь какие-то данные или произвести какие-то действия, а не просто выяснить, разбирается ли текст в данной грамматике.&lt;br /&gt;
Вообще говоря, сначала можно получить [[Контекстно-свободные_грамматики,_вывод,_лево-_и_правосторонний_вывод,_дерево_разбора#Дерево_разбора|дерево разбора]], а потом уже, обходя его, выполнять эти действия.&lt;br /&gt;
В этом случае происходит дублирование функционала: промежуточное сохранение данных в виде дерева разбора не нужно, а иногда его просто слишком расточительно хранить в памяти целиком.&lt;br /&gt;
В связи с этим хочется какие-то действия производить уже на этапе разбора.&lt;br /&gt;
&lt;br /&gt;
Например, мы хотим не только построить дерево разбора для арифметических выражений, а ещё и вычислить значение этого выражения. Возможно, даже не строя само дерево разбора.&lt;br /&gt;
 &lt;br /&gt;
Такой подход называется '''синтаксически управляемой трансляцией'''.&lt;br /&gt;
&lt;br /&gt;
==Синтаксически управляемая трансляция==&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
'''Синтаксически управляемое определение''' ''(англ. syntax-directed definition)'' является [[Контекстно-свободные_грамматики,_вывод,_лево-_и_правосторонний_вывод,_дерево_разбора|контекстно-свободной]] грамматикой с атрибутами и правилами. Атрибуты связаны с грамматическими символами, а правила — с продукциями. &lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
'''Синтаксически управляемая трансляция''' ''(англ. syntax-directed translation)'' {{---}} это трансляция, при которой в [[Предиктивный_синтаксический_анализ| процессе разбора]] строки сразу выполняются какие-то действия, без использования промежуточного представления в виде дерева разбора.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Синтаксически управляемая трансляция вводит две новые сущности: '''атрибут''' и '''транслирующий символ'''.&lt;br /&gt;
&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
'''Атрибут''' ''(англ. attribute)'' {{---}} дополнительные данные, ассоциированные с грамматическими символами. Если $X$ представляет собой символ, а $a$ — один из его атрибутов, то значение $a$ в некотором узле дерева разбора, помеченном $X$, записывается как $X.a$. Если узлы дерева разбора реализованы в виде записей или объектов, то атрибуты $X$ могут быть реализованы как поля данных в записях, представляющих узлы $X$. Атрибуты могут быть любого вида: числами, типами, таблицами ссылок или строками.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
Дерево разбора, в каждом узле которого атрибуты уже вычислены, называется '''аннотированным''' ''(англ. annotated)'', а процесс вычисления этих атрибутов {{---}} '''аннотированием''' дерева разбора.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Определение&lt;br /&gt;
|id = tr_char&lt;br /&gt;
|definition =&lt;br /&gt;
'''Транслирующий символ''' {{---}} нетерминал, который раскрывается в $\varepsilon$ и в момент раскрытия выполняет связанное с ним действие. Действия пишутся в фигурных скобках рядом с транслирующим символом.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Будем рассматривать в качестве примера грамматику для арифметических выражений с операторами $+$ и $*$:&lt;br /&gt;
&lt;br /&gt;
$&lt;br /&gt;
S \to E \\ &lt;br /&gt;
E \to E + T \mid T \\&lt;br /&gt;
T \to T * F \mid F \\&lt;br /&gt;
F \to n \mid (E) &lt;br /&gt;
$&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Стоит отметить, что не существует гарантии наличия даже одного порядка обхода дерева разбора, при котором вычислятся все атрибуты в узлах. Рассмотрим для примера следующие нетерминалы $A$ и $B$:&lt;br /&gt;
&lt;br /&gt;
{| style=&amp;quot;background-color:#CCC;margin:0.5px&amp;quot;&lt;br /&gt;
!style=&amp;quot;background-color:#EEE&amp;quot;| Продукция&lt;br /&gt;
!style=&amp;quot;background-color:#EEE&amp;quot;| Семантические правила&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| $A \to B$&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| $A.s = B.i \\ B.i = A.s+1$&lt;br /&gt;
|}&lt;br /&gt;
Данные правила циклические: невозможно вычислить ни $A.s$ в узле, ни $B.i$ в дочернем узле, не зная значение другого атрибута. &lt;br /&gt;
Далее будет рассмотрено два класса синтаксически управляемых грамматик, для которых можно однозначно определить порядок вычисления атрибутов.&lt;br /&gt;
&lt;br /&gt;
==Синтезируемые атрибуты==&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
'''Атрибут''', значение которого зависит от значений атрибутов детей данного узла или от других атрибутов этого узла, то атрибут называется '''синтезируемым''' ''(англ. synthesized attribute)''.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
Грамматика называется '''S-атрибутной''' ''(англ. S-attributed definition)'', если с атрибутами выполняются только операции присваивания значений других атрибутов, а внутри транслирующих символов происходят обращения только к атрибутам этого транслирующего символа. То есть в грамматике используются только синтезируемые атрибуты. Дерево разбора для такой грамматике всегда может быть аннотировано путем выполнения семантических правил снизу вверх, от листьев к корню.&lt;br /&gt;
}}&lt;br /&gt;
===Пример S-атрибутной грамматики===&lt;br /&gt;
Выпишем синтаксически управляемое определение для грамматики арифметических выражений с операторами $+$ и $*$ (здесь $\{ADD {{...}} \}$ и $\{MUL {{...}} \}$ {{---}} [[Атрибутные_транслирующие_грамматики#tr_char|транслирующие символы]]. Если в продукции несколько раз встречается одинаковый нетерминал, будем добавлять к нему индексы, считая от начала продукции.):&lt;br /&gt;
&lt;br /&gt;
{| style=&amp;quot;background-color:#CCC;margin:0.5px&amp;quot;&lt;br /&gt;
!style=&amp;quot;background-color:#EEE&amp;quot;| Продукция&lt;br /&gt;
!style=&amp;quot;background-color:#EEE&amp;quot;| Семантические правила&lt;br /&gt;
!style=&amp;quot;background-color:#EEE&amp;quot;| Пояснения&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| $S \to E$&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| $S.val=E.val$&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| &lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| $E_0 \to E_1 + T\ \{ADD\  res = op_1 + op_2\}$&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| $ADD.op_1=E_1.val \\ ADD.op_2=T.val \\ E_0.val=ADD.res $&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| В фигурных скобках {{---}} действия транслирующего символа ADD. $op_1$, $op_2$ и $res$ {{---}} атрибуты транслирующего символа. &lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| $E \to T$&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| $E.val=T.val$&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| &lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| $T_0 \to T_1 * F \ \{MUL\  res = op_1 \times op_2\}$&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| $MUL.op_1=T.val \\ MUL.op_2=F.val \\ T_0.val=MUL.res$&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| В фигурных скобках {{---}} действия транслирующего символа MUL. $op_1$, $op_2$ и $res$ {{---}} атрибуты транслирующего символа. &lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| $T \to F$&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| $T.val=F.val$&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| &lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| $F \to n$&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| $F.val=n.val$&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| &lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| $F \to (E)$&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| $F.val=E.val$&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
В нашем примере видно, что $val$ зависит только от детей в дереве разбора, то есть это синтезируемый атрибут. Результат умножителя ($MUL.res$) зависит только от атрибутов атрибутов самого умножителя ($MUL.op_1$ и $MUL.op_2$), а значит тоже является синтезируемым(аналогично с сумматором $ADD$). &lt;br /&gt;
&lt;br /&gt;
[[Файл:3mul5add4.png|500px|thumb|center|Аннотированное дерево разбора для '''$3*5+4$''']]&lt;br /&gt;
&lt;br /&gt;
После такого разбора в $S.val$ будет лежать вычисленное значение выражения. Можно, например сразу напечатать его, добавив к нему правило $\{print(S.val)\}$.&lt;br /&gt;
&lt;br /&gt;
==Наследуемые атрибуты==&lt;br /&gt;
&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
'''Атрибут''', значение которого зависит от значений атрибутов братьев узла или атрибутов родителя, называется '''наследуемым''' ''(англ. inherited attribute)''. &lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Определение&lt;br /&gt;
|definition =&lt;br /&gt;
Грамматика называется '''L-атрибутной''' ''(англ. L-attributed definition)'', если значения наследуемых атрибутов зависят только от родителей и братьев слева (то есть не зависят от значений атрибутов братьев справа).&lt;br /&gt;
}}&lt;br /&gt;
===Пример L-атрибутной грамматики===&lt;br /&gt;
Для наглядности рассмотрим грамматику объявления переменных &lt;br /&gt;
(в начале строки идет тип, затем через запятую имена переменных. Примеры строк, разбираемых в ней: '''int a''' или '''real x,y,z''' и подобные):&lt;br /&gt;
&lt;br /&gt;
$&lt;br /&gt;
D \to TL \\&lt;br /&gt;
T \to int \mid real \\&lt;br /&gt;
L \to L,id \mid id&lt;br /&gt;
$&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Выпишем продукции (с транслирующими символами) и ассоциируем с ними семантические правила&lt;br /&gt;
(здесь $\{ENTRY {{...}} \}$ {{---}} [[Атрибутные_транслирующие_грамматики#tr_char|транслирующий символ]]. Если в продукции несколько раз встречается одинаковый нетерминал, будем добавлять к нему индексы, считая от начала продукции.):&lt;br /&gt;
&lt;br /&gt;
{| style=&amp;quot;background-color:#CCC;margin:0.5px&amp;quot;&lt;br /&gt;
!style=&amp;quot;background-color:#EEE&amp;quot;| Продукция&lt;br /&gt;
!style=&amp;quot;background-color:#EEE&amp;quot;| Семантические правила&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| $D \to TL$&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| $L.inh = T.type$&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| $T \to int$&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| $T.type = integer$&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| $T \to real$&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| $T.type = real$&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| $L_0 \to L_1,id\ \{ENTRY addtype(key, value)\}$&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| $L_1.inh = L0.inh \\ ENTRY.key=id.text \\ ENTRY.value=L_0.inh$&lt;br /&gt;
|-&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| $L \to id\ \{ENTRY addtype(key, value)\}$&lt;br /&gt;
|style=&amp;quot;background-color:#FFF;padding:2px 30px&amp;quot;| $ENTRY.key=id.text \\ ENTRY.value=L.inh$&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Семантическое правило  $L.inh = T.type$, связанное с продукцией $D \to TL$, определяет наследуемый атрибут $L.inh$ как тип объявления. Затем приведенные правила распространяют этот тип вниз по дереву разбора с использованием атрибута $L.inh$. Транслирующий символ $ENTRY$, связанный с продукциями для $L$, вызывает процедуру $addtype$ для добавления типа каждого идентификатора к его записи в таблице символов (по ключу, определяемому атрибутом $text$).&lt;br /&gt;
&lt;br /&gt;
[[Файл:Real_id1,_id2,_id3.png|600px|center|thumb|Аннотированное дерево разбора для '''$\mathbf{real}\ id1,\ id2,\ id3$'''|600px]]&lt;br /&gt;
&lt;br /&gt;
==Пример работы с атрибутами в нисходящем разборе==&lt;br /&gt;
Рассмотрим работы с атрибутами на примере LL(1)-грамматики арифметических выражений, которая уже была разобрана [[Построение FIRST и FOLLOW#Пример | ранее]] и расширим код [[Предиктивный_синтаксический_анализ | разборщика]] для нее:&lt;br /&gt;
&lt;br /&gt;
$&lt;br /&gt;
E \to TE' \\&lt;br /&gt;
E' \to +TE' \mid \varepsilon \\&lt;br /&gt;
T \to FT' \\&lt;br /&gt;
T' \to * FT' \mid \varepsilon \\&lt;br /&gt;
F \to n \mid (E)&lt;br /&gt;
$&lt;br /&gt;
&lt;br /&gt;
В данной реализации рекурсивные функции от нетерминалов получают на вход (если необходимо) наследуемые атрибуты узла и возвращают вершины дерева разбора, в атрибутах которых записан результат вычислений соответствующего подвыражения. Однако этот код легко изменить, чтобы он только вычислял значение выражения и не строил дерево разбора. Как мы видим, $val$ {{---}} синтезируемый атрибут, $acc$ {{---}} наследуемый атрибут, $ADD$ {{---}} транслирующий символ. Синим подсвечены строки, отвечающие за работу с атрибутами.&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;tex&amp;gt;\mathtt{Node}&amp;lt;/tex&amp;gt; {{---}} структура следующего вида:&lt;br /&gt;
 '''struct''' Node&lt;br /&gt;
     children : '''map&amp;lt;String, Node&amp;gt;'''&lt;br /&gt;
     name : '''string'''&lt;br /&gt;
     val : '''int'''                  &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// атрибут нетерминала&amp;lt;/font&amp;gt;&lt;br /&gt;
     '''function''' addChild('''Node''')    &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// функция, подвешивающая поддерево к данному узлу&amp;lt;/font&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 E() : '''Node'''&lt;br /&gt;
     Node res = Node(&amp;quot;E&amp;quot;)&lt;br /&gt;
     '''switch''' (curToken)&lt;br /&gt;
         '''case''' n, '('  :&lt;br /&gt;
             res.addChild(T())            &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// подвешиваем левого сына&amp;lt;/font&amp;gt;&lt;br /&gt;
             &amp;lt;font color=&amp;quot;blue&amp;quot;&amp;gt;temp = res.children[&amp;quot;T&amp;quot;].val&amp;lt;/font&amp;gt; &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// атрибут левого сына&amp;lt;/font&amp;gt;&lt;br /&gt;
             &amp;lt;font color=&amp;quot;blue&amp;quot;&amp;gt;Node rightSon = E'(temp)    &amp;lt;/font&amp;gt; &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// отдадим атрибут левого сына правому как наследуемый атрибут&amp;lt;/font&amp;gt;&lt;br /&gt;
             &amp;lt;font color=&amp;quot;blue&amp;quot;&amp;gt;res.addChild(rightSon)     &amp;lt;/font&amp;gt;  &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// подвешиваем правого сына сына&amp;lt;/font&amp;gt;&lt;br /&gt;
             &amp;lt;font color=&amp;quot;blue&amp;quot;&amp;gt;res.val = res.children[&amp;quot;E'&amp;quot;].val&amp;lt;/font&amp;gt;&lt;br /&gt;
             '''break'''&lt;br /&gt;
         '''default''' :&lt;br /&gt;
             &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;error&amp;lt;/font&amp;gt;(&amp;quot;unexpected char&amp;quot;)&lt;br /&gt;
     '''return''' res&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 E'(acc) : '''Node'''&lt;br /&gt;
     Node res = Node(&amp;quot;E'&amp;quot;)&lt;br /&gt;
     '''switch''' (curToken) &lt;br /&gt;
         '''case''' '+' :&lt;br /&gt;
             consume('+')&lt;br /&gt;
             res.addChild(Node(&amp;quot;+&amp;quot;))&lt;br /&gt;
             res.addChild(T())&lt;br /&gt;
             &amp;lt;font color=&amp;quot;blue&amp;quot;&amp;gt;temp = res.children[&amp;quot;T&amp;quot;].val&lt;br /&gt;
             ADD.res = ADD(acc, temp)  &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// ADD проведет вычисления из наследуемого атрибута add и атрибута ребенка &amp;quot;T&amp;quot;&amp;lt;/font&amp;gt;&lt;br /&gt;
             res.addChild(E'(ADD.res)) &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// результат вычислений будет передан правому ребенку как наследуемый атрибут&amp;lt;/font&amp;gt;&lt;br /&gt;
             res.val = res.children[&amp;quot;E'&amp;quot;].val&amp;lt;/font&amp;gt;&lt;br /&gt;
             '''break'''&lt;br /&gt;
         '''case''' '$', ')' :&lt;br /&gt;
             &amp;lt;font color=&amp;quot;blue&amp;quot;&amp;gt;res.val = acc&amp;lt;/font&amp;gt;&lt;br /&gt;
             '''break'''&lt;br /&gt;
         '''default''' :&lt;br /&gt;
             &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;error&amp;lt;/font&amp;gt;(&amp;quot;unexpected char&amp;quot;)&lt;br /&gt;
      '''return''' res&lt;br /&gt;
&lt;br /&gt;
 F() : '''Node'''&lt;br /&gt;
     Node res = Node(&amp;quot;F&amp;quot;)&lt;br /&gt;
     '''switch''' (curToken)&lt;br /&gt;
         '''case''' n :&lt;br /&gt;
             consume(n)&lt;br /&gt;
             res.addChild(Node(curToken)) &lt;br /&gt;
             &amp;lt;font color=&amp;quot;blue&amp;quot;&amp;gt;res.val = n.val&amp;lt;/font&amp;gt;&lt;br /&gt;
             '''break'''&lt;br /&gt;
         '''case''' '(' :&lt;br /&gt;
             consume('(')&lt;br /&gt;
             res.addChild(Node(&amp;quot;(&amp;quot;))&lt;br /&gt;
             res.addChild(E())&lt;br /&gt;
             &amp;lt;font color=&amp;quot;blue&amp;quot;&amp;gt;rev.val = res.children[&amp;quot;E&amp;quot;].val&amp;lt;/font&amp;gt;&lt;br /&gt;
             consume(')')&lt;br /&gt;
             res.addChild(Node(&amp;quot;)&amp;quot;))&lt;br /&gt;
         '''default''' :&lt;br /&gt;
             &amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;error&amp;lt;/font&amp;gt;(&amp;quot;unexpected char&amp;quot;)&lt;br /&gt;
     '''return''' res&lt;br /&gt;
&lt;br /&gt;
Функции для $T$ и $T'$ строятся аналогично.&lt;br /&gt;
&lt;br /&gt;
[[Файл:2add3add7.png|600px|center|thumb| Дерево разбора для '''$2\ +\ 3\ +\ 7$''']]&lt;br /&gt;
&lt;br /&gt;
==Атрибуты в ANTLR==&lt;br /&gt;
&lt;br /&gt;
Общедоступный генератор разборщиков ANTLR&amp;lt;ref&amp;gt;[http://www.antlr.org/ ANTLR {{---}} Parser generator]&amp;lt;/ref&amp;gt; поддерживает синтаксически управляемое определение. &lt;br /&gt;
&lt;br /&gt;
Рассмотрим для той же грамматики арифметических выражений с операторами &amp;lt;tex&amp;gt;+,\ *&amp;lt;/tex&amp;gt;, скобками и выводом результата выражения пример на ANTLR.&lt;br /&gt;
&lt;br /&gt;
 grammar Expression;&lt;br /&gt;
 '''@header''' { package ru.ifmo.ctddev.wiki; } &lt;br /&gt;
&lt;br /&gt;
Естественным образом можно добавлять действия в продукции, где это нужно. Действия выполняются после предыдущего элемента грамматики и до следующего.&lt;br /&gt;
&lt;br /&gt;
Стартовый нетерминал печатает результат:&lt;br /&gt;
 s : expr { System.out.println($expr.val); };&lt;br /&gt;
&lt;br /&gt;
В продукции для нетерминала &amp;lt;code&amp;gt;expr&amp;lt;/code&amp;gt; определяется возвращаемое значение (&amp;lt;code&amp;gt;['''int''' val]&amp;lt;/code&amp;gt;). Обращение к этому атрибуту имеет вид &amp;lt;code&amp;gt;$expr.value&amp;lt;/code&amp;gt;. В фигурных скобках записаны семантические правила.&lt;br /&gt;
&lt;br /&gt;
Разобранные нетерминалы возвращают результат, вычисленный в поддереве(&amp;lt;code&amp;gt;returns [int val]&amp;lt;/code&amp;gt;) как свой синтезируемый атрибут, процесс вычисления которого описан в фигурных скобках &amp;lt;code&amp;gt;{ $val = $exprP.val; }&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Наследуемые атрибуты передаются нетерминалу как параметр(&amp;lt;code&amp;gt;exprP[$term.val]&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
 expr '''returns''' ['''int''' val]&lt;br /&gt;
     : term exprP[$term.val]     { $val = $exprP.val; }&lt;br /&gt;
     ;&lt;br /&gt;
&lt;br /&gt;
 exprP['''int''' i] '''returns''' ['''int''' val]&lt;br /&gt;
     :                                              { $val = $i; } &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt; // &amp;lt;tex&amp;gt;\varepsilon&amp;lt;/tex&amp;gt;-правило&amp;lt;/font&amp;gt;&lt;br /&gt;
     | '+' term expr = exprP[$i + $term.val]        { $val = $expr.val; }&lt;br /&gt;
     ;&lt;br /&gt;
	&lt;br /&gt;
 term '''returns''' ['''int''' val]&lt;br /&gt;
     : fact termP[$fact.val]     { $val = $termP.val; }&lt;br /&gt;
     ;&lt;br /&gt;
&lt;br /&gt;
 termP['''int''' i] '''returns''' '''[int''' val]&lt;br /&gt;
     :                                              { $val = $i; }&lt;br /&gt;
     | '*' fact expr = termP[$i * $fact.val]        { $val = $expr.val; }&lt;br /&gt;
     ;&lt;br /&gt;
&lt;br /&gt;
 fact '''returns''' ['''int''' val]&lt;br /&gt;
     : '(' expr ')'                  { $val = $expr.val; }&lt;br /&gt;
     | NUM                           { $val = Integer.parseInt($NUM.text); }&lt;br /&gt;
     ;&lt;br /&gt;
&lt;br /&gt;
Техническая деталь для ANTLR, правила для лексического анализатора:&lt;br /&gt;
 WS : [ \t \r \n]+ -&amp;gt; skip ;&lt;br /&gt;
 NUM : [0-9]+ ;&lt;br /&gt;
&lt;br /&gt;
== Примечания ==&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
* Альфред Ахо, Рави Сети, Джеффри Ульман. Компиляторы. Принципы, технологии, инструменты. Издательство Вильямс. Первое издание. 2003. Стр. 279 {{---}} 305.&lt;br /&gt;
* Альфред Ахо, Рави Сети, Джеффри Ульман. Компиляторы. Принципы, технологии, инструменты. Издательство Вильямс. Второе издание. 2008. Стр. 383 {{---}} 398.&lt;br /&gt;
* [https://theantlrguy.atlassian.net/wiki/display/ANTLR4/Parser+Rules#ParserRules ANTLR Documentation {{---}} Rule Attribute Definitions]&lt;br /&gt;
* [http://www.amazon.com/The-Definitive-ANTLR-4-Reference/dp/1934356999| The Definitive ANTLR 4 Reference]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Методы трансляции]]&lt;br /&gt;
[[Категория: Нисходящий разбор]]&lt;/div&gt;</summary>
		<author><name>95.161.221.199</name></author>	</entry>

	</feed>