ТЕМА 3. Деревья разбора (начало лекции) 3.1 Левые и правые порождения Для ограничения числа выборов в процессе порождения цепочки полезно потребовать, чтобы на каждом шаге заменялся крайний слева нетерминал одним из тел его продукций. Такое порождение называется левым * (leftmost), и для его указания используются отношения и . Если lm lm используемая грамматика G не очевидна из контекста, то её имя G также добавляется внизу. Аналогично можно потребовать, чтобы на каждом шаге заменялся крайний справа нетерминал на одно из тел. В таком случае порождение называется правым (rightmost), и для его обозначения используются символы * и . Имя используемой грамматики также при необходимости rm rm записывается внизу. Пример. Рассмотрим грамматику для выражений E I | E E | E * E | E I a | b | Ia | Ib | I 0 | I1 Примером левого порождения является E E E I E Ia E ba E ba I ba I 0 ba a0, lm lm lm lm lm а примером правого – 1 lm lm E E * E E * I E * I1 E * b1 I * b1 a * b1. rm rm rm rm rm rm Любое порождение имеет эквивалентные левое и правое порождения. * Это означает, что если w – терминальная цепочка, а A – нетерминал, то A w * * тогда и только тогда, когда A w, а также A w тогда и только тогда, когда lm * A w. rm 3.2 Выводимые цепочки Порождения из стартового символа грамматики приводят к цепочкам, имеющим особое значение. Они называются «выводимыми цепочками» («sentential form»). Итак, если G N , , P, S цепочка из N – КС-грамматика, то любая * , для которой S , называется выводимой цепочкой * (сентенциальной формой). * * lm rm Если S , то является левовыводимой цепочкой, а если S , то – правовыводимой. Примечание – Заметим, что язык L G образуют выводимые цепочки из *, состоящие исключительно из терминалов. Пример. Рассмотрим грамматику выражений (см. выше). Например, E * I E является выводимой цепочкой, поскольку существует порождение: E E * E E * E E * E E E * I E . Однако это порождение не является ни левым, ни правым, так как на последнем шаге заменяется среднее E. 2 Примером левовыводимой цепочки может служить a * E с таким левым порождением: E E * E I * E a * E. lm lm lm Аналогично, порождение E E * E E * E E * E E rm rm rm показывает, что E * E E является правовыводимой цепочкой. 3.3 Деревья разбора Дерево известное в компиляции как «дерево разбора», является основной структурой данных для представления исходной программы. В компиляторе древовидная структура исходной программы облегчает её трансляцию в исполняемый код за счёт того, что допускает естественные рекурсивные функции для выполнения этой трансляции. Некоторые грамматики допускают, что терминальная цепочка имеет несколько деревьев разбора. Такое свойство делает грамматику непригодной для описания языков программирования, поскольку в этом случае компилятор не мог бы распознать структуру некоторых исходных программ, и, как следствие, не мог бы однозначно определить исполняемый код, соответствующий программе. 3.3.1 Обзор терминов, связанных с деревьями Дерево – это односвязный граф с не менее чем двумя вершинами. Деревья представляют собой множества узлов с отношением родитель – сын. 3 Узел имеет не более одного родителя, изображаемого над узлом, и нуль или несколько сыновей, изображаемых под ним. Родителей и их сыновей соединяют линии. Примеры деревьев представлены на рис. 3.1. а) б) Рис. 3.1 – Примеры деревьев разбора: а – для грамматики выражений; б – для грамматики палиндромов Один узел, корень, не имеет родителя; он появляется на вершине дерева. Узлы без сыновей называются листьями. Узлы, не являющиеся листьями, называются внутренними узлами. Сын сына и так далее узла называется его потомком; соответственно, родитель родителя и так далее – предком. Узлы считаются потомками и предками самих себя. Сыновья узла упорядочиваются слева направо и изображаются в этом порядке. Если узел N находится слева от узла M, то считается, что все потомки узла N находятся слева от всех потомков M. Пример. На рис. 3.1а показано дерево разбора, которое использует грамматику выражений. Корень отмечен нетерминалом E. В корне применена продукция E E E, поскольку три сына корня отмечены слева направо как E, +, E. В левом сыне корня применена продукция E I , так как у этого узла один сын, отмеченный нетерминалом I. 4 Пример. На рис. 3.1б показано дерево разбора для грамматики палиндромов P | 0 |1| 0P0 |1P1. В корне применена продукция P 0P0, а в среднем сыне корня – P 1P1. Отметим, что внизу использована продукция P . Это использование, при котором у узла есть сын с отметкой , является единственным случаем, когда в дереве может быть узел, отмеченный . Примечание – Дерево разбора даёт информацию о правилах, использованных при выводе терминальной цепочки, но не даёт исчерпывающей информации об очерёдности применения правил, за исключением того факта, что правила к некоторой вершине дерева применяются ранее, чем к вершинам соответствующего поддерева. 3.3.2 Построение деревьев разбора Будем рассматривать КС-грамматику G N , , P, S . Деревья разбора для G – это деревья, обладающие такими свойствами: 1) каждый внутренний узел отмечен нетерминалом из N; 2) каждый лист отмечен либо нетерминалом, либо терминалом, либо . При этом, если лист отмечен , то он должен быть единственным сыном своего родителя; 3) если внутренний узел отмечен A, и его сыновья отмечены слева направо X1, X 2 , …, X k соответственно, то A X1 X 2 ... X k является продукцией в P. Отметим, что X может быть лишь в одном случае – если он отмечает единственного сына, и A – продукция грамматики G. 5 3.3.3 Крона дерева разбора Если выписать слева направо отметки листьев любого дерева разбора, то получим цепочку, которая называется кроной дерева и всегда является цепочкой, выводимой из нетерминала, отмечающего корень. Особый интерес представляют деревья разбора с такими свойствами: 1) крона является терминальной цепочкой, т. е. все листья отмечены терминалами или ; 2) корень отмечен стартовым символом. Кроны таких деревьев разбора представляют собой цепочки языка рассматриваемой грамматики. Ещё один способ описания языка грамматики состоит в определении его как множества крон тех деревьев разбора, у которых корень отмечен стартовым символом, а крона является терминальной цепочкой. Пример. На рис. 3.2 представлен пример дерева с терминальной цепочкой в качестве кроны и стартовым символом в корне. Оно основано на грамматике для выражений. Крона этого дерева образует цепочку a* a b00 . 6 Рис. 3.2 – Дерево разбора для a * a b00 в языке для грамматики выражений 3.3.4 Лево- и правосторонний вывод Для каждого дерева разбора может существовать несколько выводов, но левосторонний и правосторонний выводы всегда единственны. Грамматика называется неоднозначной, если в языке, порождаемом данной грамматикой, существует цепочка, имеющая два или более деревьев разбора. Итак, каждой цепочке, выводимой в КС-грамматике, может быть поставлено в соответствие несколько деревьев разбора; 7 каждому выводу может соответствовать несколько различных выводов; для каждого дерева существуют и единственны лево- и правосторонний выводы; если грамматика однозначна, то каждой цепочке языка, порождаемой данной грамматикой соответствует: единственное дерево разбора; единственные лево- и правосторонний выводы. 8