Текст
                    THE THEORY OF PARSING,
TRANSLATION AND COMPILING
volume 2: COMPILING
ALFRED V. AHO
Bell Telephone Laboratories, Inc.
Murray Hill, N. J.
JEFFREY D. ULLMAN
Department ot Electrical Engineering
Princeton University
Prentice-Hall, Inc.
Englewood Cliffs, N. J
1973

А. АХО, ДЖ- УЛЬМАН ТЕОРИЯ СИНТАКСИЧЕСКОГО АНАЛИЗА, ПЕРЕВОДА И КОМПИЛЯЦИИ Том 2 Компиляция Перевод с английского А. Н. Бирюкова и В. А. Серебрякова Под редакцией В. М. Курочкина ИЗДАТЕЛЬСТВО «МИР» МОСКВА 1978
УДК 519.682.14-681.142.2 Второй том фундаментальной монографии известных амери- канских ученых посвящен методам оптимизации синтаксических анализаторов, теории синтаксически управляемого перевода, а также способам организации памяти при переводе. Большое вни- мание уделяется методам оптимизации объектной программы. Авторы проделали значительную работу по отбору и систематиза- ции многочисленных результатов, полученных в последние годы; они строят изложение па едином подходе к задачам перевода и задачам оптимизации программы. Книга предназначена тем, кто работает в области системного и теоретического программирования, преподаст или изучает эти дисциплины, а также разработчикам математического обеспече- ния ЭВМ. Редакция литературы по математическим наукам 20205__017 А *7“78 © Перевод иа русский язык, «Мир», 1978
ПРЕДИСЛОВИЕ Конструирование компиляторов — один из первых больших разделов системного программирования, которые получают сей- час строгое теоретическое обоснование. В т. 1 этой книги изло- жены необходимые для такого обоснования сведения из матема- тики и теории языков и основные методы проведения быстрого синтаксического анализа. Том 2 служит продолжением т. 1,но, за исключением гл. 7 и 8, он ориентирован на несинтаксичес- кие аспекты в конструировании компиляторов. Материал в т. 2 излагается в основном так же, как и в т. 1, но доказательства здесь несколько более схематичны. Мы попы- тались по возможности облегчить чтение, включив в книгу мно- го примеров, каждый из которых иллюстрирует одно нли два понятия. Так как акцент делается на идеи, а не на языковые или машин- ные подробности, то основанный на этой книге курс должен со- провождаться лабораторными занятиями по программированию, чтобы студент мог получить некоторые навыки в применении обсуждаемых идей к практическим задачам. Для таких занятий можно порекомендовать упражнения на программирование, при- веденные в конце разделов. Часть лабораторного курса должна быть посвящена вопросу генерации кода для таких конструкций языка программирования, как рекурсия, пересылка параметров, взаимодействие подпрограмм, адресация массивов, циклы и т. д. О пользовании книгой Книга возникла на основе записей лекций, прочитанных на старших курсах Принстонского университета и Стивенсовского технологического института. Материал т. 2 использовался в Сти- венсовском институте как семестровый курс конструирования ком- пиляторов, следующий за семестровым курсом, основанным на т. 1. С точки зрения изучения конструирования компиляторов одни разделы книги, как мы полагаем, важнее других. При первом 5
ПРЕДИСЛОВИЕ чтении можно пропустить все доказательства, а также гл. 8 и разд. 7.4.3, 7.5.3, 9.3.3, 10.2.3 и 10.2.4. Как и в т. 1, в конце каждого раздела помещены задачи и замечания по литературе. Задачи, не являющиеся ни проблема- ми для исследования, ни открытыми проблемами, мы приблизи- тельно упорядочили в соответствии с уровнем их сложности. Для этого использовали звездочки: упражнения, не помеченные звездочкой, служат для проверки понимания основных определе- ний; для решения упражнений с одной звездочкой требуется одна существенная догадка, а упражнения с двумя звездочками значительно сложнее. Благодарности В дополнение к благодарностям, выраженным в предисловии к т. 1, мы хотели бы поблагодарить Карела Чулика, Амелию Фонг, Майка Хэммера и Стива Джонсона за полезные замечания. Альфред В. Ахо Джефри Д. Ульман
МЕТОДЫ ОПТИМИЗАЦИИ 7 СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ В этой главе мы рассмотрим различные методы, с помощью которых можно уменьшать размер и/или повышать скорость ра- боты синтаксических анализаторов. Сначала исследуем вопрос об уменьшении объема памяти, требующейся для матриц предшествования. Мы увидим, что в определенных случаях, среди которых многие представляют практический интерес, матрицу предшествования размера тхп удается заменить двумя векторами длины тип соответственно. Кроме того, покажем, как видоизменять матрицу предшествова- ния, не затрагивая построенный по ней алгоритм разбора типа „перенос —свертка". Затем мы опишем, как по грамматике слабого предшествова- ния можно механически получить синтаксический анализатор на языке Флойда—Эванса, а потом рассмотрим различные, приемы, применяемые для уменьшения размера полученного анализатора. Наконец, подробно изучим различные преобразования, с по- мощью которых можно уменьшить размер LR-анализатора без ослабления его способности обнаруживать ошибки. Детально исследуются метод „простых LR" Де Ремера и метод расщепле- ния грамматики Кореньяка. Методы, описанные в этой главе, показывают, какие типы оптимизации возможны для анализаторов, построенных с по- мощью приемов гл. 5 тома 1. Возможны и многие другие типы оптимизации, но законченного „каталога" их не существует. Чи- тателям, желающим получить только общее представление о ме- тодах оптимизации синтаксических анализаторов, рекомендуем помещенный в конце главы обзор ее содержания. 7.1. ФУНКЦИИ ПРЕДШЕСТВОВАНИЯ Матрицу с элементами —I, 0, +1 или „пусто" будем назы- вать матрицей предшествования. Матрицы предшествования очевидным образом применяются при построении алгоритмов 7
ГЛ. 7. МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ разбора, использующих технику предшествования. Например, можно применить матрицу предшествования для представления отношений предшествования Вирта — Вебера для грамматики предшествования, сопоставив — 1 О + 1 пусто с с с с ошибкой Матрицей предшествования можно также воспользоваться для того, чтобы представить шаги алгоритма разбора типа „пере- нос—свертка". Одно из таких представлений можно получить, сопоставив — 1 с переносом О с ошибкой + 1 с сверткой В этом разделе мы покажем, как матрицу предшествования часто удается представить в сжатой форме парой векторов, на- зываемых функциями предшествования. 7.1.1. Теорема о представлении матрицы Пусть М — матрица предшествования размера тхп. Будем говорить, что пара (f, g) векторов с целочисленными компонен- тами представляет М, если (1) / = (/„ Л, •••, W, (2) g = (gi, g2....g„), если Л1,7 = —1, fi = gj’ если M,y = 0, fl>gf, если Можно использовать fug вместо М следующим образом. Для того чтобы определить М,7, отыщем Д, и gj. Если f;<gj, Ij -gj или положим Мц = — 1, 0 или 4-1 соответственно. За- метим, что при таком использовании fug вместо М у матрицы не будет пустых элементов, потому что между и gj всегда выполняется одно из отношений <, = или >. Векторы fug будем называть функциями предшествования для М. Используя fug для представления М, можно сокра- тить объем памяти, требующейся для матрицы предшествования, с тхп до mg-п элементов. Следует, однако, отметить, что не для всякой матрицы предшествования функции предшествования существуют. в
7.1. ФУНКЦИИ ПРЕДШЕСТВОВАНИЯ Пример 7.1. Рассмотрим грамматику простого предшествова- ния G с правилами .S —faSc|bSc|c Отношения предшествования Вирта — Вебера для G образуют матрицу, изображенную на рис. 7.1. Мы будем называть ее мат- рицей отношений предшествования Вирта — Вебера, чтобы избе- жать путаницы с термином „матрица предшествования". Отноше- ния предшествования, показанные на рис. 7.1, можно представить также в виде матрицы предшествования (рис. 7.2). Можно далее шествования Вирта — Вебера. 1 2 3 4 5 Рис. 7.2. Матрица предшество- вания М. представить эту матрицу предшествования функциями предшест- вования f = (l, 0, 0, 2, 0) £ = (0, 1, 1, 1, 0) Нетрудно убедиться, что это действительно функции предшество- вания для М. Например, ft — 2, g5 = 0 и, значит, поскольку /4 > Si,: f и g действительно представляют элемент M4S со значе- нием +1 • Элемент Л141 матрицы предшествования имеет значение „пусто". Однако f. = 2, a g4 = 0. Таким образом, если мы будем использо- вать fug для представления М, надо будет заменить значение Л1П на 4~1 (так как /у > gf). Аналогично пустые элементы Л411, М|6, Л142 и Л143 все будут иметь значение +1, а Л112, Л113, Мг„, М35, М51, Л155 получат значение 0. Пустые элементы в исходной матрице предшествования указы- вают на ошибочные ситуации. Поэтому, если использовать функ- ции предшествования для представления отношений предшест- вования, утратится возможность обнаружения ошибки в том случае, когда не выполняется ни одно из трех отношений пред- шествования. Но эта ошибка все равно выявится при попытке 9
ГЛ. 7. МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ выполнить свертку, когда окажется, что нет правила с такой правой частью, которая находится в верхушке магазина. Тем не менее такая задержка в обнаружении ошибки может оказаться неприемлемо дорогой платой за удобство использования функций предшествования вместо матриц предшествования; это зависит от того, насколько важно раннее обнаружение ошибки в конкрет- ном компиляторе. □ Пример 7.2. Потерю возможности своевременно обнаруживать ошибки можно в значительной степени компенсировать, построив для грамматики предшествования алгоритм разбора типа „пере- нос—свертка", в котором с отношениями <• и — будет связана 12 3 4 Рис. 7.3. Матрица предшествования М'. операция перенос, а с отношением •>—операция свертка. Кроме того, для построения функции действия алгоритма разбора типа „перенос—свертка" требуются только отношения предшествова- ния с областью определения N (J S U {$} и множеством значений S U {$}. Например, можно сопоставить <• и < с —1, •> с +1 и получить из матрицы, приведенной на рис. 7.1, матрицу пред- шествования М' (рис. 7.3). Пустые элементы обозначают ошибоч- ные ситуации. Можно показать, что векторы / = (0, 0, 0, 2, 0) и g=(l, 1, 1, 0) — функции предшествования для М'. Эти функции предшество- вания обладают тем преимуществом, что для пустых элемен- тов М14, М,4, М,4 и М5Л обе имеют значение 0 = — h = £?4 = О)- Поэтому, обозначая нулем ошибочную ситуацию, мы сохраняем возможность обнаружения ошибки, заложенную в исходной матрице М'. Подробнее мы рассмотрим эту проблему в разд. 7.1.3. □ Сначала мы дадим алгоритм, который по данной матрице предшествования М находит функции предшествования для М, 10
7.1. ФУНКЦИИ ПРЕДШЕСТВОВАНИЯ если они существуют. В следующем разделе опишем модифика- цию этого алгоритма, где по данной матрице предшествования с элементами —1, +1 и „пусто“ строятся функции предшество- вания для этой матрицы, которые по возможности чаще пред- ставляют пустые элементы нулями. Прежде всего заметим, что если две строки матрицы пред- шествования М совпадают, то их можно слить в одну строку, и это не повлияет на факт существования функций предшествова- ния для М. По той же причине можно слить совпадающие столбцы. Матрицу предшествования, в которой все совпадающие строки и столбцы слиты, назовем приведенной матрицей пред- шествования. Ясно, что, если сначала привести матрицу пред- шествования, легче будет строить функции предшествования. Алгоритм 7.1. Вычисление функций предшество- вания. Вход. Матрица М размера тхп с элементами —1, 0, 4-1 и „пусто". Выход. Два целочисленных вектора f = ..., fm) и g = - fe. • • • > g„), У которых при Mtj = — 1 Л = при M,7 = 0 h>gj при М;у=4-1 или „пет", если такие векторы не существуют. Метод. (1) Построим ориентированный граф, содержащий не более т—п вершин и называемый графом линеаризации для М. Сна- чала пометим т вершин буквами Fu F... .... Fm, а оставшиеся п вершин буквами G3, 62........0„. В дальнейшем граф будет преобразовываться, причем в каждый момент будут существовать некоторая вершина F h представляющая Ft, и некоторая вер- шина Gy, предстаиляоошая Gf. Вначале Ft = Ft и Gy- Gy для всех I и Затем для всех i и / выполним шаг (2) или (3). (2) Если Л/,у = 0, построим новую вершину N, сливая F, с Gf. Теперь М представляет все те вершины, которые ранее представ- лялись вершинами Ft и Gy. (3) Если М,7= 4-1, проведем дугу из F/ в Gy. Если М,7 = —1, проведем дугу из Gy в Ft. (4) Если полученный граф содержит циклы, выдаем сообще- ние „нет". (5) Если граф линеаризации ациклический, положим значение /,• равным длине самого длинного пути, начинающегося в Fit а gj—длине самого длинного пути, начинающегося в Оу. □ it
ГЛ. 7. МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ На шаге (4) алгоритма 7.1 для выяснения, циклический или нет ориентированный граф G, можно применить следующий общий метод: (1) Пусть G— исходный граф. (2) Найти в данном графе вершину IV, не имеющую прямых потомков. Если таких вершин нет, граф G — циклический. В про- тивном случае удалить АР). (3) Если полученный граф пуст, то граф G — ациклический. В противном случае повторить шаг (2). Установив в некоторый момент, что граф ациклический, вос- пользуемся для нахождения на шаге (5) алгоритма 7.1 длины самого длинного пути, начинающегося в произвольной вершине, следующим методом разметки вершин. Пусть G — ориентированный ациклический граф. (1) Сначала пометить все вершины графа G нулями. (2) Повторять шаг (3) до тех пор, пока метки графа G не перестанут изменяться. Метка при каждой вершине будет равна длине самого длинного пути, начинающегося в этой вершине. (3) Выбрать в G некоторую вершину IV. Пусть N имеет пря- мых потомков А\-, JVa, ..., с метками /2, .... 1к. Заме- нить метку вершины N на rnax{Zj, /2, ..., ZJ-ф 1. (Если k = 0, то меткой вершины N оставить 0.) Проделать этот шаг для всех вершин графа G. Ясно, что шаг (3) для каждой вершины повторяется не бо- лее I раз, где I—длина самого длинного пути в G. Граф линеаризации, построенный по М, показан на рис. 7.5. Заметим, что на шаге (2) алгоритма 7.1 сливаются три пары вершин: (Fs, GJ, (Е„ GJ и (F,, GJ. г) Строго говоря, надо удалить также и дуги, входящие в N.—Прим. перев. 12
7.1. ФУНКЦИИ ПРЕДШЕСТВОВАНИЯ Граф линеаризации — ациклический. В результате выполнения шага (5) алгоритма 7.1 получаются функции предшествования / = (0, 1, 2, I, 3) и g=(3, 2, 0, 2, 1). Например, /5 = 3, по- скольку длина самого длинного пути, начинающегося в верши- не Г5, равна 3. □ Теорема 7.1. Матрица предшествования имеет, функции пред- шествования тогда и только тогда, когда ее граф линеаризации ациклический. Доказательство. Достаточность. Сначала отметим, что алгоритм 7.1 выдает на выходе функции f и g только тогда, когда граф линеаризации ациклический. Достаточно показать, что если fag вычисляются при помощи алгоритма 7.1, то (1) Mtj = 0 означает, что f^g/, (2) М;/=+1 означает, что ft> g/t (3) Л1,у = — 1 означает, что fi<.gf- Утверждение (1) сразу следует из шага (2) алгоритма 7.1. Для того чтобы доказать утверждение (2), заметим, что при ТИ17 = 4- 1 к графу линеаризации добавляется дуга (?,, 67). Сле- довательно, fi > gy, так как, если граф линеаризации ацикличе- 13
ГЛ. 7. МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ ский, длина самого длинного пути, начинающегося в вершине Fh должна быть по крайней мере на единицу больше длины самого длинного пути, начинающегося в G,. Утверждение (3) доказы- вается аналогично. Необходимость. Допустим, что матрица предшествования М имеет функции предшествования fug, по граф линеаризации содержит цикл, состоящий из последовательности вершин V,,... ..., A7ft, Л14+1, где Nk+1 = N1 и £>1. Тогда на шаге (3) для всех г, можно найти такие вершины Н,- и /;+1, что (1) Н/ и /,-+> — вершины, вначале помеченные буквами F и G, (2) Ht и /,+1 представляются вершинами N, и Д1/+1 соответ- ственно, (3) либо //,• есть Fr, Il+1 есть Gs и —+ 1, либо Hi есть Gr, /,+1 есть I-,. и Alsr = —1. Из правила (2) алгоритма 7.1 видно, что если вершины Fr и Gs представляются одной и той же вершиной Nто fr должно равняться gs, если f и g—функции предшествования для М. Предположим, что f и g—функции предшествования для М. Пусть h, = fг, если Н; есть Fr, и ht = gr, если Я,- есть О,- По- ложим h'i равным fr, если 7; есть Fr, и равным g,, если 7Z есть Gr. Тогда /ij > Лг — Л, > Л;, = .. . /ift > h'k+1 Но так как Яй+1 совпадает с Я,, то h'k+1=h1. Однако уже было показано, что h1 > h'k+1. Таким образом, матрица предшествова- ния с циклическим графом линеаризации не может иметь функ- ций предшествования. □ Следствие. Алгоритм 7.1 вычисляет функции предшествования для М, если они существуют, и выдает ответ „нет" в против- ном случае. □ 7.1.2. Применения к разбору, основанному на операторном предшествовании Для любой матрицы, элементы которой принимают не более трех значений, можно попытаться найти функции предшествова- ния. Описанный метод применим независимо от того, что именно представляют элементы. Чтобы проиллюстрировать это, покажем сейчас, как применяются функции операторного предшествова- ния для представления отношений операторного предшество- вания. 14
7.1. ФУНКЦИИ ПРЕДШЕСТВОВАНИЯ Пример 7.4. Рассмотрим нашу любимую грамматику 60 с пра- Т — Т*Е | F F—>(E)\a Матрица отношений операторного предшествования для G„ изоб- ражена на рис. 7.6. $ * а,1 : мат- М‘. Если заменить <• на —1, i на 0 и •> на 4-1, то получится приведенная матрица предшествования М' (рис. 7.7). В ней 15
ГЛ. 7. МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ слиты строки, помеченные символами а и ), и столбцы, поме- ченные символами ( и а. Граф линеаризации для М' изображен на рис. 7.8. С помощью этого графа находим функции предше- ствования f = (0, 0, 2, 4, 4) и g' = (О, 5, 1,3, 0) для матрицы М'. Следовательно, функциями предшествования для исходной матри- цы будут / = (0, 0, 2, 4, 4, 4) и g=(0, 5, 1, 3, 5, 0). □ 7.1.3. Функции слабого предшествования Как уже отмечалось, с элементами -1,0 и +1 матрицы из алгоритма 7.1 можно связать отношения предшествования Вирта — Вебера <♦, Л. и •> соответственно. Если функции предшество- вания Найдены, то отношение предшествования между симво- лами X и Y можно определить, применив первую функцию к X, а вторую к У. В этом случае для всех пар X и У между сим- волами X и Y выполняется какое-нибудь отношение предшест- вования, вследствие чего обнаружение ошибки задерживается до тех пор, пока не будет достигнут конец входной цепочки или пока не потребуется проделать невозможную свертку. Однако метод функций предшествования можно применить для представления шагов работы алгоритма разбора типа „перенос — свертка", сохранив некоторую возможность обнаруживать ошибки, которая отражается пустыми элементами исходной матрицы отношений предшествования. Определим матрицу слабого пред- шествования М как (тхп)-матрицу с элементами —1, — 1 и „пусто". Элементы со значением —1, вообще говоря, обозначают переносы, элементы со значением 4-1 обозначают свертки, а пус- тые элементы — ошибки. С помощью такой матрицы можно опи- сать функцию „перенос—свертка" алгоритма разбора типа „перенос — свертка" для грамматики слабого предшествования, грамматики (1,1)-предшествования и простой грамматики со сме- шанной стратегией предшествования. Назовем векторы f и g функциями слабого предшествования для матрицы слабого предшествования М, если fi<g,- всякий раз, когда Л4у = —1, a когда Д417 = + 1. Условие fi = gj можно использовать как указание на ошибоч- ную ситуацию, представляемую пустым элементом М,-. Вообще говоря, не всегда, когда Л4,7—пустой элемент, удается удовлет- ворить условию fi—gj, но желательно сохранить, насколько это возможно, способность обнаружения ошибок, заложенную в ис- ходной матрице. Таким образом, можно рассматривать проблему нахождения функций слабого предшествования для матрицы слабого пред- шествования М как задачу отыскания функций, которые в наи- большем числе случаев порождают нули для пустых элементов матрицы М. Мы предпочитаем не заменять сразу все пустые 16
7.1. ФУНКЦИИ ПРЕДШЕСТВОВАНИЯ элементы матрицы слабого предшествования нулями, поскольку это ограничило бы число матриц слабого предшествования, имею- щих функции слабого предшествования. Некоторые пустые эле- менты, возможно, придется заменить на —1 или -|-1 для того, чтобы существовали функции слабого предшествования (см. упр. 7.19). Кроме того, может оказаться, что к некоторым пустым элементам анализатор никогда не обращается, поэтому нет необ- ходимости заменять их нулями. В связи с этим приобретает важность понятие независимых вершин в ориентированном ациклическом графе. Говорят, что две вершины Л', и jV,2 ориентированного ациклического графа независимы, если нет пути из в Л’2 или из Л12 в Л\. Алгоритм 7.1 можно было бы непосредственно применять для построения функции слабого предшествования для матрицы М, но в том виде, в каком он описан, он не позволяет максимизи- ровать число нулей, порождаемых для пустых элементов. Тем не менее мы используем три пер- вых шага алгоритма 7.1 для по- строения графа линеаризации для М. Из теоремы 7.1 известно, что М имеет функции слабого пред- Рис. 7.9. Матрица отношений пред- Рис. 7.10. Приведенная матрица шествования Вирта—Вебера для Go. слабого предшествования. шествования тогда и только тогда, когда граф линеаризации для М ациклический. Независимые вершины графа линеаризации определяют, какие пустые элементы матрицы М можно сохра- нить. Другими словами, равенство f, = g_, должно выполняться только для независимых вершин F; и G,-. Конечно, если пред- почтение отдано условию f; = gj, то могут быть другие пары не- зависимых вершин, для которых отвечающие им числа нельзя сделать равными. Пример 7.5. Матрица отношений предшествования Вирта — Вебера для грамматики О„ показана на рис. 7.9. Столбцы, отве- 17
ГЛ. 7. МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ чающие нетерминалам, выброшены, поскольку мы будем пользо- ваться этой матрицей только в применении к алгоритму типа „перенос — свертка". Соответствующая приведенная матрица сла- бого предшествования показана на рис. 7.10, а построенный по ней граф линеаризации изображен на рнс. 7.11. В этом графе вершины, помеченные буква- /^\ ми и G., независимы. Не- Рнс. 7. II. Граф линеаризации. зависимы также 02 и 04, а вершины FT и 03 не являют- ся независимыми. □ Можно обобщить шаг (5) алгоритма 7.1 так, чтобы по- лучались функции предшест- вования, максимизирующие число нулей, отвечающих пу- стым элементам. Определе- ние компонент векторов пред- шествования состоит в при- сваивании числовых меток вершинам графа линеариза- ции. Всем вершинам из лю- бого множества попарно не- зависимых вершин присваи- вается одно и тоже число, по у вершины, являющейся предком одной или более вершин, присваемое число должно быть больше, чем у любого из ее потомков. Числа присваиваются вершинам следующим образом. Во-пер- вых, множество вершин графа линеаризации разбивается на кисти независимых вершин так, чтобы общее число пар F, G, объеди- ненных в кисть, было по возможности большим. Вообще говоря, различных разбиений множества на кисти может быть много и некоторые пары F, G могут оказаться предпочтительнее других. Эта часть процесса вполне может оказаться большой комбина- торной задачей. Как только граф разбит на множество кистей, на последнем можно1) ввести линейный порядок <, при котором С < С для кистей С и С' тогда и только тогда, когда С содержит вершину, являющуюся потомком некоторой вершины из С. Если С„, Си... . . ., Ск — последовательность кистей, расположенных в описан- ном порядке, то всем вершинам из Со присваивается 0, всем вершинам из С, присваивается 1 и т. д. ') Нс всегда. —Прим, перге. 18
7.1. ФУНКЦИИ ПРЕДШЕСТВОВАНИЯ Пример 7.6. Рассмотрим граф линеаризации для G„, изобра- женный на рис. 7.11. Множество {£,, F,, 04}— одна из кистей независимых вершин. То же можно сказать и о множествах {F4, 02, GJ, {F2, GJ, {Gn GJ и {Fs, GJ. Но кисть {G4, G3 не подходит, так как обе вершины в ней помечены буквой G, и это не дает ну- левого элемента в матрице слабого а ( ) + * $ £ -1 -1 -1 -1 -1 предшествования. Кисть {F3, GJ может оказаться предпочтительнее, чем {F2, GJ, потому что соотношение f3—g1 т -1 -1 +1 +1 -1 +1 г 0 0 +1 +1 +1 +1 позволяет обнаружить ошибку, когда во входной цепочке появляются ком- бинации символов аа, а(, )а или ) (, а 0 0 +1 +1 +1 +1 ) 0 0 +1 +1 +1 +1 в то время как с помощью соотно- шения /2= g4 удается обнаружить ошиб- ку только для пар Та и Т (. Кроме того, заметим, что если мы обнаружим ошиб- ку, когда появится аа, нам не удастся свернуть а в F, и потому комбинации ( -1 -1 0 0 -1 0 + -1 -1 0 0 -1 0 * -1 -1 0 0 -1 0 $ -1 -1 0 0 “1 0 символов Fa и Та никогда не встре- тятся. Рис 7.12. Окончательный Таким образом, одним из возможных вид матрицы предшсствова- вариантов объединения вершин в кисти кия для °0' будет {Л}, {F., G2, GJ, {FJ, {GJ, {F3, GJ. Расположив кисти слева направо в описанном порядке, по- лучим функции слабого предшествования / = (0,2,4, 1) и£=(4, 1, 3, 1). Эти функции определяют матрицу предшествования, изоб- раженную на рис. 7.12. □ 7.1.4. Преобразование матриц предшествования Пример 7.6 показывает, что к некоторым элементам матрицы предшествования Вирта—Вебера, соответствующим ошибочным ситуациям, алгоритмы разбора типа „перенос — свертка" для грам- матик простого и слабого предшествования (алгоритмы 5.12 и 5.14) никогда не обращаются. Если удастся выделить эти эле- менты и чем-нибудь заменить, можно будет при нахождении функций слабого предшествования, покрывающих максимально возможное число элементов, которые отвечают ошибочным ситуа- циям, не принимать их во внимание. Чтобы понять, как можно модифицировать матрицы отноше- ний предшествования, сначала договоримся, какие два алгоритма разбора типа „перенос—свертка" мы будем считать строго экви- валентными. Для записи алгоритмов разбора воспользуемся обо- значениями, введенными в разд. 5.3 (том 1). 1?
ГЛ. 7. МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ Определение. Пусть Л2 = (Д, ff,) ') и Л,,-—1[г,р,]—два алго- ритма разбора типа „перенос — свертка" для КС-грамматики G = (N, S, Р, S). Будем называть Л, и Лг строго эквивалентными, если их поведение одинаково для всех входных цепочек. Другими словами, если входная цепочка w принадлежит языку L (G), то оба алгоритма разбора допускают w. Если w не принадлежит L(G), то оба алгоритма выдают сообщение об ошибке после оди- накового числа шагов и на одной и той же фазе. Если это произошло на фазе свертки, то ошибочное отношение находится после просмотра одного и того же числа символов в магазинах. Проанализируем, какие пустые элементы матрицы канониче- ских отношений предшествования Вирта—Вебера можно изме- нять, не влияя на поведение алгоритма разбора, построенного по этой матрице согласно алгоритму 5.12. Основная польза от такого анализа состоит в том, что удается найти хорошие кисти для функций слабого предшествования, подобно тому, как это делалось в предыдущем разделе. Пустые элементы, которые нельзя изменять, будем называть существенными. Доказываемая ниже теорема характеризует существенные пустые элементы. Сначала введем некоторые обозначения. Предположим, что G = (N, S, Р, .S)— КС-грамматика. Пусть Мс — матрица канони- ческих отношений предшествования Вирта — Вебера для G. (Каноническими мы называем отношения, построенные прямо по определению.) Будем отмечать такие отношения предшествования нижним индексом с. Если между символами X и К не выпол- няется ни одно из отношений предшествования Вирта—Вебера, будем писать Х?СУ. Затем можно построить произвольную матрицу М, состоящую из <•, JL, •> и пустых элементов. Если М имеет те же размеры, что и Мс, то будем называть М матрицей отношений предшест- вования для G. Если элемент (X, К) матрицы М пустой, будем писать Х?К. Для построения алгоритма разбора типа „перенос—свертка" Ле = ([с, gc) Для грамматики G, использующего отношения пред- шествования Вирта—Вебера, которые содержатся в Мс, можно применить алгоритм 5.12. Применяя алгоритм 5.12, можно также построить для G другой алгоритм разбора типа „перенос — свертка" Л = (/,£), использующий отношения предшествования, которые содержатся в М. Корректность алгоритма разбора Лс гарантирует теорема 5.15, а аналогичной гарантии для Л нет. Однако в теореме 7.2 устанавливается необходимое и достаточное условие для того, чтобы алгоритм Л был строго эквивалентен алгоритму Лс. ') Здесь Д —это функция переноса —свертки, a gt — функция свертки. 20
7.1. ФУНКЦИИ ПРЕДШЕСТВОВАНИЯ Теорема 7.2. Алгоритм Л строго эквивалентен алгоритму Лс тогда и только тогда, когда для всех X и Y из N U 5- и а, Ь из 2 и {$} и А мз N удовлетворяются следующие четыре условия: (1) (а) Если X <•,. Y, то X <• У, (б) если X А=,, У, то X Л Y, (в) если Ху>са, то Х»>а. (2) Если Ь?с.а, то Ь? а. (3) Если А?с а, то либо (а) А? а, либо (б) для всех 7- из Nl)2, для которых А——правило из Р, утверждение Zi>ea ложно. (4) Если Х?СА, то либо (а) X? А, либо (б) для всех Z из NljS, для которых А—> Za— правило из Р, утверждение X <t_cZ ложно. Доказательство. Достаточность. Согласно условию (1), шаги алгоритмов Л и Лс должны совпадать до тех пор, пока последний не обнаружит ошибку. Следовательно, достаточно показать, что если два алгоритма разбора достигают конфигура- ции Q (Хх ... Хт, at ... аг, л) и Q Н^ ошибка, то Q |— ошибка. Более того, механизмы обнаружения ошибки в алгорит- мах Л и Лс совпадают. Сначала предположим, что в конфигурации Q fc (Хт, at) = ошибка, но f(X„, aL) =7= ошибка. Покажем, что это приводит к противоречию. Итак, предположим, что X^icax верно, а Х,„? а± не выполняется. По условию (2) символ Хт должен быть нетер- миналом. По условию (3) для всех У, для которых правило Х,„—принадлежит Р, утверждение Yi>ea, ложно. Из анализа алгоритма разбора, использующего технику пред- шествования, видно, что нетерминал помещается в верхушку магазина только в том случае, если предыдущим шагом была свертка. Тогда в Р есть такое правило Хт—шК, что прежде, чем попасть в конфигурацию Q, оба алгоритма сделали шаг (X, ... Хт_,аУ, а1 . . . аг, л') |— Q. Но это означает, что У^а^ получили противоречие. Другая возможность состоит в том, что в конфигурации Q gc(Xt ... Хт, г) —ошибка, но g(Xx ... Хт, е) ^ошибка. Надо рассмотреть лишь случай, когда X„'t>l,a1, Хт>>а1 и существует такое число s, что ХДсХ3 + 1, причем Xj — cX^^ и Х, = Х/+1 для s < i < т, но ХДХ1 + 1 не выполняется. Считаем, что Xi+1 — нетерминал, поскольку Лс может поместить в магазин после Х5 терминал только в том случае, когда Х^.<«сХ4+1 или Х3 CXS + 1. По условию (4), если XJ + 1 —> Уа принадлежит Р, то не может быть Xs <• сУ. Но XJ+, мог бы появиться в магазине вслед за Xs, только если бы была возможна свертка некоторой цепочки Уа 21
ГЛ. 7. МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ в Xi+i. Другими словами, должна существовать конфигурация (А\ . . . XsYa, br ... bk, л"), приводящая к Q и такая, что (Xt...X,Ya, b1...bl!, л") |—(А\ . . . Х,Х,П, ^...b*, n"i). Но тогда было бы <•<. Y вопреки условию (4). Необходимость. Нетрудно показать, что если не удовлетво- ряется условие (1), алгоритмы разбора не являются строго экви- валентными. Поэтому опустим эту часть доказательства и займемся более сложными случаями. Случай 1: Пусть не удовлетворяется условие (2). Это значит, что для некоторой пары Ь, а верно bica и неверно bfa. Так как G- грамматика простого предшествования (и, следовательно, приведенная), в L(G) найдется слово вида wbx. Посмотрим, как происходит разбор цепочки wba согласно алгоритмам и А. Поскольку wbx£L(G), ни тот, ни другой алгоритм не сможет обнаружить ошибку, прежде чем символ а из wba не станет следующим входным символом. Таким образом, оба анализатора должны достичь некоторой конфигурации (Sa, baS, л), когда b помещается в верхушку магазина и образуется конфигурация (Sab, а$, л). Так как Ь?£.п верно, а Ь?а нет, алгоритмы Ас и А не являются строго эквивалентными. Случай 2: Пусть нарушено (3). Это значит, что верно Д?са, неверно А?а и в Р есть такое правило А—>аХ, что X S>t. а. Так как G — приведенная грамматика, найдутся правовыво- димая в 6 цепочка fiAw и цепочка х £ £*, для которых А =>г аХ~>г ... =>гр„=^>,х. Кроме того, найдется такая цепочка l/£S*, что Согласно лемме 5.3, если Y—последний сим- вол какой-либо из цепочек . .., 0„ или х, то К«>£а. Заметим, что при разборе цепочки yxw первый символ це- почки w не будет перенесен в магазин, пока не выполнится свертка ух в flA. Поэтому разбор цепочки уха будет происходить точно так же, как и разбор цепочки yxw, пока не будет достиг- нута конфигурация (80Д, aS, л'). Но Afca верно, а А?а нет, так что эти два алгоритма не являются строго эквивалентными. Случай 3: Пусть нарушено условие (4). Другими словами, верно Х?еА, неверно Х?А и в Р есть такое правило А —Ха, что X<XCY. Пусть —правовыводимая цепочка и А =>г Ха =>г У; =>г ...=>, у,, => х. Далее, пусть ЬХи—такая правовыводи- мая цепочка, что 6 —А у и X=?“z. Тогда, согласно лемме 5.3, для X и первых символов цепочек у1( ..., и х выполняется отношение <«с. Кроме того, для последнего символа каждой правовыводимой цепочки в выводе X =>( z и первого символа цепочки х выполняется отношение «>с. При разборе цепочки yzxw будет достигнута конфигурация ($6Х, да$, л), а затем конфигурация (JpbXA, wS, л'). Анализа- торы попытаются здесь произвести свертку по правилу, в резуль- 22
7.1. ФУНКЦИИ ПРЕДШЕСТВОВАНИЯ тате применения которого в цепочке fiAw появился символ А. Если XfcA верно, а Х?А нет, снова приходим к противоречию тому, что анализаторы строго эквивалентны. □ Пример 7.7. Рассмотрим грамматику простого предшествования G с правилами Е—>Е + Л | А А—>-Т T +T*F]F F — (В | а В—+Е) Ясно, что 7.(0) =L(G0). Матрица канонических отношений пред- шествования Вирта — Вебера для G приведена на рис. 7.13. Выясним, какие элементы на рис. 7.13 можно изменить в соот- ветствии с теоремой 7.2. Условие (1) гласит, что непустые эле- менты не изменяются. Условие (2) утверждает, что все пустые элементы, расположенные на пересечении последних шести столб- цов и последних шести строк, существенны. По условию (3) (Е, $)—существенный пустой элемент, так 23
ГЛ 7. МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ как есть правило £—А и А •>$ верно. Оставшиеся в последних шести столбцах пустые элементы несущественны, и, значит, оии могут меняться произвольным образом. По условию (4) пустой элемент ($, В) существен, так как есть правило В—> Е) и $<«Е верно. Оставшиеся в первых пяти столбцах пустые элементы можно произвольно изменять. □ Если алгоритм разбора типа „перенос—свертка" для обратимой грамматики слабого предшествования строить с помощью алго- ритма 5.14, то можно показать, что анализаторы, аналогичные анализаторам А и Лс из теоремы 7.2, строго эквивалентны тогда и только тогда, когда удовлетворяются первые три условия тео- ремы 7.2 *). Пример 7.8. Применим условия (1)—(3) теоремы 7.2 к матрице отношений слабого предшествования для G„, приведенной на рис. 7.9. Легко видеть, что все пустые элементы, стоящие в по- следних шести строках, существенны. Кроме них есть только один существенный пустой элемент, а именно (В, $), так как правило Е—>Т принадлежит Р и ?•>$ верно. Изучим граф линеаризации, изображенный на рис. 7.11. Мы видим, что для него нет таких функций предшествования, что каждому существенному пустому элементу соответствует 0. В противном случае вершины Е4, Gz, G3 и С4, например, были бы объединены в одну кисть. На этом можно закончить описание использования функций предшествования для построения анализаторов. Однако мы могли бы воспользоваться несколько более слабым определением экви- валентности анализаторов. Строгая эквивалентность — очень сильное условие. На прак- тике желательно, чтобы два алгоритма разбора типа „перенос — свертка" считались эквивалентными, если они допускают одну и ту же входную цепочку или оба выдают сообщение об ошибке в одном и том же месте ошибочной входной цепочки. Таким образом, может оказаться, что один анализатор сразу сообщил об ошибке, в то время как другому понадобилось сделать не- сколько сверток (но не переносов из входной цепочки), прежде чем выдать аналогичное сообщение. При таком условии, которое будет называться просто эквивалентностью, можно значительнее видоизменять отношения предшествования, сохраняя эквивалент- ность анализаторов (см. упр. 7.13). При таком расширенном определении эквивалентности алго- ритм разбора типа „перенос — свертка", использующий функции предшествования, приведенные в табл. 7.1, эквивалентен анали- 5 Напомним, что свертки в анализаторе слабого предшествования не зависят от матрицы предшествования. 24
УПРАЖНЕНИЯ затору, построенному при помощи алгоритма 5.14 по матрице отношений слабого предшествования, приведенной на рис. 7.9. □ Подробно эта более слабая форма эквивалентности будет изучаться в разд. 7.2—7.4. УПРАЖНЕНИЯ 7.1.1. Для следующих грамматик найдите функции слабого предшествования или докажите, что таких функций нет: (а) 5-т54|Д 4->(S)|( ) (б) Е-^Е + Т\ + Т\Т T-+T*F\F F—>(E)\a 7.1.2. Покажите, что если М' — матрица, полученная из Л4 перестановкой некоторых строк и/или столбцов, то векторы fug, построенные для М' алгоритмом 7.1, будут получаться переста- новкой компонент векторов, построенных для М. 7.1.3. Найдите функции предшествования для матрицы, изо- браженной на рис. 7.14. +1 +1 +1 +1 +1 4-1 -1 +1 +1 4-1 -1 -1 -1 +1 +1 4-1 -1 -1 -1 -1 +1 + 1 -1 -1 '1 -1 -1 0 Рис, 7.14. Матрица предшествования. 25
ГЛ. 7. МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ 7.1.4. Постройте алгоритм, определяющий, имеет ли матрица такие фунции предшествования [ и g, что f — g. *7.1.5. (а) Покажите, что описанный после алгоритма 7.1 метод, определяющий, является ли ориентированный граф ациклическим, действительно работает. (б) Покажите, что можно сделать так, чтобы этот метод ра- ботал за время 0(п) + 0(е), где п— число вершин, а е— число дуг данного графа. Указание: Выберите некоторую вершину. Рас- красьте все вершины, лежащие на пути, ведущем из этой вершины либо к листу, либо к уже раскрашенной вершине. Если встре- тится лист, удалите его, поднимитесь к его прямому предку, а затем продолжите процесс раскраски. 7.1.6. (а) Покажите, что метод разметки, приведенный после алгоритма 7.1, позволяет найти длину самого длинного пути, начинающегося в произвольной вершине. (б) Покажите, что этот метод можно определить так, чтобы он требовал времени 0(n) + 0(e), где п— число вершин, а е — число дуг данного графа. 7.1.7. Придумайте алгоритм, который по матрице М с эле- ментами —1,0, 4-1, „пусто" и по константе k выясняет, суще- ствуют ли такие векторы f и g, что (1) если Mjj = — 1, то f/ + k < g:, (2) если Л1,7 = 0, то |Д— (3) если Л1;у- = +1, то fi>g}+k. Определение. Пусть М— матрица слабого предшествования. Последовательность целых чисел ilt i2, ..., ift, где k — четное число, большее 3, назовем циклом матрицы М, если (1) Л1уу11 =—1 Для нечетных /, Mi ( ^+1для четных/ и Al;lift= + 1 или (2) Л1,у.+ 1 =+1 для нечетных /, Me i.=—1 для четных j и М,щй = — 1. 1 1 7.1.8. Покажите, что функции слабого предшествования для матрицы слабого предшествования существуют тогда и только тогда, когда она не содержит циклов. 7.1.9. Пусть М — матрица слабого предшествования и i, j, k, I — такие индексы, что (1) М1к = Мл = — 1, Mjk=+1 и Mit есть „пусто", 26
УПРАЖНЕНИЯ ИЛИ (2) Л11й = Л1/; = +1, Л1уй =—1 и Мц есть „пусто". Пусть М' получается в результате замены в матрице М элемента Mit на —1 в случае (1) или на +1 в случае (2). Покажите, что f и g—функции слабого предшествования для М тогда и только тогда, когда они являются функциями слабого пред- шествования для М'. Определение. Будем говорить, что две строки (два столбца) матрицы предшествования совместимы, если во всех случаях, когда их соответствующие элементы не совпадают, один из них пустой. Совместимые строки (столбцы) можно слить, заменив их новой строкой (столбцом) так, что непустые элементы каждой из прежних строк (столбцов) совпадают с соответствующими непустыми элементами новой строки (столбца). 7.1.10. Покажите, что операции слияния строк и столбцов сохраняют свойство матрицы не иметь линеаризующих функций. Функции предшествования можно применять также для пред- ставления отношений <• и ,*=, используемых функцией свертки в алгоритме разбора типа „перенос—свертка", построенном по алгоритму 5.12. Сначала найдем матрицу слабого предшество- вания М, в которой —1 представляет <•, +1 представляет а пустые элементы представляют и •>, и ошибку. Затем попы- таемся отыскать для М функции предшествования, опять пробуя заменить возможно большее число пустых элементов нулями. 7.1.11. Представьте отношения <• и Ду, приведенные на рис. 7.13, функциями предшествования. С помощью теоремы 7.2 найдите существенные пустые элементы и попытайтесь сохра- нить их. *7.1.12. Покажите, что если принять определение строгой экви- валентности анализаторов слабого предшествования, то пустой элемент (X, Y) матрицы отношений предшествования Вирта — Вебера будет существенным тогда и только тогда, когда удовле- творяется одно из следующих условий: (1) X и У принадлежат 2 U {$}, (2) X принадлежит N, У принадлежит 2 U {$} и есть такое правило X—* а/, что Z>>cy. В следующих задачах термин „эквивалентность" понимается в смысле примера 7.8. *7.1.13. Пусть и Л — те же алгоритмы разбора типа „пе- ренос— свертка" для грамматики простого предшествования, что и в теореме 7.2. Докажите, что они эквивалентны тогда и только 27
ГЛ. 7, МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ тогда, когда удовлетворяются следующие условия: (1) а) Если то X <• У, (б) если X , И, то X i У, (в) если X ~!>са, то X •> а. (2) Если Ь?са, то b <• а ложно. (3) Если А?са и /1<«ц или ХДа, то нет такого вывода А =>г а1Х1^=>г... ^>ra,„Xa, т 1, что Х,?са и X, ~i> а для 1 Хт < т и Хт'->еа или Хт—терминал и Хт •> а. (4) Если Л1<«а или А1Л=а для некоторого а, то нет вывода /4j => Д, =>...=> Дт => Ва, т~^\, символа X и правила В —>- Ур, для которых (а) Х?СД,-, но X <•/!,, где (б) Х?СВ, но Х<(В; (в) Х<У. 7.1.14. Покажите, что анализатор, использующий функции предшествования из примера 7.8, эквивалентен каноническому анализатору предшествования для (У. 7.1.15. Пусть М — матрица отношений предшествования, полу- ченная из матрицы канонических отношений предшествования Вирта —Вебера Мс в результате замены некоторых пустых эле- ментов на •>. Покажите, что анализаторы, построенные по М и Мс с помощью алгоритма 5.12 (или 5.14), эквивалентны. *7.1.16. Рассмотрим алгоритм разбора типа „перенос — сверт- ка" для грамматики простого предшествования, в котором после каждой свертки проверяется, какое из отношений <• или выполняется между символом, стоящим непосредственно слева от основы, и символом, в который свертывается основа. При каких условиях произвольная матрица отношений предшествова- ния будет порождать анализатор, строго эквивалентный (или эквивалентный) анализатору такого типа, построенному по матри- це канонических отношений предшествования Вирта — Вебера? **7.1.17. Покажите, что всякий КС-язык порождается грам- матикой предшествования (не обязательно обратимой), для кото- рой можно найти функции предшествования. Проблемы для исследования 7.1.18. Придумайте эффективный алгоритм нахождения функ- ций предшествования для грамматики слабого предшествования G, позволяющий построить анализатор, эквивалентный кано- ническому анализатору предшествования для G. 28
7.2. ОПТИМИЗАЦИЯ АНАЛИЗАТОРОВ ФЛОЙДА — ЭВАНСА 7.1.19. Разработайте хорошие процедуры нейтрализации оши- бок, которыми можно было бы воспользоваться при разборе с помощью функций предшествования. Упражнения на программирование 7.1.20. Разработайте программу, реализующую алгоритм 7.1. 7.1.21. Напишите программу, реализующую алгоритм разбора типа „перенос — свертка", который использует в качестве функ- ций fug функции предшествования. 7.1.22. Напишите программу, определяющую, является ли КС-грамматика грамматикой предшествования, для которой существуют функции предшествования. 7.1.23. Напишите программу, которая получает на вход грам- матику простого предшествования G, имеющую функции пред- шествования, и выдает для G диализатор типа „перенос — свертка", использующий функции предшествования. Замечания по литературе Флойд [1963j применил функции предшествования для представления матрицы отношений операторного предшествования. Вирт и Вебер [1966] предложили применять их для представления отношений предшествования Вирта — Вебера. Алгоритмы вычисления функции предшествования были даны Флойдом [1963], Виртом [1965], Беллом [1969], Мартином [1972], а также Ахо и Ульманом [1972а]. Теорема 7.2 взята из работы Ахо и Ульмана [19726], где содержатся также ответы на вопросы, сформулированные в упр. 7.1.13 и 7.1.15. Упр. 7.1.17 заимствовано у Мартина [1972]. 7.2. ОПТИМИЗАЦИЯ АНАЛИЗАТОРОВ ФЛОЙДА —ЭВАНСА Алгоритм разбора типа „перенос—свертка" демонстрирует принципиально простой метод разбора. Однако при реализации двух функций анализатора мы сталкиваемся с проблемами эффек- тивности. В настоящем разделе будет исследован вопрос о том, как сконструировать алгоритм разбора типа „перенос — свертка" для обратимой грамматики слабого предшествования, поль- зуясь языком Флойда—Эванса. В центре внимания будут методы, позволяющие уменьшать объем получаемой программы на языке Флойда—Эванса, не затрагивая поведения анализатора. Хотя здесь рассматриваются только грамматики предшествования, мето- ды этого раздела применимы также при реализации анализаторов для всех остальных классов грамматик, описанных в гл. 5 (том I). 29
ГЛ. 7. МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ 7.2.1. Механическое построение анализаторов Флойда — Эванса для грамматик слабого предшествования Начнем с того, что покажем, как можно механически по- строить анализатор на языке Флойда—Эванса для обратимой грамматики слабого предшествования. Язык Флойда — Эванса описан в разд. 5.4.4. Алгоритм проиллюстрируем примером. Как всегда, возьмем для примера грамматику слабого пред- шествования G„ с правилами (1) Е^ЕГТ (2) Е- >Т (3) T^T*F (4) Т~Е (5) Г-»(Е) (6) F —> а Отношения предшествования Вирта — Вебера для приве- дены на рис. 7.9. По каждой строке этой матрицы предшество- вания будем генерировать операторы анализатора на языке Флойда — Эванса. Будем пользоваться четырьмя типами опера- торов: оператор переноса, оператор свертки, оператор проверки и вычисляемый оператор перехода ’). Операторам будем присваи- вать символьные метки, указывающие как на тип оператора, так и па верхний символ магазина. В таких метках буква 5 озна- чает перенос, Я —свертку, С —проверку и G — переход. За этими буквами в метках стоит символ, находящийся в верхушке мага- зина. Сначала сгенерируем операторы переноса, а затем свертки. Для грамматики слабого предшествования отношения пред- шествования <• и JL означают перенос, a •>—свертку. ^-строка на рис. 7.9 порождает операторы (7,2,1) SB: Е\)—^Е)\ *S) + | *S4- $£ |$ | допуск Е | | ошибка х) Введение вычисляемого оператора перехода означает расширение языка Флойда —Эванса по сравнению с описанием его в разд. 5.4,4, Эго расшире- ние заключается в том, что следующая метка может быть выражением, содер- жащим знак который, как и в разд. 5.4.4, представляет неизвестный сим- вол, соответствующий символу, расположенному в указанной позиции в стеке, илн символу, на который происходит заглядывание вперед. Мы не будем останавливаться на деталях реализации такого оператора, но читатель может сам убедиться, что введенные здесь вычисляемые операторы перехода легко реализовать на доступной ему вычислительной машине. 30
7.2. ОПТИМИЗАЦИЯ АНАЛИЗАТОРОВ ФЛОЙДА — ЭВАНСА Первый оператор означает, что если Е находится в верхушке магазина и текущий входной символ есть ), то ) помещается в верхушку магазина, считывается следующий символ и проис- ходит переход на оператор, помеченный S). Если первый опера- тор неприменим, проверяем, является ли текущий входной сим- вол знаком Ч-. Если второй оператор неприменим, опять про- веряем, совпадает ли текущий входной символ с символом $. Соответствующим действием анализатора будет тогда переход в заключительное состояние допуск, если в магазине содержится цепочка $£. В противном случае выдается сообщение об ошибке. Заметим, что если в верхушке магазина находится Е, то ника- кие свертки невозможны. Поскольку вторая компонента метки представляет собой сим- вол, находящийся в верхушке магазина, во многих случаях удается избежать его ненужной проверки, если известно, что это за символ. Зная, что в верхушке магазина находится сим- вол Е, можно было бы заменить операторы (7.2.1) на SE: |) — )| *5) I н—+ | * s+ $#|$ | допуск | | ошибка Здесь оператор ошибки стоит последним не случайно. Когда Е находится в верхушке магазина, текущим входным символом должен быть один из символов ), + или $. В противном слу- чае мы получаем ошибку. Соответственно упорядочив операторы, можно сначала провести проверку на ), потом на а затем на $ и, если ни один из этих символов не является текущим входным символом, сообщить об ошибке. Строка, отвечающая на рис. 7.9 символу Т, порождает опе- раторы (7.2.2) ST: (»^*| -s.S’» RT: Е + Т\ СТ Т\ Е\ СТ СТ: |) | SE 1+ I SE |$ I SE | | ошибка Здесь порождает первый оператор, Т^>), 7'»>+ и Т>>$ указывают, что, если в верхушке магазина находится символ Т, надо выполнить свертку. Так как мы рассматриваем грамматику слабого предшествования, то в соответствии с лем- мой 5.4 при свертке всегда применяется правило с самой длин- 31
7.2, ОПТИМИЗАЦИЯ АНАЛИЗАТОРОВ ФЛОЙДА — ЭВАНСА ГЛ. 7. МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ ной правой частью их всех применимых правил. Таким образом, сначала выясняем, содержится ли в верхушке магазина комби- нация Е + Т. Если да, то заменяем Е-Т на Е. В противном случае свертываем Т в Е. Какой бы из Т^Т-операторов ни при- менялся, известно, что в верхушке магазина находится символ Т. Поэтому можно написать RT: Е-р#]—> Е\ СТ #|-£| СТ и тем самым вновь избежать ненужной проверки верхнего сим- вола магазина. После выполнения свертки проверяется, была ли она закон- ной. Иными словами, выясняется, что представляет собой теку- щий входной символ: ), + или $. Для этого используется группа операторов проверки, помеченных СТ. Если текущий входной символ — не ), не + и не $, то выдается сообщение об ошибке. Порядок действий, при котором вначале делается свертка, а за- тем проверяется, надо ли было ее делать, может не всегда ока- заться желательным, но, выполняя эти действия именно в таком порядке, мы получаем возможность совместить общие операции проверки. Для проведения такой проверки введем вычисляемый опера- тор перехода вида G- #| | S# указывающий, что верхний символ магазина должен стать послед- ним символом метки. Можно заменить операторы проверки в (7.2.2) последователь- ностью операторов СТ: 1) 1 G 1 + 1 G 1$1 G 1 1 ошибка G: #1 1 S# Теперь можно применять эти операторы проверки и в других последовательностях. Например, если в Ga свертка выполняется, когда в верхушке магазина находится Т, то новым верхним сим- волом магазина должен быть символ Е. Таким образом, все опе- раторы в группе СТ передают управление на метку SE. Однако, вообще говоря, возможны свертки и в несколько различных нетерминалов, и тогда тот же вычисляемый оператор перехода работает с другими верхними символами магазина. Наконец, ради удобства позволим операторам иметь более одной метки. Польза от такого допущения, которое несложно 32 реализовать, станет ясной в дальнейшем. Приведем алгоритм, использующий изложенные идеи. Алгоритм 7.2. Построение анализатора Флойда- Эванс а по обратимой грамматике слабого пред- шествования. Вход. Обратимая грамматика слабого предшествования G = = (N, 2, Р, S). Выход. Анализатор на языке Флойда—Эванса для G. Метод. (1) Найти для G отношения предшествования Вирта — Вебера. (2) Линейно упорядочить множество NllSU{$}; например, так: \Xlt Ха, •. ., X„j. (3) Порождать операторы для X,, Х2, ..., Хт следующим образом. Допустим, что X,- не является начальным символом и либо Х;<* а, либо X(=La для всех а из а2...а.]} и X,- •> b для всех Ь из {Ьъ b2, ..., bj. Кроме того, предположим, что А,—>ахХ;, А, —cz2X;, ..., Aft — czfiX, -правила, в которых X, —последний символ правой части, расположенные так, что а‘х,- не является суффиксом цепочки а„Х,. при р <q. Считаем, что Ah—>аАХг имеет номер ph, \^h^k. Затем порождаем операторы SXp |Я1—*«1 I *Sai |а2—+аг | \at^af \ * Sak RXp ах#| —»АХ| выдача р, CXt а2#| — А2| выдача р2 CXt а„#\ —выдача рк СХ( | | ошибка СХр l&i I ° \ьг | G l&z ’ I О | | ошибка 2 А. Ахо, Дж. Ульман, т. 2 33
ГЛ. 7. МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ 7.2. ОПТИМИЗАЦИЯ АНАЛИЗАТОРОВ ФЛОЙДА — ЭВАНСА Если / — 0, то первый оператор группы RXj имеет также метку SX{. Если й = 0, то оператор ошибки в группе RX, имеет метку RX[. Если X; — начальный символ, то делаем все, как раньше, и добавляем в конец группы SX,- оператор S# | $ | допуск S$— начальное состояние анализатора. (4) Добавить вычисляемый оператор перехода G: #1 IS# □ Пример 7.9. Рассмотрим грамматику 0я. По строке F матрицы предшествования можно получить операторы SF: RF1): Т *#|- 'Л выдача 3 CF #ь г 7'1 выдача 4 CF 1 1 ошибка CF: 1) G 1+ 1 G 1* 1 G 1$ 1 G 1 1 ошибка Заметим, что третий оператор 1 не нужен, потому что сравнение, выполняемое вторым оператором, всегда дает положительный результат. В принципе можно включить в алгоритм 7.2 про- верку, позволяющую не порождать ненужные операторы. В даль- нейшем мы будем считать, что ненужные операторы не порож- даются. По строке а получаем операторы Sa: Ra: #1 ->Е| выдача 6 Са Са’. 1) 1 G i+ 1 G 1* 1 Q 1$ 1 1 1 ошибка G Отметим, что операторы проверки для а совпадают с операто- рами проверки для F. В следующем разделе мы опишем в общих чертах алгоритм, объединяющий излишние операторы. На самом деле операторы *) Отметим использование нескольких моток у одного оператора. Здесь группа SF пуста. проверки, помеченные меткой СТ, всегда можно слить с опера- торами, помеченными меткой CF, написав С а'. CF: 1* 1 G СТ'. 1) 1 G 1+ 1 G 1$ 1 G 1 1 ошибка В нашем алгоритме слияния будут также выполняться частные объединения такого рода. Строка матрицы предшествования, помеченная символом (, порождает операторы S(: |(-*(l *S( |а—*-а| *3а | | ошибка Аналогичные операторы порождаются строками, помеченными символами +> * и $. □ В качестве упражнения предлагаем проверить, что алгоритм 7.2 порождает для G корректный правый анализатор. 7.2.2. Усовершенствование анализаторов Флойда — Эванса В данном разделе мы изучим методы, применяемые для умень- шения числа операторов переноса и проверки в анализаторе Флойда—Эванса, построенном с помощью алгоритма 7.2. Наш основной метод состоит в слиянии общих операторов переноса и общих операторов проверки. По ходу дела могут добавляться дополнительные операторы, вызывающие безусловные переходы, но мы будем считать, что их относительный вес сравнительно мал. Обсудим, как выполняется слияние операторов переноса; тот же метод применим и для слияния операторов проверки. Пусть G = (N, 2, Р, S)— обратимая грамматика слабого пред- шествования и М— ее матрица отношений предшествования Вирта—Вебера. Матрица М определяет операторы переноса и проверки, возникающие в алгоритме 7.2. По матрице предшествования М построим совмещенную мат- рицу переносов Ms следующим образом: (1) Выбросим все элементы •> и заменим на <д. (Так как мы интересуемся только переносами, отношения <• и X можно отождествить.) (2) Если две или более строки полученной матрицы совпадают, заменим их одной строкой в Ms, причем свяжем с этой новой 2* 35 34
ГЛ. 7. МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ строкой множество тех символов из N U 2 U {$}, с которыми были связаны исходные строки. (3) Выбросим все строки, не содержащие элементов <• ; полу- ченную матрицу обозначим Л1^. Пример 7.10. Совмещенная матрица переносов для Go, полу- мещепная матрица переносов точно отражает ситуации, в которых анализатор выполняет перенос. □ По совмещенной матрице переносов ЛД построим неупорядо- ченный помеченный ориентированный граф (Д, 7?), называемый графом переносов, связанным с /VI,: (1) Для каждой строки матрицы Als, помеченной символом Y, в А найдется вершина, помеченная символом Y. (2) Существует одна дополнительная вершина, помеченная символом 0, которая представляет фиктивную пустую строку. (3) Если строка Y матрицы /И, покрывается строкой Z мат- рицы Л1у (т. е. в каждом столбце, где Y имеет элемент <• , строка Z тоже имеет элемент <•), то дуга (У, Z) содержится в Эта дуга помечена числом, равным числу столбцов, в которых Z имеет элемент <•, a Y—нет. Заметим, что строка Y может быть пустой. Метку дуги (Y, Z) обозначим через l(Y, Z). Пример 7.11. Рассмотрим матрицу переносов Л15, приведенную на рис. 7.16. Граф переносов, связанный с Ms, изображен на рис. 7.17. □ Ясно, что граф переносов представляет собой ориентирован- ный ациклический граф с единственным корнем 0. Число опе- раторов переноса, порождаемых алгоритмом 7.2, равно числу элементов переноса (<• или Л.) матрицы предшествования М. Используя матрицу переносов и сливая строки с совпадаю- щими элементами переноса, можно уменьшить число требуемых операторов переноса. Метод заключается в построении для графа переносов ориентированного остовного дерева (остова) (т. е. под- множества дуг, которое образует дерево и включает в себя все вершины графа) наименьшего веса. Здесь весом остова назы- вается сумма меток его дуг. 36
7.2. ОПТИМИЗАЦИЯ АНАЛИЗАТОРОВ ФЛОЙДА — ЭВАНСА Путь из 0 в Z, проходящий через У, в графе переносов допускает следующую интерпретацию. Метка 1(0, У) равна числу операторов переносов, построенных для строки У матрицы Ms. Таким образом, число операторов переноса, порождаемых для строк У и Z, равно 1(0, У) -(-1(0, Z). Однако, если в графе есть У, Уг % К путь из 0 в Z, проходящий через У, можно сначала сгенери- ровать операторы переноса для У. Для того чтобы построить операторы переноса, соответствующие Z, можно взять операторы переноса для У и написать перед ними те из операторов пере- носа для Z, которые еще не написаны. Тогда для строк У и Z будет порождена такая последовательность операторов переноса: SZ: Операторы переноса для элементов строки Z, не содержащихся в строке У, SY: Операторы переноса для элементов строки У. 37
ГЛ. 7. МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ Число операторов переноса для Y и Z будет, таким образом, равно /(0, Z) = 1(0, Z), а не 1(0, У) -J-1(0, Z). Мы по- путно получили операторы переноса для У. Можно обобщить этот прием и построить алгоритм, который, получая на вход произвольный ориентированный остов графа переносов, выдает множество операторов переноса, „соответст- вующих“ этому остову. Число операторов переноса равно сумме меток всех дуг остова. Метод можно представить в виде сле- дующего алгоритма. Алгоритм 7.3. Построение множества операторов переноса по остову. Вход. Матрица переносов Л1а и остов ее графа переносов. Выход. Последовательность операторов языка Флойда — Эванса. Метод. Для каждой вершины У остова, за исключением корня, строим последовательность операторов L. |Cj—i-aj *Saf | | * Sll^ I a-n a„ I * San I I L' Здесь L — метка строки У в матрице Л1, (т. е. множество меток SX(, ..., SXm, где Xt, .... Хт— символы, строки которых в матрице предшествования образуют строку У в Л1Д. L' — метка прямого предка вершины У в остове; aY, .... а„ — столбцы, покрываемые строкой У матрицы Als, но не ее прямым предком. Для вершины 0 добавляем новый вычисляемый оператор перехода: 0- #1 | R# Операторы, соответствующие вершинам, можно располагать в любом порядке, но если оператор I Г непосредственно предшествует оператору с меткой L', то его можно выбросить. □ Пример 7.12. Дерево, изображенное на рис. 7.18, является остовом графа переносов, изображенного на рис. 7.17. С помощью алгоритма 7.3 по дереву рис. 7.18 порождается приведенная ниже последовательность операторов. Конечно, последовательность операторов, порождаемая алгоритмом 7.3, не 38
7.2. ОПТИМИЗАЦИЯ АНАЛИЗАТОРОВ ФЛОЙДА — ЭВАНСА единственно возможная; допустимы и другие последовательности. Под SY,- подразумевается множество строке Yt матрицы переносов. меток, соответствующее SX4: 1 01 — 011 1 o6 — a, | •» Sae 1 1 0 105 — Os 1 * Sa5 | &3 * [ * Sa3 1 * ^6 1 * ScLq SK3: | a1 —► a21 * Sflj |a4—>a4| «• Sa4 1 1 0 si-?. 1 Oa — o2 1 # Sa2 0- #1 1 R4 □ Теорема 7.3. Алгоритм 7.3 строит такую последовательность операторов языка Флойда — Эванса, что замена ею последователь- ности операторов переноса, построенных алгоритмом 7.2, не отражается на поведении анализатора Флойда—Эванса. Доказательство. Заметим, что если сначала вычисляется последовательность операторов, полученная для вершины Y по алгоритму 7.3, то затем будут выполняться в точности те опера- торы, которые были сгенерированы для предков вершины Y. Легко показать, что эти операторы служат для проверки того, 39
ГЛ. 7. МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ что в следующей позиции входной цепочки стоит один из символов, столбцы которых покрываются строкой Y матрицы переносов. Оператор с меткой 0 гарантирует, что если не выполняется перенос, то происходит переход на соответствующую /^-группу. □ Если дан граф переносов, то найти его остов, для которого алгоритм 7.3 порождает наименьшее число операторов переноса, удивительно просто. Легко видеть, что, не считая операторов безусловного перехода, число операторов, вырабатываемых алго- ритмом 7.3 (каждый из них имеет вид |а—>а| для неко- торого а), в точности равно сумме меток дуг дерева. Алгоритм 7.4. Построение остова наименьшего веса по графу переносов. Вход. Граф переносов (A, R) для матрицы предшествования М. Выход. Остов (A, R'), для которого сумма 2 ^(Х, (X. Y)sS' принимает наименьшее значение. Метод. Для каждой вершины Y из А, отличной от корня, выбрать такую вершину X, что величина ЦХ, К) принимает наименьшее значение для всех дуг, входящих в Y. Включить (X, Y) в R'. □ Пример 7.13. Остов на рис. 7.18 получен по графу переносов рис. 7.17 с помощью алгоритма 7 4. □ Теорема 7.4. Число операторов переноса, которые строит алгоритм 7.3 по остову, минимально для данного графа пере- носов, если в качестве остова выбрано дерево, порождаемое алго- ритмом 7.4. Доказательство. Поскольку каждая вершина, кроме корня графа (A, R), имеет единственного прямого предка, граф (A, R’) должен быть деревом. В каждом остове графа (A, R) в каждую отличную от корня вершину входит одна дуга — отсюда сразу следует минимальность дерева (A, R'). □ Заметим, что, как и в случае матрицы переносов, по матрице предшествования М можно построить матрицу сверток Мг, вы- бросив из М все элементы, кроме •>, и слив совпадающие строки. После этого полностью аналогично графу переносов определяется граф сверток и минимизируется число операторов проверки с помощью алгоритма, аналогичного алгоритму 7.4. Детали построения мы оставляем читателю. Приведем пример минимизации полного анализатора Флойда—Эванса для грам- матики Go. 40
7.2. ОПТИМИЗАЦИЯ АНАЛИЗАТОРОВ ФЛОЙДА - ЭВАНСА Пример 7.14. Матрицы 34, и Мг для Go показаны в табл. 7.2. Здесь Y = {(, + ,*, $} и Z = {F,a,)\. Таблица 7.2 Применяя алгоритм 7.4 для слияния операторов переноса и операторов проверки, получаем следующий анализатор Флойда — Эванса для 60. Начальный оператор помечен меткой 5(: S + : S S$: (-( I *3( I « -+a | * Sa I I 0 SE: I ) —) I *S) l + —+ l *S 4- S#1) IS I допуск I I 0 ST: I* | 0: # I I R# RT: £ + # I выдача 1 CT # I выдача 2 CT SF: RF: -^T\ выдача 3 CF # I выдача 4 CF Sa: Ra: # I выдача 6 Ca S): RY- (£# I выдача 5 C) RE: R(: R + : R *: R$: I I ошибка CF: Ca: C): I* I G CT: I G l + I G l$ I G I I ошибка G: # I I s# £) Здесь этот оператор выполняется только в том случае, если в верхушке магазина находится Е. Если бы это было не так, пришлось бы заменить # символом Е (или, в общем случае, начальным символом). 41
ГЛ, 7, МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ Предпоследний оператор играет роль 0 для операторов про- верки. □ Можно улучшать анализаторы на языке Флойда—Эванса, исходя и из других соображений. Одним из таких улучшений может служить преобразование, при котором два оператора объединяются в один. Например, второй оператор анализатора для Go можно объединить с оператором, помеченным меткой Sa, и написать | а —> F | выдача 6 Са Если надо слегка изменить поведение анализатора, можно внести в него дальнейшие изменения. Одним из них может быть задержка в обнаружении ошибок. Например, анализатор для Go из разд. 5.4.3 использует только 11 операторов, по в некоторых случаях обнаружение ошибок в нем задерживается. Необходимо подчеркнуть, что на языке Флойда — Эванса можно записать любой из рассмотренных в гл. 5 анализаторов. Для того чтобы сделать это эффективно, можно применить при- емы, аналогичные тем, которыми мы пользовались в настоящем разделе. Наконец, встает вопрос реализации анализатора, записанного на языке Флойда—Эванса. Оператор языка может вызвать одну из следующих элементарных операций: чтение входного символа, сравнение символов, запись символов в магазин, выталкивание символов из магазина, порождение выходной цепочки. Реализо- вать эти операции весьма просто. Следовательно, можно написать программу, которая будет отображать анализатор на языке Флойда—Эванса в последовательность таких элементарных опе- раций. Для выполнения этой последовательности элементарных операций достаточно небольшого интерпретатора. УПРАЖНЕНИЯ 7.2.1. С помощью алгоритма 7.2 постройте анализаторы на языке Флойда — Эванса для следующих грамматик слабого пред- шествования: (a) S—♦ S + / | / I—> (S)\а (S)\a (б) S 05’1 101 (в) Е-^Е + Т\Т T-*T*F\F F —> F Р \ Р Р—*(Е)(а) 42
УПРАЖНЕНИЯ 7.2.2. Воспользуйтесь методами этого раздела для улучшения анализаторов, построенных в упр. 7.2.1. 7.2.3. Найдите матрицы переносов и сверток для матрицы слабого предшествования, приведенной на рис. 7.19. Рис. 7,19. Матрица слабого предшествования. 7.2.4. Постройте графы переносов и сверток для матриц пе- реносов и сверток, найденных в упр. 7.2.3. 7.2.5. Примените алгоритм 7.3 для нахождения кратчайшей последовательности операторов переноса и проверки для графов, построенных в упр. 7.2.4. *7.2.6. Разработайте алгоритм построения детерминированного левого анализатора па языке Флойда — Эваиса для LL(l)-rpaM- матики. 7.2.7. С помощью напишите на языке LL (1 )-грамматики алгоритма, разработанного в упр. 7.2.6, Флойда — Эванса левый анализатор для Е -+ТЕ' Е’ + ТЕ'\е Т -^FT' Г ~^*ЕТ'\е F -~(Е)\а *7.2.8. Пользуясь методами этого раздела, улучшите анализа- тор, построенный в упр. 7.2.7. 43
ГЛ. 7. МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ *7.2.9. Разработайте алгоритм построения детерминированного правого анализатора на языке Флойда — Эванса для LR(l)-rpaM- матики. 7.2.10. С помощью алгоритма, разработанного в упр. 7.2.9, постройте правые анализаторы для Go и грамматики из упр. 7.2.7. * 7.2.11. Пользуясь методами этого раздела, улучшите анали- заторы, построенные в упр. 7.2.10. Сравните полученные анали- заторы с анализаторами, разработанными в примерах 5.47 и 7.14, а также с анализатором из упр. 7.2.8. * 7.2.12. Можно ли по анализатору на языке Флойда—Эванса определить, является ли он корректным анализатором слабого предшествования для данной грамматики? * 7.2.13. Разработайте алгоритм порождения программы на язы- ке Флойда — Эванса, моделирующей детерминированный МП- преобразователь. Как можно улучшить полученную программу? Проблемы для исследования Ясно, что настоящий раздел не дает полного представления об изучаемом предмете и анализаторы, написанные на языке Флойда—Эванса, можно и далее существенно улучшать. Поэто- му мы предлагаем следующие направления дальнейших иссле- дований. 7.2.14. Изучите, как можно оптимизировать различные ана- лизаторы типа „перенос—свертка" при реализации их на языке Флойда—Эванса. В частности, можно рассмотреть алгоритмы разбора LL(fe)-, ОПК-грамматик, грамматик расширенного пред- шествования, простых грамматик со смешанной стратегией пред- шествования и Ы7(£)-грамматик. 7.2.15. Обобщите методы оптимизации анализаторов, допустив отсрочку в обнаружении ошибок, слияние операторов и/или другие разумные изменения программ на языке Флойда—Эванса. 7.2.16. Разработайте вариант языка Флойда—Эванса для реа- лизации алгоритмов разбора. Ваш язык должен обладать сле- дующим свойством: каждый оператор языка реализуется с по- мощью некоторого постоянного числа машинных команд на символ оператора языка. При разработке языка ориентируйтесь на „обыкновенную" вычислительную машину с прямым доступом. 44
7.3. ПРЕОБРАЗОВАНИЯ НА МНОЖЕСТВАХ LRW-ТАБЛИЦ Упражнении на программирование 7.2.17. Постройте набор элементарных операций, используе- мых для реализации операторов языка Флойда—Эванса. Напи- шите интерпретатор, выполняющий эти операции. 7.2.18. Постройте компилятор, принимающий на вход про- грамму на языке Флойда—Эванса и выдающий для нее после- довательность элементарных операций, которую может выполнить интерпретатор из упр. 7.2.17. 7.2.19. Напишите программу, которая строила бы анализаторы на языке Флойда—Эванса для некоторого полезного класса КС-грамматик. 7.2.20. Сконструируйте анализатор на языке Флойда—Эванса для одной из грамматик, данных в приложении к тому 1. Вклю- чите в него программу нейтрализации ошибок, вызываемую каж- дый раз, когда обнаруживается ошибка. Программа нейтрали- зации ошибок должна корректировать магазин и/или входную цепочку так, чтобы можно было возобновить нормальный разбор. Замечания по литературе Язык Флойда — Эванса и его варианты пользуются популярностью при написании синтаксических анализаторов. Методы построении анализаторов на этом языке разрабатывались рядом авторов, в том числе в работах Билза [1969|, Билза и др. 11969]. Де Рсмера [1968], Эрли [1966], Хейнса и Шютте [1970]. Приемы построения анализаторов на языке Флойда—Эванса, описан- ные в этом разделе, впервые встречаются у Читэма [1967]. Ихбиа и Морзе [1970] предложили использовать в языке Флойда—Эванса вычисляемые опе- раторы перехода и метод оптимизации, описанный в разд. 7.2.2. В работе Лафранса [1970] приведены некоторые методы нейтрализации ошибок для анализаторов на языке Флойда — Эванса. 7.3. ПРЕОБРАЗОВАНИЯ, ОПРЕДЕЛЕННЫЕ НА МНОЖЕСТВАХ 1Я(А:)-ТАБЛИЦ Оставшаяся часть главы посвящена обсуждению вопроса оп- тимизации ЬЙ(А)-анализаторов. Мы уделяем так много внимания ЬК(й)-анализаторам по двум причинам. Во-первых, Ьй(/г)-грам- матики представляют собой наиболее широкий естественный класс однозначных грамматик, для которых удается построить детерминированные анализаторы. Во-вторых, применяя методы оптимизации, можно строить Ы7(/г)-анализаторы, успешно кон- курирующие с анализаторами других типов. В гл. 5 был дан алгоритм разбора для ЬР(А)-грамматик. Ядром алгоритма служит множество Ьй(£)-таблиц, управляю- щих работой анализатора. В разд. 5.2.5 приведен алгоритм, 45
ГЛ. 7. МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ применяемый для автоматического построения канонического множества Ы?(А)-таблнц для ЬК(й)-грамматики (алгоритм 5.7). В то же время, как отмечалось, для грамматики, представ- ляющей практический интерес, это каноническое множество 1^(й)-таблиц при k Ja 1 может оказаться неприемлемо большим. Тем не менее ЬК(£)-алгоритм разбора, использующий канониче- ское множество иШ'ртаб.тиц (канонический ЬК(й)-анализатор), обладает рядом привлекательных свойств. (1) Анализатор быстро работает. Входная цепочка длины п анализируется за сп тактов, где с—малая константа. (2) Анализатор обладает хорошей способностью к обнаруже- нию ошибок. Например, предположим, что ха—префикс неко- торой цепочки рассматриваемого языка, a xab не является префиксом никакой цепочки. Обрабатывая входную цепочку вида xaby, канонический ЕЩ1)-анализатор произведет разбор подцепочки х, прочтет символ а, а потом сообщит об ошибке. Таким образом, он объявит об ошибке, как только авапцепоч- кой впервые станет входной символ Ь. Вообще канонический LR (^-анализатор при разборе входной цепочки слева направо сообщает об ошибке при первой же возможности. Анализаторы предшествования не обладают способностью обнаруживать ошибки так рано. Например, при разборе цепочки xaby анализатор предшествования прежде, чем сообщить об ошибке, может просмотреть сколь угодно много символов под- цепочки у. (См. упр. 7.3.5.) ЪЦй)-анализаторы совмещают высокое быстродействие и хо- рошую способность к обнаружению ошибок, свойственные LR(fe)- анализаторам. Однако не каждый детерминированный язык имеет LL-грамматику, и, вообще говоря, для описания языка прог- раммирования и его перевода часто удается найти более „есте- ственную" LR-грамматику. По этой причине вплоть до конца настоящей главы мы будем изучать методы построения компакт- ных LR (^-анализаторов. Многие из этих методов применимы также и к ЬЬ(й)-грамматикам. В данном разделе мы рассмотрим ЬК(й)-апализаторы с точки зрения общей теории. Будем говорить, что два ЬК(&)-анализа- тора эквивалентны, если, получив на вход цепочку w, они оба либо допускают W, либо сообщают об ошибке, находясь на одном и том же символе цепочки w. Такая эквивалентность очень близка к „эквивалентности", с которой мы встретились в при- мере 7.8. В данном разделе мы приведем несколько преобразований, применяемых для уменьшения размера ЕН(й)-ан.ализатора и по- рождающих эквивалентный LR(ft)-anaAH3aTop. В разд. 7.4 изло- жим методы, позволяющие по некоторым типам ЬЁ(А)-грамматик 46
7.3. ПРЕОБРАЗОВАНИЯ НА МНОЖЕСТВАХ ЬВДУТАВЛИЦ непосредственно получать ЫД£)-анализаторы, эквивалентные каноническому ЬК(/г)-анализатору, но имеющие существенно меньшие размеры. Методы, рассматриваемые в этом разделе, можно применять и к каноническим анализаторам. Наконец, в разд. 7.5 мы опишем более подробную реализацию LR-апализа- гора, в которой общие операции просмотра можно совмещать. 7.3.1. ОБЩЕЕ ПОНЯТИЕ LR(&| ТАБЛИЦЫ Основу ЫД&)-алгоритма разбора (алгоритма 5.7) образует множество ЬР(/г)-таблиц. Вообще говоря, существует много раз- личных множеств таблиц, которыми можно воспользоваться для построения эквивалентных анализаторов для одной и той же ЬД(/г)-грамматики. Следовательно, можно поставить задачу оты- скания множества таблиц, обладающего некоторыми нужными свойствами, например минимальностью. Для того чтобы понять, как можно изменять множество ЕК(й)-таблиц, разберем поведение ЬД(£)-алгорипиа разбора во всех подробностях. Этот алгоритм помещает МД/р-таблицы в магазин. Е1Д£)-таблица, находящаяся в верхушке магазина, уп- равляет поведением алгоритма разбора. Каждая таблица пред- ставляет собой пару функций </, g>. Напомним, что функция действия / по аванцепочке устанавливает, какое действие надо предпринять. Действием может быть: (I) перенос очередного входного символа в магазин, (2) свертка содержимого верхней части магазина в соответствии с известным правилом, (3) сооб- щение об окончании разбора, (4) сообщение о том, что во вход- ной цепочке найдена синтаксическая ошибка. Вторая функция, а именно функция перехода g, вызывается после каждого пере- носа и каждой свертки. Функция перехода по символу грамма- тики либо определяет имя другой таблицы, либо выдает код ошибки. В качестве примера рассмотрим ЫД1)-таблицу, приведенную на рис. 7.20. В ЫД&)-алгоритме разбора таблица может воз- действовать на поведение анализатора двумя способами. Допу- стим, что таблица 7\ находится в верхушке магазина. Функция действия таблицы определяет работу анализатора. Например, если аванцепочкой является символ Ь, то анализатор выполняет свертку, применяя правило 3. Если же аванцепочкой является символ а, то анализатор помещает текущий входной символ (в данном случае а) в магазин и, поскольку g(a) = T,, записы- вает в верхушку магазина вслед за а имя таблицы 7\1). v) Как отмечалось в гл. 5, не обязательно записывать в магазин символы грамматики. Но так как поведение ЬИД)-аиализатора становится понятнее, если в магазине есть символы грамматики, мы будем считать в этом разделе, ’То символы грамматики тоже помещаются в магазин. 47
ГЛ- 7. МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ Сразу после свертки таблица задает другой тип работы ана- лизатора. Предположим, что содержимое магазина есть аА 7\ЬТг$Т3 и таблица Тг вызывает свертку согласно правилу S—*bS. Тогда анализатор удалит из магазина четыре символа (два символа грамматики и две таблицы), оставив в нем цепочку аДТ1). Теперь ДейстВие Переход _ а Ь е S А а. Ь ’’ ~~S 3 ~Х~ ~ь. X й ~ Рис. 7.20. ЬК(1)-таблица. управление передано таблице Tt. В верхушку магазина поме- щается нетерминал S и вызывается функция перехода таблицы 1\, которая определяет, что в верхушку магазина нужно поме- стить таблицу 7\=g(S). Мы будем считать, что узловыми при LR-разборе являются моменты, когда в верхушку магазина помещается новая таблица. Такую таблицу назовем управляющей. Изучим характеристики LR-анализатора в терминах последовательности управляющих таблиц. Если управляющая таблица Т вызывает перенос, то следующая управляющая таблица определяется непосредственно с помощью функции переходов таблицы Т. Если, с другой сто- роны, управляющая таблица Т вызывает свертку, то следующая управляющая таблица определяется с помощью функции пере- ходов (('+1)-й сверху таблицы, содержащейся в магазине, где i—длина правой части правила, применяемого для выполнения свертки. Может показаться, что трудно определить, какая таб- лица находится в указанном месте, однако можно построить алгоритм, определяющий множество возможных таблиц. Попытаемся установить, в каком случае два множества LR(fe)- таблиц определяют эквивалентные анализаторы. Мы сформули- руем критерии поведения анализаторов, из которых должно быть ясно, что понимать под эквивалентностью. Сначала дадим определение множества ЬК(/г)-таблиц, обобщающее определение, приведенное в разд. 5.2.5. Теперь как элемент возможного дей- ствия, так и элемент возможного перехода может быть спе- циальным символом <р, который можно интерпретировать как „несущественный" элемент. Мы увидим, что многие из элементов типа „ошибка" в ЬР(А)-таблицах никогда не используются, т. е. независимо от входной цепочки к некоторым элементам типа 2) Заметим, что когда каноническому Ы?(6)-аналнзатору предстоит выпол- нить свертку по правилу I, правая часть правила i всёгда будет суффиксом цепочки символов грамматики, находящейся в магазине. Таким образом, в процессе разбора не возникает необходимости сравнивать правую часть правила с находящейся в магазине цепочкой символов грамматики. 48
7.3. ПРЕОБРАЗОВАНИЯ НА МНОЖЕСТВАХ LR№) ТАБЛИЦ „ошибка" Ы7{й)-анализатор никогда не обращается. Таким обра- зом, можно произвольно менять эти элементы; при этом анали- затор будет работать по-прежнему. Определение. Пусть Q — КС-грамматика. Множеством LR(A)- таблиц для G назовем пару («Г, То), где «Г—множество таблиц для 6 и таблица Та, называемая начальной, принадлежит S'. Таблица для G — это пара функций </, g>, где (1) f — отображение из 2** в множество, состоящее из эле- ментов ср, ошибка, перенос, допуск и свертка i для всех пра- вил с номерами I, (2) g отображает NuS в S'U {ср, ошибка}. Если ясно, о какой таблице ТГ1 идет речь, будем писать вместо (S', Г,) просто S'. Каноническое множество ЬЩй)-таб- лиц, построенное в разд. 5.2.5, удовлетворяет данному здесь определению множества ЬК(й)-таблиц. Заметим, что в канони- ческом множестве ЬК(й)-таблиц элемент ср никогда не встречается. Пример 7.15. Пусть G определяется правилами (1) S--.SA (2) S —> Л (3) А-^аА (4) А-.Ь Множество Ы}(1)-таблиц для Q приведено на рис. 7.21. Мы увидим, что анализатор, использующий множество таб- лиц на рис. 7.21, проводит разбор, не привлекая для этого Действие Переход a b е S А а Ь Ту S 5 X X Тг Ту Тг Тг 4 4 4 Р Р V Тг 2 Т, X Тг •с Рис. 7.21. Множество ЬК(1)-таблиц. непосредственно грамматику G. Просто таблицы „подходят" грам- матике, т. е. в Них фигурируют только символы из G, и вызы- ваемые свертки выполняются по правилам, действительно суще- ствующим в G. □ Переопределим ЬК(й)-алгоритм разбора, опираясь на понятие Множества Ы7(й)-таблиц, введенное выше. Этот алгоритм по суще- ству тот же, что и алгоритм 5.7, если элемент ср рассматривать Как элемент ошибки. Для удобства определим алгоритм заново. 4?
ГЛ. 7. МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ Определение, Пусть (аГ, Та)— множество ИК(£)-таблиц для КС-грамматики G = (N, S, P,S). Конфигурацией ЬР(£)-анализа- тора для (^, Т„) назовем тройку (Т^Х^А . . . ХяТт, w, л), где (1) Т, принадлежит «Г, и Го—начальная таблица; (2) X. принадлежит Nu^, (3) к> принадлежит 2*; (4) л — выходная цепочка, состоящая из номеров правил. Первая компонента конфигурации представляет содержимое магазина, вторая — непросмотренную часть входной цепочки, третья — построенный к этому моменту разбор. Начальная конфигурация анализатора — это конфигурация вида (Т„, w, е) для некоторой цепочки w из 2*. Как и раньше, такт алгоритма разбора будем представлять с помощью отно- шения |—, заданного на множестве конфигураций. Предположим, что анализатор находится в конфигурации (Т„Х1Т1 . . . XmTm, w, л), где Tm^<f, g> —таблица из S'. Пусть aigS* и и = FIRSTt(®). Это означает, что w представляет непро- смотренную часть входной цепочки, а и — аванцепочку. (I) Если f(и)=перенос и ai = o®', где а £2, то (Г„Х17’1... Х„Та, aw', л) Ь (ТЛТ' ... XmTmaT, w', л) где T — g(a). В этом случае выполняется перенос; при этом следующий входной символ а записывается в магазин, а за ним в верхушку магазина помещается таблица g(e). (2) Пусть f (и) — свертка i и А—>-7 — правило с номером i, )у| = г. Будем считать, что r^m и g'>. Таблица Тт_,—это таблица, которой передается управление, когда из магазина удаляется цепочка Xm_r+1 Тм_г+1 . .. XmTm. Тогда (W, ... XmTm, w, л) Н .. Xm-rTm.rAT, w, ni) где Т = g'(A). В этом случае выполняется свертка по правилу А—>у. Номер этого правила приписывается к выходной цепочке, цепочка длины 21 у | удаляется из верхушки магазина и заме- няется цепочкой АТ, где T = g'(A) и g'—функция переходов зерхней оставшейся в магазине таблицы. Заметим, что при свертке символы, удаляемые из магазина, не просматриваются. Поэтому возможна такая свертка, когда удаляемые символы грамматики не составляют правой части правила, управляющего сверткой1). (3) Если f (и) — ц>, ошибка или допуск, то нет такой очеред- ной конфигурации С, что (TaXiT1 ... Х,,Т.Л, w, я)|— С. г) Это не случится, если используется каноническое множество таблиц. Вообще говоря, такая ситуация нежелательна, и ее можно допустить только в том случае, когда есть уверенность, что ошибка будет вскоре все равно обнаружена, W
7.3. ПРЕОБРАЗОВАНИЯ НА МНОЖЕСТВАХ ГКИ-ТЛВЛИЦ Очередной конфигурации нет также и в следующих случаях: в правиле (1) w = e (т. е. входная цепочка исчерпана) или g(a) не является именем таблицы, в правиле (2) г > т (т. е. в мага- зине недостаточно символов) или g'(A) не является именем таб- лицы. Назовем конфигурацию (7’0Х17’1 . . ХтТт, ш, я) сигналом ошибки, если очередной конфигурации нет. Исключение состав- ляет конфигурация (TtlST1, е, я), которую в случае 7\ = </,£> и fte] = допуск будем называть допускающей. Отношения |—* и |—+ определяются как обычно. Конфигурацию С назовем достижимой, если С„—*С Для некоторой начальной конфигурации С,,. Приведем теперь алго- ритм разбора. Алгоритм 7.5. LR(A)-a л г о р и т м разбора. Вход. КС-грамматика G — (N, 2, Р, S), множество («Г, Т„) LR(fe)- таблиц для О и входная цепочка tog 2*. Выход. Последовательность правил я или сигнал ошибки. Метод. (1) Построить начальную конфигурацию (Та, w, е). (2) Пусть С — последняя построенная конфигурация. Постро- ить такую очередную конфигурацию С, что С НС', и затем повторить шаг (2). Если очередной конфигурации нет, перейти к шагу (3). (3) Пусть С — (а, х, я) — последняя построенная конфигура- ция. Если С—допускающая конфигурация, выдать я и остано- виться. В противном случае сообщить об ошибке. □ Ясно, что этот алгоритм можно реализовать с помощью детер- минированного МП-преобразователя с правым концевым маркером. Если алгоритм 7.5 достигает допускающей конфигурации, то выходная цепочка я называется разбором для входной цепочки W. Разбор я называют корректным, если я — правый разбоо Для w в соответствии с грамматикой G. Подобно этому, множе- ство 1.Е(7<)-таблиц называют корректным для грамматики G. если алгоритм 7.5 порождает корректный разбор для любой Цепочки из L(G) и не порождает разбора ни для какой цепочки го, не принадлежащей L(G). По теореме 5.12 каноническое множество ЕР(£)-таблиц для СР(й)-грамматики G корректно для G. Однако произвольное множество ЬЕ(А)-таблиц для грамматики G, разумеется, не обя- зательно корректно для G. Пример 7.16. Проследим последовательность шагов алгоритма 7.5 на входной цепочке ab при условии, что алгоритм исполь- $1
ГЛ. 7. МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ зует множество LR(1 )-таблиц, приведенное на рис. 7.21, а на- чальной таблицей служит 7\. Начальная конфигурация есть (Г,, ab, е). Действием таб- лицы Т\ на аванцепочке а будет перенос, а переходом — 7\, так что (Л. ab, е)Н(ЛаЛ, Ь, е) Действием таблицы Т\ на символе b также будет перенос, но переходом — Тг, поэтому (7\а7\, b, е) Н (7'|ц7'1ЬТ2, е, е) Действием таблицы Т, на символе е будет свертка 4; правило 4 — это А—>&. Таким образом, верхняя таблица и символ грамма- тики удаляются из 7'1о7’1Ь7’!, в результате чего остается цепочка 7'1п7’1. Переход таблицы 7\ на символе А есть Т8, так что (7',а7'1&7'2> е, е)Н (Т^аТ^АТ,, е, 4) Действие таблицы Г, на аванцепочке сесть ср. Другими словами, построить очередную конфигурацию не удается. Так как (7’,«7'1Д7’3, е, 4) не является допускающей конфигурацией, она — сигнал ошибки. Поскольку ab^L(G), это множество таблиц, очевидно, не корректно для грамматики из примера 7.15. □ 7.3.2. Эквивалентность множеств таблиц Опишем теперь, что значит, что два множества ЬД(^)-таблиц эквивалентны. Самая слабая эквивалентность, которая может нас заинтересовать, означает, что алгоритм 7.5, работающий с двумя множествами таблиц, порождает один и тот же разбор для цепочек, принадлежащих языку L(G), и что цепочки, не анализируемые при использовании одного множества таблиц, не анализируются и при использовании другого множества таб- лиц. Ошибочные ситуации могут обнаруживаться в разное время. Самая сильная эквивалентность, которую можно рассматри- вать, требует, чтобы при работе с двумя множествами таблиц порождались одинаковые последовательности шагов разбора. Иными словами, пусть (7’0, w, е) и (Т'„, w, е)— начальные конфи- гурации для двух множеств таблиц S’ и S’’. Тогда для всех 1>0 при использовании таблиц из S' (Т„, w, (Т^Т, ... XmTm, х, я) тогда и только тогда, когда при использовании таблиц из S'1 (T’t, w, е)\—‘{TtXiT'i ... Х'пТ'п, х', л') причем т = п, х—х1, л = л' и Х; = Х(' для 1 т. 52
7.3. ПРЕОБРАЗОВАНИЯ НА МНОЖЕСТВАХ ЬК(А)-ТАЕЛНЦ Каждое из этих определений позволяет разработать такие методы преобразований множеств таблиц, что соответствующие эквивалентности сохраняются. Здесь мы будем рассматривать некоторую промежуточную эквивалентность. Конечно, требуется, чтобы алгоритм 7.5, использующий одно множество таблиц, находил для входной цепочки w разбор тогда и только тогда, когда он находит этот же разбор для w, используя другое мно- жество таблиц. Более того, как и в определении самой сильной эквивалентности, потребуем, чтобы алгоритм 7.5 выполнял одну и ту же последовательность шагов разбора для каждой входной цепочки независимо от того, какое множество таблиц определяет эти шаги. Однако разрешим при работе с одним множеством еще производить свертки, в то время как при работе с другим разбор уже может закончиться. Такое определение оправды- вается следующими соображениями. Если во входной цепочке есть ошибка, желательно, чтобы это обнаруживалось при использовании любого из множеств таблиц и чтобы при этом местонахождение ошибки было опре- делено как можно точнее. Нежелательно, чтобы в то время, как одно множество таблиц позволяет обнаружить ошибку, дру- гое множество требовало бы просмотра еще многих входных символов. Это связано с тем, что Для создания разумных и понятных методов диагностики нужно, чтобы ошибка обнаружи- валась как можно ближе к тому месту, где она находится. В практических ситуациях, когда встречается ошибка, управ- ление передается программе нейтрализации ошибок, которая изменяет оставшуюся часть входной цепочки и/или содержимое магазина так, чтобы анализатор мог продолжить разбор остатка входной цепочки и за один просмотр входа найти возможно больше ошибок. Было бы очень жаль, если бы работа анализа- тора, обработавшего значительные части входной цепочки до обнаружения ошибки, оказалось бессмысленной. Исходя из этого, введем понятие эквивалентности множеств таблиц. Оно пред- ставляет собой частный случай того неформального понятия эквивалентности, которое обсуждалось в разд. 7.1. Определение. Пусть (JT, Т,.) и («Г', 7’о)—два множества 1-К(/г)-таблиц для КС-грамматики G = (N, 2, Р, S). Пусть w — входная цепочка из S’, Со = (?’„, w, е), С'а = (Т'о, w, е), а Со i— С\ г— С21— . .. и G|— СЦ— ...—соответствующие последова- тельности конфигураций, построенные алгоритмом 7.5. Назовем множества («Г, Т„) и Т'„) эквивалентными, если для всех и для произвольной цепочки w удовлетворяются следующие четыре условия: (1) Если С; и С; обе существуют, то их можно записать в виде С,- = (Т0Х17’1... Х,„Тт, х, л) и C’t = (ЦХ^... X„T'm, х, я), 53
ГЛ. 7. МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ т. е. пока существуют обе последовательности конфигураций, они совпадают во всем, за исключением имен таблиц. (2) С/—допускающая конфигурация тогда и только тогда, когда C'i—допускающая конфигурация. (3) Если конфигурация С,- определена, а C't нет, то вторые компоненты у С,., и Ci совпадают. (4) Если конфигурация С/ определена, а С,- нет, то вторые компоненты у С('_! и С/ совпадают. Условия (3) и (4) утверждают, что если при работе с одним множеством таблиц обнаруживается ошибка, то при работе с дру- гим множеством после этого не должно быть чтения символов на входе, т. е. не выполняются действия перенос. Но условия (3) и (4) допускают, чтобы в то время, как одно из множеств вы- зывало остановку на несущественном действии или на действии ошибка, другое требовало выполнить одно или более действий свертка. Отметим, что ни одно из множеств таблиц не обязано быть корректным для G. Тем не менее, если два множества таблиц эквивалентны и одно из них корректно для G, то другое также будет корректным для G. Пример 7.17. Рассмотрим ЬР(1)-грамматику с правилами (1) S^aSb (2) S —► ab Множество , 7’„) — каноническое множество ЬР(1)-таблиц для G —показано на рис. 7.22. На рис. 7.23 приведено другое множество ЬР(1)-таблиц для G — множество ("И, (/„). Исследуем поведение ЬР(1)-алгоритма разбора, использующего S' и QZ, на входной цепочке abb. Используя «Г, алгоритм разбора делает последовательность тактов (Т„, abb, e)j— (1\аТ,г, bb, е) I— (Т„аТ,ЬТ5, Ь, е) Последняя конфигурация — сигналошибки. Используя множество таблиц Щ, алгоритм разбора действует так: (U„, abb, е) |— (£/oat72, bb, е) Н (UtflUJjUt, b, е) Ь, 2) Последняя конфигурация—ошибочная. Заметим, что канонический анализатор сообщает об ошибке, как только он впервые обна- ружит во входной цепочке второй символ Ь. Анализатор, исполь- зующий множество таблиц ‘U, прежде чем сообщить об ошибке, 54
7.3. ПРЕОБРАЗОВАНИЯ НА МНОЖЕСТВАХ 1.R''«)-ТА БЛИЦ свертывает ab в S. Правда, второй символ Ь ие записывается в магазин, поэтому условия эквивалентности не нарушаются. Нетрудно показать, что множества оГ и '"1 действительно экви- валентны. Существует алгоритм, позволяющий определить, экви- Дейсп&е Переход а ь g 8 а ь Го S X X т Тг X X X А X X X Тг S S X т3 Тг Те Тг X 8 X X X Те Тг 8 S X Тг Тг Те Те X X 2 X X X те X X 1 X X X Тг X S X X X Те Те X 2 X X X X Те X 1 X X X X валентно ли произвольное мно- жество ЬР(/г)-таблиц для LR(fe)- грамматики каноническому мно- жеству ЬР(/г)-таблиц для этой грамматики. Построение такого алгоритма оставляем в качестве упражнения. □ Действие Переход а b e J a b Uo S X X иг и, V? % X A иг 5 s X Us u2 Ue Us V X X JO V Us ut X 2 2 Us X 1 1 <p Рис. 7.22. Множество таблиц Рис. 7.23. Множество таблиц (</; Го». tfli, 7.3.3. ((-недостижимые множества таблиц Многие из элементов ошибка канонического множества LR(fe)- таблиц никогда не используются ЬК(А)-алгоритмом разбора. Такие элементы ошибка можно заменить элементами ср, действительно несущественными в том смысле, что ни в какой достижимой кон- фигурации они не влияют на вычисление очередной конфигурации. Мы покажем, что все символы ошибка у функции переходов канонического множества таблиц можно заменить элементами <р и, если данная таблица может стать управляющей только сразу после свертки, аналогичную замену можно проделать и для функ- ции действия. Определение. Пусть (S', Т„)— множество Ы?(£)-таблиц, k 1 и С = (7'0Х17',Х27'а...Хя>7'я, w, л) — любая достижимая конфигурация. Пусть ГЯ = <Л g> и и = ^FIRSTs(to). Будем говорить, что в S' нет достижимых эле- 55
ГЛ. 7. МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ ментов ср, или, короче, «Г q-недостижимо, если для любой конфигурации С справедливы следующие утверждения: (1) (2) Если f (и) = перенос, то g(a)^cp, где а — первый символ цепочки и. (3) Если/ (и) =свертка i, правило с номером I есть А—>-У^...Уг, г>0 и g'>, то g'(A)=/=cp. Неформально можно сказать, что множество ЬК(й)-таблиц ср-недостижимо, если все элементы ср, появляющиеся в таблицах, никогда не используются алгоритмом 7.5 при разборе цепочек. Приведем теперь алгоритм, заменяющий в каноническом мно- жестве ЬК(й)-таблиц по возможности большее число элементов ошибка на ср так, чтобы полученное множество таблиц осталось ср-недостижимым. Применяя этот алгоритм к каноническому множеству LR(fe)- таблиц, можно отыскать и заменить на <р все элементы ошибка, которые никогда не используются ЬЕ(й)-алгоритмом разбора. Алгоритм 7.6. Построение ср-не д ос т и ж и мо г о мно- жества ЬР(й)-таблиц с максимально возможным числом элементов ср. Вход. ЕР(й)-грамматика G = (N, S, Р, S), где и кано- ническое множество («Г, Т„) ЬР(й)-таблиц для G. Выход. Эквивалентное множество (JT', Т‘„) ЬР(й)-таблиц, где все неиспользуемые элементы ошибка заменены символами ср. Метод. (1) Для каждой таблицы T = <f, g> из S’ построить новую таблицу </', g'>, где g(X), если g (X) =/= ошибка <р в противном случае Пусть (оГц То) — множество построенных таким образом таблиц. (2) Множество таблиц (<&", Т'о) строится затем следующим образом: (а) Т'о принадлежит JT'; (б) ДЛЯ каждой таблицы Т — '/, g> из <8\— {Т'„} включить в таблицу Т’ =<f, g~>, где /' определяется так: (i) /' (и) = / (и) всякий раз, когда / (и) ошибка; (ii) если / (vb) — ошибка для некоторых v £ и и для некоторого ci€- существует такая таблица </1т gt> из S’и что /[ (ап) = перенос и gL (а) = Т, то /' (ц&)=ошибка; £'(*) = { 56
7.3. ПРЕОБРАЗОВАНИЯ НА МНОЖЕСТВАХ ЕК(А)-ТАВЛИЦ (iii) если / (и) = ошибка для некоторой цепочки и £ S* и для некоторого agS существует такая таблица </\, gt> из оГ,, что (аи) = перенос и gi(a) = T, то f'(u) = ошибка; (iv) в противном случае /' (и) = ср. □ На шаге (1) алгоритма 7.6 все элементы ошибка в функциях переходов заменяются на элементы ср, так как при k > 1 кано- нический ЕЕ(А)-анализатор всегда обнаруживает ошибку сразу после операции переноса. Следовательно, значение ошибка у функ- ции переходов никогда не используется. Шаг (2) алгоритма 7.6 заменяет на ср значение ошибка у функ- ции действия таблицы Т, если нет такой таблицы </\, g,y и та- кой аванцепочки аи, что (аи) — перенос и g1(a) = Т. При таких условиях таблица Т может появиться в верхушке магазина только сразу после свертки. Однако, если ошибка есть, канонический Ей(1)-апализатор сообщит о ней перед сверткой. Таким образом, в таблицах, аналогичных Т, никакие элементы ошибка не за- прашиваются и, значит, могут рассматриваться как несущест- венные. Отметим еще раз, что алгоритм 7.6 в том виде, как он был определен, работает только для множеств ЬР(£)-таблиц с В случае ЁЙ(О)-грамматики аванцепочка всегда пуста. Поэтому все ошибки должны распознаваться при обращении к функции переходов. Следовательно, в множестве LR(0)-таблиц не все эле- менты ошибка у функций переходов несущественны. В качестве упражнения предлагаем выяснить, какие из этих элементов не- существенны. Пример 7.18. Пусть G—ЬК(1)-грамматика с правилами (1) S-^SaSb (2) S — е Каноническое множество ЬК(1)-таблиц для G показано на рис. 7.24, а, а множество таблиц, полученное в результате при- менения алгоритма 7.6, — на рис. 7.24,6. Заметим, что на рис. 7.24,6 все элементы ошибка в правых половинах таблиц (у функций переходов) заменены элементами ср. У функций действия таблица Та, согласно правилу (2а) алго- ритма 7.6, оставлена без изменений. Действия перенос встре- чаются только в таблицах Т3 и 7V, они приводят к тому, что управляющей становится одна из таблиц Tt, Т„ или Т7. Поэтому элементы ошибка у функций действия этих таблиц не меняются. В ряде других мест ошибка заменена на <р. □ 57
ГЛ. 7. МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ Теорема 7.5. Множество таблиц S", построенное алгорит- мом 7.6, q-недостижимо и эквивалентно каноническому множе- ству S'. Доказательство. Эквивалентность множеств S' и S'' оче- видна, так как единственное изменение, которое вносится в мно- жество «Г, состоит в том, что элементы ошибка заменяются на <р, а —каноническое множество ЕИ(1)-таблиц; б — <р-недостижимое множество таблиц. а ЬИ(£)-алгоритм разбора не отличает ошибку от ср1). Покажем теперь, что если алгоритм 7.5, использующий множество таблиц S", обращается к элементу <р, то множество S'' не было пра- вильно построено по S'. Пусть S~' не ср-недостижимо. Тогда должно найтись такое наименьшее число i, что С\—'С, где С„— начальная конфигура- ция и в конфигурации С алгоритм 7.5 запрашивает элемент ср множества S''. Поскольку Та не изменяется на шаге (2а), должно быть i>0. Пусть С = (Г„Х1Г,. . ,ХЯГЯ, w, я), где Тя = <7, g> и FIRSTj. (ш) = и. Элемент ср может встретиться в трех случаях. Случай Г. Предположим, что /(н) = ср. Тогда, согласно шагам (26 ii) и (26 iii) алгоритма 7.6, предыдущим тактом анализатора должна была быть свертка, а не перенос. Значит, С„|— ‘ ~LC |—С, где C' = (TaX1T1...Xm^Tm.1Y1Ul...YrUr, х, я') <р-элементы введены только для того, чтобы отметить элементы, кото- рые можно менять. 58
7.3. ПРЕОБРАЗОВАНИЯ НА МНОЖЕСТВАХ LR(fe)-TABЛИЦ и свертка выполнялась по правилу Хт—>Y1...Yr (л представ- ляет собой цепочку л', к которой приписан номер этого правила). Рассмотрим множество ситуаций, по которому построена таб- лица Uг. (Если г = 0, вместо Ur читай 7’т_1.) Это множество должно включать ситуацию [Хт—и]. В определении допустимой ситуации требовалось, чтобы существовала такая цепочка у g 2*, что ХА...Х,„иу— правовыводимая цепочка. Пред- положим, что нетерминал Хт появляется в результате примене- ния правила А—>-aXr„fi. Иными словами, в пополненной грам- матике есть вывод S' =>) уАх=$г уаХ„$х=?*г уаХтиу где уа — Так как и g FIRST (Рх), ситуация [А—> —► аХ,„-Р, о] должна быть допустима для Xi...Xm, если о = = FIRST (х). Можно заключить, что в каноническом множестве таблиц действие таблицы Тт па цепочке и не „ошибка", и, значит, во- преки предположению в алгоритме 7.6 оно не могло оказаться замененным на ср. Случай 2; Предположим, что f (и) = перенос, а — первый сим- вол цепочки и, g(a) = q>. Поскольку f (и) = перенос, в множестве ситуаций, связанном с таблицей Тт, найдется такая ситуация вида[А—► а-ар, и], что и g EFF(aPo)n[A—>а-ар,о]—допустимая ситуация для активного префикса Х1...Хт (см. упр. 7.3.8). Но тогда ситуация [А—,-аа-р, и] допустима для Хг...Хта и А\... ...X„fl—также активный префикс. Следовательно, множество допустимых ситуаций для XY...Xma непусто, и g(a) не может быть элементом ср вопреки предположению. Случай 3; Предположим, что f (и) = свертка р, где правило с номером р есть А—► Хг... Хт, — и g'(A) = cp. Тогда ситуация [Л—<-Хг...Хт-, н] допустима для Х1...Хт, а ситуация [А —---X,. . ,Х„, и] допустима для Х1...ХГ.1. Как и в случае 1, приходим к выводу, что найдется ситуация [В—- аА-р, и], допустимая для Xj...Xr_1A, и, значит, g'(А) не может быть элементом ср. □ Можно также показать, что алгоритм 7.6 заменяет на ср мак- симально возможное число элементов ошибка в каноническом множестве таблиц. Поэтому, если произвольный элемент ошибка из заменить на ср, полученное множество таблиц не будет более ср-недостижимым. 7.3.4. Слияние таблиц с помощью совместимых разбиений В этом разделе мы опишем важный метод, применяемый для уменьшения множества ЬК(/г)-таблиц. Этот метод состоит в том, что две таблицы сливаются в одну, когда это не отражается на 59
ГЛ. 7. МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ поведении ЕР(й)-алгоритма разбора, использующего рассматри- ваемое множество таблиц. Пусть дано ф-недостижимое множество таблиц и Т\, Тг—две таблицы из этого множества. Предполо- жим, что всякий раз, когда элементы действия или перехода таблиц не совпадают, один из них есть <р. В этом случае будем говорить, что таблицы 7\ и Т2 совместимы, и их можно слить, рассматривая Т\ и Т2 как одну таблицу. Далее, предположим, что 7\ и Т2 не совпадают только в одном элементе перехода, который в одной таблице представляет собой Т3, а в другой Т4. Если Тг и 7\ совместимы, можно одновре- менно слить Т, с 7\ и Tt с Т2. Слияние таблиц можно еще выполнить в том случае, когда Т3 и Tt несовместимы только из-за того, что несовпадающими элементами перехода служат Л и Т2. Опишем такой алгоритм слияния, определив понятие совме- стимого разбиения множества таблиц. Затем покажем, что все члены каждого блока совместимого разбиения можно одновре- менно объединить в одну таблицу. Определение. Пусть («Г, Т„) — ф-недостижимое множество БР(/г)-таблиц и П —{:7\, ..., }— разбиение на яГ. Другими словами, У, и ^2 U . и ?’;, — tr" и if tЛ ift = 0 для всех i j. Будем называть Г( совместимым разбиением ширины р, если для всех блоков ifi, 1 =Ср, из принадлежности элементов </1; и </2> блоку ift вытекает, что (1) при f2(u) Ф f2(u) хотя бы одно из значений /Ди) и /Ди) есть ф, (2) при g^Xj^gJX) либо (а) хотя бы одно из значений g^X) и g2(X) есть ср, либо (б) gt(X) и g2(X) принадлежат одному и тому же блоку разбиения П. Совместимые разбиения множества ЬР(й)-таблиц можно найти методами, сходными с методами нахождения неразличимых со- стояний не полностью определенного конечного автомата. Наша цель состоит в нахождении совместимых разбиений наименьшей ширины. Изложим алгоритм, показывающий, как с помощью совместимых разбиений ширины р на множестве БР(/г)-таблиц найти эквивалентное множество, содержащее р таблиц. Алгоритм 7.7. Слияние с помощью совместимых разбиений. Вход, ф-недостижимое множество («Г, Т2) ЬК(/г)-таблиц и со- вместимое разбиение П = {сУ,, ..., afp} на it. Выход. Эквивалентное ф-недостижимое множество (оГ', Т'„) ЬД(£)-таблиц, для которого #<$Г = р. 60
7.3. ПРЕОБРАЗОВАНИЯ НА МНОЖЕСТВАХ ЬВД-ТАВЛИИ Метод. (1) Для каждого i, 1 гДi^p, по блоку разбиения П построить таблицу Uf — <f, g'e следующим образом: (а) Если </', g'> g#',- и f (п)У=ср для аванцепочки и, поло- жить f(u) = f' (и). Если такой таблицы в нет, положить /(«) = <₽ (б) Если <f, g'>€#’j и g(X)€#’y, положить g(X) = (7;. Если в То нет такой таблицы, что g'(X) g ofs, положить g(X) = ср. (2) Гё—таблица, построенная по блоку, содержащему Та. □ Корректность построения, выполняемого алгоритмом 7.7, сле- дует из определения совместимого разбиения. Пример 7.19. Рассмотрим нашу обычную грамматику арифме- тических выражений G„: (1) Е -^Е + Т (2) Е --Т (3) Т (4) Т ->F (5) F — (E) (6) F- —- а <р-недостижимое множество ЕР(1)-таблиц для G„ показано па рис. 7.25. Легко видеть, что как таблицы Т,, и Tia, так и таблицы Tlt и Т2„ совместимы. Поэтому можно построить совместимое раз- биение, где блоками будут {Т3, Г40}, {Г14, Г20} и все остальные таблицы. После замены {7"3, на 1)г и {Т\4, Г2(1} па U2 мно- жество таблиц станет таким, как оно представлено на рис. 7.26. Заметим, что элементы перехода Г3, Гi0, Г14 и соответственно изменены на LE или U2. Совместимое разбиение, приведенное выше, иаилучшее из всех, которые можно найти. Например, Т1е и 7\, почти совместимы, и можно было бы сгруппировать их в один блок разбиения, если бы удалось сгруппировать в один блок этого же разбиения таб- лицы Г„ и Г20. Но Т10 и Тг,, не согласуются в действиях для + , * И ). □ Докажем, что алгоритм 7.7 порождает на выходе эквивалент- ное ср-недостижимое множество ЬР(А)-таблиц. Теорема 7.6. Пусть S~'—множество 1^.(к)-тоблиц, построен- ное по S' алгоритмом 7.7. Тогда S' и S" эквивалентны и оба ср-недостижимы. Доказательство. Пусть таблица Т’ из S’’ построена по блоку совместимого разбиения, содержащему таблицу Т из S'. ’ 61
Действие Пгргхов Т, Л Л Т< Те \ Т-, h Те Тк Т, Тг Тп Т» ^15 Те Т,7 Туь Т^ Ло Тг, а Е Т Рис. 7.25, <р-иедостнжимое множество таблиц для Со.
Действие Переход ff + *()e Г 7 С я + * ( ) Го г, Л Та Ту То Г, То Тз Тп Тп Тп л6 ?ie Л 7 Г, в Г19 Uy иг S X X S X X р S <р <р А <р 2. S <£> ф 2. X 6 6 X X 6 S X X S X X S X X S X X S X X S X X tp S ip S <р р 2 S р 2 tp X 6 6 X 6 X S X X S X X tp 1 S p 1 X 5 5 X X 5 S X X S X X S X X S X X p S p p S p <p 1 £ <p 1 p X 5 5 X 5 X p 4 4 <p A 4 p 3 3 p 3 3 Тг Uy T4 p p Ts p p p p p p 7"y p p pppppppp To Ts Uy Tyy f ? Туг p f Туг Uy Та P p Тъ p p p u2 т4 p p t5 p P P P P TM P P T1S p p P p P 7,7 p p pppippppp Лв т8 Uy Tyy p p Туг p ppp ppT-jpp f 'P P TyS Uy Tyy P P иг Tyy P P P P p P P p P P P P p P P P P P P P P p P p P p Туг P p P Туг ~p Туз p p T2y P Тут P P p p p p p p p p p p p p Рис. 7.26. Совмещенное множество таблиц.
ГЛ 7. МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ Пусть Сс = (7'(|, w, ё) и CJ = (TJ, w, ё)—начальные конфигурации ЬЁ(&)-анализатора, использующего S и S’’ соответственно. Пока- жем, что (7.3.1) Со l(T0X1T1. . .ХтТ,„, х, п) для анализатора, исполь- зующего S', тогда и только тогда, когда Со ‘(T'oXtT'y...XaT'm, х, л) для анализатора, исполь- зующего S'. Это означает, что единственное различие между случаями, когда ЬЕ(/г)-апализатор использует S и S', состоит в том, что, исполь- зуя S1, анализатор заменяет таблицу Т из S представителем содержащего ее блока разбиения II. Докажем утверждение (7.3.1) индукцией по i. Начнем с не- обходимости условия. Базис, то -0, тривиален. Для проведения шага индукции предположим, что утверждение (7.3.1) верно для i. Докажем, что оно верно для i + 1. Так как множество S' <р-не- достижимо, действия таблиц Т„ и Т'„, на FlftSTs(x) совпадают. Пусть это общее действие — перенос, а—первый символ цепочки х и элемент перехода таблицы Тт на а есть Т. В соответствии с алгоритмом 7.7 и определением совместимого разбиения пере- ходом таблицы Т’т иа а будет Т' тогда и только тогда, когда Т'— представитель содержащего Т блока разбиения П. Если действие—свертка по некоторому правилу с г симво- лами в правой части, то, сравнивая таблицы 7'„.ги T'm_r, убеж- даемся, что утверждение верно для i-J- 1. Для доказательства достаточности нужно только заметить, что, если в Т'т у функции действия для цепочки FIRST(х) стоит элемент, отличный от <р, таблица Т'т должна совпадать с Тт, поскольку множество S' ф-недостижимо. □ Итак, алгоритм 7.7 сохраняет эквивалентность в самом силь- ном смысле. Анализатор, использующий два таких множества таблиц, всегда вычисляет очередные конфигурации за одно и то же число шагов независимо от того, имеет ли входная цепочка разбор. 7.3.5. Отсрочка в обнаружении ошибок Наш основной метод уменьшения множества Е13(&)-таблиц должен сливать таблицы всегда, когда это возможно. Однако две таблицы можно слить в одну только тогда, когда они сов- местимы. В данном разделе мы обсудим метод, применяемый для замены в некоторых таблицах существенных элементов ошибка элементами свертка с тем, чтобы увеличить число совместимых пар таблиц в множестве ЬН(/г)-таблиц. В качестве примера рассмотрим таблицы Т\ и Tllt приведен- ные на рис. 7.25. Для удобства представим их функции дейст- 64
7.3. ПРЕОБРАЗОВАНИЯ НА МНОЖЕСТВАХ ЕК(й)-ТАВЛИЦ вия отдельно в виде рис. 7.25(a). Если изменить действие таб- лицы Тt на аванцепочке ) с ошибки на свертку 6 и действие таб- лицы Тп на аванцепочке е с ошибки на свертку 6, то Tt и Tlt станут совместимыми и можно будет слить их в одну таблицу. Однако, прежде чем выполнять такие замены, хотелось бы удо- стовериться, что ошибки, обнаруживаемые таблицей 7\ на ) и таблицей 7R, на е, будут обнаружены на одном из последующих шагов перед операцией переноса. В этом разделе мы получим Действие ТА: Г„: а + * ( ) е X X 6 6 6 6 X X 6 6 X Рис. 7.25(a) условия, при которых можно отсрочить обнаружение ошибки, не изменив позиции во входной цепочке, в которой ЕК(£)-анализа- тор сообщает об ошибке. В частности, легко показать, что в ка- ноническом множестве таблиц любая такая замена допустима. Предположим, что ЬК(/г)-анализатор находится в конфигура- ции (T0XiI\ . . . XmTa, w, л) и действием таблицы Т,„ на аван- цепочке /./ —ГП?ЗТА(гЩ служит ошибка. Предположим далее, что этот элемент ошибка заменяется в Т„, на свертку р, где р— но- мер правила А —> . . . Y г. Эту ошибку впоследствии можно обнаружить двумя способами. При свертке из магазина удаляются 2/ символов и управле- ние передается таблице Т„-г. Если у функции переходов таб- лицы Tm_r символу А отвечает элемент <р, то можно сообщить об ошибке, заменив <р элементом ошибка. С другой стороны, сим- волу А у функции переходов таблицы Tm_r может соответство- вать некоторая таблица Т. Если действием таблицы Т на аван- цепочке и служит ошибка или элемент <р (который можно заменить на ошибку, чтобы сохранить свойство <р-педостижимости), то можно обнаружить ошибку и на этой стадии. Удастся обнару- жить ошибку и в том случае, когда действием таблицы Т на аванцепочке и будет свертка р' и описанный выше процесс по- вторится. Короче говоря, мы хотим, чтобы таблицы, которые становятся управляющими после свертки по правилу р, не вызы- вали на аванцепочке и переноса (или допуска). Заметим, что для того, чтобы заменить ошибку на свертку, нам приходится во всей широте использовать определение экви- валентности множеств ЕН(/г)-таблиц. При разборе с новым мно- жеством таблиц последующие конфигурации могут вычисляться 3 А. Аю, Дж. Ульман, т. 2 65
ГЛ. 7. МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ на несколько шагов позже, чем при разборе с помощью старого множества, но входные символы при этом считываться не будут. Чтобы описать условия, при которых допустима такая замена, нужно для любой таблицы, появляющейся при разборе в верхушке магазина, знать, какие таблицы могут встретиться в магазине в качестве (г-Т 1)-й таблицы сверху. Определим сначала три функ- ции на таблицах и цепочках символов грамматики. Определение. Пусть (оГ, Т„) — множество ЬЕ(/г)-таблиц для грамматики G = (N, 2, Р, S). Расширим область определения функции GOTO из разд. 5.2.3. Функция GOTO отображает S X (N (J 2)* в S' следующим образом: (1) GOTO(7', е) = Т для всех Т из S'. (2) Если Т = </, g>, то GOTOfT, X) = g(X) для всех X из N (J 2 и Т из S. (3) GOTOpr, <zX) = GOTO(GOTO(7", а), X) для всех а из (N (J 2)* и Т из S. Весом таблицы Т из (S', ТА будем называть такое наиболь- шее число г, что если GOTOfTo, а)— Т, то \а\^г. Нам придется также пользоваться функцией GOTO-1, „обрат- ной" к GOTO. Она отображает множество S' х (N II 2)* в множество всех подмножеств множества S. Положим GOTO“1(7’, a) — (71'| GOTO(T', а) — Т\. Наконец, определим функцию NEXT)?, р), где T£S~, ар — номер правила А —► X, .. . Хг: (1) Если вес таблицы Т меньше г, то NEXT^T, р) не опре- делено. (2) Если вес таблицы Т не меньше г, то NEXT(7\ р) ={'/'' | существуют такие T’fS и a g (N U Х)г, что Т" g GOTO-1(T, а) и Г _GOTO(7’", Л)}. Таким образом', NEXT^T, р) дает все таблицы, которые могут стать управляющими после Т, если Т находится в верхушке магазина и вызывает свертку по правилу р. Заметим, что не требуется', чтобы верхними г символами магазина были Х1...ХГ. Единственное требование: чтобы в магазине было не меньше г символов. Если таблицы канонические, можно показать, что среди всех цепочек длины г множество GOTO-1(7’, а) будет не- пустым только для a = Xj ... Хг. В качестве упражнений (см. конец разд. 7.3) предлагаем уста- новить некоторые алгебраические свойства функций GOTO и NEXT. Функция GOTO для множества ЬК(/г)-таблиц хорошо описы- вается с помощью помеченного графа. Вершины графа GOTO помечены именами таблиц, и если GOTO(7’,-, X)=Tj, то из вер- шины, помеченной Tit в вершину, помеченную Tf, проведена дуга, 66
7.3. ПРЕОБРАЗОВАНИЯ НА МНОЖЕСТВАХ LRW-ТАВЛИЦ помеченная X. Следовательно, если GOTO(T, Х3Хг ... ХГ) = Т', то существует такой путь из вершины Т в вершину Т', что метки дуг, составляющих этот путь, образуют цепочку ХгХ3 .. . Хг. Вес таблицы Т можно интерпретировать как длину кратчайшего пути из То в Т в графе GOTO. По графу GOTO легко вычисляется функция NEXT. Для того чтобы найти NEXTfT, i), где правило с номером i есть А—► . Хг, найдем в графе GOTO все такие вершины Т", что из Т" в Т проходит путь длины г. Затем для каждой такой вершины Г" включим GOTO(7'", Д) в NEXTfE, Г). Пример 7.20. Граф GOTO для множества таблиц рис. 7.25 приведен на рнс. 7.27. Из этого графа получаем, что GOTO(7’e, (Е)) = 7'18, так как GOTO(76, ( ) = 7\, GOTO(7’5, Е) = Г9 и GOTO(7\,)) - 7\- Таблица Ts имеет вес 2, поэтому NEXTfTj, 5), где правило 5 есть F—►(£•), не определено. Вычислим теперь NEXT(7\5,5). Путь длины 3 в Т16 выхо- дит только из трех таблиц, а именно из Т„, Те и Т,. Поэтому GOTO(7’„, F) = T3, GOTO(7’e, F) = T3 и GOTO(7'„ F) = Tit, так что NEXT(T15,5)-={7’„ TI4}. □ Дадим теперь алгоритм, преобразующий ф-недостижимое множество таблиц так, чтобы некоторые ошибки обнаруживались позже во времени, но па том же месте входной цепочки. Наш алгоритм не будет самым общим, но из него будет ясно, как осуществляются и более общие преобразования. Мы будем заменять некоторые элементы ошибка и элементы Ф у функций действия па элементы свертка. Для каждого из- меняемого элемента мы точно определяем правило, которое нужно применить при новой свертке. Допустимые замены образуют так называемое множество отсрочки. Каждый элемент множества отсрочки представляет собой тройку (Т, и, Г), где Т — имя таб- лицы, и — аванцепочка и i—номер правила. Элемент (Т, и, г) указывает, что нужно изменить действие таблицы Т па авапце- почке и на свертку г. Определение. Пусть , Т„)— множество ЕК(/г)-таблиц для грамматики G = (N, 2, Р, S). Назовем подмножество множества аГх2*йх/) множеством отсрочки для (cF~, Та), если удовлетво- ряются следующие условия: Если (Т, и, 1) g S' и Т = </, g>, то (1) f (и') - ошибка или ф; (2) если правило; есть А-*-а и 7' = GOTO(7'0, Р), то а—суф- фикс цепочки Р; (3) нет такого правила Г, что (Г, и, F) также принадлежит (4) если Т' g NEXTIT, i) и Т' = </', g'>, то/' («)=ошибка или <р. Л7 з*
ГЛ. 7. МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ Условие (1) утверждает, что на свертку заменяются только элементы ошибка и ср. Условие (2) гарантирует, что свертка по правилу i возможна только тогда, когда в верхушке магазина находится цепочка а. Условие (3) обеспечивает однозначность, а (4) означает, что свертки, вызванные появлением дополнитель- ных сверток, в конечном итоге будут проделаны без переносов. 68
7.3. ПРЕОВРЛЗОВЛНИЯ НА МНОЖЕСТВАХ ЬНИ-ТАБЛИЦ По повод)' условия (4) заметим, что (Т’, и, j) также может входить в S. В этом случае значение f (и) также будет изме- нено с ошибки или ср на свертку /. Поэтому, прежде чем будет выдано сообщение об ошибке, возможно, придется выполнить последовательно несколько сверток. Нахождение множества отсрочки, позволяющего максимизи- ровать общее число совместимых таблиц в множестве LR(£)-ra6- лиц, составляет большую комбинаторную задачу. В одном из приведенных ниже примеров мы коснемся некоторых эвристи- ческих методов нахождения соответствующих множеств отсрочки. Но сначала покажем, как используется множество отсрочки при преобразовании данного множества Ы?(/г)-таблиц. Алгоритм 7.8. Отсрочка в обнаружении ошибок. Вход. Е1Дй)-грамматика G = (N, S, Р, S), ф-недостижимое мно- жество (S', Г,,) ЬК(й)-таблиц для G и множество отсрочки д'. Выход. <р-педостижимое множество оГ' ЬР(1г)-таблиц, экви- валентное S. Метод. (1) Для каждого элемента (Т, и, i) из S, где T = <.f,g>, за- менить f (и) на свертку i. (2) Предположим, что (Т,и, г) £ 53 и правило г есть А->а. Для всех Т’ — <f, g'>, для которых GOTOfT1', а) = Т и g'(А) — <р, заменить g' (А) на ошибку. (3) Предположим, что (Т, и, I) принадлежит S и Т’ = <f, g’> принадлежит NEXT^T, i). Если f (и) — <р, заменить f (и) па ошибку. (4) Полученное множество таблиц, имена которых сохранены, представляет собой S'. □ Пример 7.21. Рассмотрим грамматику G с правилами (1) S-> AS (2) S->b (3) А -> аВ (4) В-^аВ (5) В-+Ь ф-недостижимое множество LR(1 )-таблиц для G, построенное в результате применения алгоритма 7.6 к каноническому мно- жеству ЬК(1)-таблиц для G, приведено па рис. 7.28. Можно, например, заменить оба элемента ошибка у функций действия таблицы 7’4 на свертку 5 и элемент ошибка в таблице 7\ на свертку 2. Другими словами, мы выбираем множество отсрочки 9> = {(Т4, а, 5), (Tt, b, 5), (Tf, е, 2)}. Правило 5 есть В-+Ь и GOTO}?,,, b) ^(jOTO(7’2, b) = Т,. Таким образом, эле- 69
Действие Переход а Ь е 8 А в а ь т0 S 8 X т. Тг р Тз Та Та р р А р 'Р р р р Тг S 3 Р Ч тг р Тз Та Т. S 8 X р р т6 Тг та т> X X 2 р р р р р Та р <р 1 р р р р р Г6 3 3 Р р р f р 'f Т1 S' S' X р р т3 Тг Т6 те 5 5 X V р у f р Т9 4 4 V р •р р р Рис. 7.28. ф-иедостижимое множество таблиц для Go. Действие Переход а b е S А в а ь То 8 3 X Л Тг X Тз Та т, Р Р А р •ф р 'f Тг 3 3 f Та Тг X Тз Та Тг S S X X р Г(. G Тз Та 5 5 2 р р р р Та Р Р 1 f V / 'f <р т6 3 3 У7 ‘f р р р р т7 S 8 X X f Тя Тг Та Ts 5 S 2 р р р 'f •f Тз 4 4 f р •f ~Р Рис. 7.29. Множество таблиц после применения алгоритма отсрочки в обнаружении ошибок.
7.3. ПРЕОБРАЗОВАНИЯ НА МНОЖЕСТВАХ ЕК(й)-ТЛВЛИЦ менты, расположенные в То и Т„ под В, нужно изменить с <у иа ошибку. Аналогично элементы, расположенные в Т„ и 7, под S, заменяются на ошибку. Поскольку NEXTfT,, 5) и NEXT(78, 2) пусты, никакие элементы <р у функций действия заменить на ошибку нельзя. Полученное множество таблиц по- казано на рис. 7.29. Можно, если угодно, воспользоваться алгоритмом 7.7, взяв в качестве совместимого разбиения разбиение, в котором таблица Т, сгруппирована с 7\, Т± с 1\ и Т,: с Те. (Возможны также три другие попарные комбинации.) Новое множество таблиц приведено на рис. 7.30. □ Действие Переход а b е 5- А в а b д S S X 7, и X Тз Та т, S S А 75 7, X Тз Та Т3 S S X X Тз Т-, Та 5 5 2 У’ f р р П 3 3 1 р р р р Р 7, 5 S X X ¥ т. 7, Та т3 4 4 у р р Р Рис. 7.30. Совмещенное множество таблиц. Теорема 7.7. Алгоритм 7.8 порождает ^-недостижимое мно- жество таблиц , эквивалентное множеству об. Доказательство. Пусть С„ = (Та, w, е) — начальная кон- фигурация LR (^-анализатора (использующего либо <&", либо Д''— имена таблиц совпадают). Пусть С„ Н С, . . |— С„ — вся после- довательность тактов, выполненных анализатором, работающим с Д’, и С,, С; I—• • Е- Сп—соответствующая последовательность для Д’'. Так как Д"' образуется из Д’ в результате замены только элементов ошибка и <р, должно быть т/'Х-и и С(=С,для 1 ^7 1 п. (Это означает, что хотя имеются в виду разные таб- лицы, имена их совпадают.) Покажем, что либо т = п, либо, если т>н, после того как дости- гается конфигурация С„, не выполняются переносы и не будет допуска. Если т = п, то утверждение теоремы очевидно, и если С„— допускающая конфигурация, то т = п. Поэтому предположим, 71
ГЛ. 7 МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ что С„ сигнализирует об ошибке и т > п. Согласно определению множества отсрочки, поскольку в конфигурации Са действием является ошибка, а в конфигурации С'п нет, действием в С'п должна быть свертка. Поэтому пусть s — наименьшее целое, большее п и такое, что действие в конфигурации есть пере- нос или допуск. (Если такого s не существует, то теорема до- казана.) Итак, найдется такое наименьшее г, п <_ r^s, что элемент у функции действия, к которому происходит обращение в конфигура- ции С'г, присутствует в одной из таблиц множества S'. Случай r=s не исключается, поскольку, безусловно, в S' был перенос или допуск конфигурации С'г. Элемент действия, запрашиваемый в конфигурации С)_„ имел вид свертка i для некоторого i. Со- гласно нашему определению г, этот элемент должен был появиться в результате применения алгоритма 7.8. Пусть 7\ и Тг— управляющие таблицы в конфигурациях C'r_t и С’г соответственно. Тогда Т„ £ NEXT(7\, i), что противоречит условию (4) определения множества отсрочки. □ Приведем теперь достаточно полный пример, который демон- стрирует, как находить множества отсрочки и совместимые раз- биения. Здесь во многом используются эвристические методы. Поскольку эти методы нигде далее не описываются, мы настоя- тельно рекомендуем читателю внимательно разобраться в данном примере. Пример 7.22. Рассмотрим множество таблиц для Go, показан- ное на рис. 7.25. Наш подход заключается в том, чтобы для увеличения числа таблиц с аналогичными функциями действия применить алгоритм 7.8, заменяющий действия ошибка дейст- виями свертка. В частности, попытаемся слить в одну все таб- лицы, вызывающие одинаковые свертки. Попробуем слить таблицы Т,л и Т’21, поскольку они обе свер- тывают по правилу 5, и таблицы Т, и 7’1Х, свертывающие по правилу 6. Для того чтобы слить таблицы Т1а, Т21, нужно сделать так, чтобы действием таблицы 7\5 на ) и таблицы Т21 на е стала свертка 5. Затем нужно проверить, какие действия отвечают символам ) и в в таблицах из множеств NEXT(7\5, 5) = {7’л, 7\J и NEXT(7'21,5) = Т20}. Поскольку Т, и Tlt на ) обе имеют действием q>, нужно заменить эти <р на ошибку и на этом закончить преобра- зование. Правда, тогда Т, и Tw не будут более совместимыми, как и таблицы Тт1 и Т2„', поэтому мы заменим действия таблиц Та и 7\, на символе ) на свертку 4 и свертку 3 соответственно. Теперь проанализируем множества таблиц \ 11X7(7',,, 4) = = NEXT(7’14, 3) = {Тг, 7’13}. Аналогичные рассуждения приводят нас к выводу, что действия таблиц Т2 и Т13 па ) нужно заме- 72
7.3. ПРЕОБРАЗОВАНИЯ НА МНОЖЕСТВАХ LRttl-ТЛБЛИЦ нить не на ошибку, а на свертку 2 и свертку 1 соответственно. Далее видим, что NEXT(7'„, 2) - -{7’1| —NliXTf?',.,, 1). Нужно заменить действие таблицы Та на символе ) на ошибку, и тогда будут учтены все изменения, необходимые для замены действия 7',,, на символе ) на свертку 5. Посмотрим, что произойдет, если заменить действие таблицы 7\, на символе е па свертку 5. NEXT(7’al, 4)^{7’10, Г2„}, но за- менять действия таблиц Т13 и Тг0 на символе е на ошибку не- желательно, поскольку, возможно, не удастся слить эти таб- лицы с Т3 и 7'„. Поэтому заменим действия таблиц 7\0 и 7'20 на символе е на свертку 4 и свертку 3 соответственно. Далее находим, что NEXT(7\0. 4) = NEXTfr,,, 3) = {T„ Т19} Мы не будем заменять действия таблиц 71, и 7\, на символе е на ошибку, так что пусть действием таблицы Т, на символе е будет свертка 2, а таблицы Ты — свертка 1. Затем находим, что NEXT(T„, 2) = NEXT(Tle, 1) = {Г8, Т18} В этих таблицах заменим действия на символе е па ошибку. Мы сделали таблицы Ти и Т2] совместимыми, и это не по- влияло на возможную совместимость таблиц Т3 и 7’10, Ты и Т2а, Т2 и Ts, Tls и 7’,,,, Ти и Т,„. Исследуем возможность сделать 7'4 и Тг1 совместимыми, заменив действие таблицы Та на сим- воле ) и таблицы Т„ на символе е на свертку 6. Поскольку NEXT(7’J, 6) — {7’э, 7'14|- и NEXT(TU, 6) = {7’10, TjJ, изменения, внесенные в Т3, Т1а и Ти, Т.а, без затруднений переносятся па таблицы Та и 7’11. Все множество отсрочки состоит из эле- ментов [Л, ), 2] [Т, , е, 2] [Т3, ), 4| [Т10> е, 4] [7\, ), 6] [Тп, е, 6] [Лз, ) 1] [Л», е, 1] [Л4, ), 3] [Т20, е, 3] [Т15, ), 5] [Г21, е, 5] Результат применения алгоритма 7.8 к множеству таблиц рис. 7.25 с таким множеством отсрочки показан на рис. 7.31. Заметим, что к функциям переходов не добавлено ни одного элемента ошибка. Из рис. 7.31 видно, что следующие пары таблиц совместимы: T’s» ^10 Т„ Tti Л|> ^20 ^21 73
Действие Переход Рис 7.31. Результат применения алгоритма отсрочки в обнаружении ошибок.
7.3. ПРЕОБРАЗОВАНИЯ НА МНОЖЕСТВАХ ЕВД-ТАВЛИЦ Более того, если эти пары образуют блоки совместимого разбиения, можно сгруппировать еще и такие пары: Т 8» ^Х8 Т12 т„ т„ 7\»> Л» т2, Л т1», Т 1, Если алгоритм 7.7 применить к разбиению, блоками кото- рого служат приведенные выше пары и одноэлементные множе- ства {Ге} и {TJ, то получится множество таблиц, показанное Действие Переход а + * ( ) e £ T F a + * ( ) 7» S X s X X r, Тг T3 Те TS F Т, У V V X A f V V f Te ? f V Тг V 2 s 2 2 F V 4 f T1 F т3 4 4 4 4 4 V F F F F Те X 6 6 X 6 6 4 V f f F Ъ S X X s X X 4 Тг T3 Те f f Ts f те S X X s X X V 713 Тг Те F V T3 f т7 8 X X s X X F V Tie Те F 4> T3 f Те V s V 4 s X V V <? Te 4> f Tie V 1 s V 1 1 V V F T7 f f ти f 3 3 V 3 3 V f F V F 4> f Т,5 X 5 5 X 5 5 F <p F 'f F Рис. 7.32, Множество таблиц после применения алгоритма слияния. на рис. 7.32. Представителем в каждом случае будет та из пары таблиц, которая имеет меньший индекс. Интересно отметить, что множество таблиц на рис. 7.32 получается непосредственно из G„ с помощью метода „SLR", излагаемого в разд. 7.4.1. Для того чтобы проиллюстрировать эффект отсрочки в обна- ружении ошибок, разберем ошибочную входную цепочку а). Используя множество таблиц рис. 7.25, канонический анализа- 75
ГЛ. 7. МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ тор выполнит только один такт Го, «), ^НГо^), е] Действием таблицы Т, на символе ) будет ошибка. С другой стороны, используя для разбора этой же входной цепочки множество таблиц рис. 7.32, анализатор выполнит по- следовательность тактов Го, а),<|НГо«Л, ), «] Н[ТЛ, ), 6] НГоТ’П, ). 64] НГ»£Л, ), 642] Здесь, прежде чем сообщить об ошибке, анализатор сделает еще три свертки. □ 7.3.6. Исключение сверток по цепным правилам Изучим теперь важное преобразование множества LR(fe)-ra6- лиц, не сохраняющее эквивалентности в смысле предыдущих разделов. Это преобразование не приведет к возникновению дополнительных операций переноса и не вызовет свертки, если исходное множество таблиц обнаружит ошибку. Напротив, в ре- зультате этого преобразования некоторые свертки будут пропус- каться. Это приведет к тому, что таблица, появляющаяся в магазине, не всегда будет связана с записанной под ней цепоч- кой символов грамматики (хотя она всегда будет совместима с таблицей, связанной с этой цепочкой). Преобразование, рассмат- риваемое в этом разделе, должно осуществляться над цепными правилами; мы изучим его несколько менее формально, чем пре- дыдущие преобразования. Правило вида А —>-В, где А и В — нетерминалы, называется цепным. Правила такого вида часто встречаются в грамматиках, описывающих языки программирования. Так, цепные правила часто возникают при использовании контекстно-свобод- ной грамматики для описания приоритетов операций в языках программирования. Например, если цепочку ах + а3*а3 следует трактовать как щ + (о, « а3), то говорят, что операция * имеет более высокий приоритет, чем операция -)-. Наша грамматика G„, описывающая арифметические выраже- ния, вводит для * более высокий приоритет, чем для 4-. Грам- матика G„ состоит из правил (1) Е-.Е-Т (2) Е-+Т (3) T—>T*F (4) T—+F 76
7.3. ПРЕОБРАЗОВАНИЯ НА МНОЖЕСТВАХ Ы?(й)-ТАВЛИЦ (5) F—^(E) (6) F—< а Можно считать, что нетерминалы Е, Т и F порождают выраже- ния различных приоритетов в соответствии с приоритетами опе- раций. Е порождает выражения, приоритет которых равен 1. Это цепочки символов Г, разделенные знаками +- Операция + имеет приоритет 1. Т порождает выражения приоритета 2; они состоят из символов F, разделенных знаками ». Выражения приоритета 3 — это выражения, порожденные нетерминалом F, п их можно считать первичными выражениями. Таким образом, при разборе цепочки л, —в соответст- вии с грамматикой 6„ сначала нужно свернуть а2*а3 в Т, а затем свернуть это Т вместе с а, в выражение Е. Единственная цель, которой служат два цепных правила Е—>Т и Т—> F, состоит в том, чтобы позволить тривиально свертывать выражения более высокого приоритета в выражения более низкого приоритета. В компиляторе правила перевода, связанные обычно с.такими ценными правилами, означают просто, что переводы нетерминалов в левой и правой частях правила совпадают. При таком условии можно, если угодно, исключить свертки по цепным правилам. Некоторые языки программирования имеют 12 и более приори- тетов операций. Поэтому, если разбор ведется в соответствии с грамматикой, отражающей иерархию приоритетов, то анализа- тор часто будет выполнять последовательности сверток по цепным правилам. Если удастся исключить такие последовательности сверток, скорость разбора значительно возрастет. В большинстве практических случаев это удается сделать, не изменив получае- мого перевода. В данном разделе мы опишем преобразование на множестве ЕИ(/г)-таблиц, позволяющее исключить свертки по цепным пра- вилам везде, где это надо. Пусть (оГ, То) — ср-недостижимое множество Ы<(1г)-таблиц для ЕК(/г)-грамматики G = (N, 2, Р, S). Предположим, что оГ содер- жит максимально возможное число элементов <р. Пусть А—< В — цепное правило из Р. Допустим, что Ер(/г)-алгорптм разбора, использующий это множество таблиц, обладает следующим свойством: всякий раз, когда основа УлУг . .. Уг свертывается в В при аванцепочке и, очередным шагом будет свертка В в А. Часто оказывается воз- можным изменить множество таблиц так, чтобы основа У^Уг- . • Уг свертывалась в Л за один шаг. Выясним, при каких условиях это можно сделать. Пусть р— номер правила А-->В. Предположим, что Т = — — такая таблица, что /(uj —свертка р для некоторой 71
ГЛ, 7. МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ аванцепочки и. Пусть S’’ = GOTO'1 (Т, В) и ‘U = {U\U~ GOTO(7', Л), T'ZsF'}. Множество состоит из таблиц, которые могут появиться в магазине непосредственно под В, при условии, что над В находится таблица Т. Если (JT, То)— кано- ническое множество ЕН(/г)-таблиц, то <?i = NEXT(T, р) (упр. 7.3.19). Для того чтобы исключить свертку по правилу р, заменим для каждой таблицы </', g'> из S~' значение элемента g' (В) с имени таблицы Т па g' (Л). Тогда вместо двух тактов, а именно (yT'Y1U1Y1U2. ..YrUr, w, л) w, ni) (yT'AU, w, nip) анализатор сделает только один такт (уТ’ YJJzYsU2. . -YrUr, w, л) p (yT'AU, w, :ti)*) Такая замена элемента g'(В) возможна при условии, что элементы таблицы Т и всех таблиц из “1Z совпадают всегда, кроме тех случаев, когда аванцепочка вызывает свертку по пра- вилу р. Другими словами, пусть T = <f, g> и 4l = {</i, gi>, <ft, g3>, <fm,gm>}- Тогда требуется, чтобы (1) для всех и из Е** если / (и) — не ф и не свертка р, то ft (и)—либо ср, либо совпадает с f (и) при ip/pm, (2) для всех X из NljS если g(X)pq>, то gt (X) — либо ср, либо совпадает с g (X) при icgpm. Если оба эти требования удовлетворяются, преобразуем таблицы в множествах Р-' и 'Н так: (3) положим g'(B)^g'(A) для всех </', g'> из , (4) при I Р /Р m (а) для каждого и g заменим /, (и) на f (и), если fj(u)= ср и f (и)—не ср и не свертка р, (б) для каждого XgNuS заменим gt (X) на g(X), если g(X) pq>. Изменение, обусловленное применением правила (3), может сделать таблицу Г недостижимой, если ее можно достичь только в результате обращения к элементам g'(В) таблиц </', g'> из множества оГ'. Заметим, что измененный анализатор может помещать в мага- зин символы и таблицы, которые не записывались туда исходным анализатором. Например, предположим, что исходный анализатор выполняет свертку в нетерминал В и затем перенос: (уТ’ Y,U,Y'JJ3... YrUr, aw, п) (уТ'ВТ, aw, ni) Н (уТ'ВТаТ", w, Ш) х) На самом деле в результате описанных замен анализатор достигает конфигурации (уТ’ВИ, а>, га'), а не (yT'AU, ш, ni). Впрочем, эго замечание не влияет на ход дальнейших рассуждении.— Прим, перед. 78
7.3. ПРЕОБРАЗОВАНИЯ ПЛ МНОЖЕСТВАХ ЬВД-ТЛБЛИЦ Новый анализатор выполняет ту же последовательность тактов, но в магазине будут появляться другие символы. В этом случае будет (уТ' .YrU,., aw, л) (yT'AU', aw, ni) H (yT'AU' aT", w, ni) ftytn T = <j, g>, T'= <j', g'y и U = <fh g;>. Тогда t/ = g'(d). Таблица U' была построена no U в соответствии с правилом (4), сформулированным выше. Поэтому, если f (v) = перенос, где v = = FIRST (аи>), то ясно, что f'i (о) = перенос. Более того, известно, что g,(a) совпадает с g(a). Значит, новый анализатор выполняет правильную последовательность тактов, за исключением того, что он игнорирует вопрос о том, была ли в действительности произведена свертка но правилу А—-В. На последующих тактах анализатор не просматривает символы грамматики, находящиеся в магазине. Так как элементы пере- хода таблиц U' и 'Г совпадают, можно быть уверенным в том, что поведение обоих анализаторов будет одинаковым (за исклю- чением сверток по цепному правилу А—► В). Эго преобразование можно повторить с новым множеством таблиц, чтобы исключить возможно больше сверток по несущест- венным с точки зрения семантики цепным правилам. Пример 7.23. Исключим возможно больше сверток по цепным правилам в множестве БР(1)-таблиц для грамматики Go, пред- ставленной на рис. 7.32. Таблица Тг вызывает свертку по пра- вилу 2, т. е. по правилу Е—>Т. Множеством таблиц, которые могут появиться в магазине непосредственно под Тг, является {Т„, Т„}, так как GOTO (Г,, Е) = '1\ и GOTO (Г,, Е) = ТЙ. Нужно проверить, что таблицы Т, и Т(, а также Т2 и Т„ совместимы везде, кроме элементов свертка 2. Действие таблицы Т3 па » есть перенос. Действие таблиц 7\ и Т„ на * есть гр. Пере- ход таблицы Г2 на * есть Т,. Переход таблиц 7\ и Тй на * есть <р. Следовательно, Т2 и Т,, а также Т2 и Тй совместимы. Поэтому можно заменить переход таблицы Т„ на нетерминале Т с Тг на Tt и переход таблицы Тй на нетерминале Т с Тй па Тй. Нужно также заменить действия таблиц 7\ и Т„ на символе с гр на перенос, поскольку действие Т2 на есть перенос. Наконец, за- меняем переходы таблиц Т3 и Т„ на символе * с гр на 7’,, потому что переход таблицы Тг на * есть 7\. Таблица Т, теперь недостижима из Т„, и, значит, ее можно исключить. Рассмотрим операции свертка 4, содержащиеся в таблице Т3. (Правило 4 — это правило 7’—► F.) Множеством таблиц, которые могут появиться непосредственно под Т3, является [Га, Тй, 71,}. Теперь GOTO(Т„, Т)^, GOTO(7’5, 7’1 -7\ и GOTO(7’„, Т) = Т13. (До описанного преобразования GOTO(7’0, Т) =GOTO (7’ь, Т) = Т.,А 79
ГЛ. 7. МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ Нужно проверить, что таблица Т3 совместима с каждой из таб- лиц Tj, Ts и Т13. Ясно, что это так, поскольку действие таб- лицы Т3 — есть либо <р, либо свертка 4, а переходы ее все равны ф. Таким образом, можно заменить переходы таблиц Т„, 7, и Т, на символе F па 7\, Та и Т13 соответственно. Это делает таб- лицу Т3 недостижимой из Т„. Полученное множество таблиц показано на рис. 7.33,а. Таб- лицы Тг и Т3 исключены. Заметим, что в столбцах, расположенных под символами Е, Т и F, все элементы перехода оказались совместимыми. По- этому можно слить эти три столбца в один. Пометим этот новый столбец символом Е. Новое множество таблиц приведено на рис. 7.33,6. В алгоритм разбора осталось внести лишь одно изменение, а именно при вычислении элементов перехода вместо символов Т и F использовать Е. В результате множество таблиц рис. 7.33,6 приводит к разбору согласно остовной грамматике (1) Е^Е-'-Е (3) Е^Е*Е (5) £-т(£) (6) Е —► а определенной в разд. 5.4.3. Разберем, например, входную цепочку (о —а)*а с помощью множества таблиц рис. 7.33,6. ЬЕ(1)-анализатор выполняет такую последовательность тактов: [70, (а -}-в) * а, е] ]— [7„ (76, а 4- а) * а, е] Н[70 (Т\аТа, 4-а)*а, е] I—17. (Т3ЕТе, -ь-а)*а, 6] Н[7.(76БТ,4-Т6>е)*а, 6] И[7.(75Б7в4-7,07'., )*а, 6] H[7,(7,£784-7e£Tls, )»a, 66] Н[7„(Г5£Г„ )««, 6611 Н[7„(75Б78)Л„ 661J |— [7,Б7'1, *а, 6615] \-[ТаЕТ^Т3, а, 6"15] Н[7„£71«-7.а7'а, е, 6615] |— \Т0ЕТ1 « Т3ЕТи, е, 66156] [7.Б7., е, 661563] Последняя конфигурация—допускающая. Канонический LR(1)- анализатор для G, при разборе этой же входной цепочки сделал 80
Действие Переход а + * ( ) е £ Т Г а + * ( ) т, Та Тъ Те Та ts тп ^5 3 X X 3 X X р 3 3 р X А х 6 6 х 6 6 3 X X 3 X X S X X 3 X X 3 X X 3 X X р 3 S р S X p 1 51 1 1 p 3 3 p 3 3 X 5 5 X 5 5 Г, 7, 7, Tt p p T5 p p p p p Te T7 p p pppppppp Ts T& Ts TA p p Ts p P rt3 Tn Ta p p 76 p P p 714 T4 p p 7s p p p p p Ts T-j p 715 pppppT7pp pppppppp pppppppp а Действие Переход a + * (. ) e £ a + * ( ) To s X X J X X Tf Ta Ts V» T, V 3 3 V X A ‘f Ts T7 f 'f Ta X 6 6 X 6 6 'f f ‘P Ts 3 X X s X X rs Ta f T5 T, s X X s X X Т,з Ta <e Ts 'P Ъ 3 X X s X X ^14 Ta Ts T6 4> s s f 3 X 'f 4> Te T1 T,s Tn P 1 s <? 1 1 f T1 'f 7l4 V 3 3 f 3 3 4> f <f f 'P Г,5 X 5 5 X 5 5 'P 4> б Рис. 7.33. Множество ЬК(1)-таблиц после исключения цепных правил! а—до слияния столбцов; б —после слияния столбцов.
ГЛ, 7. МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ бы пять дополнительных тактов, соответствующих сверткам по цепным правилам. □ Метод исключения цепных правил формально описан в алго- ритме 7.9. Хотя мы и не будем подробно доказывать его кор- ректность, этот алгоритм позволит нам исключить все свертки по цепным правилам, если для каждого нетерминала грамматика содержит не более одного цепного правила. Даже если какой-то нетерминал имеет более одного цепного правила, этот алгоритм все-таки будет работать достаточно хорошо. Алгоритм 7.9. Исключение сверток по цепным правилам. Вход. Ы7(/г)-грамматика G = (N, X, Р, S) и ф-недостижимое множество (<$", Р„) таблиц для G. Выход. Измененное множество таблиц для G, „эквивалентное" множеству (оГ, Ро) в том смысле, что оно позволяет так же рано обнаруживать ошибки, но может привести к неудаче при свертке по некоторым цепным правилам. Метод. (1) Упорядочить нетерминалы так, чтобы N = {A1, ..., Д„} и если Д(—> Ду—цепное правило, то i<j. Возможность такого упорядочения обеспечивается однозначностью грамматики. (2) Выполнять шаг (3) последовательно для / = 1, 2, . . ., п. (3) Пусть Д;—►Ду—цепное правило с номером р и Тг—таб- лица, вызывающая действие свертка р на одной или более аванцепочках. Предположим, что Тг принадлежит множеству NEXT (7\, р)') и для всех аванцепочек либо действия таблиц Тг и Т, совпадают, либо одно из них есть ср, либо действием таблицы Тг служит свертка р. Наконец, допустим, что элементы перехода таблиц Тг и Т., также либо совпадают, либо один из них есть <р. Построим теперь новую таблицу Т... элементы кото- рой всегда совпадают с отличными от ср элементами таблиц Тъ иТ2. Исключение составляют элементы, соответствующие тем аван- цепочкам, которым в таблице Т3 отвечает свертка р. В этом случае действия таблицы Т3 будут совпадать с соответствующими действиями таблицы Т.г. Затем преобразуем каждую таблицу Т = <f, g>, для которой g(A;) = Тз и g (Ду) = Г,, положив g (Д;) = -вЙ/) = 7’3. (4) По окончании преобразований шага (3) устраним все таб- лицы, не являющиеся более достижимыми из начальной таб- лицы. □ Установим ряд результатов, необходимых для доказательства того, что для ЕЕ(1)-грамматики алгоритм 7.9 полностью исклю- ) Следует отметить, что всякий раз, когда применение тага (3) влечет за собой изменение множества таблиц, соответственно изменяется и связанная с этим множеством функция NEXT. 82
7.3. ПРЕОБРАЗОВАНИЯ НА МНОЖЕСТВАХ ЬДВД-ТАБЛИЦ чает свертки по цепным правилам, если нет двух правил вида А—-Я и А—. С, при условии что ни из какого нетерминала грамматики не выводится только пустая цепочка. (Такойнетерминал легко убрать, причем после этого грамматика останется LR(1)- грамматикой.) Лемма 7.1. Пусть G= (N, S, Р, S) — E~R(\y грамматика, обла- дающая тем свойством, что для каждого С g N существует такая цепочка w=£e из что C^*w. Допустим, что А =>+ В с по- мощью последовательности ценных правил. Пусть и — множества LR(iy ситуаций, допустимых для активных префик- сов уЛ и у В соответственно. Тогда удовлетворяются следующие условия: (1) Если [С —- aj-XPj, а] б All11 —►а2>Ур1, b] g Л2, то X У. (2) Если [С —> ctj-Pj, a] g и ft g EFF(fig<)1), то в нет такой ситуации вида [D—>а2-р2, с], что ftgEFF(P2c), кроме, быть может, ситуации [В—►В-.Р], где А=е>*ЕьА>В с помощью после- довательности цепных правил. Доказательство. Предоставляем читателю в качестве упражнения убедиться в том, что нарушение условия (1) или (2) приводит к противоречию с 1-Е(1)-условием. □ Следствие. кр(1утаблицы, построенные по и ц1г, совпа- дают на всех, элементах перехода и действия, кроме случаев, когда один из них есть <р или когда таблица, построенная по I,, вызывает на этом элементе свертку по цепному правилу. Доказательство. Согласно теореме 7.7, поскольку две таблицы построены но множествам допустимых ситуаций для цепочек, оканчивающихся нетерминалом, все элементы ошибка несущественны. Выполнение условия (1) леммы 7.1 обеспечивает отсутствие конфликтов в элементах перехода; условие (2) утверж- дает, что конфликтов нет и в элементах действия, за исключе- нием разрешимых конфликтов, относящихся к цепным прави- лам. □ Лемма 7.2. В ходе работы алгоритма 7.9 каждая таблица является результатом слияния списка (возможно, длины 1) LR(1 )- таблиц Т\, ...,Ти, построенных по множествам допустимых ситуаций для некоторых активных префиксов уД2......уЛ,;, где А;—>-А,-+1 принадлежит Р для \^1^п. Доказательство. Оставляем в качестве упражнения. □ ]) Заметим, что здесь Pi может равняться е; тогда Hi на аванцепочке & вызывает свертку, В противном случае Hi вызывает перенсс. 83
ГЛ. 7. МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ Теорема 7.8. Пусть алгоритм 7.9 применяется к LR(1 )-грам- матике G и ее каноническому множеству ЕЯ^-таблиц ST. Если G имеет для каждого нетерминала не более одного цепного правила и ни из какого нетерминала не выводится только е, то получен- ное множество таблиц не содержит сверток по цепным пра- вилам. Доказательство. Интуитивно ясно, что леммы 7.1 и 7.2 гарантируют, что все пары таблиц 7\ и Т,, рассмотренные на шаге (3), действительно удовлетворяют условиям этого шага. Формальное доказательство оставляем в качестве упражнения. □ УПРАЖНЕНИЯ 7.3.1. Постройте канонические множества ЬК(1)-таблиц для следующих грамматик: (a) S—+ABAC А —-aD B^b\c C~^c\d D —> DO | О (б) S^aSSIb (в) S — SSajb (г) Е^Е-'-Т\Т T-^T»F\F F-P-F\P P-^(E)\a\a(L) L—*L, Е\Е 7.3.2. Используйте каноническое множество таблиц из упр. 7.3.1(a) и алгоритм 7.5 для разбора входной цепочки аОЬаООс. 7.3.3. Покажите, как можно реализовать алгоритм 7.5 (а) с помощью детерминированного МП-преобразователя, (б) в виде анализатора на языке Флойда — Эванса. 7.3.4. Постройте анализатор па языке Флойда — Эванса для грамматики G„ по (а) множеству Ы?(1)-таблиц, приведенному на рис. 7.33, а, (б) множеству ЬИ(1)-таблиц, приведенному на рис, 7.33,6. Сравните полученные анализаторы с анализатором из упр. 7.2.11. 84
УПРАЖНЕНИЯ 7.3.5. Рассмотрим грамматику G, порождающую язык L -- {сг"Оа'В"1 i, U {Оа'Ча'с” | i, п^О}: S — А | ОВ А -^аАЬ |0 |ОС В-* **аВс\ 1 | 1С С —► аС | а Сконструируйте для G анализатор простого предшествования и LR(1)-анализатор. Покажите, что анализатор простого предше- ствования при разборе цепочки а"1а'Ь, прежде чем сообщить об ошибке, прочтет все символы а, следующие за символом 1. Покажите, что канонический ЬК(1)-анализатор сообщит об ошибке, как только прочтет символ 1. 7.3.6. С помощью алгоритма 7.6 постройте ср-недостижимые множества ЬК(1)-таблиц для каждой грамматики из упр. 7.3.1. 7.3.7. Пользуясь методами настоящего раздела, постройте наименьшее эквивалентное множество ЬК(1)-таблиц для каждой грамматики из упр. 7.3.1. 7.3.8. Пусть — каноническая система множеств Ы?(/г)-ситуа- ций для ЬИ(й)-грамматики G = (N, 2, Р, S). Пусть Л—множество ситуаций, принадлежащее . Покажите, что (а) если [Л—их-р, а]£Л, то и g FOLLOW,,(Л), (б) если Л не является начальным множеством ситуаций, то Л содержит по меньшей мере одну ситуацию вида [Л—>аХ-р, и] для некоторого X из NUS, (в) если [В—с-р, uJgaZ и В=Л=В', то в Л есть ситуация вида [Л —>a-By, и], (г) если [Л—юс-Вр, и] g Л и EFFj (Ври) содержит символ а, то Л есть ситуация вида [С—>-ау, v| для некоторых у и о. (Этот результат позволяет получить простой метод вычисления элементов перенос в ЬИ(1)-анализаторе.) *7.3.9. Покажите, что если в множестве S~' ЬК(й)-таблиц, построенном алгоритмом 7.6, заменить какой-нибудь элемент ошибка па ср, то новое множество таблиц не будет более <р-не- достижимым. *7.3.10. Покажите, что канонический ЬИ(й)-анализатор сооб- щает об ошибке либо в начальной конфигурации, либо сразу после операции переноса. **7.3.11. Пусть G — ЬК(й)-грамматика. Найдите верхнюю и нижнюю границы для числа таблиц в каноническом множестве ЬК(й)-таблиц для G. Можете ли Вы найти разумные верхнюю 8$
ГЛ. 7. МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ и нижнюю границы числа таблиц в произвольном допустимом множестве Ь1?(й)-таблиц для G? *7.3.12. Видоизмените алгоритм 7.6 так, чтобы им можно было воспользоваться для построения «р-недостижимого множества ЬК(О)-таблиц для Ы?(О)-грамматики. *7.3.13. Разработайте алгоритм нахождения всех элементов ср в произвольном множестве ЬР(/г)-таблиц. *7.3.14. Разработайте алгоритм нахождения всех элементов ср в произвольном множестве ЬП(й)-таблиц. **7.3.15. Разработайте алгоритм нахождения всех элементов <р в 1-С(й)-таблице разбора. *7.3.16. Разработайте удобный алгоритм нахождения совмести- мых разбиений множества LR (/г)-таблиц. 7.3.17. Найдите совместимые разбиения множеств Ы?(1)-табли11 из упр. 7.3.1. 7.3.18. Покажите, что отношение совместимости И?(£)-таблиц рефлексивно и симметрично, но не транзитивно. 7.3.19. Пусть (S', Т„)— каноническое множество ЬР(й)-таблиц для Ьй(й)-грамматики G. Покажите, что множество GOTO (Г,,, а) непусто тогда и только тогда, когда а—активный префикс грам- матики G. Верно ли это утверждение для произвольного допу- стимого множества ЬР(й)-таблнц для G? *7.3.20. Пусть S’ — каноническое множество Ы?(й)-таблнц для G. Найдите верхнюю границу веса произвольной таблицы из S' (как функцию от G). 7.3.21. Пусть S’ — каноническое множество 1_Р(А')-таблиц для LR (/г)-грамматики G = (X, S, Р, S). Покажите, что NEXT(T, р) для всех TPS' равно {GOTO(7”, Л) | Т’ С GOTO*1 (Т, а), прави- ло р есть А —> а}. 7.3.22. Дайте алгоритм вычисления NEXT(7\ р) для произ- вольного множества ЕД(й)-таблиц для G. *7.3.23. Пусть S'—каноническое множество ЬВ(й)-таблиц. Предположим, что для каждой таблицы Т С S', содержащей одно или более действий свертки, выбирается одно правило с номе- ром р, по которому Т производит свертку, и все действия ошибка и (р заменяются на свертку р. Покажите, что полученное множество таблиц эквивалентно S'. *7.3.24. Покажите, что с помощью алгоритма 7.9 не всегда удается исключить свертки по цепным правилам из множества ЬК(^)-таблиц для ЬК(й)-грамматики. В6
УПРАЖНЕНИЯ *7.3.25. Докажите, что алгоритм 7.9 строит множество LR(fe)- таблиц, эквивалентное исходному, не считая сверток по цепным правилам. 7.3.26. Будем говорить, что бинарная операция 0 связывает слева направо, если цепочку о.ОйОс следует понимать как ((а6Ь)9с). Постройте Ы?(1)-грамматику, порождающую выражения над алфавитом, состоящим из символов {а, (, )} и знаков операций { + , —, *, /, t}. Все операции бинарные, за исключением -|- и —, которые и бинарны, и (префиксно) унарны. Все бинарные операции, кроме f, связывают слева направо. Бинарные операции + и — имеют приоритет 1, операции » и / — приоритет 2, опе- рация t и две унарные операции — приоритет 3. * *7.3.27. Разработайте метод автоматического построения LR(1)- анализатора для языка выражений. Выражения определяются над множеством операций со связками и приоритетами, как в упр. 7.3.26. * 7.3.28. Докажите, что множества таблиц и ‘U из при- мера 7.17 эквивалентны. * *7.3.29. Покажите, что проблема определения эквивалентности двух множеств БР(/г)-таблиц разрешима. Определение. Следующие правила порождают арифметические выражения, в которых 6lt 02, . .., 0„ представляют бинарные опе- рации п различных приоритетов. О, имеет самый низкий приори- тет, а 0„ — самый высокий. Операции связывают слева направо Е^Е&Е^Е, Это же множество выражений можно получить с помощью так называемой ,,LR(l)-rpaMMaTHKH с индикаторами": (1) Е, EfyEf (2) Et —а (£„) О i п (3) Ei —и: 0 i п В этих правилах индексы можно рассматривать как индикаторы нетерминала Е и терминала 0. Условия, налагаемые на индика- торы, отражают приоритет операций. Например, первое правило 87
ГЛ. 7. МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ указывает, что выражение ритета I, за которым идет Рис. 7.34. Дерево разбора приоритета i — это выражение прио- операция приоритета /, а за ней — выражение приоритета / при усло- вии 0 '7 i п. Начальный символ имеет приоритет 0. Дерево разбора для выражения a02(«0ja), аналогичного аф + а), изображено па рис. 7.34. На дереве показаны значения индикаторов,свя- занных с нетерминалами. Хотя грамматика с индикаторами при отсутствии индикаторов неодно- значна, можно построить LR(l)-no- добный анализатор, использующий для правильного разбора входной цепочки индикаторы с 1-Д(1)-табли- цами. Такой LR(1 )-анали.затор пред- ставлен на рис. 7.35. Чтобы проиллюстрировать пове- дение этого анализатора, разберем входную цепочку a02(a0jO). Анали- затор начинает работу в конфигура- ции ([То, 0J, е), в которой с начальной таблицей Т„ связан индикатор 0. Действием пары [7’0, i] на входном символе а служит перенос, поэтому анализа- тор переходит в конфигурацию 0]a7’2, 02(a0ja), е). Действие Переход а ( ) е Е а в; ( ) [То,;] S X 5 X X it,,;] Тг X [Д.О] X [7,,/] X S X X А X X [T„j] X X Тг X 3 X 3 3 X X X X X ГГз.ОЗ S X S X X Тг X 17-3,0] X 174,Д S X S X X [Т6,Д Тг X [7з,01 X (Д,Ч X S X S X X X [Д,д X т7 [Те/] X Я1 X Я2 R2 X X [Д.д X X Л X 2 X 2 2 X X X X X Рис. 7.35. 1_1?(1)-анализатор с индикаторами из упр. 7.3.30. 88
УПРАЖНЕНИЯ Действием таблицы 7\ на входном символе 02 является свертка по правилу 3, т. е. по правилу Е—>а. Переход пары [Т„, /] на символе Е есть [7\, /]. Значение индикатора передается от То к 7\. Таким образом, анализатор переходит в конфигурацию ([Л, 0]£’[7'1> 0], О2(п0,а), 3) Законченная последовательность шагов анализатора выгля- дит так: ([7\>, 0]. 002(0010), е) I—([Л-°]оЛ1 0г(о0!О), е) Н ([Л, 0]£[7\ 0], Одоб^), 3) Н ([Т,, 0]£[7\, О]02[7\, 2], (а0,а), 3) f-([T„O]£[T„O]0s[T„2]([T„ 0], аО,а), 3) ([Л, 0]£[Л. О]02[7'1, 2]([7'3, 0]оЛ 01й), 3) ^([Л,0№1,0]62[Л,2]([7’3,0]£|Л,0], М), 33) (| Л, 0]£[Л, ОМЛ, 2]([7’3, 0]£[Л, О]01[7’1, 1], О), 33) н ([Л. 0]4Л, ОШЛ. 2]([TS, 0]£’[7’6, 0]01[7'4, 1]оЛ, ), 33) н ([Л, 0]£[7’1, 0]02[Л, 2]([тз, 0]£[7'6, 0]01[7’4, 1]£[Л, 1], ), 333) н ([Л, 0]£[Л. ОМЛ, 2]([Л, О]Е[ТМ 0] ), 33311) Н ([Т„, 0]£[Т„ 0№,2]([Т„ 0]£[Л, 0])Л, е, 3331,) Н ([Л, 0]£[Л, ОВД, 2]£[Л, 2], е, 3331,2) I--([То> 0]Е[Т1, 0], е, 3331,21,) **7.3.30. Покажите, что анализатор, приведенный на рис. 7.35, правильно разбирает все выражения, порождаемые грамматикой с индикаторами. 7.3.31. Постройте LR(1)— анализатор для грамматики без индикаторов с операциями п различных приоритетов. Каков размер этого анализатора по сравнению с анализатором с ин- дикаторами, приведенным на рис. 7.35? Сравните быстродейст- вия двух таких анализаторов. *7.3.32. Постройте LR(1)— подобный анализатор с индикато- рами для языка выражений, включающих бинарные операции, причем одни операции связывают слева направо, другие — справа налево. **7.3.33. Следующая грамматика с индикаторами порождает выражения, включающие бинарные операции п различных при- оритетов: (1) Ei (2) (3) R^-O^R^., (4) п О :С i п О i < j k "С п О Л !Л i < п 89
ГЛ. 7. МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ Постройте для этой грамматики ЬЦ1)-подобный анализатор син- дикаторами. Указание'. Хотя в этой грамматике у R два указа- теля, анализатору нужен только первый из них. 7.3.34. Закончите доказательство леммы 7.1 и ее следствия. 7.3.35. Докажите лемму 7.2. 7.3.36. Закончите доказательство теоремы 7.8. Открытая проблема 7.3.37. При каких условиях можно после исключения сверток по цепным правилам слить все столбцы перехода для нетер- миналов, как это делалось для грамматики Go? Предлагаем чи- тателю исследовать возможность связать этот вопрос с оператор- ным предшествованием. Напомним, что G„— грамматика оператор- ного предшествования. Проблемы для исследования 7.3.38. Разработайте дополнительные методы преобразования множеств LR-таблиц, сохраняющие „эквивалентность11 в понима- емом нами смысле. 7.3.39. Разработайте методы компактного представления LR- таблиц, использующие преимущества элементов ср. Упражнения на программирование 7.3.40. Придумайте элементарные операции, которыми можно пользоваться при реализации ЁР(1)-анализатора. Такими опе- рациями могут быть чтение входного символа, запись символа в магазин, выталкивание определенного числа символов из ма- газина, посылка в выходную цепочку и т.д. Постройте интер- претатор, выполняющий эти элементарные операции. 7.3.41. Постройте программу, получающую на вход множе- ство LR(1)-Ta6nnn и порождающую на выходе последовательность элементарных команд, которая моделирует ЬР(1)-анализатор, работающий с этим множеством таблиц. 7.3.42. Постройте программу, получающую па вход множество ЬЦ1)-таблиц и порождающую на выходе последовательность элементарных команд, которая моделирует ЬЦ1)-анализатор, работающий с этим множеством таблиц. 7.3.43. Напишите программу, добавляющую к каноническому множеству LR-таблиц несущественные элементы. 90
7.4. МЕТОДЫ ПОСТРОЕНИЯ 1.К(Ь)-АНАЛИЗАТОРОВ *7.3.44. Напишите программу, которая для построения ком- пактных множеств таблиц применяет эвристические методы реа- лизации отсрочки в обнаружении ошибок и выполнении слия- ния таблиц. 7.3.45. Реализуйте алгоритм 7.9, исключающий, когда это возможно, свертки по цепным правилам. Замечания по литературе Преобразования, описанные в этом раздело, были предложены Ахо и Ульманом (1972в, 1972г]. Пейджер (1970] рассмотрел другой подход к задаче упрощения ЬК(А)-анализаторов, при котором анализатор изменяется так, чтобы ошибки обнаруживались пс в той же позиции входной цепочки, что и в случае канонического анализатора; кроме того, для определения нужной свертки требуется просматривать содержимое магазина. Идея использования в LL-грамматиках и анализаторах индикаторов принадлежит Льюису, Розен- кранцу и Стирнзу, В работе Льюиса и Розенкранца (19711 сообщается, что использование индикаторов при обработке выражений и условных операторов позволило уменьшить синтаксический анализатор в их компиляторе Алгола 60 с 37 до 29 Ы.(1)-таблиц разбора. 7.4. МЕТОДЫ ПОСТРОЕНИЯ 1_Н(£)-АНАЛИЗАТОРОВ Объем работы, выполняемой при построении множеств LR]/?)- ситуаций (и, следовательно, канонического ЬИ(й)-анализатора), резко возрастает с увеличением размера грамматики и с ростом длины аванцепочки k. Для больших грамматик объем вычисле- ний, требующихся для построения канонического множества ЕИ(/г)-таблиц, оказывается неприемлемо большим даже при k= 1. В этом разделе мы изучим ряд более практичных методов пост- роения допустимых множеств Ь1?(1)-таблиц для некоторых LR(1)- грамматик. Первый рассматриваемый нами метод заключается в построе- нии для грамматики G канонической системы множеств LR(0)- ситуаций. Если каждое множество ЕИ(О)-ситуаций непротиворе- чиво *), то для G можно построить допустимое множество ЬИ(0)-таблиц. Если множество ЕР(0)-ситуаций противоречиво, то для разрешения конфликтов, возникающих между действиями при разборе, имеет смысл попытаться воспользоваться в этом множестве ситуаций аванцепочками. Экономия при таком подхо- де достигается за счет того, что заглядывание вперед применя- ется только тогда, когда оно необходимо. Для многих грамматик эгот подход позволяет получить множество таблиц, значительно меньшее, чем каноническое множество 1_Р(А)-таблиц для G. ’) Множество 1.1? (7?)-ситуаций называют непротиворечивым, если по нему можно построить ЕВ(я)-таблицу, у которой действия разбора определены однозначно. 91
ГЛ. 7. МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ Правда, для некоторых LR(/г)-грамматик этот метод не рабо- тает. Мы обсудим также другой подход к задаче построения LR(fe)- апализаторов. При таком подходе большая грамматика расщеп- ляется на части и для этих частей строятся множества LR(fe)- ситуаций, а затем для получения больших множеств ситуаций эти множества объединяются. Однако не всякое расщепление ЬК(й)-грамматики дает такие части, по которым можно построить допустимое множество таблиц для G. 7.4.1. Простые LR-грамматики В данном разделе мы попытаемся построить анализатор для ЬК(й)-грамматики, строя сначала для G систему множеств LR(0)- ситуаций. Излагаемый метод работает для грамматик, составля- ющих подкласс LR-грамматик и называемых простыми LR-грам- матиками. Определение. Пусть G = (N, 2, Р, S) — КС-грамматика (не обязательно LR(0)). Пусть 'f,,— каноническая система множеств 1Л(0)-ситуаций для G, а Л— произвольное множество ситуаций из ef\. Предположим, что если [Л—>сс-р, е] и [В—е]—две различные ситуации из Л, то удовлетворяется одно из условий; (1) пи Р, ни 6 не равны е, (2) р-щс, 6 = с и FOLLOWt(B) n EFFt(p F()I.L()WfJ.1)) 01), (3) р = е, и FOLLOWЬ(Л) П EFFJfi FOLLOW,,(В))0, (4) р = 6е и FOLLOWERFOLLOWt(B) = 0. Тогда G называется простой ЬК(й)-грамматикой (или, короче, SLR (k)-грамматикой). Пример 7.24. Пусть, как обычно, G„ — грамматика с правилами Е~^Е + Т\Т Т,7ЛЕ\Е F.(E)\a Каноническая система множеств ЕК(О)-ситуаций для G„ при- ведена на рис. 7.36; вторые компоненты, равные везде е, опущены. Go — не SLR(O)-rpaMMaTHKa, потому что Л1: например, содер- жит такие две ситуации [£'—>£.] и [£—-В. Л-Т], что FOLLOW„(£') -= {е} = EFF„[+ TFOLLOW^B)]а) г) Здесь можно воспользоваться функцией FOLLOW^_1(?I), поскольку цепочка 0 должна порождать хотя бы один символ любой цепочки, принад- лежащей EFFfe([i FOLLOWft(yi)). 2) Заметим, что FlRST0(a) — EFF0(a) — FOLLOW0(a) = {е} для всех а. 92
7.1. МЕТОДЫ ПОСТРОЕНИЯ ТК(Л)-ЛНЛЛИЗАТОРОВ Однако Go— SLR(l)-rpaMMaTHKa. Для того чтобы проверить выполнение 5Ы?(1)-условия, достаточно исследовать множества, (1) содержащие не менее двух ситуаций, (2) содержащие ситуацию, в которой точка стоит справа от всех символов. Ло: Е' -Е Ла • Е-+Е+>Т е^.е + т Е—+-Т T-+-T*F Т -^‘Е T^-T^F Г ^F Р -*(£) F —► -а F*(Е) F^-a л? • T—^T*‘F F-+.(E) Лг- Е' —+Е- F—► -a Е—гЕ- Т Л$ • P^(E-) Лч • Е—+Т- E-^E.-FT T—^T‘-f.F Л* : £->£-|-T. Лз'- Т —+F- T T- * F Л,^ F —> а- tVio' T—^T^F- Л11- F^(E). Е^-Е | Т Е—^-Т T—>.T*F T^-F Лъ* F^(.E} F-а Рис. 7.36. Множество ЬР(О)-ситуаций для Go. Итак, нас могут интересовать только множества Л,, Л2 и Л9. Для имеем FOLLOW,(Е') = и EFFJ4T FOLLOW,(E)]={ + }- Так как {е}П{ + } ~- 0, то Л, удовлетворяет условию (3) опре- деления SLR(I)-rpaMMaTHKH. По той же причине условию (3) удовлетворяют множества Л2 и Л,. Следовательно, можно заклю- чить, что G„ есть 5ЕД(1)-грамматика. □ Теперь попытаемся построить множество Е1?(1)-таблиц для SLR(l)-rpaMMaTHKH G, начиная с канонической системы а мно- жеств LR(O)-cHTyanm"i для G. Пусть некоторое множество Л из содержит только две ситуации: [Л—е] и [В—►р.у.е]. По этому множеству можно построить ЕД(1)-таблицу. Элементы перехода строятся очевидным образом, как и для LR(0)-ra6nim. Но какое действие нужно совершить, если аванцепочкой служит символ а: свертку по правилу А—>а или перенос? Ответить на этот вопрос можно, выяснив, верно ли, что a g FOLLOW,^). Если a g FOLLOWjJ/l), то а не может принадлежать EFF^y) по 93
ГЛ. 7 МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ определению 5ЕР(1)-грамматики. Поэтому действием здесь будет свертка. Если же а £ FOLI.OWJ/1), то свертка не подходит. Если agEFF(y), то действие—перенос, в противном случае — ошибка. В закопченном виде этот алгоритм приведен ниже. Алгоритм 7.10. Построение множества ЕК(й)-таблиц для SLR(£)-r р а м ма т и к и. Вход. 8ЕК(£)-грамматика G = (N, S, Р, S) и каноническая система множеств ЫДО)-ситуаций для G. Выход. Множество (S', То} Ьй(А)-таблиц для G, называемое SldR(k)-MHoxecmeoM таблиц для G. Метод. Пусть Л— множество Ы?(О)-ситуаций из Sa. LR(A)- таблица Т, связанная с Л, представляет собой пару <f, g>, по- строенную так: (1) Для всех и из S*'1 (a) f (и) = перенос, если [А —► а.р, е] принадлежит Л, (1 - и и 6 EFFt (р FOLLOWt(A)), (б) f (и] = свертка I, если [А—>а-, е]£Л, правило i есть А—> а и и g FOLLOWt(/l), (в) /(<?)= допуск, если |S' —>£•, е] £ Л ’), (г) /(п)=ошибка в остальных случаях. (2) g(X) для всех X из NUS представляет собой таблицу, построенную по GOTO(-7, X). Начальная таблица Т„ — это таблица, связанная с множеством, содержащих! ситуацию [S'^.S, е]. □ Алгоритм 7.10 аналогичен нашему первоначальному методу построения множества таблиц по системе множеств ситуаций, приведенному в разд. 5.2.5. Пусть Л' — множество таких ситуа- ций [А —»а-р, и], что [А—>а-|3, е] g Л и и g FOLLOWa(A), и пусть \Л' | Л g Sf„}. Тогда в результате применения к алгоритма 7.10 получается то же множество таблиц, что и в ре- зультате применения к метода, описанного в разд. 5.2.5. Из определения сразу видно, что каждое множество ситуаций из V,, непротиворечиво тогда и только тогда, когда G — SLR(ft)- грамматика. Пример 7.25. Построим 5И?(1)-множество таблиц для множе- ства ситуаций, показанного на рис. 7.56. Таблицу, построенную по А,, назовем 7’,-. Мы рассмотрим только построение таблицы Т,. Множество Л^—это -j[E[7’~* Т-»F]}. Пусть Т2 —<_f, gy. Так как FOLLOW(E) = { + ,), е}, то f (+) f[)J = f(e) = свертка 2. ]) Каноническая система множеств ситуаций строится ио пополненной грамматике. 94
7.4. МЕТОДЫ ПОСТРОЕНИЯ ЫЗД-ЛНАЛИЗЛТОРОВ (Правила перенумерованы как обычно.) Так как EFF(*F FOLLOW^)) = {*}, то /(*) = перенос. Для остальных аванцепочек f(a) =/[)] = ошибка. g(X) определено только для Х = Из рис. 7.36 легко видеть, что Т-. Все множество таблиц- показано на рис. 7.37. а Действие + * ( ) е £ т F Переход а + * ( ) Го S X X 3- X X 7, Тг Тъ 74 X X 7s X 7, X S X X X А X X X X 76 X X X Тг X г 8 X 2 2 X X X X X ^7 X X Тг X 4 4 X 4 4 X X X X X X X X Та X е 6 X 6 6 X X X X X X X X П S X X 8 X X 78 Tz Тъ Та X X 75 X Ts 3 X X 8 X X X Та Тъ Та X X 7s X Ъ S X X 8 X X X X 7,0 Та X X 75 X Тъ X 8 X X 8 X X X X X Те X X Л, Ъ X 1 8 X 1 1 X X X X X Тг X X Туй X 3 3 X 3 3 X X X X X X X X 7,1 X 5 5 X 5 Б X X X X X X X X Рис. 7.37. Множество ЗЕК(1)-таблиц для Go. С точностью до имен таблиц и элементов ср это множество совпадает с множеством, приведенным на рис. 7.32. □ Докажем, что алгоритм 7.10 для 5ЫД7)-грамматики G всегда строит допустимое множество ЕИ(й)-таблиц. На самом деле по- лучаемое множество таблиц эквивалентно каноническому мно- жеству ЬК(й)-таблиц для G. Теорема 7.9. Если G— SLR(k)-epaMMamuKa, то SLR(fe)-мно- жество таблиц (JF, Т„), построенное алгоритмом 7.10, эквива- лентно каноническому множеству Тс) 1ЛТ.(к)-таблиц для G. Доказательство. Пусть шбк— каноническая система мно- жеств Ы?(й)-ситуаций для G и — система множеств LR(0)-ch- туаций для G. Определим ядро множества ситуаций Л как мно- жество заключенных в скобки первых компонент ситуаций из 95
ГЛ. 7. МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ этого множества. Например, ядром множества [А—<-а.р, а] является [Л—►«•₽]*). Обозначим ядро множества Л через CORE(.Z). Все множества ситуаций в системе <Z0 различны, однако не- которые множества из S’к могут иметь одинаковые ядра. Легко показать, что = {CORE(cZ) | Л £ <5%}. Определим на множестве таблиц функцию h, соответствующую функции CORE, определенной на множествах ситуаций. Положим /г(Т) = Т', если Т — каноническая Ы?(й)-таблица, связанная с Л, а Т'— 8ЬР(£)-таблица, полученная с помощью алгоритма 7.10 из множества CORE(cZ). Легко проверить, что h коммутирует с GOTO, т. е. GOTO(ft(7’), X) = ft(GOTO(T, X)). Как и раньше, пусть Л' = {[Л—►т. •[’>, ]|[Л—>а-р, и и g FOLLOW^)} Пусть <S°i = { Мы уже знаем, что (ЛГ, Т,,) совпадает с множеством ЬК(й)-табл1щ, построенным по <5% методом, описан- ным в разд. 5.2.5. Покажем, что (еГ, 7’0) всегда можно получить, последовательно преобразуя каноническое множество (S' с, Тс) 1_Р(А)-таблиц для G. Для этого нужно проделать следующее. (1) Пусть 5*—множество отсрочки, состоящее из таких троек (Т, и, 1), что действие таблицы Т на аванцепочке и есть ошибка, а действие h(T} на и есть свертка i. Применяя к З5 и (оГ,,, Те) алгоритм 7.8, получим множество таблиц (S"c, Т'с). (2) Воспользуемся теперь алгоритмом 7.7 для слияния всех таких пар таблиц 7\ и Тг, что h(Tt) = h(T\). Новым множеством таблиц и будет (S', То). Пусть (Т, и, i) — элемент множества З5. Чтобы доказать, что З1 удовлетворяет требованиям, предъявляемым к множеству от- срочки для SFC, нужно показать, что если Т“ = </", принад- лежит NEXTfT, i), то f" (и) = ошибка. Для этого предположим, что правило z есть А —-а и T"=GOTO (То, рЛ) для некоторого активного префикса рЛ. Тогда 7’ = GOTO(T(I, ра). Предположим противное, а именно, что Р'(и)=Л=0ШИб1<а- Тогда найдется ситуация [В —>• у-6, v], допустимая для рЛ, причем wgEFF(6n)2). Каждое множество ситуаций, за исключением на- чального, содержит ситуацию, в которой слева от точки стоит хотя бы один символ (см. упр. 7.3.8). Начальное множество до- пустимо только для е. Поэтому без потери общности можно счи- тать, что у = у'Л для некоторой цепочки у'. Тогда ситуация [В—►у'-Лб, ф| допустима для р. То же справедливо и в отно- шении ситуации [Л —► -а, и].Следовательно, ситуация [Л —-а -, и] х) Далее мы не будем каждый раз оговаривать различие между [Л—►а-p] и [Л—>аф> е]. Заметим, что это утверждение справедливо независимо от того, явля- ется б пустой цепочкой или иет. 96
7.4. МЕТОДЫ ПОСТРОЕНИЯ ЬК(*)-АНАЛИЗАТОРОВ допустима для [За, и f (и) вопреки предположению не есть ошибка. Отсюда заключаем, что 5s действительно является мно- жеством отсрочки для Множество, полученное в результате применения к алго- ритма 7.8 с использованием множества отсрочки 5s, обозначим через S'!. Пусть Т — таблица из S~c, связанная с множеством ситуаций Л, и Т' — соответствующая видоизмененная таблица из S\. Тогда Т и Т' отличаются только тем, что в то время как Т сообщает об ошибке, Т' может вызвать свертку. Это про- исходит, если и g FOLLOW)?!) и только для ситуации из Л вида [A-та-, и]. Утверждение вытекает из того, что по правилу (16) алгоритма 7.10 таблица Т’ вызывает свертку при всех та- ких и, что HgFOLLOWpl) и [Л-xt- ] gCORE(J/). Определим теперь на S’i разбиение П={®1, . . ., группирующее таблицы 7\ и Тг в один блок тогда и только тогда, когда h(T1)=h (Тг)- Так как h коммутирует с GOTO, раз- биение П совместимо. Слияние таблиц в каждом блоке, прове- денное с помощью алгоритма 7.7, дает множество S'. Так как алгоритмы 7.7 и 7.8 сохраняют эквивалентность мно- жества таблиц, мы показали, что множество S' 1.Р(/г)-таблиц для G эквивалентно каноническому множеству S~c LR (^-таб- лиц для G. □ Прежде чем закончить изучение SLR-разбора, отметим, что методы оптимизации, описанные в разд. 7.3, применимы также и к SLR-таблицам. В упр. 7.4.16 выясняется, какие элементы ошибки в SLR(1 (-множестве таблиц несущественны. 7.4.2. Распространение SLR-подхода на грамматики, не явля- ющиеся SLR-грамматиками Метод построения анализатора для грамматики по канониче- ской системе множеств ЬК(О)-ситуаций обладает двумя зна- чительными преимуществами. Во-первых, для данной грамматики объем вычислений, необходимых для построения <5%, вообще го- воря, гораздо меньше объема работы по построению системы St множеств ЬР(1)-ситуаций. Во-вторых, число множеств LR(0)- ситуаций обычно гораздо меньше числа множеств 1.Р(1)-ситуаш1Й. Правда, возникает вопрос, что делать, если грамматика та- кова, что множества FOLLOW недостаточно для разрешения кон- фликта, возникающего между действиями при разборе из-за про- тиворечивости множеств LR(())-cnTyanHii? Известно несколько методов, и мы их изучим, прежде чем закончить исследование LR (О)-подхода к построению анализаторов. Один из методов состоит в том, что для разрешения неоднозначности можно по- 4 4 А. Ахо. Дж. Ульмин, т. 2 77
ГЛ. 7. МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ пытаться использовать локальный контекст. Если этот метод не приведет к успеху, можно попробовать расщепить какое-то мно- жество ситуаций на несколько подмножеств. В каждом из этих подмножеств для однозначного определения действия можно воспользоваться локальным контекстом. Проиллюстрируем на примерах оба метода. Пример 7.26. Рассмотрим Ы?(1)-грамматцку с правилами (1) S-+Aa (2) S—+dAb (3) S-^cb (4) S —< dca (5) A—>-c Несмотря на то, что язык L(0) состоит всего из четырех це- почек, грамматика G не является 5ЕР(й)-грамматикой ни для какого fe^O. Каноническая система множеств 1_Е(())-ситуаций для О приведена на рис. 7.38. Вторые компоненты опущены и я S'—+>S S —► -Aa |-cb [•dca A —> ‘C Ал'- S'-+S< <Al' S —> A’a Аз- S —t-d'Ab | d-ca A —► *c А&- S — A — •Аъ- S — Ла. *А§> 5 —^dA-b *Ач' S —dc-a A —*- с- Аз' S —>cb* A»' S —+dAb- Аю' S —*-dca- Рис. 7.38. Каноническая система множеств ЕК(О)-ситуаций. ситуаций [А—’•а.1-₽1], для кратко- сти обозначены А —|аг-ра | • • | <%„•₽„. Здесь два проти- воречивых множества ситуаций: Л4 и Л,. Более того, поскольку FOLLOW(A) = {a, b}, алгоритм 7.10 не построит по и Л7 однозначные действия для аванцепочек b и а соответственно. Тем не менее исследуем функцию GOTO, определенную на множествах ситуаций и изображенную графически на рис. 7.39J). Заметим, что этот граф — ациклический, хотя в общем случае граф пе- реходов содержит циклы. 98
7.4. МЕТОДЫ ПОСТРОЕНИЯ LR(W-AHAJIH3ATOPOB Мы видим, что достичь из Л„ можно, только имея в мага- зине с. Если свернуть с в Л, то по правилам грамматики полу- Рис. 7.39. Граф GOTO. чим, что за А может идти только а. Поэтому таблица по- строенная по Л4, содержит однозначную функцию действия: abed свертка 5 перекос ошибка ошибка Аналогично из графа GOTO видно, что достичь Л^ из можно, только имея в магазине de. В таком контексте, если с свернуть к Л, то за Л может идти только Ь. Поэтому таблица Т„ пост- роенная по содержит функцию действия a bed перенос свертка 5 ошибка ошибка Остальные Е1?(1)-таблнцы для G можно получить непосредственно по алгоритму 7.10. □ Грамматика из примера 7.26 не является SLR-грамматикой. Однако для разрешения всех неоднозначностей при разборе мы смогли использовать в множестве Ь1?(0)-ситуаций заглядывание вперед. Класс ЕК(й)-грамматик, для которых всегда можно таким 4» 99
ГЛ. 7. МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ способом построить LR-анализаторы, называется классом LR(fe)- грамматик с заглядыванием или, короче, классом LALR(&)-rpaM- матик1) (более точное определение дано в упр. 7.4.11). LALR(fe)- грамматики образуют наиболее широкий естественный подкласс ЬК(£)-грамматик, для которого заглядывание на k символов по- зволяет разрешить конфликты, возникающие при разборе, с по- мощью канонической системы tf,. множеств ЬР(О)-ситуаций. Аван- цепочки можно найти либо непосредственно по графу GOTO для либо слив множества ЬК(/г)-ситуаций с одинаковыми ядрами. LALR-грамматики включают в себя все SLR-грамматики, но не всякая LR-грамматика является LALR-грамматикой. Приведем теперь пример, когда для получения однозначных действий разбора множество ситуаций „расщепляется". Пример 7.27. Рассмотрим LR(1 (-грамматику с правилами (1) S —> Аа (2) S —>-dab (3) S -+ВЬ (4) S —fdBa (5) А —► с (6) В —<-с Эта грамматика совершенно аналогична грамматике из примера 7.26, но она не является LALR-грамматикой. Каноническая си- стема множеств LR(O)-CHTyauHft для пополненной грамматики S' —»*S A —► c- s —► *Aa В ► C* s —► *dAb t/le' s —► Aa* s —► -Bb s -+Bb* s —► *dBa c/?8- s —+dA-b A —► *c S- —*dB*a В —► *C S- —>.dAb* <A\- S' —*S- <^11* s —>dBA* s —•- A*a t/lz' s —>B*b s —+d*Ab s —*d*Ba А —► -с В —> -с Рис. 7.40. Каноническая система множеств Ы?(0)-ситуаций. приведена на рис. 7.40. Множество противоречиво, потому что неизвестно, по какому правилу нужно свертывать: по А—ю или по В-^-с. Так как FOLLOW(A) = FOLLOW(B) = {а, &}, нам О От англ. LookAhead LR(fc).— Прим, иерее. 100
7.4. МЕТОДЫ ПОСТРОЕНИЯ ЬВДЦ-АНАЛИЗЛТОРОВ не удастся устранить неоднозначность, используя в качестве аванцепочек эти множества. Следовательно, G не является SLR(1)- грамматикой. Анализ правил грамматики показывает, что если в магазине содержится только с и очередной входной символ есть а, то для свертки символа с нужно применить правило А—>с. Если оче- редным входным символом служит Ъ, то нужно воспользоваться правилом В—>с. Но если в магазине записана цепочка de и оче- рёдной входной символ есть а, то для свертки с нужно приме- нить правило В —>- с, а если очередным входным символом служит Ь — правило А—>-с. Функция GOTO для множества ситуаций приведена на рис. 7.41. К сожалению, <.Z- достижимо из Ла н тогда, когда Рис. 7.41. Граф GOTO. в магазине содержится с, и тогда, когда там записана цепочка de. Поэтому Л5 не уточняет, какая из этих двух цепочек записана в магазине, и, значит, G не является ЬАЬК(1)-грамматикой. Тем не менее для G можно построить LR(I (-анализатор, за- менив Л, такими двумя одинаковыми множествами Л’ъ и Л\, что .у: достижимо только из Ль, а Л"й—только непосредственно из Л„. Эти новые множества ситуаций дают необходимую дополнитель- ную информацию о том, что содержится в магазине. По Л'ь и Л"ь можно построить такие таблицы с однозначными функциями действия: a bed свертка 6 свертка 5 свертка 5 свертка 6 ошибка ошибка ошибка ошибка 101
ГЛ. 7. МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ Функции перехода в таблицах T't и Т'1, всегда принимают значения ошибка. □ 7.4.3. Расщепление грамматики В настоящем разделе мы изучим другой метод построения LR-анализаторов. Он не так прост в применении, как метод SLR, но работает в случаях, когда метод SLR не приводит к успеху. Мы будем расщеплять грамматику G = (N, S, Р, S) на несколько грамматик-компонент, рассматривая некоторые нетерминальные символы как терминальные. Пусть N's N—такое множество „расщепляющих" нетерминалов. Для каждого А из N' можно найти грамматику-компоненту GА с начальным символом А, вос- пользовавшись следующим алгоритмом. Алгоритм 7.11, Расщепление грамматики. Вход. КС-грамматика G = (N, S, Р, S) и подмножество N' множества N. Выход. Множество грамматик-компонент 0А для каждого А € N'. Метод. Для каждого A g N' построить 0А так: (I) В правых частях всех правил из Р заменить каждый не- терминал BgN' на В. Обозначим через N множество {В | В g N'j- и через Р новое множество правил. (2) Положим Gj—(N—N' и {A}, E UN, Р, А). (3) Применить алгоритм 2.9 для исключения из ОА бесполез- ных нетерминалов и правил. Получившаяся в результате грам- матика и есть Ga. □ Мы займемся сейчас задачей построения ВР(1)-анализаторов для всех грамматик-компонент и объединения этих анализаторов. Для различных компонент можно, вообще говоря, строить ана- лизаторы разных типов. Например, для разбора выражений можно применить анализатор операторного предшествования, а все остальное разбирать с помощью LL(1 (-анализатора. Представляет интерес вопрос о том, как можно распространить методы настоя- щего раздела на различные типы анализаторов. Пример 7.28. Пусть Go—наша обычная грамматика и N'= = {Е, 7")— множество расщепляющих нетерминалов. Тогда Р со- стоит из правил Е^Ё+f\Т T^t* F\F F—*(E)\a 102
7.4. МЕТОДЫ ПОСТРОЕНИЯ Е₽(А:)-АНАЛИЗАТОРОВ Таким образом, Ge=({E}, {£, Т, +}, {£ —+Ё-\-Т | T}t Е) и Gt = ({T,F}, {Г, £,(,), а, *(, {7'->7’*/7|ЛТ). □ Опишем теперь метод построения ЬЕ(1)-анализаторов для некоторых больших грамматик. Этот метод состоит в том, что сначала данная грамматика расщепляется на ряд меньших грамматик. Если для каждой грамматики-компоненты удается найти систему непротиворечивых множеств LR(I (-ситуаций и если удовлетворяются некоторые условия, связывающие эти множества, то для исходной грамматики множество LR(l)-cHrya- ций строится путем объединения множеств ситуаций для грам- матик-компонент. Основная идея метода такова: построение систем множеств ЬЕ(1)-ситуацнй для нескольких меньших грам- матик и последующее их объединение обычно требует значи- тельно меньшей работы, чем построение канонической системы множеств LR(l)-CHTyaUHfi для одной большой грамматики. В алгоритме расщепления грамматики нетерминал А рассма- тривается как начальный символ соответствующей грамматики, a FOLLOW(/1) — как множество возможных аванцепочек для начального множества ситуаций, отвечающего подграмматике Ол. Основная цель—объединение некоторых множеств ситуаций, имеющих одинаковые ядра. Сходство этого алгоритма с SLR(I)- алгорнтмом очевидно. В самом деле, как мы увидим, SLR(I)- алгоритм представляет собой алгоритм расщепления грамматики с N'=N. В законченном виде метод выглядит следующим образом. (I) Для данной грамматики G = (N, S, Р, S) находим подходя- щее множество расщепляющих нетерминалов N'sN. Включаем S в N’. Это множество должно быть достаточно велико для того, чтобы грамматики-компоненты были небольшими и чтобы для каждой компоненты легко строилось множество LR(I(-таб- лиц. В то же время число компонент не должно быть слишком большим, чтобы при построении множества таблиц метод не ока- зался непригодным. (Последнее замечание относится только к грамматикам, не являющимся SLR-грамматиками. Если грамма- тика является SLR-грамматикой, то подойдет любой выбор мно- жества N', а наименьшее множество таблиц будет получено при N = N'.( (2) После выбора множества N' находим грамматики-компо- ненты по алгоритму 7.11. (3) Применяя описанный ниже алгоритм 7.12, вычисляем множества LR(l)-CHTyauHft для каждой из грамматик-компонент. (4) Воспользовавшись затем алгоритмом 7.13, объединяем множества-компоненты в систему множеств ситуаций для ис- ходной грамматики. Этот прием не всегда дает систему непроти- 103
ГЛ. 7. МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ воречивых множеств ситуаций для исходной грамматики. Одна- ко, если система непротиворечива, множество ЬЕ(1)-таблиц строится затем по обычным способом. Алгоритм 7.12. Построение множеств LR(I)-CHTya- ций для грамматик-компонент исходной грамма- тики. Вход. Грамматика G = (N, S, Р, S), подмножество N' множества N, содержащее S, и грамматики-компоненты GA для всех A gN' Выход. Множества LR(1 (-ситуаций для всех грамматик-компо- нент. Метод. Для удобства обозначений положим N' = {St, .S,„}. Будем обозначать Gs. как G^ Пусть Л— множество ЬР(1)-ситуаций. Вычислим замыкание Л' множества Л относительно GA. Метод вычисления напоми- нает алгоритм 5.8, но не совпадает с ним. Л' определяется сле- дующим образом: (1) Л s Л' (т. е. все элементы множества Л принадлежат л'}. (2) Если [В—>-а-СР, и\£.Л' и С—-у— правило из GA, то [С—► - у, o]g^' для всех v g FIRST°(P'u), где р'—это цепочка р, в которой все символы из N заменены соответствующими сим- волами из N. Таким образом, в ситуациях все аванцепочки принадлежат 2*, а первые компоненты соответствуют правилам грамматики GA. Для каждой грамматики О,- построим систему ,. множеств LR(I (-ситуаций для G,: (I) Пусть Л^—замыкание (относительно О;.) множества {ГЗ,—> • а, а]| S(—>-а—правило грамматики О,- и a g FOLLOWpfS,)}. Положим if, — (2) Повторять шаг (3) до тех пор, пока к , не перестанут добавляться новые множества ситуаций. (3) Пусть X принадлежит Nu^UN. Если ЛЦш^, положим Л' = {[А —кхХ-Р, и] |[Д —>а-Хр, и] g Л}. Добавим к t замыкание ^"(относительно G,) множества ^'.Итак, Л”=<ХУ[О(Л, X). □ Отметим, что результат не изменится, если пополнить каждую грамматику-компоненту нулевым правилом вместо того, чтобы включать FOLLOW(A) в множество аванцепочек начального мно- жества ситуаций. Пример 7.29. Применим алгоритм 7.12 к грамматике Go с N' = {£, Т}. Находим, что I’'OLI.OW(£(—), е] и FOLLOW(7') = = {+• * )> е}- Таким образом, согласно шагу (1), Л% состоит 104
7.4. МЕТОДЫ ПОСТРОЕНИЯ ЬК«)-АНАЛИЗАТ0Р0В из ситуаций [£—> •£ + ?, +/)/е] [Е—+-Т, +/)/г] Аналогично Л1 состоит из ситуаций [Г — -t*F, +/*/)/е] [T-+-F, +/*/)/е] [£—.(£), +/*/)/е] [F—►•о, +/*/)/«] Вся система множеств ситуаций, построенных для 0£, пока- зана на рис. 7.42, а такая же система для От — на рис. 7.43. Рнс. Л1- 1 [£_.£ + ?, +/)/е] 1 [Е-+-Т, +/)/е] Л1' \Е^~Е- + Т, +Ш \Е^Т., +/)/«] |£ —£+•Т, +/)/«] Ль- [Е-^Ё+Т; +/)/«! 7.42. Система множеств ситуаций для Од. Рис. Хр1 —► -Т »F, +/*/)/е] .т. ПТ’ — -F, +/•/)/₽] [F—•(£). + /*/)/«] ([F-..0, +/»/)/«] Л1Г= [Г—f. .F, +/*/)/е] ЛГ- ir-^-F; +!»/)/е} л1'- [/’-—(•£). +/•/)/«] [F —а., +/./)/!!] т |'[7’ —T..F, +/»/)/«] М- JF—.(£), +/./)/«] ([F—-•«. +/*/)/«) ЛГ- [F^(E-), +/»/)«] ЛГ- |Т —T.F., +/*/)е] Л1- [F^(E)-, +/./)е] 7.43. Система множеств ситуаций для Су. Заметим, что когда строится по Л?, символ Т, например, является терминалом, и операция замыкания ие дает новых ситуаций. □ Приведем теперь алгоритм, который при определенных усло- виях строит по множествам ситуаций, образованным для грам- 105
ГЛ. Г. МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ матик-компопент с помощью алгоритма 7.12, множества LR(I)-ch- туаций для исходной грамматики. Алгоритм 7.13. Построение множества LR(I(-таблиц по множествам LR(l)-c нту аци й для грамматик-ком- п он е и т. Вход. КС-грамматика G = (N, S, Р, S), расщепляющее мно- жество нетерминалов N' = S2, и система {Л'о, Л{, ... ..., Л‘п} множеств ЬК(1)-ситуаций для всех грамматик-компо- нент G;. Выход. Допустимое множество ЬК(1)-таблиц для G или сооб- щение о том, что данные множества ситуаций ие позволяют по- лучить допустимое множество таблиц. Метод. (1) В первых компонентах всех ситуаций заменить символы вида S,- на Sz. Все S; принадлежат N'. Для измененных таким образом множеств ситуаций сохраним прежние обозначения. (2) Пусть 3„ = > -St, <’]} Применить к 3„ операцию по- полнения и обозначить новое множество также через 3„. В объ- единенной системе множеств ситуаций 3„ будет „начальным" мно- жеством. Операция пополнения. Если множество Л содержит ситуацию, у которой первая компонента имеет вид А—-сс-Вр и для некоторых S,gN' и у g (N U 2)*, то к Л добавить Л{. Повто- рять эту процедуру до тех пор, пока к Л будут добавляться новые множества ситуаций. (3) Построим систему множеств ситуаций, достижимых из 5„. Сначала = Затем повторяем шаг (4) до тех пор, пока к & не перестанут добавляться новые множества ситуаций. (4) Пусть 3 g^. Можно представить 9 в виде Л U Л1'U Л!г‘U ..ил'.", где Л—либо пустое множество, либо одно нз мно- 1п жеств {[SJ—г S1, е|} или {[SJ—>5,-, е]}. Для всех X из N (J2 положим Л' = G0T0(4, X) и л\? = G0T0(4>, X)* 1). Обозначим п п через 3' объединение Л' и таких Л[*. Применим операцию по- полнения к 3' и обозначим новое множество также через 3'. Пусть KGOTO2) — такая функция, что KGOTO(5, Х) = 3', если 3, X и 3' связаны описанным выше образом. Добавим множе- J) Здесь имеется в виду функция GOTO для G, . Если X —расщепляющий 1 п нетерминал, то вместо X берем X. 2) Буква К обязана своим появлением А. Дж. Кореньяку, автору описы- ваемого метода. 106
7.4. МЕТОДЫ ПОСТРОЕНИЯ ЕВ(6)-АНАЛИЗАТОРОВ ство 3' к системе <5°, если его там еще нет. Будем повторять «тот процесс до тех пор, пока какие-то 3 и XgNuS позво- ляют добавить к новое множество KGOTO(5, X). (5) Когда к if перестанут добавляться новые множества си- туаций, построим по if множество Ы?(1)-таблиц, пользуясь методами разд. 5.2.5. Если таблица Т —<_f, g> была построена по множеству 3, то дДХ)-К6ОТО(7, X). Если хотя бы одно из множеств ситуаций порождает конфликты действий при раз- боре, сообщаем об ошибке. □ Пример 7.30. Применим алгоритм 7.13 к множествам ситуа- ций, приведенным на рис. 7.42 и 7.43. Результат выполнения шага (1) очевиден. В процессе выполнения шага (2) сначала образуется множество 30~{[Е'—>-•£,«]}, а после применения операции пополнения—множество 5'„ = |[£'—> •£, е]) U ЛХ. В начале шага (3) if ~ {50|. Переходя к шагу (4), сначала вычисляем 5'1=GOTO(.70, Е) ► Е, ej} (J Л? Другими словами, GOTO({[£'—► е](, £) = {[£'—>£, е]} и G0T0(-7f, Е) = ЛХ. Множество йОТО(Л^, Е) пусто. Операция пополнения ие расширяет 3t. Затем вычисляем 5, — GOTO(.7„, Т) = = Л^и<^Г- Операция пополнения не расширяет Зг. Продолжая в том же духе, получаем систему множеств ситуаций для ff: з„ = {[е’ ^.е, <}ил„£ил; Зх = {[£' — £., 3., = Л? и лГ 3, = .7., = Л? U ЛХ U ЛХ з\ = лХ и лХ з — лХ з„ = лХилХ з^лХилХ з10=лХ з„=лХ Все множества ситуаций из if непротиворечивы, и, значит, по if можно построить множество ЕЕ(1)-таблиц, приведенное на рис. 7.44. Таблица If соответствует 3 Это множество таблиц совпало с множеством на рис. 7.37. Далее мы увидим, что это произошло не случайно. □ Покажем теперь, что такой подход позволяет получить мно- жество LR(1 (-таблиц, эквивалентное каноническому множеству 107
ГЛ, 7. МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ LR(I (-таблиц. Начнем с того, что охарактеризуем объединенную систему множеств ситуаций, построенную на шаге (4) алгорит- ма 7.13. Действие Переход а + * с ) е £ т F а + * ( та 5 X X £ X X 7, Тг Тв Л X X То X X S X X X А - X X X X То X X X Тг X 2 S X 2 2 X X X X X Т7 X X Тъ X 4 4 X 4 4 X X X X X X X X Та X 6 6 X 6 6 X X X X X X X X То S X X 3 X X Тв Тг Тъ Та X X То X те S X X S X X X Ts Тв Та X X То X Т7 S X X 3 X X X X 7ю Та X X То. X Тв X S X X S X X X X X То X X 7ц Т» X 1 3 X 1 1 X X X X X т7 X X Т,0 X 3 3 X 3 3 X X X X X X X X Т« X 5 5 X 5 5 X X X X X X X X Рис. 7.44. Множество таблиц для б0, построенное алгоритмом 7.13. Определение. Пусть KGOTO— функция, определенная на шаге (4) алгоритма 7.13. Расширим ее область определения, очевидным образом включив в нее цепочки символов, т. е. (1) KGOTO(3', е) = 3, (2) KGOTOp, aX) = KGOTO(KGOTO(3', а), X). Пусть G = (N, 2, Р, S) — КС-грамматика и N' — расщепляю- щее множество. Будем называть ситуацию [А —*а.ф, а] квази- допустимой для цепочки у, если она допустима (в смысле разд. 5.2.3) или в пополненной грамматике есть такой вывод S' 8tBx =2>* 6182Ax=i>r бДар, что (1) бДа = у, (2) BgN', (3) а б FOLLOW(B). Отметим, что если ситуация [А —>аф, а] квазидопустима для у, то существует такая авапцепочка Ь, что ситуация [А—>-аф, Ь] допустима для у (Ь может совпасть с а). 108
7.4. МЕТОДЫ ПОСТРОЕНИЯ ЬВ(6)-АНАЛИЗАТОРОВ Лемма 7.3. Пусть G (X, S, Р, S) —КС-грамматика, упоми- навшаяся выше, и KGOTO(5I(, у) = 3 для некоторой цепочки у из (X(jS)*. Тогда 3—множество квазидопустимых ситуаций для у. Доказательство. Докажем лемму индукцией по |у|. Базис, у = е, опустим, так как при проведении шага индукции он станет очевидным. Пусть у = у'Х и ЗС—множество квазидопустимых ситуаций для у', равное KGOTOPo, у'). Пусть 3€ = з1[и ... ОЗ^АСлучай, когда [S'->-S, е] или [S'—>5-е] принадлежит Зь, проанализи- ровать легко, поэтому подробности мы опустим. Предположим, что [А —>аф, а] принадлежит 3 = KGOTOp,,, у'у). Ситуация [А—>-аф, а] могла попасть в 3 тремя путями. Случай /: Допустим, что [А—► а-₽, aJgGOTOp^, X) для р некоторых р, a = a'X и [А—>-а'-ХР, а]^3'т. Тогда ситуация р [Л—i-a'-XP, а] квазидопустима для у', а отсюда следует, что ситуация [А—>«•[>, а] квазидопустима для у. Случай 2\ Допустим, что [А—>-a>p, a]gGOTO (З'р, X) и а = е. Тогда найдется ситуация [В—>-дгХ-Сд2, &], принадлежа- щая ООТСЦЗ'р’, X), и вывод С =?>[ Aw, где а € FIRST (wd2b). Сле- довательно, ситуация [В—s-Sj-XCSs, &] квазидопустима для у', а ситуация [В —►61Х-С62Ь] квазидопустима для у. Если первым символом цепочки w служит а или w=e и а появляется в 32, то ситуация [Д—>«•₽, а] допустима для у. Аналогично, если ситуация [В —> SxX-CSj, &] допустима для у, то допустимой для у будет и ситуация [Д—а]. Поэтому предположим, что w = e, 62=?>*е, а = Ь и ситуация [В—►3]Х-(?б2, Ь] квазидопустима для у. Тогда существует вывод S' =г>‘ SsDx=>' Ь,ЬгВх=ог WtXC^^‘, д^ХАх где б3б1б1Х = у, DgN' и b £ FOLLOW (В). Таким образом, по- скольку а — Ь, ситуация [А—а] квазидопустима для у. Случай 3: Допустим, что [А—>-a-f}, а] попадает в 3 на шаге (4) при выполнении операции пополнения. Тогда а = е и в GOTO(3',-P, X) должна быть такая ситуация [В—>61Х-С62, Ь] что С =5>’£>»]=?> ? Дк’ак,1, DgN' и <jg FIRST (wjc) для некото- рого Сё FOLLOW (О). Другими словами, D = Sr, а [А—а] попадает в Я* при присоединении множества 3;. Далее все ана- логично случаю 2. Теперь докажем утверждение, обратное к сформулированному выше, а именно: если ситуация [А—►«•[>, а] квазидопустима 109
ГЛ. 7. МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ для у, то она принадлежит 3. Мы не рассматриваем более про- стой случай, когда ситуация допустима для у. Предположим поэтому, что ситуация [ Л > <z • fi, а] квазидопустима, но недо- пустима. Тогда существует вывод S' =>j 6,йл'=>,' 6|62Ла'=>л SjSjtzpx где у = 6162а, BgN' и agFOLLOW(B). Если то можно записать а в виде а'Х. Тогда ситуация | Ла'• Х'р, а] квази- допустима для у' и, значит, принадлежит Ж• Отсюда сразу сле- дует, что [Л—►a-P, a] g 3. Поэтому будем считать, что а = е. Рассмотрим два случая, соответствующие 62#=е и 62 = е. Случай Г. 62#=е. Тогда существуют выводы В=>)63С=>Г б3б4Хб6 и 66=5>*Л. Значит, ситуация [С—>б4'Хб5, а] квазидо- пустима для у' и потому принадлежит Ж. Отсюда вытекает, что [С- >б4Х-65, а]£3. Так как 66=?>'Л, нетрудно показать, что либо при выполнении операции замыкания, либо при выполнении операции пополнения ситуация [А—а] попадает в S'. Случай 2: 62 = е. В этом случае существует вывод S' =>', 63С1/=>гб3б4Х66у, где д^у^’Вх. Тогда ситуация [С—>-64.Хб5, с], где с— FlRST(y), допустима для у'. Следовательно, [С —- б,А'-65, с] €5. Так как б,у—/,Вх, то при выполнении операции попол- нения в 3 включаются ситуации вида [В- --е, Ь], где В• в— правило, а Ь принадлежит FOLLOW(B). Поскольку В=>'Л, ситуация [А—>-а-₽, а] добавляется к 3 либо при замыкании (в смысле определения, данного при описании алгоритма 7.12) множества, содержащего [В <•£, Ь], либо при последующем вы- полнении операции пополнения. □ Теорема 7.10. Пусть (N, 2, Р, S) — КС-грамматика и (S, То)— множество 1ЛЦ1)-таблиц для 6, построенное алгоритмом 7.13. Пусть (S~c, Тс)—каноническое множество. Эти два множества таблиц эквивалентны. Доказательство. Из леммы 7.3 вытекает, что таблица из множества S', связанная с цепочкой у, совпадает в действиях с таблицей из S~c, связанной с у, везде, где в S', стоит дей- ствие, отличное от ошибка. Поэтому, если два множества не эквивалентны, можно найти такую входную цепочку w, что при работе с S’, анализатор делает последовательность тактов (Тс, w) |—* (ТСХ1Т1... XmTm, х)1), после чего сообщает об ошибке, а при работе с S' он делает последовательность тактов (Т,, х) х) .. YnUttaU, х') J) Для простоты мы опустили в этих конфигурациях выходные цепочки. 110
7.4. МЕТОДЫ ПОСТРОЕНИЯ ЬК(6)-АНАЛИЗАТОРОВ Предположим, что таблица U„ строится по множеству ситу- аций 3. Тогда 3 содержит такую ситуацию [А—>-а.(3, Ь], что и agEFF(P). Так как ситуация [А—>-а.р, е] квазидопу- стима для Уг. . .Y„, то по лемме 7.3 существует вывод S' =Ф’ fAy=i>ryapy для некоторого у, где уа = У1... Уа. Так как есть вывод Fj.. . У„ =>,Х,. . .Хт, то 3 содержит ситуацию [В—>-6-в, с], допустимую для Х1...Хт, где aCEFF(sc). (Случай в = е и а-=с не исключается. В самом деле, это будет в том случае, если последовательность тактов (ЛХ^.-.Х,,^, х) имеет ненулевую длину. Если длина равна нулю, то роль ситу- ации [В—>-б-в, с] играет [А—>а-р, &].) Так как a = FIRST(x), предположение о том, что при работе с множеством аГ' анализатор сообщает об ошибке в конфигура- ции (ТГ1Х/Г',.. .Х„Т'т, х), неверно. Теорема доказана. □ Сравним алгоритм расщепления грамматики с SLR-алгорит- мом. Алгоритм расщепления представляет собой обобщение SLR- метода в следующем смысле. Теорема 7.11. Пусть G = (N, 2, Р, S) —КС-грамматика. G является SLR (1)-грамматикой тогда и только тогда, когда алгоритм 7.13 работает успешно с расщепляющим множеством N. В этом случае множества таблиц, порождаемые этими двумя методами, совпадают. Доказательство. Если N' = N, то ситуация [А —► a-р, а] квазидопустима для у тогда и только тогда, когда ситуация [А—*а.р, Ь] допустима для некоторых b и а из FOLLOW(A). Это следует из того, что если В=£*6С, то FOLLOW(B)sz sFOLLOW(C). Из леммы 7.3 вытекает, что SLR-множества ситуаций совпадают с множествами, построенными алгоритмом 7.13. □ Теорема 7.9 представляет собой, таким образом, следствие теорем 7.10 и 7.11. В алгоритме 7.13 законченная процедура построения канони- ческого Е§(1)-анализатора применяется к каждой грамматике-ком- поненте. Поэтому интуитивно, если грамматика не является SLR-грамматикой, желательно собрать в одной из компонент все те особенности дайной грамматики, из-за которых оиа не является SLR-грамматикой. Проиллюстрируем это рассуждение примером. 111
ГЛ. 7. МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ Пример 7.31. Рассмотрим ЬР(1)-грамматику (1) 3 — Аа (2) 3 —>-dAb (3) S—>-cb (4) S^BB (5) А--+с (6) В—*Вс (7) В^Ь Действие Переход а ь с d е А в а ь с d X В 3 S X 7, Тг Тз X Та Ts 76 7, X X X X А X X X X X X X Тг 5 X X X X X X X Тг X X X Тз X 3 3 X X X X Та X Та Тг X т. X 7 1 X 7 X X X X X X X 75 5 X X X X X X X 710 X X 76 X X 3 X X X 7„ X X X Лг X Т-, X X X X 1 X X X X X X X Т» X X X 4 X X X X X Тг X Т, X 6 6 X е X X X X X X X Tw X X X X 3 X X X X X X X 7,1 X 3 X X X X X X X Лз X X Тп X 5 X X X X X X X X X X 7К X X X X 2 X X X X X X X Рис. 7,45. Множество LR(1)-таблиц. Из-за правил (1)—(3) и (5) она не является SLR-грамматикой Взяв в качестве расщепляющего множества {S, В), объединим эти четыре правила в одну грамматику-компоненту, а затем применим к ней ЬР(1)-метод. Алгоритм 7.13 применительно к такому расщепляющему множеству выдаст множество LR(I)- таблиц, показанное на рис. 7.45. □ 112
УПРАЖНЕНИЯ Наконец, отметим, что ии алгоритм 7.10, ни алгоритм 7.13 не используют в полной мере технику отсрочки в обнаружении ошибок и слияния таблиц. Например, каноническое множество 5ЬК(1)-грамматики из упр. 7.3.1(a) состоит из 18 ЬР(1)-таблиц. Алгоритм 7.13 даст множество, содержащее не менее 14 LR(1)- таблиц, алгоритм 7.10 — множество из 14 8ЬР(1)-таблиц. В то же время, разумно используя отсрочку в обнаружении ошибок и выполняя слияние таблиц, можно получить множество из 7 ЬР(1)-таблиц. УПРАЖНЕНИЯ *7.4.1. Рассмотрите класс {Gj, где G„ содержит правила Aj—t-ajAj А; —>а;В.: | bt B; —► ajBj | &, G2, ...} LR(0)-rpaMMaTHK, 1 i< n 1 i' Ф j sj. n 1 < iX л 1 < i, Jn Покажите, что число таблиц в каноническом множестве ЬР(О)-таблиц для G„ экспоненциально зависит от п. 7.4.2. Покажите, что все грамматики из упр. 7.3.1 являются SLR(l)-rpaMMaTHKaMH. 7.4.3. Покажите, что каждая ЬР(О)-грамматика является SLR(0)-rpaMMaTHKOfl. *7.4.4. Покажите, что каждая простая ССП-грамматика яв- ляется SLR(l)-rpaMMaTHKoft. 7.4.5. Покажите, что грамматика из примера 7.26 не является 8ЬР(й)-грамматикой ни для какого *7.4.6. Покажите, что всякая ЬЬ(1)-грамматика является SLR(1 (-грамматикой. Всякая ли ЬЬ(2)-грамматика является 8ЕК(2)-грамматикой? 7.4.7. С помощью алгоритма 7.10 постройте анализаторы для всех грамматик из упр. 7.3.1. 7.4.8. Пусть ё?с— каноническая система множеств LR(fe)-CH- туаций для G. Пусть —система множеств ЬР(О)-ситуаций для G. Покажите, что а7с и Л'» имеют одинаковые множества ядер. Указание'. Положите Л =йОТО(Л0, а), где — начальное множество системы 'fc, и проведите индукцию по | а |. 7.4.9. Покажите, 4toCORE(GOTO(^, a)) = GOTO(CORE(^), а), где, как и ранее, Л ё &е. из
ГЛ. 7. МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ Определение. Грамматика G —2, Р, S} называется ЬЕ(й)-грамматикой с заглядыванием и обозначается LALR(&), если следующий алгоритм позволяет получить множество LR(fe) -таблиц: (I) Построить для G каноническую систему if, множеств ЬР(£)-ситуаций. (2) Для каждого Л € if с обозначим через Л' объединение таких что CORE(®) = CORE(^(. (3) Пусть <5° — множество всех Л', построенных на шаге (2). Множество ЕЦ(й)-таблиц строится по if обычным образом. 7.4.10. Покажите, что если G— SLR(fe)-rpaMMaTHKa, то оиа является LALR(fe)-rpaMMaTHKoft. 7.4.11. Покажите, что описанный выше алгоритм построения LALR-таблиц порождает множество таблиц, эквивалентное ка- ноническому множеству. 7.4.12. (а) Покажите, что грамматика из примера 7.26 яв- ляется ЬАЬЁ(1)-грамматикой. (б) Покажите, что грамматика из примера 7.27 не является 1.АЬ1?(&)-грамматикой ии для какого k. 7.4.13. Пусть G — грамматика с правилами L—>* R |о R->-L Покажите, что G является ЬАЬР(1)-грамматикой и не яв- ляется SLR(l)-rpaMMaTHKoft. 7.4.14. Покажите, что существуют LALR-грамматики, не яв- ляющиеся LL-грамматиками, и обратно. *7.4.15 . Пусть G — LALR-грамматика, а — каноническая система множеств 1^(0)-ситуаций для G. Будем говорить, что if. имеет конфликт „перенос —свертка", если некоторое мно- жество содержит ситуации [А—i-а1] и [В—>f}-ay], где ngFOLLOW(A). Покажите, что в случае такого конфликта LALR-анализатор всегда выполняет перенос. *7.4.16 . Пусть (cF, Т„) — множество 8ЬК(1)-таблиц для SLR(1 (-грамматики G = (N, S, Р, S). Покажите, что (1) все элементы ошибки у функций переходов несущественны, (2) все элементы ошибки, соответствующие входному символу а у функции действия таблицы Т, существенны тогда и только тогда, когда удовлетворяется одно из следующих условий: (а) Т — начальная таблица 7"0, (б) в cF есть такая таблица Т' = <.f, g>, что T = g(b) для некоторого 114
УПРАЖНЕНИЯ (в) в <S есть такая таблица Т' =<f, g>, что Т принадле- жит NEXTfE', i) и [(a) = свертка. *7.4.17. Пусть G = (N, S, Р, S) — КС-грамматика. Покажите, что G является ЬЕ(£)-грамматикой тогда и только тогда, когда для каждого расщепляющего множества N' £ N все грамматики- компоненты Ga являются ЬЕ(&)-грамматиками, A gN'. [Замечание: G может не быть ЬЕ(£)-грамматикой, но все же иметь такое расщепляющее множество N', что для AgN' все GA будут LR(fe)- грамматиками.) 7.4.18. Выполните упр. 7.4.17 для случая 1Л.(/г)-грамматик. 7.4.19. Воспользуйтесь алгоритмами 7.12 и 7.13 для постро- ения множества ЬЕ(1)-таблиц для G„, взяв в качестве расщеп- ляющего множества {Е, Т, F}. Сравните полученное множество таблиц с множеством на рис. 7.44. 7.4.20. При каких условиях алгоритмы 7.12 и 7.13 для всех расщепляющих множеств нетерминалов будут порождать для G одно и то же множество ЬЕ(1)-таблиц? *7.4.21. Предположим, что с помощью ЬАЬЕ(1)-алгоритма не удается построить множество ЬЕ(1)-таблиц для грамматики G = (N, X, Р, S) из-за того, что возникает множество ситуаций, содержащее такие ситуации [А—>-а-, а] и [В—► (Ьу, &], что у#=е и aCEFF(yb). Покажите, что если N'sN — расщепляющее множество и AgN', то алгоритм 7.13 также не даст множества ЬЕ(1)-таблиц с однозначно определенными действиями разбора. 7.4.22. Попытайтесь с помощью алгоритмов 7.12 и 7.13 по- строить множество ЬЕ(1)-таблиц для грамматики нз упр. 7.27, взяв в качестве расщепляющего множества {S, А}. 7.4.23. Примените алгоритмы 7.12 и 7.13 для построения множества ЬР(1)-таблиц для грамматики из упр. 7.3.8(a), име- ющей 7 таблиц. * 7.4.24. Воспользуйтесь методами отсрочки в обнаружении ошибок и слияния таблиц для нахождения эквивалентного мно- жества из 7 Ы?(1)-таблиц для грамматики из упр. 7.3.1 (а). * 7.4.25. Приведите пример (1,1)-ОПК-грамматики, которая не является SLR(1 (-грамматикой. * 7.4.26. Покажите, что если применить алгоритм 7.9 к мно- жеству 81-Р(1)-таблиц для грамматики, имеющей не более одного цепного правила для каждого нетерминала, то все свертки по цепным правилам будут исключены. Проблемы для исследования 7.4.27. Найдите дополнительные способы построения неболь- ших множеств ЬК(/г)-таблиц для ЬЕ(А)-грамматик, не использу- 115
ГЛ. 7. МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ юшие преобразований, подробно описанных в разд. 7.3. Ваши методы не обязательно должны работать для всех LR(£)-rpaMMa- тик, но они должны быть применимы хотя бы к грамматикам, представляющим практический интерес, например к тем, кото- рые приведены в приложении к тому I. 7.4.28. Когда ЬВ(й)-анализатор достигает ошибочной конфи- гурации, на практике обычно вызывается программа нейтрали- зации ошибок, изменяющая входную цепочку н содержимое магазина так, чтобы можно было продолжить нормальный разбор. Один из методов преобразования ошибочной конфигурации ЬИ(1)-анализатора состоит в том, что на входной лейте разыс- кивается один из определенных входных символов. После того как такой входной символ а найден, в магазине разыскивается таблица g>, построенная по множеству ситуаций Л, со- держащему ситуацию вида [А—>--а, а], A#=S. Процедура нейт- рализации ошибок состоит в удалении всех входных символов вплоть до а и стирании в магазине всех символов и таблиц, расположенных выше Т. Затем в магазин помещается нетерми- нал А и вслед за ним таблица g(A). Из упр. 7.3.8(b) следует, что §(Л)^= ошибка. Суть такого метода нейтрализации ошибок в том, что символы грамматики, расположенные в магазине выше Т, вместе с входными символами вплоть до а рассматриваются как порождение символа А. Оцените эмпирически или теоре- тически эффективность такой процедуры нейтрализации ошибок. Разумным критерием эффективности может служить вероятность правильной нейтрализации ошибок из множества „обычных" оши- бок программиста. 7.4.29. При расщеплении грамматики грамматики-компоиеиты можно анализировать по-разному. Исследуйте методы объедине- ния различных типов анализаторов для грамматик-компонент. В частности, можно ли разбирать одну компоненту снизу вверх, а другую сверху вниз? У пражнения на программирование 7.4.30. Напишите программу, строящую по SLR(I)-rpaMMa- тике множество SLR(] (-таблиц. 7.4.31. Напишите программу, которая в множестве LR(1)-Ta6- лиц находит все недостижимые элементы ошибки. 7.4.32. Напишите программу, строящую по LALR(l)-rpaM- матике LALR(I (-анализатор. 7.4.33. Постройте SLR(l)-aHanH3aTop с нейтрализацией оши- бок для одной из грамматик, приведенных в приложении к тому 1. 116
7.5. АНАЛИЗИРУЮЩИЕ АВТОМАТЫ Замечания по литературе Простые LR(£)-rpaMMaTHKH и ЕАЬР(й)-грамматикн впервые изучались Де Ремером |1969, 1971]. Им же предложен метод построения для грамматики канонического множества ЬР(О)-ситуацин и использования аванцепочек для разрешения неоднозначностей при разборе. Прием расщепления грамматики применительно к LR-анализаторам впервые применил Корёньяк [1969]. Упр. 7.4.1 заимствовано у Эрли [1968]. Процедура нейтрализации оши- бок, описанная в упр. 7,4.28, предложена Ленпиусом [1970]. Упр. 7.4.26 взято из рабозы Ахо и Ульмана [1972 г]. 7.5. АНАЛИЗИРУЮЩИЕ АВТОМАТЫ Вместо того чтобы смотреть на LR-аиализатор как на про- грамму с LR-таблицами в качестве данных, мы будем считать в этом разделе, что LR-таблицы управляют анализатором. Такой взгляд на LR-разбор позволяет разработать другой подход к задаче упрощения LR-анализаторов. Основная идея этого раздела заключается в том, что если LR-таблицы размещаются в управляющем устройстве анализатора, то каждую таблицу можно рассматривать как состояние автомата, реализующего LR-алгоритм разбора. Такой автомат можно рас- сматривать как использующий магазин конечный автомат с „по- бочным эффектом". Методом, аналогичным алгоритму 2.2, можно минимизировать число состояний этого автомата. 7.5.1. Канонический анализирующий автомат В LR-алгоритме разбора решение о переносе или свертке есть результат просмотра k следующих входных символов и обра- щения к управляющей таблице, которой служит таблица, распо- ложенная в верхушке магазина. Если выполняется свертка, то новая управляющая таблица определяется после исследования таблицы, содержавшейся в магазине под свертываемой основой. Вполне можно считать, что сами таблицы являются частями программы, а управление программой в свою очередь представ- ляет собой управляющую таблицу. Типичным примером может служить программа, написанная на некотором легко интерпре- тируемом языке, так что различие между множеством таблиц, управляющих программой разбора, и самой интерпретируемой программой несущественно. Пусть G — LR(O)-rpaMMaTHKa и (^г, Т„) — множество LR(O)- таблиц для G. По множеству таблиц построим для G апализи- рущий автомат, который имитирует поведение ЕВ(0)-алгоритма разбора для G, работающего с множеством таблиц . Отметим, что если Т = <_f, g>— ЕП(О)-таблица из <Sr, то f(e) — это перенос, свертка или допуск. Поэтому можно называть таб- лицы таблицами переноса или свертки в зависимости от значе- 117
ГЛ. 7. МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ ния функции действия. Вначале для каждой таблицы есть одна программа. Эти программы интерпретируются как состояния анализирующего автомата для G. В состоянии переноса Т —<J, g> выполняются такие действия: (I) Имя состояния Т помещается в магазин. (2) Следующий входной символ, скажем а, удаляется из вход- ной цепочки, и управляющее устройство переходит в состоя- ние g(a). В рассмотренных ранее вариантах LR-анализа входной сим- вол а также помещался в магазин вслед за таблицей Т, Но, как уже отмечалось, нет необходимости запоминать в магазине сим- волы грамматики, поэтому вплоть до конца раздела никакие символы грамматики помещать в магазин мы не будем. В состоянии свертки происходит следующее: (I) Пусть Л—>-а—правило i, по которому нужно свернуть. Верхние | а. |—I символов удаляются (выталкиваются) из мага- зина1). (Если а = е, то в верхушке магазина находится управ- ляющее состояние.) (2) Определяется имя состояния, находящегося теперь в вер- хушке магазина. Пусть это состояние T = g>. Управляющее устройство переходит в состояние g(A), и выдается номер пра- вила I. Особо отметим случай, когда действие „свертка" на самом деле означает допуск. В этом случае весь процесс заканчивается и автомат переходит в (допускающее) заключительное состояние. Легко показать, что алгоритм с определенными так состояния- ми работает с магазином в точности так же, как LR(A)-ananH- затор (не считая того, что здесь мы не записываем в магазин символы грамматики), если отождествить имена состояний с име- нами таблиц, из которых состояния получаются. Единственное исключение состоит в том, что ЬД(£)-алгоритм разбора помещает в верхушку магазина имя управляющей таблицы, а здесь имя этой таблицы не записывается в магазин, поскольку оно явля- ется именем таблицы, с которой работает устройство управле- ния программой. Определим теперь анализирующий автомат, непосредственно выполняющий эти действия. Для каждого состояния (т. е. таб- лицы) в смысле, определенном выше, существует состояние авто- мата. Входными символами для такого автомата служат терми- L) Мы убираем из магазина |а| —1, а не | а | символов потому, что таб- лица, соответствующая самому правому символу цепочки а, находится в уп- равляющем устройстве, а ие была помещена в магазин. 118
7.5. АНАЛИЗИРУЮЩИЕ АВТОМАТЫ налы грамматики и сами имена состояний. В состоянии перено- са выполняются действия только над терминалами, а в состоянии свертки—только над именами состояний. В самом деле, переход из состояния Т' в состояние Т, в котором вызывается свертка по правилу А —>а, должен существовать только тогда, когда Т принадлежит 0010(7”, а). Следует помнить, что такой автомат нечто большее, чем ко- нечный автомат, в котором состояния имеют побочные эффекты, связанные с магазином. Другими словами, каждый раз, когда возникает переход в новое состояние, с магазином что-то проис- ходит—свойство, которого лишена модель системы, представ- ляющая собой конечный автомат. Тем не менее можно умень- шить число состояний анализирующего автомата, применяя алгоритм, аналогичный алгоритму 2.2. Отличие в этом случае со- стоит в том, что мы должны быть уверены, что, если два со- стояния попадают в один и тот же класс эквивалентности, все их последующие побочные эффекты совпадут. Дадим теперь фор- мальное определение анализирующего автомата. Определение. Пусть G = (N, 2, Р, S)—ЬЕ(О)-грамматика и (<£Г, 7'0)— ее множество ЬК(О)-таблиц. Определим не полностью определенный автомат М, называемый каноническим анализирую- щим автоматом, как пятерку (S', Sum’ll {$}, б, Т„, где (I) S'—множество состояний, (2) 2 и os7"—множество возможных входных символов (символы из 2 находятся на входной ленте, а символы из оГ — в магазине, по- этому S— не только множество состояний, но и подмножество входов анализирующего автомата), (3) 6—отображение множества. S'X(2u<F) в S', определяе- мое так: (а) если 7'€<F — состояние переноса, то 6(Т, а) = GOTO (Т, а) для всех а £2, / (б) если TPS—состояние свертки, вызывающее свертку по правилу А —>а, и Т' ё GOTO*1 2 (Т, а) (т. е. Т ё GOTO (Г, а)), то 6(Т, 7”) =GOTO (7”, Д), (в) в остальных случаях 6{Т, X) не определено. Канонический анализирующий автомат является конечным преобразователем с побочными эффектами, связанными с магази- ном. Его поведение можно описать в терминах конфигураций, представляющих собой четверки вида (а, Г, ш, л), где (1) а—содержимое магазина (верхний символ расположен справа), (2) Т — управляющее состояние, II»
ГЛ. 7. МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ (3) w— непросмотренная часть входной цепочки, (4) л — порожденная к этому моменту выходная цепочка. Шаги автомата можно изобразить с помощью отношения |—, заданного на множестве конфигураций. Если Т — состояние пе- реноса и б (Т, а) = Т', будем писать (а, Т, aw, л) |— (аТ, Т', w, л). Если Т вызывает свертку по правилу А—>у с номером i и б (Г, Т') = Т", то пишем (аТ'Р, Т, w, л) (— (аТ’, Т", w, ле) для всех р длины |у| — 1. Если | у | = 0, то (а, Т, w, л) (аТ, Т", w, ле). В этом случае Т и Т' совпадают. Заметим, что если считать, что в верхушке магазина может находиться символ управляющего состояния, то получатся конфигурации обычного LR-алгоритма разбора. Отношения |—', |—* и |—+ определяются обычным образом. Начальная конфигурация — это конфигурация вида (е, То, w, е), а допускающая конфигурация имеет вид (Т„, 7\, е, л). Если (е, Т„, w, е) |— * (Т„, 7\, е, л), то л называется разбором, порож- денным автоматом М для цепочки w. Пример 7.32. Рассмотрим ЬК(О)-грамматику G с правилами (1) S—*aA (2) S—<- аВ (3) А—-ЬА (4) А—>с (5) В — ЬВ (6) B-^d порождающую регулярное множество ab* (c + d). На рис. 7.46 представлено множество из десяти ЬР(0)-таблиц для G. Т„, Тг и Т„— состояния переноса. Таким образом, у нас по- лучился анализирующий автомат с правилами переноса б (7’0, а) = Т, б(Т2, с) = Тв б (Л, ф=т, 6 (Л- Ъ)=т„ б (Т5, с) = Т, 6(T„d)=T, Найдем правила перехода для состояний свертки Т„ Tt. Те, Т„ Ts и Tt. Таблица Ts вызывает свертку по правилу S—>аА. Так как GOTO-1(T3, аА) = \Т„\ и GOTO(T0, S) — T1, то един- ственным правилом для Т, будет б (Т3, Tll) = Ti. Таблица Т. 120
7.5. АНАЛИЗИРУЮЩИЕ АВТОМАТЫ вызывает свертку по правилу В—*d. Так как GOTO"1(717, d) = = \Тг, Т:>\, GOTO (Т2, В) = Т4 и GOTO(T5, В) = 7’,, то прави- лами для Т, будут 6(Т„ 7\)--=Tt и S(T7, ТЪ) = Т„. ДейстВие Переход Рис. 7.46. Множество ЬК(О)-таблиц. Полностью правила свертки таковы: 6(Т8, 7\>) = т\ S(T4, То) = л 6(ТС, Т2) = Т3 б(Л, Т5) = Т8 /5(Т„ Та) = Т4 6(Т71Т5) = Т9 '6(Т8, 7\) = Т3 6(Ta,TJ = Ts в(Т„Тг) = Т, 6(Т„, 7\) = 7’s Граф переходов анализирующего автомата изображен на рис. 7.47. Если на вход канонического автомата подать цепочку abc, то он пройдет последовательность конфигураций (е, Т„, abc, е) |— (То, Тг, Ьс, е) Н (ТJ2> Т5, с, е) Н (То7'27’5, 7’в, е, е) Ts, е, 4) Н (Т0Т2, Т3, е, 43) Н(Т0> 7\, е, 431) 121
ГЯ. 7. МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ цепочки abc анализирующий □ Таким образом, для входной автомат порождает разбор 431. Рис. 7.47. Граф переходов канонического автомата. 7.5.2. Расщепление функций состояний Использование анализирующего автомата для построения анализаторов имеет ряд преимуществ перед другими подходами. Например, часто удается расщепить функции некоторых состоя- ний и связать их с двумя различными последовательными сос- тояниями. Если состояние А расщепляется на два состояния А: и А2, а В — иа В, и В2, то иногда можно слить, например, А2 и Вг, в то время как слить А и В нельзя. Так как объем работы, выполненной в состояниях и Аг (или В, и В2), равен объему работы, выполненной в состоянии А (или В), то общее количество работы в результате расщепления не увели- чивается. Вместе с тем, если удается слить состояния, то можно достичь экономии. В этом разделе мы исследуем, как расщепить функции некоторых состояний для того, чтобы затем попытаться совместить общие действия. Каждое состояние свертки расщепим на два состояния: состо- яние выталкивания и следующее за ним состояние опроса. Пред- 122
7.5. АНАЛИЗИРУЮЩИЕ АВТОМАТЫ положим, что Т—состояние свертки, вызывающее свертку по правилу А—* а с номером i. При расщеплении состояния Т образуется состояние выталкивания, единственная функция кото- рого— удалить верхние |а| — 1 символов из магазина. Если а = е, то в состоянии выталкивания в верхушку магазина запи- сывается имя Т. Кроме того, в состоянии выталкивания порож- дается номер правила I. После этого управляющее устройство переходит в состояние опроса, в котором выясняется имя состояния, находящегося в данный момент в верхушке магазина, например U, и происхо- дит переход в состояние GOTO((7, А). Расщепленное состояние сВертки Рис. 7.48. Расщепление состояния свертки В графе переходов состояние свертки Т можно заменить состоянием выталкивания с тем же именем Т и состоянием оп- роса, обозначенным Т'. Все дуги, входящие в старое Т, будут входить также и в новое Т, а дуги, выходящие из старого Т, теперь будут выходить из Т'. Одна непомеченная дуга идет из нового Т в Т'. Это преобразование отражено на рис. 7.48, где правило i есть А—>а. Состояния переноса и состояние допуска не расщепляются. Автомат, построенный по каноническому анализирующему автомату описанным способом, называется расщепленным кано- ническим анализирующим автоматом. Пример 7.33. На рис. 7.49 показан расщепленный автомат, построенный по анализирующему автомату рис. 7.47. Состояния переноса изображены квадратами, состояния выталкивания — тре- угольниками, а состояния опроса и допуска — кружками. 123
ГЛ. 7. МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ Для того чтобы сравнить поведение этого расщепленного ав- томата с поведением автомата из примера 7.32, рассмотрим по- Рис. 7.49. Расщепленный канонический автомат. следовательность тактов, пройденную расщепленным автоматом при разборе входной цепочки abc: (е, Т„, abc, е) (То, Тг, Ьс, е) Н (Т0Т2, Л, с, е) I— (Т0Т27’5, Tt, в, е) Н (Т0Т2Т5, г;, е, 4) н (T0TaT6, Т„ е, 4) 124
7.5. АНАЛИЗИРУЮЩИЕ АВТОМАТЫ н (Т„Л, Т’„ е, 43) Н (ТТ„ е, 43) н Т’, е, 431) Н- (Т„, TIt е, 431) □ Пусть Л-1, и Л42—два анализирующих автомата для грамма- тики G. Будем называть Л4, и Л4а эквивалентными, если для любой входной цепочки w они порождают один и тот же разбор или оба выдают сигнал ошибки, прочитав одинаковое число вход- ных символов. Таким образом, мы пользуемся тем же определе- нием эквивалентности, что и в случае двух множеств Ы?(А)-таблиц. Если канонический и расщепленный канонический автоматы работают параллельно, то легко видеть, что их магазины совпа- дают всякий раз, когда расщепленный автомат переходит в со- стояние переноса или опроса. Поэтому должно быть ясно, что эти два автомата эквивалентны. Расщепленный анализирующий автомат можно упрощать двумя способами. Первый состоит в том, что некоторые состояния, действия которых не нужны, полностью исключаются. При вто- ром способе сливаются неразличимые состояния. В первом слу- чае исключаются некоторые состояния опроса. Автомат, полученный из расщепленного канонического авто- мата после таких упрощений, будем называть полуприведенным. Пример 7.34. Рассмотрим расщепленный анализирующий авто- мат, изображенный на рис. 7.49. Состояния Т', и Т’, имеют ТЗлько по одному переходу — этот переход помечен символом Т„. В результате наших преобразований этн состояния и переходы в То будут исключены. Полученный полуприведеиный автомат показан на рис. 7.50. □ Теорема 7.12. Расщепленный канонический анализирующий ав- томат М, и его полуприведеиный автомат М., эквивалентны. Доказательство. В результате действий, производимых в состоянии опроса, содержимое магазина ие изменяется. Более того, если из состояния опроса Т есть только один переход, то состояние, которым помечен этот переход, должно находиться в верхушке магазина всякий раз, когда Мг переходит в состоя- ние Т. Это утверждение вытекает из определений канонического автомата и функции GOTO. Таким образом, первое преобразо- вание не влияет на последовательности операций с магазином, входом или выходом, совершаемых автоматом. □ Займемся теперь задачей минимизации числа состояний полу- приведенного автомата. Будем сливать состояния, побочные эф- 125
ГЛ, 7. МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ фекты которых (отличные от записи их имен в магазин) совпа- дают и переходы из которых по соответствующим дугам приво- дят к неразличимым состояниям. Алгоритм минимизации анало- гичен по духу алгоритму 2.2, хотя и отличается от него ввиду того, что надо принять во внимание операции с магазином. Определение. Пусть Af = (Q, X, 6, <?„, {gj) — полуприведен- ный анализирующий автомат, где (/„— начальное состояние, а qt— состояние допуска. Заметим, что QsX, Символом е будем „помечать" не помеченные еще переходы. Будем говорить, что р и q из Q О-неразличимы, и писать р =° q, если граф переходов для М удовлетворяет одному из следующих условий (случай p = q не исключается): (1) р и q оба являются состояниями переноса; (2) р и q оба являются состояниями опроса; (3) р и q оба являются состояниями выталкивания, и в этих состояниях автомат удаляет из магазина одинаковое число сим- волов и порождает один и тот же номер правила (другими сло- вами, в состояниях р и q автомат свертывает по одному и тому же правилу); (4) p = q = q1 (заключительное состояние). В остальных случаях р и q О-различимы. В частности, состоя- ния разных типов всегда О-различимы. Будем говорить, что р и q k-не различимы, и писать p~kq, если они (k—1)-неразличимы и удовлетворяется одно из следую- щих условий: (1) р и q являются состояниями переноса и (а) для любого a gS(J{e} дуги, помеченные символом а, либо выходят и из р и из q, либо не выходят ни из р, ни из q; если дуги, помеченные символом а, выходят из р и q и входят в р' и q' соответственно, то р' и q' (k—1 (-неразличимы; (б) нет состояния опроса с переходами, помеченными буквами р и q, в (k — 1)-неразличимые состояния; (2) р и q являются состояниями выталкивания и выходящие из них дуги ведут в (k—1 (-неразличимые состояния; (3) р и q являются состояниями опроса и для всех состоя- ний з либо р и q оба имеют переход на s, либо оба его не имеют (в первом случае переходы происходят в (k— 1)-неразли- чимые состояния). В остальных случаях состояния р и q будем называть k-pas- личимыми. Будем говорить, что р и q неразличимы, и писать p = q, если они ^-неразличимы для любого k^O. В противном случае р и q будем называть различимыми. 126
7.3. АНАЛИЗИРУЮЩИЕ АВТОМАТЫ Лемма 7.4. Пусть M — (Q, X, 6, qa, (у^)—полуприведенный автомат. Тогда (1) =* для всех k есть отношение эквивалентности на Q, (2) если =к = то =i4+1 = ==*+2 = ... . Доказательство. Предлагаем в качестве упражнения (аналог леммы 2.11). □ Пример 7.35. Рассмотрим полуприведенный автомат, изобра- женный на рис. 7.50. Вспомнив множество ЬР(0)-таблиц, по Рис. 7,50. Полуприведенный автомат. которому был построен этот автомат (рис. 7.46), видим, что все шесть состояний выталкивания вызывают свертки по разным правилам, и значит, они О-различимы. Состояния остальных ти- пов по определению 0-неразличимы с состояниями того же типа, так что классы эквивалентности отношения таковы: (7’0, Т2, 7\}, {Л}, ГЛ, {Т.}, {7,}, {Т,}, {Т8}, {TJ, {T't, Т'„ Г„ Т',}. 127
ГЛ. 7. МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ 7.5. АНАЛИЗИРУЮЩИЕ АВТОМАТЫ Для того чтобы найти W, заметим, что состояния 7\ и Ть 1-различимы, так как из Т'„ в О-различимые состояния Т3 и Ts есть переходы с метками Тг и Т,, -соответственно. Далее, Т„ 1-различимо с 7, и Т„, поскольку из первого есть переход с меткой а, а из последних нет. Т'е и Т, 1-различимы, так как из них есть переходы в О-различимые состояния, помеченные именем Т2. Аналогично пары состояний T't и Т'о, Т', и T's, Т'в и Т' 1-различимы. Остальные пары, являющиеся О-неразличимыми, также и 1-неразличимы. Таким образом, классы эквивалент- ности отношения г=‘, содержащие более одного элемента, — это [Гё, 7Д и {Т2, Тё}- Находим далее, что =2 = =*. □ Рис. 7.51. Приведенный автомат. Определение. Пусть 2, б, q6, {9i}) — полуприведеи- ный автомат. Обозначим через Q' множество классов эквива- лентности отношения == Класс эквивалентности, содержащий q, будем обозначать [9]. Приведенным автоматом для УЙХ назовем 128 автомат Af„ = (Q', 2', б', [^0], где (1) 2' = (2 — Q)UQ', (2) б' ([?], а) = [6(9, а)] для всех q£Q и ag2j{e} — Q, (3) б'([9], [р]) = [б(9, р)] для всех q и pEQ. Пример 7.36. В примере 7.35 мы нашли, что T'e—T's и T,ssT',. Приведенный автомат для автомата на рис. 7.50 изображен на рис. 7.51. Состояния Т’, и Т'7 выбраны в качестве представителей двух классов эквивалентности, содержащих более одного элемента. □ Из определения отношения s следует, что определение при- веденного автомата корректно, т. е. правила (2) и (3) определе- ния не зависят от выбора представителя класса эквивалентности. Нетрудно также показать, что приведенный и полуприведен- ный автоматы эквивалентны. По существу, эти два автомата всегда будут совершать аналогичные последовательности тактов. Состояние приведенного автомата представляет класс эквивалент- ности, содержащий соответствующее состояние полуприведенного автомата. Формально это соответствие описано ниже. Теорема 7.13. Пусть М1—полуприведенный автомат и Л12 — соответствующий приведенный автомат. Тогда для всех суще- ствует такая последовательность Tlt... , Тт, Т, что (е, То, w,e)^(TJ\...Tm, Т, х, л) тогда и только тогда, когда (е, [Т„], w, е) ([Л] [Л]- • [Тт], [Г], х, п) где Т,,— начальное состояние автомата Мг, а [н] обозначает класс эквивалентности, содержащий состояние и. Доказательство. Элементарная индукция по i. □ Следствие. М7 и М2 эквивалентны. □ 7.5.3. Обобщение на 1Щ£)-анапизаторы Канонический анализирующий автомат можно построить также и по множеству ЬК(й)-таблиц для КК(й)-грамматики с k > 0. Здесь мы исследуем случай k—l. Анализирующий автомат в этом случае работает во многом аналогично каноническому ана- лизирующему автомату для Ьй(О)-грамматики, не считая того, что о каждой таблице в отдельности нельзя сказать, является ли она таблицей переносов, сверток или допускающей таблицей. Как и ранее, каждой таблице будет соответствовать состоя- ние автомата. Находясь в конфигурации (T0Tt . .. Тт, Т, w, я), автомат действует так: (1) Находит аванцепочку a = FJRST (и>). 5 л. Ахо, Дж. Ульман, т. 2 129
ГЛ. 7. МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ (2) Принимает решение о том, нужно ли выполнить перенос или свертку, т. е. если T = <f, g>, то вычисляется f (а). (а) Если f (а) — перенос, то автомат переходит в кон- фигурацию (Т<1Т1 ... TmT, Т', w', я), где T' = g(a} и aw' = w. (б) Если f (а) — свертка i и правило i есть А—>а, где |а| = г>0, то автомат переходит в конфигурацию (Т0Т, . . . T„_r+1, Т', w, яг), где T'=g' (Л), если Т,„_г+1 = - в’>- (Если правило имеет вид А—>е, то возникает конфигурация (Т„Т1 ... ТтТ, Т', w, ni), где T'=g(A), T = <f, g>-) (в) Если f (а) = допуск или ошибка, то автомат оста- навливается и сообщает, что входная цепочка либо до- пущена, либо отвергнута. Можно по-разному расщепить состояния автомата так, чтобы операции с магазином оказались выделенными, имея при этом в виду слить в дальнейшем общие операции. Здесь мы изучим следующую схему расщепления состояний. Пусть Т — состояние, соответствующее таблице T = (.f,g>. Расщепим его иа состояния чтения, заталкивания, выталкивания и опроса: (1) Образуем состояние чтения Т, в котором считывается следующий входной символ. (Состояния чтения изображены на рисунках кружками.) (2) Если f (а) = перенос, образуем состояние заталкивания Та и проведем дугу, помеченную символом а, из состояния чте- ния Т в это состояние заталкивания. Если g(a) = T', проведем непомеченную дугу/из Та в состояние чтения Т'. Состояние за- талкивания Т“ имеет двойной эффект. Входной символ а уда- ляется из входной цепочки, и имя таблицы Т заталкивается в магазин. (Состояния заталкивания изображены на рисунках квадратами.) (3) Если f (а) = свертка г, образуем состояние выталкива- ния Т, и состояние опроса Т2. Из Т в 7\ проведена дуга, по- меченная символом а. Если правило i есть А—► «, то в состоя- нии Т\ из магазина удаляются верхние | а | — 1 символов и по- рождается номер правила г. Если а = е, то в состоянии Т, в ма- газин помещается имя исходной таблицы Т. (Состояния вытал- кивания изображены треугольниками.) Затем из Tt в Т2 проведем непомеченную дугу. В состоянии Т2 выясняется, какой символ находится в данный момент в верхушке магазина. Если GOTO-1(7’, а) содержит Т', a GOTO(T', А) = Т", проведем из Т2 в состояние чтения Т" дугу, помеченную символом Т'. (Состоя- ния опроса также изображаем кружками. Метки на дугах отли- чают эти состояния от состояний чтения.) 130
7.5. АНАЛИЗИРУЮЩИЕ АВТОМАТЫ Таким образом, если f (с) = перенос и f (b) = свертка i, то состояние Т будет выглядеть так, как показано на рис. 7.52. (4) Состояние допуска не расщепляется. Состояние чтения */ Т \ Состояние / 1 у&нталкивония '‘свертка /\ Состояние а (г\ ~с‘стсяние заталкивания \J2 ) опроса Рис. 7.52. Возможное представление состояния Т. Пример 7.37. Рассмотрим Ьр(1)-грамматику с правилами (1) S-+AB (2) А—>аАЬ (3) А—*е (4) В—+ЬВ (5) В— b Множество ЬИ(1)-таблиц для G приведено на рис. 7.53. Действие а Ь е S Переход А В а ь То S 3 X Л Тг X Тз X л X X А X X X X X Тг X S X X X Тг X Тз Тз S 3 X X Т6 X Тз X Тг X Л 1 X X X X X Тз X S 5 X X Т7 X Тз т6 X 5- X X X X X Тз т7 X X 4 X X X X X h X 2 X X X X X X Рис. 7.53. Множество ЬК(1)-табл1Ш- Анализирующий автомат, получающийся в результате при- менения описанной выше процедуры расщепления состояний, изображен на рис. 7.54. □ 131
ГЛ. 7. МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ Рис. 7.54. Расщепленный автомат для 1,1?(1)-грамматики. Число состояний расщепленного автомата для Ы?(1)-грамма- тики можно уменьшить несколькими способами: (1) Если из состояния опроса выходит только одна дуга, это состояние опроса можно выбросить. Это упрощение в точности аналогично соответствующему ЬК(0)-упрощению. М2
7.5. АНАЛИЗИРУЮЩИЕ АВТОМАТЫ (2) Пусть Т — такое состояние чтения, что в каждом нуги, ведущем в Т, последняя дуга, входящая в состояние выталки- вания, всегда помечена одним и тем же входным символом или символом е. Тогда состояние чтения можно исключить. (Можно видеть, что в этом случае состояние выталкивания имеет только одну исходящую дугу и она помечена этим символом.) Пример 7.38. Рассмотрим автомат, показанный на рис. 7.54. У него три состояния опроса со степенью по выходу 1, а имен- Начило Рис. 7.55. Полуприведенный автомат. но Т'о, Т'3 и T't. Эти состояния и исходящие из них дуги мож- но выбросить. Исследуем состояние чтения Т„. В состояние Т, можно попасть только по путям, выходящим из Т3 и Т'3 или из Та и Т'я. В обоих случаях меткой предыдущего входного символа служит Ь, т. е. если в состоянии Ts или Та на входе появляется Ь, то автомат переходит в состояние Т, или Тья для выполнения сверт- ки. Символ b остается во входной цепочке до тех пор, пока 133
ГЛ. 7. МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ автомат, находясь в состоянии Т„ не прочтет его и не решит перейти в состояние Ть„ для выполнения переноса. Так как известно, что Ь на самом деле появляется во входной цепочке, состояние Т, лишнее; в состоянии Tbs автомат может поместить имя состояния Та в магазин, не считывая следующего входного символа, так как если автомат достиг состояния Те, то этим входным символом должен быть символ Ь. Аналогично можно исключить состояние Т2. Полученный в результате автомат показан на рис. 7.55. □ Как и в случае полуприведенного ЬК(0)-автомата, можно слить совместимые состояния, не затронув поведения автомата. Предоставляем читателю рассмотреть этот вопрос самостоятель- но. На рис. 7.55 можно слить только пару Г, и Т'7. 7.5.4. Обзор содержания главы В этой главе мы изложили ряд методов, применяемых для уменьшения размера и повышения скорости работы синтакси- ческих анализаторов. Как же нужно действовать при построе- нии анализатора для данной грамматики с точки зрения всех предоставляемых возможностей? Во-первых, надо принять решение о том, каким методом раз- бора воспользоваться — восходящим или нисходящим. Соответст- вующее решение принимается в зависимости от того, какой пе- ревод нужно получить. Этот вопрос мы рассмотрим в гл. 9. Если удобно воспользоваться нисходящим анализатором, то рекомендуется ЬЬ(1)-анализатор. Для построения такого анали- затора требуется проделать следующее: (1) Преобразовать грамматику в ЬЬ(1)-грамматику. Исходная грамматика очень редко оказывается ЬЬ(1)-грамматикой. Основ- ными средствами такого преобразования служат левая фактори- зация и исключение левой рекурсии, но гарантировать, что эти преобразования обязательно приведут к успеху, нельзя. (См. примеры 5.10 и 5.11 в томе 1.) (2) Если же удается получить эквивалентную ЬЬ(1)-грамма- тику G, то с помощью методов разд. 5.1 (в частности, с помо- щью алгоритма 5.1) легко построить для G ЬЬ(1)-таблицу раз- бора. Элементами этой таблицы на практике будут обращения к программам, которые оперируют с магазином, генерируют выходную цепочку или выдают сообщения об ошибках. (3) Для уменьшения размера таблицы разбора применяются два метода: (а) Если правило начинается с терминального символа, то этот терминальный символ нет необходимости помещать в магазин, если входной указатель перемещается. (Другими 134
7.5. АНАЛИЗИРУЮЩИЕ АВТОМАТЫ словами, если нужно воспользоваться правилом А—» аа и а—текущий входной символ, то а помещается в магазин, а входная головка сдвигается на один символ вправо.) Этот метод позволяет уменьшить число различных симво- лов, появляющихся в магазине и, следовательно, число строк в ЬЬ(1)-таблице разбора. (б) Некоторые нетерминалы с аналогичными действиями разбора можно объединить в один нетерминал с „индика- тором“, указывающим, какой нетерминал он представляет. Такому объединению легко поддаются нетерминалы, пред- ставляющие выражения. (См. упр. 7.3.28 и 7.3.31.) Если удобно воспользоваться восходящим анализатором, то рекомендуется детерминированный алгоритм разбора типа „пере- нос— свертка", такой, как 8Ы?(1)-анализатор или LALR(l)-aHa- лизатор. Синтаксис большинства языков программирования легко описать с помощью 8ЬК(1)-грамматики, так что предва- рительно требуется лишь немного видоизменить исходную грам- матику. Применение методов оптимизации позволяет существенно уменьшить размер SLR(l)- или ЬАЬК(1)-анализатора. Обычно имеет смысл исключить свертки по цепным правилам. Дальнейшее уменьшение размера анализатора возможно, если ЬАЬК(1)-анализатор реализуется в виде анализатора на языке Флойда—Эванса из разд. 7.2. Элементы действия каждой LR(1)- таблицы можно представить в виде последовательности опера- торов переноса, за которыми следуют операторы свертки, за кото- рыми в свою очередь следует один безусловный оператор ошибки. Если все операторы свертки включают одно и то же правило, то всех их вместе с последующим оператором ошибки можно заменить одним оператором, свертывающим в соответствии с этим прави- лом независимо от входной цепочки. Способность анализатора обнаруживать ошибки при такой оптимизации не затрагивается. См. упр. 7.3.23 и 7.5.13. Элементы перехода каждой LR(1)- таблицы, отличные от ср, запоминаются в виде списка пар (А, Т), означающих, что на нетерминале А в верхушку магазина поме- щается таблица Т. Переходы, отвечающие терминалам, можно закодировать в самих операторах переноса. Заметим, что эле- менты <р запоминать не требуется. После этого можно пользо- ваться методами оптимизации, описанными в разд. 7.2 и состоя- щими в том, что общие последовательности операторов сливаются. Такие подходы к построению анализаторов обладают рядом практических преимуществ. Во-первых, полученный анализатор можно чисто механически отладить, порождая входные цепочки, позволяющие проверить поведение анализатора. Например, легко построить входные цепочки, проверяющие каждый полезный элемент LL(1)- или 1^(1)-таблицы. Другое преимущество LL(1)- и ЬК(1)-анализаторов, особенно первого из них, связано с тем, 135
ГЛ. 7, МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ что небольшие изменения в синтаксис или семантику можно внести, просто изменив соответствующие элементы таблицы разбора. Наконец, читатель может убедиться в том, что некоторые неоднозначные грамматики имеют “LL”- или “LR’’-анализаторы, образованные в результате того, что конфликты разбора разре- шаются некоторым произвольным образом (упр. 7.5.14). Кон- струирование анализаторов такого типа составляет предмет дальнейших исследований. УПРАЖНЕНИЯ 7.5.1. Постройте для грамматики G„ анализирующий авто- мат М. Постройте по М эквивалентные расщепленный, полупри- веденный и приведенный автоматы. 7.5.2. Постройте анализирующие автоматы для всех грамма- тик из упр. 7.3.1. 7.5.3. Расщепите состояния автоматов из упр. 7.5.2 для по- строения приведенных анализирующих автоматов. 7.5.4. Докажите лемму 7.4. 7.5.5. Докажите, что определение приведенного автомата, данное в разд. 7.5.2, корректно, т. е. если pssq, то 6(р, а) = а) для всех а из S'uje}. 7.5.6. Докажите теорему 7.13. Определение. Пусть G = (N,2, Р, S') — пополненная КС-грам- матика, правила которой занумерованы числами 0,1, ... так, что нулевое правило есть S' —► S. Пусть S' = (#0, ..— множество специальных символов, не принадлежащих N U 2. Пусть i-e правило имеет вид А—ДЗ и S' =>’, aAw=$>rafiw. Тогда “Р#/ называется характеристической цепочкой правовыводимой цепочки ajiw. *7.5.7. Покажите, что множество характеристических цепочек для КС-грамматики регулярно. 7.5.8. Покажите, что КС-грамматика G однозначна тогда и только тогда, когда каждая правовыводимая цепочка грамма- тики G, за исключением S', имеет единственную характеристи- ческую цепочку. 7.5.9. Покажите, что КС-грамматика является Ы?(й)-грамма- тикой тогда и только тогда, когда любая правовыводимая це- почка офш, для которой S' =>* oiAw—er apto, имеет характеристи- ческую цепочку, которую можно найти, зная только аб и HlRSTt(io). 136
УПРАЖНЕНИЯ 7.5.10. Пусть G = (N, S, Р, S) — 1.К(0)-грамматика и Щ?-, 7„) — ее каноническое множество ЬЯ(0)-таблиц. Пусть /И = (^, 2 U 6, Т„ {7’J)— канонический анализирующий автомат для G. Пусть ЛГ = (<sT U {<?/}, 2 U S', 6', Т„, {<?/})—детерминированный конечный автомат, построенный по М следующим образом: (1) 6'(Т, а] = 6(7", а) для всех 7'£ и (2) 6'(Т, #;) = 7/, если 6(7", 7"') определено и Г'—состояние свертки, вызывающее свертку по правилу I. Покажите, что L(M') — множество характеристических цепочек для G. 7.5.11. Напишите алгоритм слияния „эквивалентных" состоя- ний полуприведенного автомата, построенного для LR(1 ^грам- матики. Эквивалентными здесь называются состояния, переходы из которых помечены одним и тем же множеством символов, причем одинаково помеченные переходы ведут в эквивалентные состояния т). 7.5.12. Предположим, что мы изменили определение эквива- лентности, данное в упр. 7.5.11, так, что эквивалентными теперь считаются и те состояния, переходы из которых, помеченные символом а, всегда, когда они существуют, ведут в эквивалент- ные состояния. Будет ли полученный автомат эквивалентен (в формальном смысле, т. е. при условии, что перенос запрещен, если исходный автомат сообщил об ошибке) полуприведенному автомату? 7.5.13. Предположим, что в ЬК(1)-анализирующем автомате из состояния чтения Т переходы происходят только в состояния выталкивания, свертывающие по одному и тому же правилу. Покажите, что если исключить Т и слить все эти состояния выталкивания в одно состояние, то новый автомат будет сверты- вать независимо от авапцепочки, но останется эквивалентным исходному автомату. 7.5.14. Пусть G — однозначная грамматика с правилами S —► if Ь then SE | а Е —>else S | е (а) Покажите, что L(G) не является LL-языком. (б) Постройте для G 1 -предсказывающий анализатор, считая, что всякий раз, когда в верхушке магазина находится символ Е, а следующим входным символом является else, нужно применить правило Е—►elseS. (в) При аналогичных предположениях постройте для G LR(1)- анализатор. ) Это определение можно сделать точным, задав отношения =•,’, ..., как это делалось в лемме 7.2. 137
ГЛ. 7. МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ Проблемы для исследования 7.5.15. Примените используемый метод, а именно разбиение анализатора на ряд активных компонент и слияние или исключе- ние некоторых из них, к анализаторам, отличным от LR-анали- заторов. Например, в методе, описанном в разд. 7.2, активными компонентами были строки матрицы предшествования. Разрабо- тайте методы, применимые к LL-анализаторам и различным типам анализаторов предшествования. 7.5.16. Некоторые состояния канонического анализирующего автомата обладают тем свойством, что автомат с такими состоя- ниями распознает только регулярные множества. Рассмотрим задачу расщепления состояний переноса анализирующего авто- мата на состояния просмотра и заталкивания. В состоянии про- смотра могут просматриваться входные символы и генерироваться выходная цепочка, но не производится никаких действий с ма- газином. После состояния просмотра управление передается в другое состояние просмотра или в состояние заталкивания. Таким образом, множество состояний просмотра работает как конечный преобразователь. В состоянии заталкивания в магазин помещается имя текущего состояния. Разработайте преобразова- ния, с помощью которых можно оптимизировать анализирующий автомат с состояниями просмотра и заталкивания, а также с рас- щепленными состояниями свертки. 7.5.17. Опишите методы оптимизации из разд. 7.3 в терминах методов из разд. 7.5 и наоборот. Упражнения на программирование 7.5.18. Разработайте элементарные операции, необходимые для реализации расщепленного канонического автомата. Пост- ройте для них интерпретатор. 7.5.19. Напишите программу, получающую на вход расщеплен- ный канонический автомат и строящую по нему последователь- ность элементарных операций, моделирующую поведение анали- зирующего автомата. 7.5.20. Постройте для одной из грамматик из приложения к тому 1 два ЬЙ(1)-анализатора. Один ЬР(1)-анализатор должен быть ЬЯ(1)-анализатором интерпретирующего типа, работающим с множеством ЬЕ(1)-таблиц. Другой—последовательностью эле- ментарных операций, моделирующей анализирующий автомат. Сравните размеры и скорости работы этих анализаторов. Замечания по литературе Подход, использующий анализирующий автомат, предложен Де Ремером (1969]. Определение характеристической цепочки, предшествующее упр. 7.5.7, заимствовано из того же источника. Классы неоднозначных грамматик, раз- бираемых LL- или LR-анализаторами, рассматривались Ахо и др. [1972].
ТЕОРИЯ 8 ДЕТЕРМИНИРОВАННОГО РАЗБОРА В гл. 5 мы познакомились с различными классами грамматик, для которых удается построить эффективные детерминированные синтаксические анализаторы. Были продемонстрированы некото- рые отношения включения на классах грамматик. Например, мы показали, что каждая (т, &)-ОПК-грамматика является LR(fe)- грамматикой. В настоящей главе мы пополним иерархию соотно- шений между различными классами грамматик. Можно задаться вопросом о том, какой класс языков порожда- ется грамматиками из данного класса. В этой главе мы увидим, что большинство классов грамматик из гл. 5 порождает в точности детерминированные КС-языки. Точнее, будет показано, что каждый из следующих классов грамматик порождает в точности детерми- нированные КС-языки: (1) ЬК(1)-грамматнки, (2) (1,1)-ОПК-грамматики, (3) обратимые грамматики (2,1 (-предшествования, (4) простые грамматики со смешанной стратегией предшество- вания. При выводе этих результатов применяются алгоритмы преобразо- вания грамматик одного типа в грамматики другого типа. Таким образом, для каждого детерминированного КС-языка можно найти грамматику, анализируемую с помощью алгоритма обратимого (2,1 (-предшествования или алгоритма со смешанной стратегией предшествования. Однако многие из этих преобразующих алго- ритмов зачастую дают грамматики, слишком большие для прак- тического использования. Интерес представляют три собственных подкласса детермини- рованных КС-языков: (1) языки простого предшествования, (2) языки операторного предшествования, (3) LL-языки. 139
ГЛ. S. ТЕОРИЯ ДЕТЕРМИНИРОВАННОГО РАЗБОРА Языки операторного предшествования образуют собственный под- класс языков простого_.предшествования, и он не сравним с клас- сом LL языков. В гл. 5 мы видели, что класс языков, порождаемых обратимыми грамматиками слабого предшествования, совпадает с классом языков простого предшествования. Эта иерархия язы- ков отражена на рис. 8.1. Рис. 8.1. Иерархия детерминированных КС-языков. (ПП — языки простого предшествования, ОП — языки операторного предшествования.) В данной главе мы получим эту иерархию и отметим наибо- лее характерные черты каждого класса языков. Глава состоит из трех разделов. В первом изучаются LL-языки и их свойства. Во втором рассматривается класс детерминированных языков, а в третьем —языки простого и операторного предшествования. Эта глава является своего рода лакомством — при строгой диете теории компиляции она не существенна, и при первом чте- нии ее можно опустить *)• х) Впрочем, читатели, которые не любят лакомств, могут вовсе к ней не возвращаться. 140
8.1. ТЕОРИЯ LL-ЯЗЫКОВ 8.1. ТЕОРИЯ LL-ЯЗЫКОВ Начнем с основных результатов, касающихся LL-языков и грамматик. Мы докажем следующие шесть утверждений: (1) Каждая Ы.(6)-грамматика является ЬК(й)-грамматикой (теорема 8.1). (2) Для каждого ЬЬ(/г)-языка существует LL(fe + 1)-грамматика в нормальной форме Грейбах (теорема 8.5). (3) Проблема, эквивалентны ли две произвольные LL-грамма- тики, разрешима (теорема 8.6). (4) Язык, не содержащий пустого слова, является Ыд/г)-язы- ком тогда и только тогда, когда он имеет неукорачивающую (т. е. без е-правил) LL(A 4- 1)-грамматику (теорема 8.7). (5) Для k 5s 0 множество ЬЬ(/г)-языков является собственным подмножеством множества LL(£-j- 1)-языков (теорема 8.8). (6) Существуют LR-языки, не являющиеся LL-языками (упр. 8.1.11). 8.1.1. LL- и LR-грамматики Докажем сначала, что каждая ЬЬ(£)-грамматика является ЬК(/г)-грамматикой. Это утверждение неформально можно обосно- вать так. Рассмотрим дерево вывода, изображенное схематически на рис. 8.2. Согласно ЬК(й)-условию, при просмотре входной цепочки wxy правило А —► а должно распознаваться после того, как станут известны подцепочка wx и мно- жество FIRST,,(у). С другой стороны, в ЬЬ(А)-условии для распознавания пра- вила А—► а требуется знать только w и FIRSTA(xt/). Поэтому ЬЬ(/г)-условие должно быть более сильным, чем ЬК(/г)-условие, так что каждая LL(ft)- грамматика должна быть 7Р(7г)-грамма тикой. Опишем теперь это формально. Рис. 8.2. Набросок де- Пусть дана Ы-(/г)-грамматика Сив рева вывода. ней два дерева разбора. Допустим, что первые m символов крон этих двух деревьев совпадают. Тогда каждой вершине одного дерева, слева от которой находится не более т— k листьев, помеченных терминалами, соответствует „идентичная" вершина в другом дереве.. Эта связь изображена на рис. 8.3, где заштрихованная область представляет „идентич- ные" вершины. Мы считаем, что |ш| = т — k и FIRST^Xj) = =FIRST4(x,). Сформулируем наш результат в виде леммы: 141
ГЛ, 8. ТЕОРИЯ ДЕТЕРМИНИРОВАННОГО РАЗБОРА Лемма 8.1. Пусть G — LL(k)-apaMMamuKa и и S=^1‘‘ w2B[} =ф’w2x2 — два таких левых вывода, что FIRST!(oa1xI) = FIRST;(E®ax2) при I = k + max(| wt |, |ш>2|). (Другими словами, по крайней мере k сим- волов, стоящих в uLxL и w2x2 после wt и wt, совпадают.) (1) Если т1 = тг, то wt = w2, А = В и а = р. (2) Если т2<т2, то S=y'": w28(i=£* w2x2. 5 5 Рис. 8.3. Два дерева разбора для Ы.(£)-грамматики. Доказательство. По определению ЬЦй)-грамматики при т., < т2 первые т, шагов вывода 5=Ф/Я’ w2Bf} представляют собой вывод wtAa, так как на каждом шаге этих выводов аван- цепочки совпадают. Отсюда сразу следуют утверждения (1) и (2). □ Теорема 8.1. Всякая Ъ'Цкуграмматика'} является LR(ft)- грамматикой. Доказательство. Пусть G = (N, S, Р, S) — ЬЦ/г)-грамма- тика. Предположим, что она не ЬР(/г)-грамматика. Тогда в по- полненной грамматике существуют такие два правых вывода (8.1.1) S' =ф' о.Ах, =t>r afixi (8-1-2) 8х у убу что убу — сфх2 для некоторой цепочки х2, для которой FIRSTt(x,) = = FIRST4(x1). Поскольку G по предположению не LR(1 ^грамма- тика, можно считать, что аАх2=^уВу. Можно считать, что в обоих этих выводах i и / оба больше нуля. В противном случае было бы, например, S' =р» 8' =р 8 S=>+ By=t>Sfy J) Везде в этой книге предполагается, что грамма |ика не имеет бесполез- ных правил. 142
8.1. ТЕОРИЯ LL-ЯЗЫКОВ а это означало бы, что G леворекурсивна и, следовательно, не является LL-грамматикой. Поэтому в оставшейся части доказа- тельства мы будем считать, что в выводах (8.1.1) и (8.1.2) S' можно заменить на S. Пусть ха, хр, xv и х&—терминальные цепочки, выводимые из а, Р, у и 6 соответственно, причем хах^х2 = х^хцу. Рассмотрим левые выводы, соответствующие выводам (8.1.3) S =$’, aAxt =4>r apZj =*) xax^xt (8.1.4) S =4>* уВу =4>z убу =4>" х,,Х/,у Точнее, пусть (8.1.5) S i ХаА 1| =£>г -ТаРп I ХаХрЦ =Ф i XaX$Xf (8.1.6) S i xyBQ х-убО=i ХуХ^у где р и 0 — подходящие цепочки из (Nu2)*. Согласно лемме 8.1, либо последовательность шагов в выводе £=>)л,Лц представляет собой начальную последовательность шагов в выводе S=4>)xvB0, либо обратно. Исследуем первый слу- чай; второй исследуется аналогично. Итак, вывод 8.1.6 можно записать в виде (8.1.7) S —хаАи] х«Рт] -->>/ х.рВ0 i Ху60 ==^iX.^.v.,0 —х^х^у Рассмотрим дерево разбора Т, соответствующее выводу (8.1.7). Пусть пА— вершина, отвечающая в цепочке xaAt) символу А, а пл— вершина, отвечающая в цепочке х.,В0 символу В. Эти вер- шины показаны на рис. 8.4. Заметим, что »й может быть потомком вершины пд. Цепочки xti и х6 не могут перекрываться частично: либо они не пересекаются, либо лу— подцепочка цепочки хц. Мы изобразили их на рис. 8.4 частично перекрывающимися лишь для того, чтобы легче было рассуждать в обоих случаях. Рассмотрим теперь два правых вывода, связанных с деревом разбора Т. В первом Т расширяется вправо до вершины пА включительно; во втором Т расширяется вплоть до вершины пв. Последний вывод можно записать так: S =>) уВу=Фг убу На самом деле это вывод (8.1.2). Правый вывод вплоть до вер- шины пА имеет вид (8.1.8) S =ФГ* а'Лх2 =ФГ а'0х2 для некоторой цепочки а'. Потом мы докажем, что а'= а, а сей- час примем это на веру и, получив противоречие Ы.(/г)-условию, докажем тем самым теорему. Итак, пусть а'=а. Тогда убу = а'рх2 = а0х2. Поэтому для продолжения выводов (8.1.2) и (8.1.8) до терминальной цепочки 143
ГЛ. 8. ТЕОРИЯ ДЕТЕРМИНИРОВАННОГО РАЗБОРА х,,Х(.у можно использовать один и тот же правый вывод. Но по- скольку мы считаем вершины пА и пв различными, выводы (8.1.2) и (8.1.8) различаются, а, следовательно, различаются и закон- ченные выводы. Отсюда вытекает, что цепочка xvx^y имеет два разных правых вывода и, значит, грамматика G неоднозначна. Согласно упр. 5.1.3, LL-грамматика не может быть неоднозначной. Поэтому G вопреки допущению не является LL-грамматикой. S Рис. 8.4, Дерево разбора Т. Теперь докажем, что а' = а. Заметим, что цепочка а'состав- лена из выписанных слева направо меток тех вершин дерева Т, прямой предок которых является предком вершины пА. (Чита- тель может самостоятельно проверить это свойство правых выво- дов.) Рассмотрим опять левый вывод (8.1.5), имеющий то же самое дерево разбора, что и правый вывод (8.1.3). Пусть Т'— дерево разбора, связанное с выводом (8.1.3). Шаги вывода (8.1.5) вплоть до получения цепочки xaAi] совпадают с шагами выво да (8.1.7) вплоть до получения цепочки хаЛт]. Пусть п'А— вер- шина дерева Т", соответствующая нетерминалу, который в вы- воде (8.1.7) заменяется на шаге xaArj =>, хи|3т]. Пусть П — прямо упорядоченное1) множество внутренних вершин дерева разбора Т вплоть до вершины пА, а П' — прямо упорядоченное множество внутренних вершин дерева Т' вплоть до вершины п'А. Тогда i-я 1) П—это последовательность внутренних вершин дерева Т, взятых в том порядке, в котором нетерминалы, отвечающие этим вершинам, разворачиваются в левом выводе. 144
8.1. ТЕОРИЯ LL-ЯЗЫКОа вершина множества П согласуется с i-й вершиной множества 1Г в том смысле, что обе они имеют одинаковые метки и их соот- ветствующие потомки либо согласуются, либо расположены справа от пА и п'А соответственно. Вершины дерева Т', прямым предком которых является пре- док вершины пА, имеют такие метки, что если их выписать слева направо, они образуют цепочку а. Но эти вершины согла- суются с теми вершинами дерева Т, которые образуют а', поэтому а'=а. Теорема доказана. □ Грамматика S—► Л] В А-,аА1>\0 В .аВЬЬ | 1 6 пг d Рис. 8.5. Соотношения между классами грамматик. (ЛГ — левоанализпруемые грамматики, ПГ — правоанализируемые грамматики.) является ЬЯ(0)-грамматикой, но не LL-грамматикой (пример 5.4), так что включение класса LL-грамматик в класс LR-грамматик собственное. На самом деле, если рассмотреть классы LL- и LR- грамматик вместе с классами левоанализнруемых и правоапали- зируемых (при помощи ДМП-автомата с концевым маркером) грамматик, то, согласно теоремам 5.5, 5.12 и 8.1, получится картина, изображенная на рис. 8.5. Мы утверждаем, что каждый из шести классов грамматик на рис. 8.5 непуст. Мы знаем, что LL-грамматика существует, так что надо доказать следующее: 145
ГЛ. 8. ТЕОРИЯ ДЕТЕРМИНИРОВАННОГО РАЗБОРА Теорема 8.2. Существуют грамматики, которые являются (1) LR и левоанализируемыми, но не LL, (2) "LR, но не левоанализируемыми, (3) лево- и правоанализируемыми, но не LR, (4) правоанализируемыми, но не LR и не левоанализируемыми, (5) левоанализируемыми, но не правоанализируемыми. Доказательство. Каждая из следующих грамматик при- надлежит соответствующему классу. (1) Грамматика Ga с правилами А —>- ааА | аа В —► ааВ|а является LR(1) и левоанализируемой, но не LL. (2) Грамматика Gb с правилами АЬ\Ас А-*Ав\а В —> а является LR(1), но не левоанализируемой. (См. пример 3.27, том 1.) (3) Грамматика Gc с правилами S АЬ | Вс А —► Аа | а В—>Ва\а является лево- и правоанализируемой, но не LR. (4) Грамматика Gd с правилами 5^ЛЬ|Вс А —> Ас | а В —> Вс | а С—>а является правоанализируемой, ио не LR и не левоанализируемой. (5) Грамматика Ge с правилами S^B/U)|C4c А—>ВА\а В-^а С -а является левоанализируемой,но не правоанализируемой. (См. при- мер 3.26, том 1.) □ 146
8.1. ТЕОРИЯ LL-ЯЗЫКОВ 8.1.2. LL-грамматики в нормальной форме Грейбах В настоящем разделе мы рассмотрим преобразования LL-грам- матик, сохраняющие LL-свойство. Наши первые результаты касаются «-правил. Мы дадим два алгоритма, применяя которые последовательно, можно преобразовать ЕБ(/г)-грамматику в экви- валентную LL(fe + 1)-грамматику, не содержащую е-правил. Пер- вый алгоритм изменяет грамматику так, чтобы каждая правая часть либо стала равна е, либо начиналась с символа (возможно, терминального), из которого не выводится пустая цепочка. Вто- рой алгоритм преобразует грамматику, удовлетворяющую этому условию, в грамматику без «-правил. Оба алгоритма сохраняют LL-свойство грамматики. Определение. Пусть G = (N, 2, Р, S) — КС-грамматика. Будем называть нетерминал А исчезающим, если из А выводится пустая цепочка. В противном случае символ из N и 2 назовем неисче- зающим. Таким образом, каждый термина л — неисчезающий символ. Будем говорить, что грамматика G удовлетворяет условию («), если каждое правило из Р имеет вид А—>«илиА—i-Xj... Xk, где X,— неисчезающий символ1). Алгоритм 8.1. Преобразование грамматики в грам- матику, удовлетворяющую условию (*). Вход. КС-грамматика G = (N, S, Р, S). Выход. КС-грамматика G^fNp S, Plt S,), удовлетворяющая условию (*), для которой L(G1)=Z-(G)— {«}2). Метод. _ (1) Пусть N' = N U {А | А—исчезающий нетерминал из N}. Из не- терминала А будут выводиться те же цепочки, что и из А, за исключением е. Следовательно, А будет неисчезающим. (2) Если egZ,(G), положим S^S. В противном случае А. (3) Каждое правило из Р, не являющееся «-правилом, можно единственным образом представить в виде А —► Bt ... BaXt ...Хп (где т>0, л>0 и m-|-/i>0), причем каждый символ В,-исче- зающий и, если и > 0, Xi — неисчезающий символ. Остальные X, (l</^/i) могут быть как исчезающими, так и неисчезаю- щими. Таким образом, Хг— самый левый неисчезающий символ в правой части правила. Для каждого правила А—-Bj... B„Xt. ..Х„, не являющегося «-правилом, построим Р': ’) В оригинале такая грамматика называется nonnullable.— Прим, иерее. 2) Получаемая по алгоритму 8.1 грамматика Gi ие эквивалентна исход- ной. Следуя примеру авторов, рекомендуем читателю самому в качестве упраж- нения найти и исправить ошибки алгоритма 8.1.—Прим. ред. 147
ГЛ. 8. ТЕОРИЯ ДЕТЕРМИНИРОВАННОГО РАЗБОРА (а) если mjsl, включим в Р' т правил А^В.В, ... ВтХг ... Х„ А —► В,В3 ... ВтХ1 ... Хп А — ВтХ1...Х„ (б) если п~^Л и т^О, включим в Р' правило А Хх . .. Х„ (в) кроме того, если А— исчезающий символ, включим в Р' все правила из (а) и (б), где слева вместо А стоит А. (4) Если правило А—>е принадлежит Р, включим в Р' пра- вило А—>е. (5) Положим G1 = (N1, 2, Pt, SJ, где Gr — это грамматика G' = (N', 2, Р', SJ, из которой выброшены все бесполезные сим- волы и правила. □ Пример 8.1. Пусть G — ЬЦ1)-грамматика с правилами S-, АВ А —► аА | е В —>ЬА \ е Здесь все нетерминалы исчезающие, так что введем новые не- терминалы S, А и в; первый из них будет новым начальным символом. Правила А—>аА и в—-ЬА оба начинаются с пеис- чезающего символа, поэтому их правые части имеют вид XLX2 (для шага (3) алгоритма 8.1). Таким образом, эти правила будут сохранены, а к множеству правил добавятся еще правила А—аА В—>ЬА В правиле S—>AB все символы правой части исчезающие, так что ее можно записать в виде BjB2. Это правило заменяется на четыре правила _ _ S— ЛВ|В S — АВ\В Так как S— новый начальный символ, находим, что символ S теперь недостижим. Окончательное множество правил, построен- ие
8.1. ТЕОРИЯ LL-ЯЗЫКОВ ное по алгоритму 8.1, таково: S^AB\B А —> а А А —► а А | е В^ЪА В-+ЬА\е П Докажем, что алгоритм 8.1 сохраняет свойство грамматики быть Ы_(/г)-грамматикой. Теорема 8.3. Пусть G,— грамматика, полученная из G по алгоритму 8.1. Тогда (1) L(Gl)=L(G)-H, (2) если G — LL(k)-zpaMMamuKa, то G,— тоже LL(k)-zpaM- матика. Доказательство. (1) Индукцией по длине цепочки можно показать, что для всех Л из N (а) Л=>с, w тогда') и только тогда, когда Л=>^ю, (б) A=±>*g,w тогда1) и только тогда, когда и A=i>gw. Подробное доказательство оставляем читателю в качестве упраж- нения. Утверждение (2) докажем от противного. Допустим, что оно неверно. Тогда в GI можно найти выводы Sj =>с,( =>с,г енх Sj =>о, ®Ла=>С1< К)уа=>с,г wy где FIRSTt(x) — FlRSTt(y), и Л—либо Л, либо А. По этим двум выводам можно построить соответствующие вы- воды цепочек шх и wy в грамматике G. Начнем с того, что опре- делим Л(Л) = Л(Л) = Л для N и h(a)=a для agS. Для каждого правила В —* б из Р, найдем в Р правило В—»6'/г(6), из которого оно было построено на шаге (3) алго- ритма 8.1. Другими словами, B = h(B), а 6'—некоторая (воз- можно, пустая) цепочка исчезающих символов. Всякий раз, когда правило 8 —>-6 применяется в каком-нибудь из выводов в грам- матике Gj, в соответствующем выводе в грамматике G заменим его правилом В—>- 6'Д(6), а затем произведем левый вывод це- почки е из 6', если 6'Таким образом, получаем S =>JZ wAh(a) =>fi)®|3'/i(p)/i(a) =>с; wh$)h(a) =^Gl wx S =s>q( wAh (a) =><;, Wf'h(y)h(a) =>Gl wh(y)h(a) =>с< wy Это неверно. См. предыдущую сноску.—Прим. ред. 149
ГЛ. 8. ТЕОРИЯ ДЕТЕРМИНИРОВАННОГО РАЗБОРА Шаги вывода от аур'Л(Р)Л(се.) до wh(fi)h(a) можно записать в виде u)|3'/i(P)/i(a) = оу61 ^>, геб, ^>z... =>; wf>„ — uA(P)/i(a) а шаги от wy'h(y)h(a) до wh(y)h(a)— в виде wy’h(y)Ma) = tBEj =>,we2 . ^twem = wh(y)h(a) Пусть г — FIRST(x) = FIRST(y). Мы утверждаем, что г принад- лежит FIRST(6,) и FlRST(e,) для всех I, поскольку р' и у' состоят только из исчезающих символов (если р' и у' непусты). Так как G— ЬЬ(/г)-грамматика, то б; = е,для всех i. В частности, P'/i(P) =y’h(y). Следовательно, р и у получаются по алгоритму 8.1 из одного и того же правила. Если Р'=#у', то в одном из приведенных выше выводов из нетерминала выводится е, а в дру- гом не выводится. Так как это противоречит ЕЬ(/г)-условию, заключаем, что р'=у'. Так как цепочки р и у предполагаются различными, они не могут одновременно быть пустыми, и значит, обе начинаются с одного и того же неисчезающего символа. Итак, т = п, а это противоречит предположению о том, что Р¥И’- □ Следующее наше преобразование полностью исключает из LL-грамматики «-правила. Будем считать, что e^L(G). Идея заключается в том, чтобы сначала применить к ЕЕ(й)-грамматике алгоритм 8.1, а затем, скомбинировав в выводах неисчезающие символы со всеми последующими исчезающими символами, за- менить полученную цепочку одним символом. Если грамматика является ЕЕ(/г)-грамматикой, то число последовательных исче- зающих символов, которые могут стоять за неисчезающими сим- волами, ограничено. Определение. Пусть G = (N, S, Р, S) — КС-грамматика. Обозна- чим через Vg множество символов вида [XBj. . .В„], где (1) X — неисчезающий символ грамматики G (возможно, тер- минальный), (2) В1( ..., В„ — исчезающие символы (следовательно, нетер- миналы), (3) если i =#/, то (т. е. список В,, ..., В„ не содержит повторений). Зададим гомоморфизм g из множества Vg в множество (N и 2)*, положив g([a]) = а. Лемма 8.2. Пусть G= (N, S, Р, S) — \Л.(1г)-грамматика, удов- летворяющая условию («) и такая, что из каждого нетерминала выводится хотя бы одна непустая терминальная цепочка, aVo и g определены выше. Тогда для каждой левовыводимой в G непустой 150
8.1: ТЕОРИЯ LL-ЯЗЫКОВ цепочки а существует единственная цепочка р из V"a, для ко- торой Л(р) = а. Доказательство. Цепочку а можно единственным образом записать в виде а±а2.. . а,„, mjsl, где а,- для всех i — это не- исчезающий символ, за которым следует цепочка исчезающих символов (поскольку в G каждая непустая выводимая цепочка начинается с неисчезающего символа). Достаточно показать, что [а,] для всех I принадлежит Vo- Если это не так, то а, можно представить в виде ХрВуВб, где В — некоторый исчезающий символ, а р, у и 6 состоят только из исчезающих символов, т. е. а, не удовлетворяет условию (3) определения Vo- Пусть w—такая непустая цепочка, что Вш. Тогда найдутся два различных левых вывода рвувб вувб =>; шувб w 0ВуВ6=>;Вб=>>6 =tfw Отсюда сразу получаем, что грамматика G неоднозначна и, сле- довательно, не является LL-грамматикой. □ Чтобы доказать, что всякий LL(£)-h3hk, не содержащий е, имеет LL(fe 4-1 (-грамматику без е-правил, применим следующий алгоритм. Алгоритм 8.2. Исключение из LL(fe)-r р а м ма т и к и е-п равил. Вход. ЕЕ(/г)-грамматика G, = (Nb 2, Plt SJ. Выход. LL(/a +1 (-грамматика G = (N, 2, Р, S), для которой L(G)=L(G1)-{e[. Метод. (1) Сначала воспользуемся алгоритмом 8.1 для построения ЕЕ(А)-грамматики GS = (N2, 2, Рг, S2), удовлетворяющей усло- вию (*)• (2) Исключим из G2 все нетерминалы А, из которых вы- водятся только пустые цепочки, выбросив А из правых частей правил, где они встречаются, а затем исключим все Д-правила. Обозначим полученную грамматику G3 = (N3, 2, Ря, S2). (3) Построим грамматику G = (N, 2, Р, S): (а) Пусть N — множество таких символов [Ха], что (i) X— неисчезающий символ грамматики G3, (ii) а—цепочка исчезающих символов, (iii) Ха 4 2 (т. е. не может быть одновременно X g 2 и а = е), (iv) а не имеет повторяющихся символов, (v) Ха действительно встречается в качестве подце- почки некоторой левовыводимой в G, цепочки. 151
ГЛ, 8. ТЕОРИЯ ДЕТЕРМИНИРОВАННОГО РАЗБОРА (б) S = [S2]. (в) Пусть g—такой гомоморфизм, что g ([а]) = а для всех [а] из N, и пусть g(a)=a для а из 2. Поскольку g-1(P) содержит не больше одного элемента, мы будем писать непосредственно g-1(P), если g-1(P)¥=0- Построим мно- жество Р так: (i) Пусть [Ла] g N и А—> В— правило из Р3. Тогда [Ла]—►£-1(Ра) — правило из Р. (it) Пусть [ааЛр] g N, где a g N, A g N3. Пусть А —» у — правило из Р3, причем у =£е. Тогда [ааЛр]—► ag-1(yP)— правило из Р. (iii) Пусть [aa/lp]gN, где agN. Тогда [ааЛр]—,а— правило из Р. □ Пример 8.2. Рассмотрим грамматику из примера 8.1. Алго- ритм 8.1 в этом примере уже применялся. Шаг (2) алгоритма 8.2 не изменяет грамматики. Будем порождать правила грамматики G по мере надобности, чтобы убедиться, что каждый рассматри- ваемый нетерминал встречается в некоторой левовыводимой це- почке. Начальным символом служит [S]. Существуют два S-пра- вила: с правой частью АВ и с правой частью В. Так как А и В — неисчезающие символы, а В — исчезающий, то g~1(AB) ~ = [ЛВ] и g-1(Bj —[В]. Следовательно, согласно пункту (1) шага (Зв), получаем правила [S] —► [Л В] | [В] Рассмотрим нетерминал [ЛВ]. А имеет одно правило, а именно А—*аА. Так как g_| (аЛВ) ~ |«ЛВ|, добавим правило [ЛВ]—>[аЛВ] Рассмотрев нетерминал [В], добавим еще правило [В]^[ЬЛ] Применим теперь к нетерминалу [аЛВ] пункты (ii) и (ill). Для Л и В существует по одному правилу, отличному от е-пра- вила. Так как g-1 (аЛВ) = [аЛВ], добавим правило [аЛВ] —► а [аЛВ] соответствующее Л-правилу. Так как g-1 (ЬЛ) = [ЬЛ], добавим правило [аЛВ]—>а[ЬЛ] соответствующее В-правилу. На шаге (iii) добавится правило [а Л В] —► а 152
8.1. ТЕОРИЯ LL-ЯЗЫКОВ Аналогично нетерминал [М] дает правила [М] —► b [аЛ] | b Рассмотрев затем новый нетерминал [аЛ], добавляем правила [аЛ] —► а [аЛ] | а Таким образом, для всех новых нетерминалов введены пра- вила, и построение грамматики G закончено. □ Теорема 8.4. Грамматика G, построенная по G, алгорит- мом 8.2, обладает следующими свойствами: (1) G(G) = G(G1)-^{e}, (2) если G,— LL(k)-spaMMamuKa, то G — LL(fe + 1 (-грамматика. Доказательство. Пусть g—гомоморфизм, определенный на шаге (Зв) алгоритма 8.2. (1) По индукции непосредственно получаем, что Л=>5ар (где Л^ и pg(Nu2)*) тогда и только тогда, когда g(Л) =>Jg(P) и Следовательно, [Ss]=^cte> для w из S* тогда и только тогда, когда S2=?a, ю и w^=e. Значит, L(G) = L(G3). Равенство L(G2) = L(Gt) — {e} представляет собой утверждение (1) теоремы 8.3, и легко видеть, что шаг (2) алгоритма 8.2, превращающий 02 в Gs, не изменяет порождаемого языка. (2) Второе свойство доказывается аналогично. По данному левому выводу в G найдем соответствующий вывод в G, и по- кажем, что LL(fe-f- 1 (-конфликт в первом вызывает Ы_(/г)-конфликт во втором. Параметр /г 4-1 вместо k интуитивно можно обосно- вать так: если применяется правило грамматики G, построенное на шаге (Зв) ((H) или (Hi)), то терминал а все еще остается частью аванцепочки, когда нужно выяснить, какое правило применить для аЛр. Допустим, что G не является LL(A-|-1)- грамматикой. Тогда существуют выводы S =>о, wAa. шР« wx S w Ao. =}cl wya ^'Gi wy где р-Ду но FIRSTft+1(x) = FIRSTft+1(y). Построим соответст- вующие выводы в Gs: (а) Всякий раз, когда применяется правило [Ла]—► g-1(Pa), введенное в Р на шаге (Зв1), применяем правило Л—^р из G3. (б) Всякий раз, когда применяется правило [ааЛр]—> ag-1(yP), введенное в Р на шаге (ЗвН), строим левый вывод е из а, после чего применяем правило Л—*у. (в) Всякий раз, когда применяется правило [ааЛр]—-а, строим левый вывод е из аЛр. Заметим, что этот вывод состоит не менее чем из одного шага, так как aAf}^=e. 153
ГЛ. 8. ТЕОРИЯ ДЕТЕРМИНИРОВАННОГО РАЗБОРА Таким образом, выводу соответствует единственный вывод g(S) =^atiwg(A)g(a). Если А — заключенная в скобки це- почка символов, начинающаяся с терминала, например а, то рубежом1) цепочки uig(X)g(a) служит символ, расположенный через один от w вправо. В противном случае рубеж расположен непосредственно справа от W. В обоих случаях, поскольку k4-1 символов цепочек х и у совпадают и G3— 1Л(А)-грамматика, шаги вывода в G3, соответствующие применению правил А— и А—«-у в G, должны быть одинаковыми. Чтобы показать, что вопреки предположению должно быть Р = у, достаточно исследовать три различных источника появле- ния правил грамматики G и их связь с соответствующими выво- дами в Gs. Итак, пусть 4 = [6]. Если 6 начинается с нетерминала, скажем 6 = С6', то оба вывода строятся согласно пункту (а). Тогда в G3 есть правило, скажем С—>6'', такое, что р = у = g-1 (6’6'). Если 6 начинается с терминала, например 6 = а6', то по- строение происходит согласно (б) или (в). Два вывода в G3 заменяют некоторый префикс цепочки 6 на е, а затем приме- няется правило, отличное от «-правила, из пункта (26). Легко доказать, что в обоих случаях Р = у. □ Докажем теперь, что каждый ЬЦ/г)-язык порождается LL(/a 4-1)- грамматикой в нормальной форме Грейбах. Эта теорема находит важные применения, мы будем использовать ее для получения дальнейших результатов. Предварительно докажем две леммы. Лемма 8.3. СК(к)-грамматика не может, быть леворекурсивной. Доказательство. Предположим, что G = (N, S, Р, S) имеет леворекурсивный нетерминал А. Тогда существует вывод А ^>+Аа. Если а=>*«, то легко показать, что G неоднозначна и, значит, не может быть LL-грамматикой. Поэтому будем счи- тать, что для некоторой цепочки t>gS+. Можно далее пред- положить, что А-С и для некоторой цепочки и £2* и суще- ствует вывод S гиДб wAak5 wuvkx Следовательно, существует и вывод S ауДб wAk6 гиДа*+1б =>," wuvk+1x Так как FIRST*(uv*x) = FIRST^(ut>*+1x), то для любого k при- ходим к противоречию с определением ЬЬ(/г)-грамматики. □ Лемма 8.4. Пусть G = (N, S, Р, S) — КС-грамматика, у ко- торой в множестве Р есть правило А—► Ва, где BgN. Пусть В—► рх | р21.. .| —все В-правила грамматики G, a G1 = (N, S, 4 Определение понятия рубежа см. в разд. 5.1.1. 154
8.1. ТЕОРИЯ LL-ЯЗЫКОВ jPj, S)—грамматика, полученная в результате удаления из Р правила А —► Ва и замены его правилами А —- Pjtz | р2а | I Тогда L(G1) = L(G), и если G — 1Л^(к~)-грамматика, то и 6,— тоже 1АА1г)-грамматика. Доказательство. Согласно лемме 2.14, lAfiA =L(G). Чтобы показать, что ЬЬ(/г)-свойство сохраняется, заметим, что левые выводы в G, по существу совпадают с левыми выводами в G, за исключением того, что последовательное применение правил А—> Ва и В—'В. в грамматике G осуществляется теперь за один шаг. Говоря неформально, поскольку Ва начинается с не- терминала, два шага вывода в грамматике G вызваны одной и той же /г-символьной аванцепочкой. Поэтому при разборе в со- ответствии с грамматикой G, эта аванцепочка заставляет при- менить правило А—> р,.а. Более подробное доказательство пред- лагаем в качестве упражнения. □ Алгоритм 8.3. Преобразование LL(fe)-r р а м м а т и к и в LL(fe + 1)-г р а м м а т и к у в нормальной форме Грей- ба х. Вход. ЬЬ(/г)-грамматика Gt = (Nt, 2, Pt, St). Выход. LL(Zs-j- 1)-грамматика G = (N, 2, P, S) в нормальной форме Грейбах, для которой L(G) = L(G1) — {«}. Метод. (1) С помощью алгоритма 8.2 построить по Gt LL(&4-1) грамматику G2 = (N2, 2, Рг, S), не содержащую е-правил. (2) Перенумеровать нетерминалы из множества N2, скажем Na = {А2, ..., Ат}, так, чтобы выполнялось условие: если А: —» А.а принадлежит Р,, то /> i. Согласно лемме 2.16, это можно сделать, так как по лемме 8.3 грамматика 02 не лево- рекурсивна. (3) Для i = m — 1, т — 2,..., 1 последовательно заменить все правила вида At—► Afa теми из правил вида А,-—>-ра, для которых Ау—> В уже отнесено к числу новых правил. Мы по- кажем, что эта операция приведет к тому, что у всех правил правые части будут начинаться с терминалов. Полученную грам- матику обозначим Gs = (N3, 2, Ps, S). (4) Пусть Xa для всех а из 2 будет новым нетерминальным символом. Положим N = N3 и | a g 2} Пусть Р образовано из Д, заменой всех (кроме самых левых) вхождений терминала а на и добавлением правил —>-а. Обозначим G = (N, 2, Р, S). G—грамматика в нормальной форме Грейбах. □ 155
ГЛ. 8. ТЕОРИЯ ДЕТЕРМИНИРОВАННОГО РАЗБОРА Теорема 8.5. Каждый \Л-(к}-язык порождается LL(ft+ ^-грам- матикой в нормальной форме Грейбах. Доказательство. Достаточно показать, что грамматика G, построенная алгоритмом 8.3, является LL(/?4- 1)-грамматикой, если G,— Ы_(/г)-грамматика. По лемме 8.4 G3— LL(/z 4- ^-грам- матика. Мы утверждаем, что правые части всех правил в G, начинаются с терминалов. Поскольку G, не леворекурсивна, это доказывается точно так же, как в алгоритме 2.14. Легко показать, что все операции шага (4) сохраняют LL(fe+ 1)-свойство и не изменяют порождаемого грамматикой языка. Ясно также, что G — грамматика в нормальной форме Грейбах. Доказательства этих утверждений оставляем в качестве упражнений. □ 8.1.3. Проблема эквивалентности для LL-грамматик Теперь мы уже подготовлены к тому, чтобы изложить алго- ритм, проверяющий, эквивалентны ли две ЬЬ(£)-грамматики. Однако надо ввести одно вспомогательное понятие. Определение. Пусть G = (N, 2, Р, S) — КС-грамматика. Для а из (N U 2)* определим мощность1) цепочки а в G (и обозначим ее ТН°(а)) как длину кратчайшей цепочки aigS*, выводимой из а. В качестве упражнения предлагаем читателю убедиться в том, что ТНс(ар) = ТН°(а) + ТНе(Р) и если а=>*р, то ТН°(а) <ТН°(Р). Определим далее ТН£(а, ш), где ag(Nu2)* и щ£2*\ как длину кратчайшей цепочки х£2*, для которой a=t>‘ax и w = — FIRSTfc(x). Если такой цепочки х нет, то значение ТН£(а, щ) не определено. Когда ясно, о чем идет речь, символы k и G в обозначениях THf или ТН° будем опускать. Алгоритм, проверяющий, эквивалентны ли две ЬЬ(/г)-грамма- тики, основан на следующей лемме. Лемма 8.5. Пусть G, =(N,, 2, Plt St) и G2 = (N2, 2, Pt, S2) — dee LL(k)-epaMMamuKU в нормальной форме Грейбах и L(Gt) —L(G2). Тогда существует такая константа р (зависящая от G1 и GJ, что если 51=>в,)ша=>д|(ич:, S2 гдр wy, где а и $ —незакон- ченные части цепочек wa, и шр, и FIRSTJx) = FIRST.(у), то |ТН°>(а) —ТНЙ>(Р)Ю2)- ') В оригинале thickness.— Прим, иерее. 3) Вертикальными прямыми | | здесь обозначена абсолютная величина числа, а не длина цепочки. 156
8.1. ТЕОРИЯ LL-ЯЗЫКОВ Доказательство. Пусть t—большее из чисел ТН'-'ру) и ТНе>(у), где у — правая часть правила из Р, и Рг соответст- венно. Положим р = /(/?4-1) и допустим, что вопреки утверж- дению леммы (8.1.9) ТН°>(<х) — TH0-® > р Покажем, что при таком допущении £(GX) =^=Z.(G2). Обозначим г = FIRST(x) = FIRST(y). Тогда ТН°!(р, г) <1 ТН'о(р) + р. Действительно, существует вывод и, следовательно, поскольку 02— грамматика в нормальной форме Грейбах, для некоторой цепочки 6 найдется вывод p=j>j;2iz6, состоящий не более чем из k шагов. Легко показать, что ТН°Д6ХТНе»(р)+« так как „в худшем случае" 6 — это цепочка р, к которой добав- лены правые части k правил. Отсюда заключаем, что (8.1.10) ТН°ДР, z)<fe+TH°>(6)<THG<P) + p Легко показать, что ТН°,(а, z)^TH°i(a), и потому из (8.1.9) и (8.1.10) вытекает, что (8.1.11) ТН°.(а, г) > ТН°.(Р, г) Обозначим через и кратчайшую цепочку, выводимую из 6; тогда ТНС>(Р, г) | ги |. Цепочка wzu принадлежит £(G2), так как S=>o,teiP=>e, wzu. Но a=i>c2zu неверно, потому что, согласно (8.1.11), ТНс>(а, г) > | zu |. Так как О,— ЫД/г)-грамма- тика, то если в Gt есть какой-то левый вывод цепочки wzu, он начинается с вывода S1=^>ci,iwa.. Таким образом, wzu не при- надлежит /.(Gj) вопреки условию /.KJ.l /.lG,). Отсюда полу- чаем, что ТНй1(а) — THd.(P)sgp = <(A+ 1). Случай ТН°»(Р) — — TH°i(a) > р рассматривается симметрично. □ Лемма 8.6. Для Д,ЮЛ-автомата Р проблема, допускает ли Р все цепочки над своим алфавитом, разрешима. Доказательство. По теореме 2.2.3 дополнение L(P~) языка L(P) является детерминированным языком и, значит, КС-языком. Далее, можно эффективно построить такую КС-грамматику G, что £(G) = £(P). Для проверки равенства L(G) = 0 можно при- менить алгоритм 2.7. Таким образом, можно узнать, допускает ли Р все цепочки над своим входным алфавитом. □ Наконец, мы готовы к тому, чтобы описать алгоритм про- верки двух ЬЬ(А)-грамматик па эквивалентность. Теорема 8.6. Для двух 1ДД1г)-грамматик G, = (N1, Sf) и Ga = (N2, S8, Рг, S2) проблема J = L(G2)?“ разрешима. 157
ГЛ. 8. ТЕОРИЯ ДЕТЕРМИНИРОВАННОГО РАЗБОРА Доказательство. Сначала построим по алгоритму 8.3 грамматики G) и в нормальной форме Грейбах, эквивалентные G, и G2 соответственно (за исключением, возможно, пустой це- почки, которую несложно учесть). Затем построим ДМП-авто- мат Р, допускающий входную цепочку w из (Е, U W тогда и только тогда, когда (1) w принадлежит как так и Ц02), или (2) w не принадлежит ни Цй^, ни Ц0г). Следовательно, £(Gj) = £(G2) тогда и только тогда, когда L(P) = = (S, Для проверки этого условия можно воспользоваться леммой 8.6. Таким образом, для завершения доказательства осталось показать, как строится ДМП-автомат Р. Его магазин состоит Рис. 8.6. Представление левовыводимых цепочек wa и шф из двух параллельных дорожек. Р обрабатывает входную це- почку, разбирая ее одновременно в соответствии с GJ и G). Разбор проводится сверху вниз. Предположим, что входная цепочка автомата Р имеет вид шх. После выполнения |ги| шагов левого вывода в GJ и в 02 в его магазине будет записано содержимое каждого из магазинов /г-предсказывающих анализаторов для G! и 02, как показано на рис. 8.6. Из описания алгоритма 5-3 известно, что содержимое магазина в каждом случае представляет собой незаконченные части двух текущих левовыводимых цепочек, а также некоторую дополнительную информацию, записываемую вместе с нетерми- 158
8.1. ТЕОРИЯ LL-ЯЗЫКОВ налами для управления разбором. Можно считать, таким образом, что магазин содержит символы грамматик G't и G's. Дополнительная информация добавляется автоматически. Заметим, что эти две незаконченные части могут занимать не одинаковый объем. Однако при — L(G2) мы можем, ис- ходя из сказанного выше, считать, что разность их мощностей ограничена, а тогда Р может моделировать оба вывода, произ- водя считывание и запись в магазин на фиксированное число ячеек ниже его верхушки. Так как G1 и G’,— грамматики в нор- мальной форме Грейбах, Р чередует шаги вывода в GJ и GJ, а затем сдвигает свою входную головку на одну позицию. Если в одном из разборов достигается ошибочная конфигурация, то разбор ведется в соответствии с оставшейся грамматикой и про- должается до тех пор, пока не достигается ошибочная или допускающая конфигурация. Необходимо только объяснить, как, предположив, что L(G2) = — L(G2), поместить в магазин обе незаконченные части так, чтобы они имели приблизительно одинаковую длину. По лемме 8.5 найдется такая константа р, что мощности двух незаконченных частей, возникающих при разборе префикса произвольной вход- ной цепочки, различаются не более чем на р. Для каждого символа грамматики мощности t автомат Р резервирует t ячеек на соответствующей дорожке своего мага- зина, помещая этот символ в одну из них. Поскольку GJ и GJ — грамматики в нормальной форме Грейбах, пи в одной из них нет исчезающих символов и в любом случае 1. Так как две цепочки аир, показанные на рис. 8.6, различаются по мощ- ности самое большее на р, их представления в магазине авто- мата Р различаются по длине самое большее на р ячеек. Для завершения доказательства примем, что Р отвергает входную цепочку, если две незаконченные части, записанные в' его магазин, различаются по мощности более чем на р. По лемме 8.5 в этом случае Z,(G1)#=£(G2). Кроме того, если мощности никогда не различаются более чем на р, автомат Р допускает входную цепочку тогда и только тогда, когда он находит разбор входной цепочки как в соответствии с грамма- тикой G’r, так и в соответствии с грамматикой GJ или же не находит его ни в GJ, ни в GJ. Таким образом, Р допускает все цепочки над своим входным алфавитом тогда и только тогда, когда £(G1) = L(G2). □ 8.1.4. Иерархия LL-языков Покажем, что Ы_(/г)-языки для каждого образуют соб- ственное подмножество множества LLf/г + 1)-языков. Как мы увидим, эта ситуация прямо противоположна ситуации с LR-язы- ками, где для каждого LR-языка можно найти LR(l)-rpaMMaTHKy. 159
ГЛ. 8. ТЕОРИЯ ДЕТЕРМИНИРОВАННОГО РАЗБОРА Рассмотрим последовательность языков Llt Ьг, , Lk....где Lk = | п > 1 и w g {Ь, с, bkd}n} В этом разделе мы покажем, что Lt является И,(А)-языком и не является LL(fe—1)-языком, и тем самым докажем сущест- вование бесконечной последовательности вложенных классов ЕЬ(&)-языков. Язык Lk порождается ЬЬ(А)-грамматикой S--aT T—>SA\A A-^bB\c В b^-'d'e Докажем, что каждая 1Д.(/г)-грамматика, порождающая язык Lt, должна содержать хотя бы одно е-правило. Лемма 8.7. Дзык Lk не порождается никакой LL(k)-zpaMMamu- кой без е-правил. Доказательство. Допустим противное. Тогда, восполь- зовавшись шагами (2) — (4) алгоритма 8.3, можно найти такую Ы-(А)-грамматику G = (N, {a, b, с, d\, Р, S) в нормальной форме Грейбах, что L(G) = LS. Докажем, что всякая такая грамматика порождает слова, не принадлежащие £й. Рассмотрим такую последовательность цепочек а,-, / = 1,2, . . ., что S =>{ a‘at =Ф/-1 а‘+*_16 для некоторой цепочки б. Так как G — ЬЬ(А)-грамматика в нор- мальной форме Грейбах, то а( для каждого i определяется одно- значно. В самом деле, если это не так, положим az = a-. Тогда легко показать, что а'+*Ь-'+* g Z.(G), а этого не может быть при i=£j. Значит, можно найти такое i, что | а,-1 > 2k—1. Выберем такое значение г, что af = |3B-|> для некоторых |3 и у из N* и В g N, причем ||3| и | у | равны по меньшей мере k—1. Поскольку G — ЬЬ(А)-грамматика, вывод слова имеет вид S=>? а'₽Ву=>;* + Так как G — грамматика в нормальной форме Грейбах и |р|^А—1, то ак~1Ы, B=t>*bl иу=5-*Ь"‘ для некоторых j>0, Z>1 и m^ik—1, причем i-\-k—1 — j + l + m. Если рассмотреть вывод слова а'+кможно также заключить, что В=^*сп для некоторого п>1. Наконец, рассмотрев вывод слова а‘ + к~1Ы+1+к~1 db'n, нахо- дим, что •S =^>’i a'fiBy =>; ai+k~lb'By=$*i al+k~1bJ + ‘y =^>"t а' +к~Чр + l+k~l dbm 160
8.1. ТЕОРИЯ LL-ЯЗЫКОВ Существование последнего вывода вытекает из того, что у слов ai+k-ijp + 1+k-l и ai+k-l^i+k-l совпадают (J + &—1) -f- + (/ + Z + A—1) символов. Поэтому y=$*bk-1dbm. Объединяя эти частичные выводы, получаем вывод S =>;<г'рВу =>/ а‘+к~1ЫBy =5>}а‘+ ь-Щс^у ==>] а‘+к~1ЫспЬк~1 dbm Но его результат не принадлежит Гй, так как он содержит под- цепочку вида сЬк~Ы. (Перед d должно стоять k символов Ь.) Итак, язык Lk не порождается никакой ЬЬ(А)-грамматикой без е-правил. □ Покажем теперь, что если язык L порождается LL(fe)-rpaM- матикой без е-правил, то он является LL(A—1) языком. Теорема 8.7. Если язык L порождается ЪЦк)-грамматикой без е-празил, k >2, то он порождается LL(A — 1)-грамматикой. Доказательство. В соответствии с шагом (3) алгоритма 8.3 для L можно найти ЬЦА)-грамматику в нормальной форме Грейбах. Пусть G = (N, S, Р, S) — такая грамматика. По ней можно построить LL(fe—1)-грамматику Gj^Nj, S, Plt S), где (1) Nx = N и {[4, а] | A g N, agS и A—>аа£Р для некоторой цепочки а}, (2) Рг = {4 —->-а[А, а]| А —>аа € Р} и {[4, а]—| А —*аа € Р}. В качестве упражнения предлагаем доказать, что G,— LL(A—1)- грамматика. Заметим, что приведенное здесь построение служит примером левой факторизации. □ Пример 8.3. Рассмотрим естественную LL(fe + 1 (-грамматику 0й для языка Lk из леммы 8.7: S-^aSA 1аА А —> bkd | b | c Построим для Lk ЬЬ(/г)-грамматику Gs, добавив новые сим- волы [S, а], [4,6] и [4, с]. Правила грамматики G* таковы: S—>a[S, а] 4 Ь[А, 6] | с[4, с] [S, a]—>-S4|4 [А, Ь]^Ьк~Ч(е [4, с] —е В качестве упражнения предлагаем доказать, что 0й— LL(fe •-1 (-грамматика, a G[ — ЬЦй)-грамматика. □ Теорема 8.8. Для всех k 1 класс LL(/s — \)-языков содержится строго внутри класса LL(A)-языков. 6 А. Ахо. Дж. Ульман, г. 2 161
ГЛ. 8. ТЕОРИЯ ДЕТЕРМИНИРОВАННОГО РАЗБОРА Доказательство. Ясно, что ЬЦ0)-языки образуют соб- ственное подмножество множества ЬЬ(1)-языков. По лемме 8.7 язык для k > 1 не порождается никакой ЬЦ/г)-грамматикой без е-правил. Следовательно, по теореме 8.4 он не порождается никакой LL(A—1)-грамматикой. Однако, как мы видели, он порождается ЬЦА)-грамматикой (с е-прави- лами). □ УПРАЖНЕНИЯ 8.1.1. Приведите дополнительные примеры грамматик, являю- щихся (a) LR и левоанализируемыми (детерминированно), но не LL, (б) правоапализируемыми и левоанализируемыми, но не LR, (в) LR, но не левоанализируемыми. 8.1.2. Преобразуйте ЬЬ(1)-грамматику Е-.ТЕ' Е' -^-ТЕ'\е Т^ЕТ' T'^»FT'\e F->-a\(E) в ЬЬ(2)-грамматику без е-правил. 8.1.3. Преобразуйте грамматику из упр. 8.1.2 в LL(2)-rpaM- матику в нормальной форме Грейбах. 8.1.4. Докажите утверждение (1) теоремы 8.3. 8.1.5. Дополните доказательство леммы 8.4. 8.1.6. Дополните доказательство теоремы 8.5. 8.1.7. Покажите, что грамматика Gt, построенная в доказа- тельстве теоремы 8.7, является LL(A—1)-грамматикой. 8.1.8. Покажите, что язык является Ц.(0)-языком тогда и только тогда, когда он либо пуст, либо состоит нз одного эле- мента . 8.1.9. Покажите, что грамматики и G'k из примера 8.3 являются LL(A-]-l)- и ГГ(А)-грамматикой соответственно. *8.1.10. Докажите, что каждая из грамматик в теореме 8.2 обладает приписанными ей там свойствами. *8.1.11. Покажите, что язык L = {апЬп | п > 1} и {а"сп | п 1 } детерминированный, но не LL. Указание: Предположите, что L порождается ЬЬ(/г)-грамматикой G в нормальной форме Грейбах, Покажите, что язык L(G) должен содержать цепочки, не входя- 162
ЗАМЕЧАНИЯ ПО ЛИТЕРАТУРЕ щие в L, рассмотрев для этого левовыводимые цепочки вида а'а для i> 1. 8.1.12. Покажите, что язык L — {a"bm | 1 т детермини- рованный, но не LL. Обратите внимание на то, что L представ- ляет собой конкатенацию двух ЬЬ(1)-языков: а* и {anbn | п > 1}. * 8.1.13. Покажите, что каждый ЬЬ(А)-язык порождается LL(A-£- 1 (-грамматикой в нормальной форме Хомского. * *8.1.14. Пусть /. = L, U Д U .. . U L„, где Ll для каждого 1 С i С т является LL-языком. Покажите, что если язык L регулярен, то регулярны все Lt. * *8.1.15. Покажите, что если L — LL-язык, но не регулярный, то L — не LL-язык. * 8.1.16. Покажите, что множество LL-языков не замкнуто относительно объединения, пересечения, дополнения, конкатена- ции, обращения и е-свободного гомоморфизма. ^Указание: См. упр. 8.1.11, 8.1.12 и 8.1.15. 8.1.17. Докажите, что ТН°(ар) = ТН°(а)+ ТН°(Р), и если а=Ф*Р, то ТНс(а) ТН°(р). 8.1.18. Дайте алгоритмы вычисления ТН°(а) и ТН°(а, г). 8.1.19. Покажите, что грамматика О, из алгоритма 8.1 лево- покрывает грамматику G из этого же алгоритма. 8.1.20. Покажите, что каждая LL(A)-rpaMMaTHKa Q левопокры- вается некоторой LL(A 4- 1)-грамматикой в нормальной форме Грейбах. 8.1.21. Покажите, что для А^2 каждая ГЦА)-грамматика без е-правил левопокрывается некоторой LL(A—1 (-грамматикой . **8.1.22. Покажите, что проблема существования для данной LR(fe)-rpaMMaTHKH G такого числа А', что G является LL(A')- грамматикой, разрешима. Замечания по литературе Теорема 8.1 предложена Кнутом [1967]. Результаты разд. 8.1.2 и 8.1.3 впервые появились в работе Розенкранца и Стирнза [1970]. Там же приве- дены решения задач, сформулированных в упр. 8.1.14—8.1.16 и 8.1.22. Иерар- хия Ы-(/т)-языков отмечена впервые Курки-Суопио [1969]. Результаты о разрешимости, связанные с теоремой 8.6, содержатся в бо- лее ранних статьях. Корсиьяк и Хопкрофт £1966] доказали разрешимость проблемы эквивалентности двух простых Щ1)-грамматик. Мак-Нотон [1967] показал, что проблема эквивалентности разрешима для скобочных грамматик, представляющих собой грамматики, в которых правые части всех правил заключены в круглые скобки, не встречающиеся нигде внутри правил. Не- зависимо от него Паул и Ангер [1968а] показали, что разрешима проблема 6» 163
ГЛ. 8. ТЕОРИЯ детерминированного разбора структурной эквивалентности двух грамматик, понимая под этим, что экви- валентные грамматики порождают одни и те же цепочки, а соответствующие деревья разбора совпадают во всем, кроме меток. (Две грамматики струк- турно эквивалентны тогда и только тогда, когда построенные по ним ско- бочные грамматики эквивалентны.) 8.2. КЛАССЫ ГРАММАТИК, ПОРОЖДАЮЩИЕ ДЕТЕРМИНИРОВАННЫЕ ЯЗЫКИ В настоящем разделе мы увидим, какие классы грамматик порождают в точности детерминированные языки. Среди них — классы ЬК(1)-грамматик, (1,1)-ОПК-грамматик, простых ССП- грамматик и обратимых грамматик (2,1)-предшествования. Кроме того, если детерминированный язык обладает префиксным свой- ством, то он порождается LR(0)- или (1,0)-ОПК-грамматикой. Заметим, что для любого языка можно сделать так, чтобы он обладал префиксным свойством: достаточно добавить к каждому слову данного языка концевой маркер. 8.2.1. ДМП-автоматы в нормальной форме и канонические грамматики Общая стратегия разд. 8.2 заключается в построении грам- матик по ДМП-автоматам, обладающим специальными свойствами. Эти грамматики или простые их модификации принадлежат упомянутым выше классам. Определим вначале специальные свойства, наличие которых у ДМП-автомата для нас желательно. Определение. ДМП-автомат Р = (Q, S, Г, 6, q„, Z„, F) назы- вается Л№П-автоматом в нормальной форме, если он обладает следующими свойствами: (1) Р— автомат без циклов. Это означает, что при любой входной цепочке Р делает только ограниченное число шагов. (2) F состоит из единственного состояния q,, и если (q„. w, Z„) |—* (qf, е, у), то y = Za. Другими словами, когда Р до- пускает входную цепочку, он находится в заключительном со- стоянии qf, а в магазине содержится только начальный символ. (3) Q можно представить в виде Q = Qs и Qw U Q, U где Qj, Qw и Qe — попарно непересекающиеся множества, назы- ваемые множествами состояний чтения, записи и стирания соответственно, и qf не принадлежит ни одному из них. Состоя- ния обладают такими свойствами: (а) Если qgQs, то для каждого существует такое состояние ра, что 6 (q, a, Z) = (ра, Z) для всех Z. Таким образом, если Р находится в состоянии чтения, то сле- дующий такт состоит в чтении входного символа. Кроме 164
8.2. ГРАММАТИКИ, ПОРОЖДАЮЩИЕ ДЕТЕРМИНИРОВАННЫЕ ЯЗЫКИ того, этот такт никогда не зависит от символа, записан- ного в верхушке магазина. (б) Если qgQw, то б (с/, е, Z) = (р, YZ) для некоторых р и Y ид,ля всех Z. В состоянии записи автомат всегда пишет в верхушку магазина новый символ, причем этот такт не зависит от текущего входного символа и от символа, содержавшегося в верхушке магазина. (в) Если q€Qe, то для каждого ZgT существует такое состояние pz, что б (q, е, Z) = (р7, е). В состоянии стира- ния автомат всегда убирает из магазина самый верхний символ, не считывая нового входного символа. (г) б (qf, a, Z) = 0 для всех о из S и {е} и Z ё Г. В заклю- чительном состоянии никакие переходы невозможны. (4) Если (q, w, Z) + (р, е, Z), то w=Y=e. Другими словами, последовательность тактов, в результате которой длина цепочки, содержащейся в магазине, (возможно) увеличивается, а затем вновь становится прежней, не может реализоваться при пустой входной цепочке. Последовательность тактов (q, w, Z) + (р, е, Z) называется траверсом. Заметим, что возможность или невозмож- ность траверса для данных q, р и w не зависит от символа Z, записанного в верхушке магазина. Короче говоря, в состоянии чтения автомат считывает сле- дующий входной символ, в состоянии записи пишет новый сим- вол в магазин, а в состоянии стирания исследует верхний магазинный символ и затем стирает его. Входная головка сдви- гается только тогда, когда автомат находится в состоянии чтения. Теорема 8.9. Если —детерминированный язык и сим- вол t не принадлежит £, то Lif — L(P) для некоторого ДМП- автомата Р в нормальной форме. Доказательство. Построим последовательность из шести ДМП-автоматов Р2— Pa, получая Pi+i по Р, так, чтобы у Pi+i было больше свойств ДМП-автомата в нормальной форме, чем у Р,-. В результате Ра будет нужным ДМП-автоматом в нормаль- ной форме. Сначала с помощью леммы 2.28 построим дочитывающий, а значит, н бесцикловый ДМП-автомат Р3, для которого Ь^ЦР^. Затем преобразуем Ру в Р2, воспользовавшись конструкцией из леммы 2.21 и считая Р2 расширенным ДМП-автоматом. ДМП- автомат Р, будет дочитывающим и в каждом состоянии либо будет действовать как в состоянии стирания или записи, либо не будет изменять магазин, но в любом состоянии автомата Р2 будет возможен сдвиг входной цепочки (т. е. чтение). Далее по теореме 2.23 получим Р3 из Р2. Новый автомат будет обладать всеми свойствами автомата Рг и, кроме того, не будет делать е-тактов в заключительном состоянии. 165
ГЛ. S. ТЕОРИЯ ДЕТЕРМИНИРОВАННОГО РАЗБОРА Затем построим по Р3 автомат Pt так, чтобы у него были все упомянутые свойства автомата Р3, по чтобы он допускал язык Lt, где ф не принадлежит алфавиту языка L. У авто- мата Ра будет единственное заключительное состояние qr, и он будет допускать входную цепочку только тогда, когда в магазине находится лишь начальный символ. Ра имеет два нижних мар- кера: Zo и Zr Zo служит начальным символом и за первые два такта Р, записывает над Zo символ Zj и над Z, начальный сим- вол автомата Р3. Потом Р} моделирует Р3. Если Р3 допускает входную цепочку, то при входном символе ф автомат Pt пере- ходит в новое состояние qc и стирает все содержимое магазина вплоть до Zp Затем Р, стирает Zx, переходит в состояние qt и останавливается. Для того чтобы сделать Pt автоматом в нормальной форме, осталось (1) отделить операции чтения входной цепочки от операций с магазином, (2) исключить траверсы для пустой входной цепочки. Чтобы удовлетворить требованию (1), образуем из Р, авто- мат Ръ. Для каждого состояния q автомата Ра, в котором не- возможен е-такт, кроме q — q;, построим новые состояния qa для всех а из S. Из состояния q при входном символе а происходит переход в состояние qa, после чего Pf в состоянии qa при входе е выполняет тот шаг, который автомат Ра выполнял в со- стоянии q при входе а. Наконец, видим, что проблема, верно ли, что (q,e,Z) |—+ (p,e,Z), разрешима для всех q и р. Из конструкции автомата Рг выте- кает, что разрешимость этой проблемы не зависит от Z. Построе- ние алгоритма, решающего такую задачу, оставляем в качестве упражнения. Отметим, что все построенные ДМП-автоматы, вклю- чая и Р3, не имеют циклов. Следовательно, для каждого со- стояния q существует такое единственное состояние q' (возможно, <?' = <?), что (</, е, Z)|—•(</', е, Z), но ни для какого q" неверно, что (/, е, Z) |—+ (q", е, Z). Последний ДМП-автомат /\ в нашей последовательности построим из автомата Р5, приписывая со- стоянию q все переходы, которые можно сделать из q' в таких ситуациях. Р3 и будет нужным ДМП-автоматом Р. Детальное построение, опирающееся на эти интуитивные соображения, оставляем в качестве упражнений. □ Изложим теперь метод построения по ДМП-автомату в нор- мальной форме грамматики, которую мы назовем канонической. Этот метод отличается от метода, использованного в лемме 2.26, тем, что здесь мы опираемся на специальные свойства ДМП- автомата в нормальной форме. 166
8.2. ГРАММАТИКИ. ПОРОЖДАЮЩИЕ ДЕТЕРМИНИРОВАННЫЕ ЯЗЫКИ Определение. Пусть М = (Q, S, Г, 6, q0, Za, (р/|-)— ДМП-авто- мат в нормальной форме, у которого верхушка магазина распо- ложена слева. Канонической грамматикой для Р называется грамматика G — (N, 2, Р, |//„ pj), где (1) N' — множество таких пар [рр] из QxQ,4to<? — состояние чтения или записи, а р — произвольное состояние. Из нетерми- нала |рр| выводятся в точности такие терминальные цепочки w, что, получая их на вход, автомат М делает траверс из состоя- ния q в состояние р. Другими словами, [рр] =>* w тогда и только тогда, когда (q, w, Z)--1 2 3 4 (р, е, Z) для всех Z g Г. (2) Множество правил Р' строится так: (а) Если 6 (q, a, Z) = (р', Z), включим в Р' правило [<?<?'] а Кроме того, для всех г g Qs и Qw включим в Р' правила [г/]-* [rq]a Заметим, что здесь q — состояние чтения. (б) Если 6 (q, е, Z) = (s, YZ) .и 6 (р, е, Y) = (q’, е), вклю- чим в Р' правило [рр'] —[sp] и для всех — правила [гд'З —* [r9] [sp] Здесь q — состояние записи, а р — состояние стирания. (3) Множества N и Р образуются в результате исключения из N' и Р’ соответственно бесполезных нетерминалов и правил. Правила в Р будут иметь вид (1) [??'] ^а (2) W]^[pp']a (3) [<?<?'] —[рр'] (4) [qq]^[рр'1 [гт'] Назовем правило, имеющее в этом списке номер (1), правилом типа i, 1 i 4. Заметим, что в канонических грамматиках правила обладают такими свойствами: (1) если [gg'J—<-а£Р, то q—состояние чтения, (2) если [рр']—>• [рр'] a g Р, то р' — состояние чтения, (3) если [рр']—► [pp']g/>, то q — состояние записи, ар' — состояние стирания, (4) если \qq'] —»[рр'] [rr'J € Р, то р’ — состояние записи, а г' — состояние стирания. 147
ГЛ. 8. ТЕОРИЯ ДЕТЕРМИНИРОВАННОГО РАЗБОРА Полезно также заметить следующее. Пусть q — произвольное состояние записи автомата М. В состоянии q автомат М, прежде чем считать следующий входной символ, записывает в магазин только фиксированное число символов. Другими словами, суще- ствует такая конечная последовательность состояний qlt ..., q^, что q, = q, 6 (qh e, Z) = (qi+1, V,Z) для 1 C i < k и всех Z, при- чем дй—состояние чтения. Последовательность не содержит повторяющихся элементов, и, возможно, k=l. Основанием для такого утверждения служит тот факт, что если бы в последова- тельности были повторяющиеся элементы, то автомат М не был бы бесцикловым; если длина последовательности больше то последовательность должна содержать повторения. Назовем эту последовательность состояний пишущей последовательностью для состояния q. Теорема 8.10. Если G = (N, S, Р, S)—каноническая грамма- тика, построенная по Д!ЛП-автомату в нормальной форме М= (Q, S, Г, б, q„, Z„, {qf\), то L(G) = L(M) — {e}. Доказательство. Покажем, что символ [gg'] порождает точно такие входные цепочки, для которых возможен траверс из q в q'. Для этого докажем индукцией, что (8.2.1) [gg'] =>“ w для некоторого п и тогда и только тогда, когда (q, w, Z) j—m(q’,e,Z) для некоторого m > 0 и любого Z. Достаточность. Базис, т=1, проверяется тривиально. В этом случае цепочка w должна быть символом из 2, а в Р должно быть правило [gg']—Для проведения шага индукции пред- положим, что (8.2.1) истинно для значений, меньших т, и что (q, w, Z)\—m(q', е, Z). Тогда конфигурация, непосредственно пред- шествующая (д', е, Z), должна иметь вид (р, a, Z) или (р, е, YZ). В первом случае р — состояние чтения и (g, w, Z) ]—,0-1 (р, a, Z). Следовательно, (q, w', Z) j— m~1 (p, e, Z), если w'a — w. Согласно предположению индукции, [gp]=>*to'. По определению грамма- тики G правило [gg']—-[qp]a принадлежит Р, и потому | gg'] =>* w. Во втором случае надо цепочку w представить в виде и найти такие состояния г и s, что (g, тщ, Z)|—“ (г, ш2, Z) I— (s, ауа, YZ) (Р> в, YZ) Н (?'> е- Z) глот, < m,m2 < т и последовательность переходов (s, tti2, YZ) |— (р, е, YZ) никогда ие стирает выделенный символ Y. Если 168
8.2. грамматики, порождающие детерминированные языки т£==0, то r = q и w2 = w. Таким образом, правило —> [sp] принадлежит Р. Из вида шагов автомата заключаем, что (s, w2, ¥)\—т>(р, е, У) и, значит, [sp] =0 w2. Итак, Если т1^>0, то (q, wt, Z) s- (г, e, Z) и, значит, согласно предположению, f <7/']=>*ыц. Как и раньше, [ар]=>’,и)2. Грамма- тика G устроена так, что правило [<?</']—>• [?г] [sp] принадлежит Р; следовательно, | | =>4 а1. Необходимость. Эту часть легко доказать индукцией; мы предоставляем это читателю. Наша теорема — частный случай утверждения (8.2.1) при <? = <?» и <?' = 7Л □ Следствие 1. Если L—детерминированный язык, обладающий префиксным свойством, и ебЕ1), то L порождается канонической грамматикой. Доказательство. Метод построения для такого языка ДМП-автомата в нормальной форме аналогичен методу, описан- ному в теореме 8.9. □ Следствие 2. Если Z.SS*—детерминированный язык и ф то 1,ф порождается канонической грамматикой. □ 8.2.2. Простые ССП-грамматики и детерминированные языки Приступим теперь к доказательству того, что каждая кано- ническая грамматика является простой ССП-грамматикой. Напом- ним, что простая ССП-грамматика — это такая грамматика (пе обязательно обратимая) слабого предшествования G = (N, S, Р, S), что если А—>а и В—>-а принадлежат Р, то I (4) fl I (В) = 0, где /(С) — множество нетерминальных или терминальных символов, которые могут появиться непосредственно слева от С в правовыводимой цепочке, т. е. Z(C) = {X|X<»C или ХД,С}. Начнем с того, что покажем, что каноническая грамматика является грамматикой (не обязательно обратимой) (1, 1)-пред- шествования. Лемма 8.8. Каноническая грамматика является приведенной грамматикой (т. е. не имеет бесполезных символов, е-правил и циклов). Доказательство. Метод построения канонической грам- матики исключает бесполезные символы и е-правила. Достаточно показать, что в ней нет циклов. Цикл может быть только тогда, >) Заметим, что если L обладает префиксным свойством и e£L, то Л -- {е} 169
ГЛ. 8. ТЕОРИЯ ДЕТЕРМИНИРОВАННОГО РАЗБОРА когда есть последовательность правил типа 3, скажем —► [<?,- + ]<7<+||, 1С(</, где [<7i<7i] = [<7,<7/]. Но тогда из правил по- строения канонической грамматики вытекает, что пишущая после- довательность для состояния 9, начинается с qlt q.2, .... q_, и, зна- чит, содержит повторяющиеся элементы. Это в свою очередь озна- чает, что соответствующий ДМП-автомат в нормальной форме имеет цикл. Отсюда заключаем, что на самом деле циклов в грамматике нет. □ Лемма 8.9. Каноническая грамматика является (не обяза- тельно обратимой) грамматикой (1, ^-предшествования'). Доказательство. Пусть G = (N, S, Р, S) — каноническая грамматика. Рассмотрим три возможных конфликта отношений предшествования и покажем, что ии один из них не реализуется. Случай Г. Предположим, что X <• У и X X У. Поскольку X Л. У, должно быть правило А—» ХУ типа 2 или 4. Поэтому Х = [<7</'] и либо Y 6 S и q’ — состояние чтения, либо У = [рр'] и р' — состояние стирания. Поскольку X <• Y, должно быть правило В—>ХС типа 4, где C=i-+ Ya для некоторой цепочки а. Пусть, как и раньше, Х = [<7<?']. Тогда q' должно быть состоянием записи, потому что В—+ХС—правило типа 4. Более того, Y должен иметь вид [рр'], где р' — состояние стирания, и, значит, А—►ХУ— пра- вило типа 4. Из вида правил типа 4 можно заключить, что р — второе состояние в пишущей последовательности для q'. Так как В —► ХС—правило типа 4, то С = [рр"] для некоторогор". Рассмотрим теперь вывод C=i>)Ya, который можно записать в виде [siSi] ~>z [s2s.J а2 —Of ... =>2 [s„srt] ап где [s1Si] = [pp"] и [s„s^] = [pp']. Из вида правил заключаем, что для каждого i либо s/+i = S( (если [s,sj] заменяется по правилу типа 2 или 4), либо s,-+i—состояние, которое в пишущей после- довательности для q' следует за состоянием s, (если [s,s)] заме- няется по правилу типа 3). Только в последнем случае s)+1 будет состоянием стирания, и, значит (поскольку s'n(=p') есть состоя- ние стирания), s„( = p) в пишущей последовательности для q' следует за «„-j. Так как s„_, либо есть р, либо следует за р в этой последовательности, то р появляется в пишущей после- довательности для q' дважды. Это означает существование цикла, и мы заключаем, что в канонической грамматике конфликтов между отношениями <• и i нет. L) Для того чтобы доказать, что каноническая грамматика является про- стой ССП-грамматикой, достаточно показать, что она — грамматика слабого предшествования (а ие (1,^-предшествования). Однако это дополнительное условие представляет определенный интерес, а доказательства не усложняет. 170
S.2. ГРАММАТИКИ, ПОРОЖДАЮЩИЕ ДЕТЕРМИНИРОВАННЫЕ ЯЗЫКИ Случай 2: X <• Y и X •> У. Поскольку X <• У, мы, как и в случае 1, выводим, что X-2]qq'\, где q'— состояние записи. С другой стороны, если X •> У, то есть правило А—► BZt где В=£+аХ и Z=j.+ yp. Вид правил таков, что если В =>+ «[?<;'], то q' — состояние стирания. Но мы уже нашли, что q’ — состояние записи. Отсюда заключаем, что конфликтов между <• и •> нет. Случай 3: X Л. У и Х*>У. Поскольку Хл=У, мы, как и в случае 1, выводим, что X =[<?<?'], где q' — состояние чтения или записи. Но из Х*>У, как в случае 2, заключаем, что q' — состояние стирания. Таким образом, каноническая грамматика является грамма- тикой предшествования. □ Теорема 8.11. Каноническая грамматика является простой грамматикой со смешанной стратегией предшествования. Доказательство. В соответствии с теоремой 8.10 и лем- мами 8.8 и 8.9 достаточно показать, что для каждой канони- ческой грамматики G = (N, S, Р, S) (1) если А—> т.ХУр и В—► }''[> принадлежат Р, то X^Z(B), (2) если А—-а и В—-а принадлежат Р, А=кВ, то I (4)6 П/(В) = 0. Справедливость утверждения (1) сразу следует из того, что если X <• В или X В, то X <• У. Но если существует правило А—-аХУр, тоХлУ, и потому есть конфликт отношений пред- шествования, что противоречит лемме 8.9. Рассмотрим теперь утверждение (2). А—-а и В—не могут быть различными правилами типа 2, так как если А — В = [рр'], а = [гг']а и грамматика G построена по ДМП-автомату M = (Q, S, Г, б, <?„, Z„, {<?/}), то б (г', a, Z) — (q', Z) = (p', Z) Следовательно, q' = р'. Но из вида правил типа 2 вытекает, что q.- р -r, так что А —В вопреки условию. Аналогичное рассуж- дение, которое предлагаем читателю в качестве упражнения, показывает, что А—-а и В—>а не могут быть различными правилами типа 4. Разберем теперь случай а — а, т. е. случай, когда А—-а и В—* а — правила типа 1. Вообще, если X <• У или ХЛК, то, как мы видели (доказательство теоремы 8.9, случай 1), X дол- жен быть нетерминалом. Итак, допустим, что С принадлежит и I (А), и 1(B). Тогда существуют правила OL—>CDa и Et—>-CEs, где D, =>sA(’i и Е2—УВу. Случай A — D2 или В—Е2 не исклю- чается. Положим C = [qq'], А=[рр'] и В = [гг']. Тогда р и г — состояния чтения, так как [рр']—>-йи[гг']—>а—правила типа 1. Согласно предыдущему рассуждению, каждое из состояний р и г должно появиться в пишущей последовательности для q' и, 17*
ГЛ. 8. ТЕОРИЯ ДЕТЕРМИНИРОВАННОГО РАЗБОРА следовательно, должно заканчивать эту последовательность. Зна- чит, р = г. Так как 6 (р, a, Z) = (p', Z) = (r’, Z) то р' = г', А = В вопреки условию. Таким образом, А—«а и В—не могут быть правилами типа 1. Наконец, предположим, что А—и В—— правила типа 3. Как и ранее, пусть С принадлежит Z (А) п/ (В), С = [<?<;'], А = = [рр'] и В=[гг']. Тогда каждое из состояний риг должно появиться в пишущей последовательности для q'. Если р = г, положим 8(р, е, Z) = (s, У). В этом случае a = [ss'] для некото- рого s' и о (s', е, У) = (р', е) = (г',е). Следовательно, г' = р' и опять А = В вопреки условию. Пусть тогда р=/=г. Если a = [ss'], то s стоит в пишущей последовательности для q' и после р, и после г, а, значит, появляется там дважды. Отсюда выводим, что А—>-а и В —>• а не являются правилами типа 3. Таким образом, утверждение (2) верно, и G—простая ССП-грамматика. □ Из теоремы 8.11 следует, что язык Lt порождается простой ССП-грамматикой, если L—детерминированный язык, a t— кон- цевой маркер. На самом деле верно более сильное утверждение: если t убрать с конца каждой цепочки, порождаемой канони- ческой грамматикой, то измененная таким образом грамматика останется простой ССП-грамматикой. Учитывая, что построение, убирающее концевые маркеры, будет проводиться неоднократно, мы представим его здесь в виде алгоритма. Алгоритм 8.4. Удаление правого концевого мар- кера из слов, порождаемых приведенной грамма- тикой. Вход. Приведенная грамматика G = (N, S и {«!}, Р, S), где ({(££ и L(G)=Lt для некоторого Z.SS+. Выход. Грамматика С, —(А,, 2, Р,, S), для которой L(GJ = L. Метод. (1) Убрать из Р все правила вида А—>t- (2) Заменить в Р все правила вида А—-at, где а=^=е, на А —«а. (3) Если правило А—-аВ принадлежит Р, а=£е, и B=t>‘at, добавить к Р правило А—-а. (4) Исключить из N и из полученного множества правил бес- полезные нетерминалы и правила. Обозначить новые множества нетерминалов и правил Nj и Р, соответственно. □ Теорема 8.12. Если Gt — грамматика, построенная алгорит- мом 8.4-, mo L(GI)=L. 172
8.2. ГРАММАТИКИ. ПОРОЖДАЮЩИЕ ДЕТЕРМИНИРОВАННЫЕ ЯЗЫКИ Доказательство. Поскольку каждое слово w языка L (G) имеет вид хф для xgS + , то для любого A£N из А=$*аи сле- дует, что либо ugS+, либо и—оф, где ogS*. Назовем нетер- миналы первого типа промежуточными, а нетерминалы второго типа—завершающими. Простая индукция по длине выводов пока- зывает, что если А— промежуточный нетерминал, то А=$*ои тогда и только тогда, когда А^>"ои, ugS*. Аналогично, если А— завершающий нетерминал, то тогда и только тогда, когда /1 =>□ V. Доказательство оставляем в качестве упражнения. Итак, S==>*Gwt тогда и только тогда, когда Следо- вательно, L(G1) = L. □ Теорема 8.13. Если L — детерминированный язык и e^L, то L порождается простой ССП-грамматикой. Доказательство. Пусть Z.sS+ и р(£2. Тогда, согласно следствию 2 теоремы 8.10, Ьф порождается канонической грам- матикой G = (N, S, Р, S), которая по теореме 8.11 является простой ССП-грамматикой. Пусть G1 = (N1, 2, Рг, S) — грамма- тика, построенная алгоритмом 8.4 из грамматики G. Тогда L(G1) = E. Мы докажем, что Gj—также простая ССП-грамматика. •Легко показать, что Gx не имеет е-правил и бесполезных сим- волов. Если бы грамматика Gt содержала цикл, в ней было бы правило А—>-В, входящее в Р1: но не в Р. Допустим, что пра- вило А—►ВХ принадлежит Р для некоторого X, для которого Х=>‘; р. Предположим далее, что A —>о, В=х-; А. Тогда А =>аAмф для некоторой цепочки w из (S U {<£})*; следовательно, G порож- дает цепочки, содержащие более одного символа ф. Поскольку это, как мы знаем, неверно, заключаем, что G,— приведенная грамматика. Теперь надо показать, что G,— грамматика предшествования. Так как ф встречается только на правом конце цепочек, порож- даемых в G символом S, легко показать, что в G не выполняются только те соотношения, выполняющиеся в G,, которые содержат справа символ $ (концевой маркер, встречавшийся при описании метода предшествования). Но %•>$—единственное соотношение, имеющее справа $, которое может выполняться, поэтому G, должна быть грамматикой предшествования. Далее, покажем, что в G, пет новых конфликтов А—► аАУр и В—►Ур, где X € 1(B). Как и в теореме 8.11, свойства про- стого предшествования исключают эту возможность. Наконец, мы( должны доказать, что в Рг нет пары правил А—и В—<-а, где А^В. Рассмотрим отдельно три случая. Случай 1: Допустим, что а = Си правила А—-СХ а В—► С/, где Х=^оф и Y ^>*аф, принадлежат Р. Пусть C = [qq'], Если q' — состояние чтения, то X--Y — C.. Как мы видели при дока- зательстве теоремы 8.11, левая часть правила типа 2 однозначно 173
ГЛ. 8. ТЕОРИЯ ДЕТЕРМИНИРОВАННОГО РАЗБОРА определяется его правой частью, поэтому вопреки условию А = В. Если q' — состояние записи, обозначим через р единственное состояние чтения в пишущей последовательности для q' и поло- жим 6(р, tf, Z) = (р', Z), где 6—функция переходов ДМП-автомата, по которому была построена грамматика G. После того как ДМП-автомат попадает в состояние р', он не может выполнять никаких операций, кроме стирания содержимого магазина, потому что если он будет читать входную цепочку или писать в мага- зин, то либо он допустит цепочку, содержащую в середине сим- вол С, либо X и Y окажутся бесполезными символами. Суще- ствует единственное состояние р", в котором ДМП-автомат нахо- дится после стирания символов, записанных в магазин при прохождении пишущей последовательности для q'. Поэтому опять X = Y, и мы заключаем, что А= В. Случай 2: Предположим, что а=С и правила А—>С и В—>СХ, где X =>•(£, принадлежат Р. Если С = [<??'], то q'— состояние стирания, так как А—>С— правило типа 3. Но поскольку В—>-СХ—правило типа 2 или 4, q' должно быть состоянием записи или чтения. Мы пришли к противоречию. Случай 3: Если а = С и правила А—>-СХ и В—-С принад- лежат Р, то возникает ситуация, симметричная той, что рассмат- ривалась в случае 2. Следовательно, G,— простая ССП-грамматика. □ 8.2.3. ОПК-грамматики, LR-грамматики и детерминированные языки Покажем, что каноническая грамматика является также (1, 0)- ОПК-грамматикой, а значит, согласно теореме 5.18, и LR (0)- грамматикой. Интуитивно причина того, что для разбора кано- нической грамматики при помощи алгоритма типа „перенос — свертка" не требуется заглядывать вперед, состоит в том, что каждый терминал и каждый нетерминал [qq'], где q' — состояние стирания, определяют правый конец основы. Дадим формальное доказательство, основанное па этой идее. Теорема 8.14. Каждая каноническая грамматика является (1, 0)-ОПК-ерамматикой. Доказательство. Пусть G = (N, S, Р, S) — каноническая грамматика. Предположим, что G не является (1, (^-ОПК-грам- матикой. Тогда в пополненной грамматике G' = (N’u(S'}, S, ?U{S'—>S), S') можно найти выводы $S' =$’аХАщ=^гаХрш и $S'=4фуВх=>г убх, где удх можно записать в виде а'Хру, причем |х|<1|!/|, но а'XAyK~-'i'Bx. Заметим, что всякая правовыводи- мая в G цепочка имеет открытую часть, состоящую только из 174
8.2. ГРАММАТИКИ. ПОРОЖДАЮЩИЕ ДЕТЕРМИНИРОВАННЫЕ ЯЗЫКИ нетерминалов, т. е. XgN, а а, а' и 7 принадлежат N*. В за- висимости от типа правила А—рассмотрим четыре случая. Случай 1: Допустим, что |3 = а, где а 6 2. Так как |х|<|р|, то должно быть х — у и либо 6=а, либо 6 = Ха. Если 6 = а, то X g / (Д) Г1Z (В), а это может быть, только если А—В, поскольку G— простая ССП-грамматика. Если 6 = Ха, то в Р есть правила А—<-а и В—> Ха, где Х£/(Д); это опять противоречит тому, что G — простая ССП-грамматика. Случай 2: Допустим, что |3 = Са, где CgN. Тогда, поскольку |х|^|р|, должно быть х-—у и либо б а, либо 6-=Са. Если 6 = Са, то А — В, так как правила типа 2 обратимы (теорема 8.11). Отсюда вытекает, что а' ХАу = уВх вопреки предположению. Если ё — а, то из А—»Са следует С Л. а. Так как символ С должен быть последним символом цепочки 7, то С <• В или С В и, следовательно, C<ta, а это противоречит тому, что G — грамма- тика предшествования. Случай 3: Допустим, что р = С, где CgN. Здесь четыре воз- можности: 6 = С, 6 = а, ё = Са для некоторого а С 2, в = ХС. Если 6 = С, то X принадлежит I (Д) А / (В), а это противоречит тому, что G — простая ССП-грамматика. Пусть С = [од']. Тогда q' — состояние стирания. Если 6 — а, то С — последний символ цепочки 7. Поскольку В в правовыводимой цепочке стоит справа от С, q' должно быть состоянием записи. Итак, пришли к про- тиворечию. Если 6=--Са, то q' должно быть состоянием чтения, а это не так. Если ё = ХС, то, поскольку X g Z (Д), наличие пра- вил А—-С и В—> ХС противоречит тому, что G — простая ССП- грамматика. Случай 4: Допустим, что |i = CD для С и D из N. Тогда 6 есть либо D, либо а, либо Da для некоторого а £2, либо CD. Так как правила типа 4 обратимы (доказательство теоремы 8.11), то при 6 = CD имеем А = В и а'ХАу = уВх. Пусть D = [g/]. Из вида правила Д—-CD следует, что q'— состояние стирания. Если 6 = Da, то q' должно быть состоянием чтения, и потому этот случай исключается. Если б а, то, как и в случае 3, можно показать, что q' — состояние записи. Если 6 = D, то последним символом цепочки 7 является С, а значит, CgZ(B). Наличие правил А—-CD и В—>D противоречит тому, что G — простая ССП-грамматика. □ Следствие 1. Всякий детерминированный язык L, обладающий префиксным свойством, имеет (1, 0)-ОТ1К-грамматику. Доказательство. Если e£L, результат очевиден. Если e£L, то Z. = {e}. Для этого языка легко найти (1, 0)-ОПК-грам- матику. □ Следствие 2. Если Ls'S* — детерминированный язык и ф не принадлежит X, то Еф имеет (1, (Д-ОПК-граллатаку. □ 175
ГЛ. S. ТЕОРИЯ ДЕТЕРМИНИРОВАННОГО РАЗБОРА Теперь мы можем доказать теорему о произвольных детерми- нированных языках, представляющую собой по существу пере- фразировку следствия 2. Теорема 8.15. Всякий детерминированный язык порождается некоторой (1, \)-ОТШ,-грамматикой. Доказательство. Пусть G — каноническая грамматика. С помощью алгоритма 8.4 построим по G грамматику Gt. Надо показать, что G,— это (1, 1)-ОПК-грамматика. Интуитивно про- блема состоит в том, чтобы распознать, когда для свертки нужно применить правило А—< В грамматики G,, не являющееся пра- вилом грамматики G. Заглядывание на один символ вперед по- зволяет выполнить такую свертку только тогда, когда аванцепочка состоит только из концевого маркера $. Формальное доказатель- ство оставляем в качестве упражнения. □ Теорема 8.16. (1) Всякий детерминированный язык, обладаю- щий префиксным свойством, имеет кЩ())-грамматику. (2) Всякий детерминированный язык имеет ЪВ.(У)-грамматику. Доказательство. Согласно теореме 5.18, каждая (т, k)- ОПК-грамматика является ЬК(/г)-грамматикой. Результат выте- кает из теоремы 5.18 и следствия 1 теоремы 8.14. □ 8.2.4. Грамматики расширенного предшествования и детерминированные языки К настоящему моменту мы установили, что если L—детерми- нированный КС-язык, то (1) существует такой ДМП-автомат Р в нормальной форме, что L (P) = Lt, (2) существует такая простая грамматика со смешанной стра- тегией предшествования G, что L(G) = L — {е}, (3) существует такая (1, 1)-ОПК-грамматика G, что L(G(—Л. Покажем теперь, что существует также обратимая грамматика (2, [(-предшествования G, для которой Z.(G) = Z. — {е}. Нам уже известно, что каноническая грамматика является грамматикой (1, 1 (-предшествования, хотя она не обязательно обратима. Для того чтобы получить нужный результат, выполним некоторые преобразования канонической грамматики, превращающие ее в обратимую грамматику (2, [(-предшествования. Эти преобразо- вания выглядят следующим образом: (1) Каждый нетерминал пополняется так, чтобы он „помнил" символ, стоящий слева от него в правом выводе. (2) Цепные правила исключаются в результате замены правил вида А —► В и В —> | ... | ая правилами А —>• at |... | ат. 176
8.2. ГРАММАТИКИ, ПОРОЖДАЮЩИЕ ДЕТЕРМИНИРОВАННЫЕ ЯЗЫКИ (3) Нетерминалы „расщепляются" так, чтобы каждый нетер- минал либо имел только одно правило вида А—-</, либо не имел правил такого вида. (4) Наконец, нетерминалы „растягиваются" так, чтобы устра- нить необратимость, возникшую в результате появления правил вида A —<-а. Другими словами, множество правил А,—► «, .... Ай—>а заменяется множеством At—<-А2, .... Ак_,—>Ак и At-+a. Каждая из первых трех операций сохраняет свойство грам- матики быть грамматикой (1, [(-предшествования. Четвертая может в худшем случае сделать ее грамматикой (2, [(-предшествования, но она необходима для того, чтобы обеспечить обратимость. Да- дим законченный алгоритм. Алгоритм 8.5. Превращение канонической грам- матики в обратимую грамматику (2, 1)-п р е д шест в о- ва н и я. Вход. Каноническая грамматика G = (N, S, />, S). Выход. Эквивалентная обратимая грамматика (2, 1)-предше- ствования G, = (N4, S, Р„ S4). Метод. (1) Построить по G грамматику G1 = (Ni, S, Plt S4): (а) пусть N( — множество символов Ах, где <4gN и X€Nu{$}; (б) положим Sf = Sg; (в) если А—*В, А->ВС, АВа н А—> а—правила нз Р, то в Р[ включаются соответственно правила Ах—>-Вх, Ах—^ВхСв, Ах—*Вхаи Ах--а ,для всех XgNu{$}; (г) Nj и Рг — это соответственно N, и Р'г после удаления бесполезных символов и правил. (2) Построить по Gj грамматику G2 = (N2, S, Р2, S,): , (а) убрать из Рг все цепные правила, выполняя следую- щую операцию до тех пор, пока грамматика не переста- нет изменяться: если А —>• В — рассматриваемое правило из Р4, добавить правила А—> а для всех правил В—-7, принадлежащих Plt и выбросить правило А —> В; (б) обозначим через N2 и Р,, полученные в результате множества полезных нетерминалов и правил. (3) Построить по G2 грамматику G3 = (N3, S, Ps, S4): (а) пусть N3 — множество N2 вместе со всеми символами А“, такими, что правило А—-« принадлежит Р2; (б) для каждого Аа из N'. включить в Р'г правило А“ -+а; (в) если AgN2, А—7. СР2 и а не является одиночным, терминальным символом, добавить к Р'л правило А—-7. 177
ГЛ. 8. ТЕОРИЯ ДЕТЕРМИНИРОВАННОГО РАЗБОРА для каждого а' из где h—гомоморфизм, опреде- ленный равенствами h (а) =а для всех a g S h (Ва) = В для всех Ва g NJ h (В) = В для всех В g N2 (г) обозначим через N3 и Р3 полезные подмножества мно- жеств NJ и Р3 соответственно. (4) Построить по G3 грамматику G4 = (N4, S, Pt, S4): (a) N4 = N3 и S,=S,; (б) Р,— это множество Р3, измененное так: если Л(—*а, А2—-а, .... Ak—»а — все правила из Р3 с правой частью а, взятые в некотором порядке, и k > 1, то в Р\ они за- меняются на А,—► Л2, А2—* А3, ..., А1,_1—► Лд, □ Пример 8.4, Пусть G — грамматика с правилами .8’ — A/J А —» а | b В — АС С_Г) D - , а Тогда G, определяется правилами SS Aj —»а | b В А —► АаСа А^^а^Ь С А —“ ^А DA-^a На шаге (2) алгоритма 8.5 правило СА—заменяется на С. • а. Символ Da, таким образом, бесполезен: На шаге (3) добавляются нетерминалы Л§, Л$, Аа, Аа и Са. Тогда Л$, ЛА и Са становятся бесполезными, и в результате правила грамматики G3 принимают вид 5$-^|Л^л ВА^А‘‘АСаА\АьАСаА Аа Аьа^Ь С“А-^а 378
8.2. ГРАММАТИКИ, ПОРОЖДАЮЩИЕ ДЕТЕРМИНИРОВАННЫЕ ЯЗЫКИ На шаге (4) растягиваются и СаА, а также и Аьл. Окончательно правила грамматики Gt выглядят так: ss- 4^14вя Вд-^СЛЛМ Да __Г'а Сал ->а Д ь . д ь аа ь □ Покажем, что G4— обратимая грамматика (2, ^-предшество- вания, доказав предварительно ряд лемм. Лемма 8.10. В алгоритме 8.5 (1) Z.(G1) = Z.(G), (2) Gj — грамматика (1, Хупредшествования, (3) если правила А—►« и В—-а принадлежат Райане является одиночным терминальным символом, то А —В. Доказательство. Утверждение (1) доказывается простой индукцией по длине выводов. Для доказательства утверждения (2) заметим, что если X и Y связаны в G4 одним из отношений <•, Л. или •>, то X' и Y', представляющие собой X и Y с от- брошенными индексами (если они были), связаны тем же отно- шением в G. Таким образом, G,— грамматика (1, ^-предшество- вания, поскольку такова грамматика G. Чтобы доказать (3), отметим, что правила типов 2 и 4 обра- тимы в G. Иными словами, если А—*СХ и В—^СХ принадле- жат Р, то Л = В. Отсюда, таким образом, следует, что если Ау—>СуХс и By—>-СуХс принадлежат Plt то Ау — Ву. Анало- гично, если X — терминал, а Аг—>СГХ и Ву—»-СгХ принадле- жат Pt, то Ау = Ву. Мы должны рассмотреть правила в Р,, получаемые из правил типа 3. Допустим, что у нас есть правила Ах—и Вх—>СХ. Так как бесполезные правила из G, исключены, в G должны быть правила с такими правыми частями XD и ХЕ, что D=>'; Ча и Е=^а Bfl для некоторых а и |3. Пусть X = [??'], А = [рр'], В |гг'] и C = |ss']. Тогда риг принадлежат пишущей после- довательности для q', и после каждого из них стоит S. Отсюда заключаем, что р = г. Так как правила А—и В—«С оба являются правилами типа 3, то р' — г’. Иначе говоря, пусть 6—функция переходов ДМП-автомата М, по которому была построена грамматика G. Тогда 8 (р, е, Z) = (s, YZ) для некото- рого Y, и 6 (s', е, Y) = (p',e) — (r',e). Поэтому А = В и АХ = ВХ. 179
ГЛ. 8. ТЕОРИЯ ДЕТЕРМИНИРОВАННОГО РАЗБОРА Случай Х = $ рассматривается аналогично с той лишь раз- ницей, что роль q' играет начальное состояние q,. ДМП-авто- мата М. □ Лемма 8.11. Грамматика G, из алгоритма 8.5 обладает теми же тремя свойствами, что и грамматика из леммы 8.10. Доказательство. Свойство (1) опять доказывается про- стой индукцией. Чтобы доказать (2), заметим, что на шаге (2) алгоритма 8.5 не возникает новых правых частей и, следова- тельно, новых пар, связанных отношением Л.. Кроме того, каж- дая правовыводимая цепочка в G, правовыводима и в Glt а потому легко показать, что не возникает и новых отношений <• и ?>• Для доказательства (3) достаточно показать, что если пра- вило —>-Вх принадлежит Plt то Вх не встречается в правой части никакого другого правила и, значит, является бесполез- ным символом, который удаляется на шаге (26). Нам уже известно, что в Р, пет правила Сх—>ВХ, если С-лп. Возможны только правила Сх—>Вха, Сх—>BXDB и Су—>-ХуВх. Далее, А—-В— правило типа 3, и потому если 6 = [</<:/'], то q'— состояние сти- рания. Таким образом, в Рг не может быть правил Сх—>Вха и Сх—*BXDB, поскольку С—-Во. и С—-BD— правила типов 2 и 4 соответственно. Рассмотрим правило Су—*ХуВх. Пусть Х=. [рр'] и A =[rr'J. Тогда q — второе состояние в пишущей последовательности для р', потому что С—>ХВ—правило типа (4). Кроме того, по- скольку А —-В—правило типа 3, q следует за г в любой пи- шущей последовательности, где встречается г. Но так как X в правовыводимой цепочке в G, стоит непосредственно слева от Л, г встречается в пишущей последовательности для р', причем г^=р'. Таким образом, в пишущей последовательности для р’ состояние q попадается дважды, что невозможно. □ Лемма 8.12. Грамматика G3 из алгоритма 8.5 обладает теми же тремя свойствами, что и грамматика G, из леммы 8.10. Доказательство. Свойство (1) снова доказывается „в лоб“. Для доказательства (2) заметим, что если X и Y связаны в G„ одним из отношений <•, Л. или •>, то X' и Y', представляющие собой X и Y с отброшенными верхними индексами (если они были), точно так же связаны в G2. Таким образом, Gs—грам- матика (1,1)-предшествования и свойством (2) обладает. Свой- ство (3) очевидно. □ Теорема 8.17. Грамматика 04 из алгоритма 8.5 является обратимой грамматикой (2,^-предшествования. 180
8.2. ГРАММАТИКИ, ПОРОЖДАЮЩИЕ ДЕТЕРМИНИРОВАННЫЕ ЯЗЫКИ Доказательство. Так как для каждого а из 2 содер- жит не более одного правила вида А—па, то ясно, что грам- матика G4 обратима. Легко показать, что новые конфликты от- ношений (1,1)-предшествовапия могут возникнуть только для новых связей: (1) АХ3>Ь и (2) C<f_Ax. Конфликты вида (1) возникают из-за того, что в G3 выпол- няются некоторые из соотношений By~i>b или Ву^Ь и, кроме того, Ву=>о Ах- В G3, а значит, и в G, могут выполняться также соотношения Аах~Ь или АХ<$.Ь. Конфликты вида (2) обусловлены сходными причинами. В G3 могут выполняться соотношения С Вс или С ^В'г. и, кроме того, Вс- =>Й Аах. В G3, а значит, и в G3 возможно также С 4= АС. (С — это С без индексов.) Покажем, что потенциальные конфликты вида (1) разреша- ются с помощью отношений (2,1)-предшествования. Конфликты вида (2) невозможны. Случай 1: Предположим, что САХ •> b в G, для некоторого Сс,\4 и как в G3, так и в G3 либо СЛу.с^Ь, либо САх<*Ь. Тогда С = Х% для некоторых Z и d; последнего символа в дей- ствительности может и не быть. Заметим, что, поскольку Ах •> b выполняется в G3, но не выполняется в G3, должен найтись такой вывод Аах, что С в правом выводе в грамматике G3 появ- ляется слева 'от By. Поэтому Y = X. Теперь нужно показать, что в N3 не может быть двух разных нетерминалов Вх и Ах. Другими словами, в N2 нет таких Вх и Ах, что А=£В, A=^"Ga, В^>*оа. Пусть Д = [<7<?'], В = [рр'] и Х = [гг']. Заметим, что q и р принадлежат пишущей последова- тельности для г'. Кроме того, если [ss']=S>oa и [ss"]=>na, то, рассмотрев ДМП-автомат, лежащий в основе G, заключаем, что s'=s", Таким образом, q' однозначно определяется состоянием q, а р' — состоянием р, при условии что [<7<7']=>с<2 и [рр']=>па. Отсюда следует, что поскольку q и р принадлежат пишущей последовательности для г' и q=j^p, то либо В встречается в ка- честве выводимой цепочки в выводе А=>г.а, либо А встречается в выводе /J=>Ga. Без потери общности предположим, что осуществляется пер- вая возможность. Тогда в G существует нетривиальный вывод в из Л, и в нем применяются только правила типа (3). Поэтому Ax=Z>g, Вх, и символ Вх должен был быть удален на шаге (2) алгоритма 8.5. Таким образом, заключаем, что в Ga нет сим- вола By. Случай, когда вместо С в приведенном выше рассуждении стоит $, рассматривается аналогично. Здесь роль г' будет играть начальное состояние соответствующего ДМП-автомата q„. Случай 2: Допустим, что для некоторого С в G, выполняется соотношение С <• Лх, а в С, и в G4— соотношение СЛ-АХ- Тогда 181
ГЛ. 8. ТЕОРИЯ ДЕТЕРМИНИРОВАННОГО РАЗБОРА найдется такой символ Вх, что С <фРЛ: или СА. Вх в G, и rl'x. Рассуждая, как в случае 1, заключаем, что С = X? и или наоборот. Таким образом, Ах или Вх были уда- лены на шаге 2 алгоритма 8.5. Заметим, что здесь не может быть конфликта отношений (1,1 (-предшествования и тем более (2,1 (-пред- шествования. Отсюда заключаем, что G4—обратимая грамматика (2,1 (-пред- шествования. □ Следствие 1. Каждый детерминированный язык L, обладающий префиксным свойством и не содержащий е, имеет обратимую грамматику (2,1)-предшествования. □ Следствие 2. Если 1.^'Х'— детерминированный язык и ф не принадлежит 2, то язык Ьф имеет обратимую грамматику (2,1)-предшествования. □ Теорему 8.17 можно усилить, отбросив концевой маркер, упо- мянутый в следствии 2. Теорема 8.18. Каждый детерминированный язык, не содержа- щий е, имеет обратимую грамматику (2,])-предшествования. Доказательство. Пусть Еф имеет каноническую грам- матику G. Применим к G алгоритм 8.5, а к полученной грам- матике G4 — алгоритм 8.4. Мы утверждаем, что грамматика, по- строенная алгоритмом 8.4, также является обратимой граммати- кой (2,1 (-предшествования. Доказательство оставляем в качестве упражнения. □ УПРАЖНЕНИЯ 8.2.1. Постройте ДМП-автоматы в нормальной форме, допу- скающие (а) | w g (а + Ь)*}, (б) [атЬ"а"Ьт | т, п(>1}, (в) Z.(G„). 8.2.2. Найдите каноническую грамматику для ДМП-автомата в нормальной форме Р = ({<К, <72, <7з, <7/Ь {0, 1}, (Z„, Z4, X}, 6, qa, Zo, {qД) где 6 для всех Y определяется равенствами 6(<7«, е, Г) = (<7i, 24Г) 6(91, 0, Г) = (9г, У) 6(Q1, 1, Y) = (q3, У) &(<?.. е, Г) = (<7„ ХГ) 182
УПРАЖНЕНИЯ е, X) = (qlf е) 6 (<73, е, Zt) = (q/, е) 6 (<?.,, е, 20) = (</,, е)1) 8.2.3. Найдите в упр. 8.2.2 состояния записи, чтения и сти- рания. 8.2.4. Дайте формальное доказательство теоремы 8.9. В следующих трех упражнениях имеется в виду каноническая грамматика G = (N, 2, Р, S). 8.2.5. Покажите, что (а) если [qq' — (б) если qq' — (в) если [qq' — стояние стирания, (г) если [<?(/'] —► [pp'J[rr'] g Р, то р' —состояние записи, аг' — состояние стирания. agP, то q — состояние чтения, \рр'[а£Р, то р'— состояние чтения, [pp'JgP, то q—состояние записи, а р'— со- 8.2.6. Покажите, что если [gg'jfpp'] встречается в качестве подцепочки правовыводимой в G цепочки, то (а) д' — состояние записи, (б) q'^p, (в) р принадлежит пишущей последовательности для q'. 8.2.7. Покажите, что если [</</] =>+<х[рр'], то р' — состояние стирания. 8.2.8. Докажите необходимость условия в теореме 8.10. 8.2.9. Дайте формальное доказательство теоремы 8.15. 8.2.10. С помощью алгоритма 8.5 найдите обратимые грам- матики (2,1)-предшествования для следующих детерминированных языков: (а) {а0'"с0'Ч«>0}11{Ь0пс0г'"|«>0}, (б) {0nal"0ra|n>0, m>0} и {0'”Ь1"0'1|«>0, т>0}. 8.2.11. Рассмотрите полностью случай Х = $ в лемме 8.10. 8.2.12. Закончите доказательство теоремы 8.17. 8.2.13. Докажите теорему 8.18. *8.2.14. Покажите, что КС-язык имеет ЬК(О)-грамматику тогда и только тогда, когда он детерминированный и обладает пре- фиксным свойством. г) Это правило никогда не используется. Оно требуется для того, чтобы Р был ДМП-автоматом в нормальной форме. 1»
ГЛ. S. ТЕОРИЯ ДЕТЕРМИНИРОВАННОГО РАЗБОРА 8.2.15. Покажите, что КС-язык имеет (1,0)-ОПК-грамматику тогда и только тогда, когда он детерминированный и обладает префиксным свойством. **8.2.16. Покажите, что каждый детерминированный язык имеет LR (1 (-грамматику (а) в нормальной форме Хомского, (б) в нормальной форме Грейбах. 8.2.17. Покажите, что если А—>« и В—-г/.— правила типа 4 в канонической грамматике, то А=В. *8.2.18. Если грамматика G из алгоритма 8.4 каноническая, то верно ли, что грамматика 0,, построенная в этом алгоритме, правопокрываст грамматику G? Что будет в случае, когда G — произвольная грамматика? 8.2.19. Закончите доказательство теоремы 8.12. *8.2.20. Покажите, что каждая ГР(£)-грамматика правоиокры- вается некоторой (1, /г)-ОПК-грамматикой. Указание: Видоизме- ните ЬР(£)-грамматику, заменив в правых частях правил все терминалы а новыми нетерминалами Ха и добавив новые пра- вила вида Ха—> а. Затем измените нетерминалы грамматики, чтобы запомнить множество допустимых ситуаций для активных префиксов, расположенных справа от них. **8.2.21. Покажите, что каждая ЬР(/г)-грамматика правопокры- вается ЬР(£)-грамматикой, которая является в то же время грам- матикой (1,1 (-предшествования (не обязательно обратимой). *8.2.22. Покажите, что грамматика G4 из алгоритма 8,5 право- покрывает грамматику G из этого алгоритма. Открытые проблемы 8.2.23. Верно ли, что каждая Ы?(/г)-грамматика покрывается некоторой ЬЙ(1)-грамматикой? 8.2.24. Верно ли, что каждая ЬР(£)-грамматика покрывается обратимой грамматикой (2,1)-предшествования? Утвердительный ответ на этот вопрос означал бы также утвердительный ответ на вопрос, сформулированный в упр. 8.2.23. 8.2.25. Эта проблема уже была поставлена в гл. 2, но реше- ние ее пока не получено, поэтому сформулируем ее еще раз. Разрешима ли проблема эквивалентности для ДМП-автоматов? Поскольку все конструкции этого раздела эффективно реали- зуются, мы получаем много эквивалентных формулировок этой задачи. Например, можно было бы доказывать, что разрешима проблема эквивалентности для простых ССП-грамматик или для обратимых грамматик (2,1)-предшествования. 184
8.3. ТЕОРИЯ ЯЗЫКОВ ПРОСТОГО ПРЕДШЕСТВОВАНИЯ Замечания по литературе Теорема 8.П впервые была доказана Лхо и др. [1972]. Теоремы 8.15 и 8.15 первоначально появились в работе Кнута [1965]. Теорема 8.18 заимствована у Грэхема [1970]. Упр. 8.2.21 взято нз работы Грэя и Харрисона [1969]. 8.3. ТЕОРИЯ ЯЗЫКОВ ПРОСТОГО ПРЕДШЕСТВОВАНИЯ Мы уже видели, что многие классы грамматик порождают в точности множество детерминированных языков. Однако сущест- вует несколько важных классов грамматик, не порождающих всех детерминированных языков. Один из таких классов обра- зуют LL-грамматики. В настоящем разделе мы изучим другой такой класс, а именно класс грамматик простого предшествова- ния. Мы покажем, что множество языков простого предшество- вания является собственным подмножеством множества детерми- нированных языков и несравнимо с множеством LL-языков. Бу- дет показано также, что множество языков операторного пред- шествования является собственным подмножеством множества языков простого предшествования. 8.3.1. Класс языков простого предшествования Как отмечалось в гл. 5, каждый КС-язык имеет обратимую грамматику и грамматику предшествования. Если грамматика об- ладает обоими этими свойствами, то у нас — грамматика и язык простого предшествования. Интересно изучить порождающую спо- собность грамматик простого предшествования. Они могут по- рождать только детерминированные языки, поскольку всякая грамматика простого предшествования имеет детерминированный анализатор. Докажем два основных результата, относящихся к языкам простого предшествования. Сначала покажем, что язык Lt = {а0" 1п | п 1} и {&0"1in | п 1} не является языком простого предшествования. Теорема 8.19. Языки простого предшествования образуют собственное подмножество множества детерминированных языков. Доказательство. Ясно, что каждая грамматика простого предшествования является LR(1 (-грамматикой. Для того чтобы доказать, что включение собственное, покажем, что не сущест- вует грамматики простого предшествования, порождающей де- терминированный язык Lf Интуитивно причина этого состоит в том, что никакой ана- лизатор простого предшествования для Lt не может содержать счетчика нулей, встретившихся во входной цепочке, и в то же время помнить, встретился ему в начале входной цепочки сим- 183
ГЛ. 8. ТЕОРИЯ ДЕТЕРМИНИРОВАННОГО РАЗБОРА вол а или Ь. Если анализатор запоминает в магазине первый входной символ, за которым следует строка нулей, то, как только во входной цепочке встретится цепочка единиц, анализатор не сможет определить, одна или две единицы соответствуют каж- дому записанному в магазине нулю, не стерев предварительно все нули, содержащиеся в магазине. С другой стороны, если анализатор попытается поместить в верхушку магазина указание на то, какой символ — а или b — встретился раньше, то он дол- жен будет в процессе чтения нулей выполнить последователь- ность сверток, разрушающую счетчик нулей, встретившихся во входной цепочке. Приведем теперь формальное доказательство, основанное на этом интуитивном рассуждении. Предположим, что G = (N, £,/>, S) — грамматика простого предшествования и L(G) = L1. Покажем, что этого не может быть, т. е. что всякая грамматика простого предшествования должна порождать цепочки, не принадлежа- щие L,. Допустим, что входную цепочку аО'*®, ®£ 1*, надо проана- лизировать с помощью анализатора простого предшествования, построенного для G алгоритмом 5.12. Так как аО" для любого п является префиксом некоторой цепочки из Llt каждый нуль должен в конце концов оказаться в магазине. Обозначим через «,• содержимое магазина после переноса /-го нуля. Если = для некоторого i<j, то цепочки aO-'l ‘ и aO'V либо обе допус- каются, либо обе отвергаются анализатором, и потому если i=£j, то a(#=az. Таким образом, для любой константы с можно найти такую цепочку а(, что |а,|>с и а,-—префикс любой цепочки «у при / > г (если это не так, можно построить такую последователь- ность aS:, aJi, ... произвольной длины, что = для и тем самым найти две совпадающие цепочки а). Выбе- рем наименьшее i. Тогда должна найтись такая кратчайшая це- почка р=/=е, что для каждого k «,р* = «;+т4 для некоторого /п>0. Это следует из того, что поскольку «,• не стирается, пока на входе появляются нули, символы, записываемые анали- затором в магазин, не зависят от Поведение анализатора при входной цепочке аО" должно быть цикличным, и он должен либо увеличивать длину цепочки, содержащейся в магазине, либо по- вторно приходить к ситуации с одной и той же магазинной це- почкой (последнее, как мы уже доказали, невозможно). Рассмотрим теперь поведение анализатора при входной це- почке вида Ь0"х. Обозначим содержимое магазина после чтения подцепочки Ь0к через ук. Как и раньше, можно доказать, что для некоторой цепочки yJt где / выбрано наименьшим, найдется такая кратчайшая цепочка 6 е, что для каждого k yftk = 7/^ 186
S.3. ТЕОРИЯ ЯЗЫКОВ ПРОСТОГО ПРЕДШЕСТВОВАНИЯ для некоторого q > 0. На самом деле, поскольку никогда не стирается, должно быть 6 = р и q = m. Другими словами, прос- той индукцией по г^О можно показать, что если после чтения а0‘ + г магазин содержит «,ег, то после чтения bW~r он будет со- держать ууЕг. Изучим поведение анализатора, обрабатывающего входную цепочку а0'+га*1‘+'”*. После чтения ад‘+тк магазин будет содер- жать а,Р4. Пусть s — наибольшее из чисел, обладающих тем свой- ством, что после чтения в магазине остается а,£ для некоторой цепочки £ из (NuS)* (т. е. если после этого на входе появляется 1, то один из символов цепочки а,- участвует в свертке). Ясно, что s существует; в противном случае анали- затор допустил бы цепочку, не принадлежащую L1. Аналогично пусть г — наибольшее из чисел, таких, что ана- лизатор, начав работать с цепочкой у,р* в магазине и получив на вход придет к ситуации с цепочкой y/Q в магази- не. Как и раньше, ясно, что г существует. Таким образом, для любого k входная цепочка b(K+mk}l+mk~s должна допускаться, поскольку после чтения b0J'+mk в магазине содержится цепочка а после чтения l‘+“ft~s— цепочка <Ху£. Цепочки р стираются независимо от того, что находится ниже: а,- или «у, а 1г приводит к допуску. Но так как т=£0, то для всех k не может выполняться равенство' i mk—s г —- 2 (j mk). Отсюда заключаем, что L2 не является языком простого пред- шествования. □ Теорема 8.20. Классы языков и языков простого предшест- вования несравнимы. Доказательство. Язык LA из теоремы 8.19 представляет собой ЬЬ(1)-язык, не являющийся языком простого предшество- вания. Естественная грамматика для Ll такова: S аА | ЬВ А—>0А1 101 В --0/Л 1 |011 Легко видеть, что это ЬЬ(2)-грамматика. Левая факторизация превращает ее в ЬЬ(1)-грамматику. Язык L2= {O^al" | п > 1} U {О'*Ь2'" | «5; 1} не является LL-язы- ком (см. упр. 8.3.2). L2 — это язык простого предшествования с грамматикой простого предшествования S—, А\В А —>0А1 |а В —> 062 | b □ 187
ГЛ. S. ТЕОРИЯ ДЕТЕРМИНИРОВАННОГО РАЗБОРА 8.3.2. Языки операторного предшествования Исследуем класс языков, порождаемых грамматиками опера- торного предшествования. Мы покажем, что хотя существуют неоднозначные грамматики операторного предшествования (прос- тым примером такой грамматики служит грамматика S —> А | В, А—>а, В—>а), языки операторного предшествования образуют собственное подмножество множества языков простого предше- ствования. Начнем с того, что покажем, что каждый язык опе- раторного предшествования порождается обратимой операторной грамматикой без цепных правил. Лемма 8.13. Всякая (не обязательно обратимая) грамматика операторного предшествования эквивалентна грамматике опера- торного предшествования без цепных правил. Доказательство. Легко видеть, что алгоритм 2.11, уст- раняющий цепные правила, сохраняет отношения операторного предшествования между терминалами. □ Дадим теперь алгоритм, превращающий произвольную КС- грамматику без цепных правил в обратимую грамматику без цепных правил. Алгоритм 8.6. Превращение КС-грамматики, не со- держащей цепных правил, в эквивалентную обра- тимую грамматику. Вход. КС-грамматика G = (N, 2, Р, S) без цепных правил. Выход. Эквивалентная обратимая грамматика G1 = (N1, 2, Р„ SJ- Метод. (1) Нетерминалами новой грамматики будут непустые под- множества множества N. Формально положим N; = {M|M<=N и М=£0} U{Sj}. (2) Для всех ®0, ...,№„ из 2* и Л1,, ..., Mk из NJ вклю- чить в PJ правила М—► WgAljaij. . . где М = {А | в Р су- ществует правило А—^WgBjW^ . .B^w^, для l^i<fe}, М #= 0. Заметим, что таким способом порождается только ко- нечное число правил. (3) Для всех М s N, содержащих S, включить в PJ правила (4) Устранить все бесполезные нетерминалы и правила. По- лученные полезные подмножества множеств NJ и PJ обозначить N( и Pj соответственно. □ Пример 8.5. Рассмотрим грамматику .8 —► а | aAbS Л- -а\ aSbA 188
8.3. ТЕОРИЯ ЯЗЫКОВ ПРОСТОГО ПРЕДШЕСТВОВАНИЯ На шаге (2) включаем в Р', правила {S} -» а {Д} 6{S} | a {S, A\b {S}\а {Л}6{5, А} {Л} — a {S} Ь{Л} | а {S, Л} b {Л} |а {S} b {S, Л} {S, Л} —a|a{S, Л}Ь{£, А} На шаге (3) добавляем Si—»{S}|{S, Д} На шаге (4) обнаруживаем, что все {S}- и {Д}-правила беспо- лезны, и получаем, таким образом, грамматику Sf — {S, Л} {S, Д}—>-a|a{S, Л}6{5, Л} □ Лемма 8,14. Грамматика Gir построенная по G в алгоритме 8.6, обратима, если G не содержит цепных правил, и является грамматикой операторного предшествования, если G —грамматика операторного предшествования. Кроме того, L (Gt) = L(G). Доказательство. Обратимость гарантируется шагом (2), а поскольку G не содержит цепных правил, на шаге (3) не мо- гут появиться необратимые правые части. Доказательство того, что алгоритм 8.6 сохраняет отношения операторного предшест- вования между терминалами, очевидно; мы оставляем его в качестве упражнения. Наконец, легко проверить индукцией по длине вывода, что если А^М, то A w тогда и только тогда, когда М =>0, w. □ Итак, язык операторного предшествования порождается грам- матикой в следующей нормальной форме. Теорема 8.21. Если L—язык операторного предшествования, то L = L(G) для некоторой грамматики операторного предшест- вования G = (N, 2, Р, S), такой, что (1) G — обратимая грамматика, (2) S не встречается в правых частях правил, (3) цепные правила обязательно имеют S в левой части. Доказательство. Достаточно применить алгоритмы 2.11 и 8.6 к произвольной грамматике операторного предшествова- ния. □ Превратим теперь грамматику операторного предшествования G в нормальной форме, описанной в теореме 8.21, в обратимую грамматику слабого предшествования 6\, для которой £(СЛ = = ^L(G), где ф — левый концевой маркер. Потом построим обрати- мую грамматику слабого предшествования С2, для которой L(G2) = 18?
ГЛ. 8. ТЕОРИЯ ДЕТЕРМИНИРОВАННОГО РАЗБОРА =- L(G). Тем самым мы покажем, что множество языков опера- торного предшествования является подмножеством множества языков простого предшествования. Алгоритм 8.7. Превращение грамматики оператор- ного предшествования в грамматику слабого предшествования. Вход. Обратимая грамматика операторного предшествования G =- (N, S, Р, S), удовлетворяющая условиям теоремы 8.21. Выход. Обратимая грамматика слабого предшествования Gt= = (Nj, 2 U {4. ^i> ^1), для которой L(G,) = (!L(G), где Метод. (1) Пусть N; состоит из всех таких символов [XAJ, что и A N. (2) Положим S1 = [^S]. (3) Зададим гомоморфизм h из N[ U S U {4 в N U 2 равенст- вами (а) h(a) = a для ag2(j{4> (б) /г(|аА])=аА. Д-фа) определено только для цепочек a g (N и 2)*, начинающих- ся символом из 2 U {4 и не имеющих рядом стоящих нетерми- налов. Кроме того, если значение А-1(а) определено, то оно един- ственно. Другими словами, /г-1 объединяет нетерминал со стоя- щим слева от него терминалом. Пусть Р{ состоит из всех таких правил [аД]—► h-'(aa), что А—и agS|j{4- (4) Полезные подмножества множеств N[ и Р[ обозначим и Р, соответственно. □ Пример 8.6. Пусть G определяется правилами S-* А А —>-аАЬАс | aAd | а Образуем только полезные подмножества множеств NJ и Р{ из алгоритма 8.7. Начнем с нетерминала |ф8]- Ему отвечает пра- вило [4>]—► [М]-Правилами для [^А] будут [MJ—► 4а?ЧрА]с, [фА]^ф[аА]й и [М]—Правила для [аА] и [ЬА] стро- ятся аналогично. Таким образом, правилами грамматики Gj будут [44 —[MJ [М] — [«А] [&А] с | ф [аА] d | фа [аА] а [аД ] [М] с | а[аА] d | аа [6Д]^{>[аД1[6Д]с| b[aA]d[ba □ Лемма 8.15. Грамматика GT из алгоритма 8.7 является об- ратимой грамматикой слабого предшествования и L(Gl) = ^L(G). 190
8.3. ТЕОРИЯ ЯЗЫКОВ ПРОСТОГО ПРЕДШЕСТВОВАНИЯ Доказательство. Обратимость доказать легко, и мы не будем этого делать. Чтобы показать, что G,— грамматика сла- бого предшествования, надо установить, что отношения <• и Л. в G, не пересекаются с Зададим гомоморфизм g равенст- вами (1) g(a) = a для всех a 6 2, (2) g({!) = $, (3) g([a4)] = a. Достаточно показать, что (1) если X<tY в G,, то g(X)<«g(F) или g(X)±g{Y) в G, (2) если X Л Y в G,, то g (X) g (К) или g (X) Л g (Г) в G, (3) если X ~i>Y в Glt то g (X) •> g (F) в G. Случай Г. Пусть X <• Y в Gt, где и Х#=$. Тогда в Pt есть правило с такой правой частью, скажем «Х[аД]|3, что [аЛ]=>с, Yy для некоторой цепочки у. Если а=£е, легко пока- зать, что в Р есть правило с правой частью, содержащей в ка- честве подцепочки А(Х[аД])а), и значит, g(X) = a в G. Но из вида правил в Рг следует, что g(Y) = a. Таким образом, g(X)ig(F). Если а — е и XgS, то левая часть правила с правой частью «Х[аЛ]р имеет вид [Хв] для некоторого BgN. В этом случае в Р должно быть правило, правая часть которого содержит в качестве подцепочки ХВ. Более того, В—► аДй(р)— правило из Р. Следовательно, X <• а в G. Так как в этом случае g(X) = X, мы заключаем, что g(X)<«g(F). Если = е и Х = [Ьв] для некоторых b 5 2 и BgX, обозначим левую часть, соответствую- щую правой части «Х[аД]р, через [ЬС]. Тогда в Р есть пра- вило с правой частью, содержащей в качестве подцепочки ЬС,. и С—>ВаД/г(р) принадлежит Р. Поэтому Ь <£а в G и, значит, g(X)<«g(F). Случай а = е и Х = |уВ] для некоторого BgN (а также Х = {! или Х = $) легко анализируется. Случай 2: Случай X = Y рассматривается аналогично случаю 1. Случай 3: X •> Y. Предположим, что F^=$. Тогда в Рс есть правило с такой правой частью, скажем a[aA]Zfi, что [аД]=Фс,?Х и Z=>C1F6 для некоторых у и 6. Вид правил в Pt таков, что либо Z = K и оба принадлежат 2lJ {S}, либо Z = [aB] и Y = [aC] или Y = а для некоторых В и С из N. В любом слу- чае g(Z)=g(F). В Р должно быть правило с правой частью, содержащей подцепочку Ag(Z), поскольку a[<M]Z|3 служит правой частью х) Здесь и далее символы <•, и •> обозначают отношения оператор- ного предшествования в G и отношения предшествования Вирта — Вебера в Gi. 2) h — гомоморфизм, определенный в алгоритме 8.7. 191
ГЛ. S. ТЕОРИЯ ДЕТЕРМИНИРОВАННОГО РАЗБОРА некоторого правила из Рг. Так как G не содержит цепных пра- вил, за исключением начального, у=£е, и значит, в выводе [аД] =>5, уХ g(X) выводится не из а, а из А. Поэтому g(X) •> g(Z) и g(X)>g(y) в G. Случай У = $ не вызывает затруднений. Для завершения доказательства того, что G,— грамматика слабого предшествования, нужно показать, что если правила А —> «Х[3 и В—>р принадлежат то не выполняется ни одно из соотношений Х<»в и ХЛ.В. Положим Д = [аС] и временно допустим, что C^=S. Тогда, поскольку G не содержит цепных правил, у которых в левой части стоит символ, отличный от S, можно утверждать, что р = Ур' для некоторой цепочки р'=#е, где h(Y) = a. Так как р'^=е, то А(р') содержит хотя бы один терминал. Пусть Ь — самый левый из этих терминалов. Тогда, поскольку а может встретиться в правовыводимой в G цепочке слева от С, можно считать, что а<£Ь в G. Но так как аХр служит правой частью некоторого правила из Plt то h (р) — под- цепочка правой части некоторого правила из Р, и значит, а^_Ь в G. Тем самым возможность C=£S исключается. Если C — S, то по теореме 8.21(2) должно быть а = ф. Но в этом случае, поскольку «Хр — правая часть некоторого пра- вила из Plt Ф должно встретиться в правой части некоторого правила из Р, что по нашему допущению неверно. Отсюда заключаем, что G,— грамматика слабого предшество- вания. Доказательство равенства L (<31) = фЦО) очевидно, и мы его опускаем. □ Теорема 8.22. Всякий язык операторного предшествования является языком простого предшествования. Доказательство. Согласно теореме 8.21 и лемме 8.15, если i_£-' — язык операторного предшествования, то ф!.—обра- тимый язык слабого предшествования, Легко обобщить алгоритм 8.4 так, чтобы устранить из грамматики языка фВ, построенной алгоритмом 8.7, левый концевой маркер. (Вид пра- вил в алгоритме 8.7 гарантирует, что полученная грамматика будет приведенной и обратимой.) Детали доказательста оставляем читателю в качестве упражнения. По теореме 5.16 L — язык простого предшествования. □ 8.3.3. Обзор содержания главы Отношения включения для классов языков, установленные в гл. 8, можно изобразить в виде рис. 8.7. Все включения соб- ственные. Приведем примеры языков из классов, показанных на рис. 8.7: 192
S.3. ТЕОРИЯ ЯЗЫКОВ ПРОСТОГО ПРЕДШЕСТВОВАНИЯ (а) {0"1п | п 1} — LL(1)-h3bik и в то же время язык опера- торного предшествования, (Ь) {О»!" | 1} U {О',2'11 1} — язык операторного предшест- вования, по не LL-язык, (с) 'аО» 1 "О" | т, 1} и {Ь0т 1 "О” | т, 1} и {a0”2”0m | т, n> 1 }— язык простого предшествования, не являющийся ни языком операторного предшествования, ни LL-языком, КС-языки ё детерминированные КС-языки LRC.11 -языки (1,1)- ОПК-языки ОГ(2,1) простые ССП / _________________ ОП ПП ОГСП е LL-языки Рис. Ь.7. Подклассы класса детерминированных языков. (ОГ(2,1)—языки, порождаемые обратимыми грамматиками (2, ^-предшествования, простые ССП — языки, порождаемые простыми ССП-грамматикамн, ПП —языки простого пред- шествования, ОГСП — языки, порождаемые обратимыми грамматиками слабого предшествования, ОП — языки операторного предшествования.) (d) {«СГ1"О'” | т, и > 1} и {Ь0“ 1 "О" | т, п~^ 1} — LL(1)-h3hk и в то же время язык простого предшествования, но не операторного п редшествовани я, (е) {а0"1',| njs 1} и {ЬО" 1 -п | п о» 1} — 1_П(1)-язык, но не язык про- стого предшествования, (/) {а0"1'‘ | п 5= 1} U {аОп22'' | п. 1} и {Ь0"12" | njs 1} —детерми- нированный язык, не являющийся ни языком простого пред- шествования, ни LL-языком, (g) {О'1!".|пО» I} U {О"!2"|пО» 1} — КС-язык, но не детермини- рованный. 7 А. Ахо, Дж. Ульман, т. 2 193
ГЛ, S. ТЕОРИЯ ДЕТЕРМИНИРОВАННОГО РАЗБОРА Доказательства этих утверждений предлагаем в качестве упражнений. УПРАЖНЕНИЯ 8.3.1. Покажите, что грамматика языка Lt, приведенная в теореме 8.20, является ЬЬ(2)-грамматикой. Найдите для L, LL(1 (-грамматику. *8.3.2. Докажите, что язык L.. = (O^al" | 1} U {0"Ь2'’ | п 1} не является LL-языком. Указание: Предположите, что L2 имеет LL(fe)-rpaMMaTHKy в нормальной форме Грейбах. *8.3.3. Покажите, что язык L2 из упр. 8.3.2 является языком операторного предшествования. 8.3.4. Докажите, что алгоритм 2.11 (исключение цепных пра- вил) сохраняет свойства (а) операторного предшествования, (б) (т, «(-предшествования, . (в) (т, «(-ОПК. 8.3.5. Докажите лемму 8.14. *8.3.6. Почему алгоритм 8.6 ие всегда превращает произволь- ную грамматику предшествования в грамматику простого пред- шествования? 8.3.7. Превратите следующую грамматику операторного пред- шествования в эквивалентную грамматику простого предшество- вания: S—• if b then Sj else S| if b then S| a S1 —► if b then S, else a 8.3.8. Проведите доказательство в случае 2 из леммы 8.15. 8.3.9. Дайте алгоритм устранения из языка, порождаемого некоторой грамматикой, левого концевого маркера. Покажите, что если Ваш алгоритм применить к грамматике, построенной алгоритмом 8.7, то полученная грамматика останется обратимой грамматикой слабого предшествования. 8.3.10. Покажите, что язык простого предшествования L ~ {а0п1п0т[ 1, m> 1} и (Ь0"1“0’11 л 1, т^1\ ие является языком операторного предшествования. Указание: Покажите, что во всякой грамматике для L будут одновременно выполняться отношения операторного предшествования 1 <• 1 и 1 •> 1. *8.3.11. Покажите, что язык L из упр. 8.3.10 является язы- ком простого предшествования. 194
ЗАМЕЧАНИЯ ПО ЛИТЕРАТУРЕ *8.3.12. Докажите, что языки, описанные в разд. 8.3.3, обла- дают всеми приписанными им там свойствами. 8.3.13. Приведите дополнительные примеры языков, принадле- жащих разным классам, указанным на рис. 8.7. 8.3.14. Обобщите теорему 8.18 так, чтобы можно было пока- зать, что язык L, из этой теоремы не является обратимым язы- ком (1, ^-предшествования ни для какого k. 8.3.15. Покажите, что грамматика G, из алгоритма 8.7 право- покрываст грамматику G из этого алгоритма. 8.3.16. Верно ли, что грамматика Gv построенная в алго- ритме 8.6, правопокрывает грамматику G из этого алгоритма, если G — приведенная грамматика? **8.3.17. Пусть L — язык простого предшествования {ап0а‘Ь" | г, и 0} и {0а"1а7" 11, п 0} Покажите, что для L не существует анализатора простого пред- шествования, сообщающего об ошибке сразу после прочтения символа 1 из входной цепочки вида а"\а'Ь (см. упр. 7.3.5). Открытая проблема 8.3.18. Каким образом класс обратимых языков (1, ^-пред- шествования, k > 1, связан с классами, показанными на рис 8.7? Читатель должен обратить внимание на упр. 8.3.14. Замечания по литературе Строгое включение множества языков простого предшествования в множе- ство детерминированных КС-языков, а также множества языков операторнсго предшествования в множество языков простого предшествования впервые доказано Фишером [1969]. 7*
9 ПЕРЕВОД И ГЕНЕРАЦИЯ КОДА Разработчику компилятора обычно предоставляется неполное описание языка, для которого он должен построить компилятор. Большую часть синтаксиса языка можно представить в виде КС-грамматики. В то же время точно описать объектный код, кото- рый необходимо сгенерировать для произвольной входной про- граммы, значительно труднее. Широко применимые формальные методы определения семантики языка программирования до сих пор остаются предметом исследований. В настоящей главе мы введем формальные соглашения, кото- рые можно использовать для точного описания переводов, выпол- няемых в компиляторе, и дадим примеры таких формализмов. Затем разработаем методы машинного выполнения переводов, определяемых этими формализмами. 9.1. РОЛЬ ПЕРЕВОДА В ПРОЦЕССЕ КОМПИЛЯЦИИ Напомним, что в гл. 1 компилятор определялся как транс- лятор, отображающий цепочки в цепочки. Входом компилятора служит цепочка символов, составляющая исходную программу. Выход компилятора, называемый объектной программой, есть также цепочка символов. Объектная программа может быть (1) последовательностью абсолютных машинных команд, (2) последовательностью перемещаемых машинных команд, (3) программой на языке ассемблера, (4) программой на некотором другом языке. Обсудим вкратце характеристики каждой из.приведенных форм объектной программы. (1) Метод отображения исходной программы в абсолютную программу на машинном языке, которую можно непосредственно выполнить, является одним из способов, позволяющих добиться очень быстрой компиляции. Примером компилятора такого рода служит WATFOR. Такой тип компиляции больше всего подходит 196
9.1. РОЛЬ ПЕРЕВОДА В ПРОЦЕССЕ КОМПИЛЯЦИИ для небольших программ, не использующих независимо компи- лируемых подпрограмм. (2) Перемещаемая машинная команда представляет собой ко- манду, в которой участвуют адреса ячеек памяти относительно некоторого подвижного начала. Объектная программа в форме последовательности перемещаемых машинных команд обычно на- зывается перемещаемым объектным сегментом. Этот сегмент может быть связан с другими объектными сегментами, такими, как независимо компилируемые подпрограммы пользователя, программы ввода — вывода и библиотечные функции; при этом получается единый перемещаемый объектный сегмент, часто на- зываемый модулем загрузки. Программа, собирающая модуль загрузки из совокупности сегментов, называется редактором связей. Модуль загрузки затем размещается в памяти програм- мой, называемой загрузчиком, которая превращает перемещае- мые адреса в абсолютные. После этого объектная программа готова к выполнению. Хотя редактирование связей и загрузка требуют времени, большинство промышленных компиляторов вырабатывает пере- мещаемые сегменты, чтобы получить возможность гибко исполь- зовать большие библиотечные подпрограммы и независимо ком- пилируемые подпрограммы. (3) Подход, при котором выполняется перевод исходной про- граммы в программу на языке ассемблера, которая в свою оче- редь обрабатывается ассемблером, упрощает конструирование компилятора. Однако общее время, требуемое для того, чтобы выработать программу на машинном языке, достаточно велико, так как обработка выхода такого компилятора ассемблером может занимать столько же времени, сколько и сама компиляция. (4) Некоторые компиляторы (например, Снобол) преобразуют исходную программу в другую программу на специальном внут- реннем языке. Эта внутренняя программа затем выполняется путем моделирования последовательности команд внутренней про- граммы. Такие компиляторы обычно называются интерпретато- рами. Мы можем, однако, рассматривать как пример собственно компиляции только отображение исходной программы во внут- ренний язык. В этой главе выходу компилятора не будет приписываться никакого фиксированного формата, хотя во многих примерах в качестве объектного кода берется язык ассемблера. В настоя- щем разделе мы рассмотрим в общих чертах процесс компиляции и основные методы преобразования исходной программы в объект- ный код. 197
ГЛ. 9. ПЕРЕВОД И ГЕНЕРАЦИЯ КОДА 9.1.1. Фазы компиляции В гл. I мы видели, что компилятор можно расчленить на несколько промежуточных трансляторов, каждый из которых выполняет перевод некоторого представления исходной про- граммы, пока, наконец, не будет получена объектная программа. Каждый промежуточный транслятор можно считать преобразова- нием, определяющим одну фазу компиляции, а композиция всех фаз дает компиляцию в целом. Выбор того, что назвать фазой, достаточно произволен. Удобно считать основными фазами компиляции лексический ана- лиз, синтаксический анализ и генерацию кода. Тем не менее во многих развитых компиляторах эти фазы часто разбиваются на несколько подфаз; могут также быть и другие фазы (например, оптимизация, кода). Входом компилятора служит цепочка символов. Лексический анализатор — это первая фаза компиляции. Он отображает свой вход в цепочку, состоящую из лексем и элементов таблицы имен. В ходе лексического анализа размеры первоначальной, исходной программы несколько уменьшаются, так как иденти- фикаторы заменяются лексемами, а ненужные пробелы и ком- ментарии выбрасываются. После лексического анализа перера- батываемая информация остается по существу цепочкой, но не- которые части этой цепочки являются указателями на инфор- мацию в таблице имен. Хорошая модель лексического анализатора — конечный пре- образователь. Мы обсуждали конечные преобразователи и их применение к лексическому анализу в разд. 3.3. Методы, кото- рыми можно пользоваться для помещения информации в табли- цы имен и извлечения ее оттуда, будут изложены в гл. 10. Синтаксический анализатор воспринимает выход лексического анализатора и разбирает его в соответствии с некоторой вход- ной грамматикой. Эта грамматика аналогична грамматике, ис- пользованной при описании входного языка. Однако грамматика входного языка обычно не уточняет, какие конструкции следует считать лексемами. Примерами некоторых конструкций, кото- рые обычно распознаются во время лексического анализа, слу- жат ключевые слова, константы и такие идентификаторы, как метки и имена переменных. Но эти же конструкции могут рас- познаваться и синтаксическим анализатором, и на практике не существует жесткого правила, определяющего, какие конструк- ции должны распознаваться на лексическом уровне, а какие надо оставить синтаксическому анализатору. После синтаксического анализа можно считать, что исходная программа преобразована в дерево, называемое синтаксическим. Синтаксическое дерево тесно связано с деревом вывода исходной 193
9.1. РОЛЬ ПЕРЕВОДА В ПРОЦЕССЕ КОМПИЛЯЦИИ программы и, как правило, является просто деревом вывода с удаленными цепочками цепных правил. В синтаксическом дереве внутренние вершины в основном соответствуют операциям, а листья представляют операнды, состоящие из указателей входов в таблицу имен. Структура синтаксического дерева отражает синтаксические правила языка программирования, на котором написана исходная программа. Для физического представления синтаксического дерева существует несколько способов, которые мы разберем в следующем разделе. Представление синтаксиче- ского дерева мы будем называть промежуточной программой. Фактическим выходом синтаксического анализатора может быть последовательность команд, необходимых для того, чтобы строить промежуточную программу, обращаться к таблице имен, изменять ее и выдавать, когда это требуется, диагностические сообщения. В гл. 4 — 7 мы рассмотрели модель синтаксического анализатора, порождающую левый или правый разбор. В то же время свойства синтаксических деревьев, используемых на прак- тике, позволяют легко заменить номера правил в правом или левом разборе командами построения синтаксического дерева и выполнения операций над таблицей имен. Поэтому имеет смысл считать левые и правые разборы, порождаемые анализаторами, описанными в гл. 4— 7, промежуточными программами, а между синтаксическим деревом и деревом разбора не делать сущест- венного различия. Компилятор должен также проверять, соблюдены ли опреде- ленные семантические соглашения входного языка. Приведем несколько общих примеров таких соглашений: 4 (1) каждая операторная метка, на которую есть ссылка, I должна фактически появляться в качестве метки некоторого оператора в исходной программе, (2) никакой идентификатор не может быть описан более од- ного раза, (3) все переменные должны определяться перед использова- ' нием, (4) при вызове функции число аргументов и их атрибуты должны быть согласованы с определением функции. Процесс проверки компилятором этих соглашений называется семантическим анализа^. Часто семантический анализ произво- дится сразу после синтаксического анализа, но его также мож- но выполнить и на более поздних фазах компиляции. Например, проверку того, что переменные определяются перед использо- ванием, можно произвести во время оптимизации кода, если такая фаза есть. Проверку согласованности атрибутов операн- . дов можно отложить до фазы генерации кода. В гл. 10 мы изучим грамматики свойств, служащие фор- мальным аппаратом, с помощью которого можно моделировать 199
ГЛ. 9. ПЕРЕВОД И ГЕНЕРАЦИЯ КОДА различные аспекты синтаксического и семантического анали- зов. После синтаксического анализа промежуточная программа отображается генератором кода в объектную программу. Однако для того, чтобы сгенерировать правильный объектный код, гене- ратор кода должен еще иметь доступ к информации, хранящейся в таблице имен. Например, свойства операндов данной операции определяют код, который нужно сгенерировать для этой опера- ции. Так, если А и В—переменные с плавающей точкой, то объектный код, сгенерированный для Д+В, будет иным, нежели в случае, когда А и В — целые. Во время генерации кода (или на некоторой ее подфазе) про- исходит и распределение памяти. Поэтому генератор кода дол- жен знать, представляет ли переменная скаляр, массив или структуру. Эта информация хранится в таблице имен. В некоторых компиляторах генерации кода предшествует фаза оптимизации. На этой фазе промежуточная программа под- вергается преобразованиям с целью привести ее к такой форме, из которой можно получить более эффективную объектную про- грамму. Часто бывает трудно отличить некоторые преобразования оптимизации от хороших приемов генерации кода. Несколько прие- мов оптимизации, применимых после построения промежуточной программы или в процессе ее генерации, мы рассмотрим в гл. 11. Реальный компилятор может осуществлять фазу компиляции за один или более проходов. Проход состоит в чтении входа из внешней памяти с последующей записью промежуточных резуль- татов во внешнюю память. Объем работы, выполняемой за один проход, является функцией размера машины, на которой будет работать компилятор, языка, для которого разрабатывается ком- пилятор, числа людей, занятых в разработке компилятора, и т. д. Возможно даже осуществление всех фаз компиляции за один проход. Обсуждение вопроса об оптимальном числе проходов для данного компилятора выходит за рамки нашей книги. 9.1.2. Представления промежуточной программы В этом разделе мы рассмотрим некоторые возможные пред- ставления промежуточной программы, вырабатываемой синтак- сическим анализатором. Промежуточная программа должна отражать синтаксическую структуру исходной программы. В то же время каждый оператор промежуточной программы должен относительно просто транслироваться в машинный код. Компиляторы, осуществляющие значительную работу по опти- мизации кода, создают детальное представление промежуточной программы, точно отражающее порядок выполнения исходной программы. В других компиляторах представлением промежу- 200
9.1. РОЛЬ ПЕРЕВОДА В ПРОЦЕССЕ КОМПИЛЯЦИИ точной программы служит простое представление синтаксического дерева, такое, как польская запись. Некоторые компиляторы, незначительно оптимизирующие код, генерируют объектный код по мере разбора. В этом случае «промежуточная» программа существует только условно в виде последовательности шагов алгоритма разбора. Вот несколько общепринятых представлений промежуточной программы: (1) постфиксная польская запись, (2) префиксная польская запись, (3) связные списочные структуры, представляющие деревья, (4) многоадресный код с явно именуемыми результатами, (5) многоадресный код с неявно именуемыми результатами. Рассмотрим примеры таких представлений. Польская запись для арифметических выражений была опре- делена в разд. 3.1.1. Например, оператор присваивания (9.1.1) 4 = В + С*— D с обычными приоритетами операций и знака присваивания (-=) в постфиксной польской записи имеет вид1) ABCD — * + = а в префиксной польской записи — вид = Л +В*С — D В постфиксной польской записи операнды выписаны слева направо в порядке их использования. Знаки операций стоят спра- ва от операндов в порядке выполнения операций. Постфиксная польская запись часто используется интерпретаторами в качестве промежуточного языка. Фаза выполнения программы интерпре- татором может состоять в вычислении постфиксного выражения с помощью магазина при сумматоре (см. пример 9.4). Оба типа польских выражений являются линейными пред- ставлениями синтаксического дерева выражения (9.1.1), показан- ного па рис. 9.1. Это дерево отражает синтаксическую структуру выражения (9.1.1). Можно также взять это дерево само в качест- ве промежуточной программы, закодировав его в виде связной списочной структуры. Другой метод кодирования синтаксического дерева - при- менение многоадресного кода. Например, используя многоадрес- ный код с явно именуемыми результатами, можно представить выражение (9.1.1) последовательностью операторов присван- 9 В этой записи операция — является унарной, а операции », + в = бинарными. 2С1
ГЛ. 9. ПЕРЕВОД И ГЕНЕРАЦИЯ КОДА вания 7\<----D Т\^СТ\ Т,— -\-ВТг А—Тг! , Оператор вида Д <— QBt...Br означает, что r-местную опе- рацию 0 надо применить к текущим значениям переменных Вг, а полученное значение присвоить переменной А. Соответствующий язык будет фор- х—х мально определен в разд. 11.1. ( = ) Многоадресный код с явно /—\ именуемыми результатами при каждом присваивании требует име- ( + ) ни временной переменной для того, чтобы связать с ним значение вы- / \ ражения, стоящего справа в one- z \ У \ раторе присваивания. Можно из- \А/ xlx бежать необходимости употреблять временные переменные, если поль- —У зоваться многоадресным кодом с ( с ) \ ) неявно именуемыми результатами. В такой записи каждый оператор Jl присваивания помечается числом. Ло) Затем мы убираем левую часть one- ратора и обращаемся к промежу- Рис. дд Синтаксическое дерево, точным результатам при помощи числа, приписанного оператору, вырабатывающему промежу- точный результат. Например, выражение (9.1.1) будет представ- лено последовательностью 1: -D 2: *С(1) 3: +В(2) 4: = 4(3) Здесь число в скобках адресует выражение, помеченное этим числом. Представления в виде многоадресного кода удобны с вычис- лительной точки зрения, если фаза оптимизации кода следует за фазой синтаксического анализа. В течение фазы оптимизации кода представление программы может существенно меняться. Внести существенные изменения в польское представление про- *) Заметим, что операцию присваивания нужно рассматривать иначе, чем остальные. Простая „оптимизация" состоит в том, чтобы в третьей строке за- менить Та на А, а четвертую строку выбросить. 202
9.1. РОЛЬ ПЕРЕВОДА В ПРОЦЕССЕ КОМПИЛЯЦИИ межуточной программы значительно труднее, чем в представление ее в виде связной списочной структуры. В качестве второго примера рассмотрим представление опе- ратора (9.1.2) if/ = J then Sj else где S’, и S2 обозначают произвольные операторы. Возможным постфиксным польским представлением этого опе- ратора может быть } J EQUAL? L2 JFALSE S[ L JUMP S2 Здесь и S2—постфиксные представления для .S’, и S2 соответ- ственно; EQUAL? — бинарная операция, дающая значение истина, Рис. 9.2. Дерево вывода. если оба аргумента равны, и ложь в противном случае; L2 — константа, именующая начало .Sy, JFALSE — бинарная операция, вызывающая переход на место, указываемое вторым аргументом, если значение первого аргумента ложь, и не вызывающая никаких действий, если значение первого аргумента истина; константа L именует первую следующую за S2 команду; JUMP—унарная операция, вызывающая переход на место, указываемое аргу- ментом. Дерево вывода оператора (9.1.2) приведено на рис. 9.2. Суще- ственную информацию, содержащуюся в этом дереве вывода, можно представить синтаксическим деревом, приведенным на рис. 9.3, где S; н S2 — синтаксические деревья S, и S2. Синтаксический анализатор, генерирующий промежуточную программу, разбирал бы выражение (9.1.2), просматривая дерево на рис. 9.2, но его выходом была бы последовательность команд построения синтаксического дерева рис. 9.3. 203
ГЛ. 9. ПЕРЕВОД И ГЕНЕРАЦИЯ КОДА В синтаксическом дереве, вообще говоря, внутренняя вер- шина представляет операцию, операндами которой служат ее прямые потомки. Листья синтаксического дерева соответствуют идентификаторам. Фактически листья являются указателями на таблицу имен, в которой хранятся имена и атрибуты соответст- вующих идентификаторов. {.оператор „ еаш“> Рис. 9.3. Синтаксическое дерево. Часть выхода синтаксического анализатора составляют команды занесения информации в таблицу имен. Например, кон- струкция исходной программы вида INTEGER / будет преобразована в команду, заносящую атрибут „целое" в позицию таблицы имен, зарезервированную для идентифика- тора I. Явного представления этой конструкции в промежуточ- ной программе не будет. 9.1.3. Модели процесса генерации кода Генерация кода — это отображение промежуточной программы в цепочку. Мы будем считать его функцией, определенной на синтаксическом дереве и на информации, содержащейся в таб- лице имен. Характер отображения зависит от исходной про- граммы, конкретной машины и качества желаемого объектного кода. Одна из простейших схем генерации кода состоит в том, что каждый оператор многоадресного представления отображается в последовательность команд па выходном языке, независимо от контекста команд в многоадресном представлении. Например, оператор присваивания вида А— + АС может отображаться в три машинные команды LOAD В ADD С STORE А 204
УПРАЖНЕНИЯ Здесь мы предполагаем, что используется однопроцессорная машина, в которой команда LOAD В помещает содержимое ячейки В в сумматор, ADD С складывает1) содержимое ячейки памяти С с содержимым сумматора, a STORE А помещает со- держимое сумматора в ячейку А. Команда STORE содержимого сумматора не изменяет. Однако если в сумматоре уже хранилось содержимое ячейки В (например, в результате выполнения предыдущей команды при- сваивания В*—ЁОЕ), то команда LOAD В становится лишней. Кроме того, если следующая команда имеет вид F------|-Дби А нигде больше не используется, то не нужна и команда STORE А. В разд. 11.1 и 11.2 мы изложим несколько приемов генера- ции кода по операторам многоадресного представления. УПРАЖНЕНИЯ 9.1.1. Нарисуйте синтаксические деревья для следующих операторов входного языка: (а) А = (В—С)/(В4-С) (в Фортране), (6) /=LENGTH (С1ЦС2) (в ПЛ/1), (в) if В > С then if D > Е then А : = В + С else А : = В — С else А := В*С (в Алголе). 9.1.2. Найдите постфиксные польские представления для программ из упр. 9.1.1. 9.1.3. Сгенерируйте многоадресный код с явно именуемыми результатами для операторов из упр. 9.1.1. 9.1.4. Постройте детерминированный МП-преобразователь, отображающий префиксную польскую запись в постфиксную польскую запись. 9.1.5. Покажите, что не существует детерминированного МП- преобразователя, отображающего постфиксную польскую запись в префиксную польскую запись. Существует ли недетерминиро- ванный МП-преобразователь, выполняющий такое отображение? Указание: См. теорему 3.15. 9.1.6. Разработайте алгоритм вычисления постфиксного поль- ского выражения, использующий магазин. 9.1.7. Сконструируйте МП-преобразователь, который, полу- чая на вход выражение w из L(G0), порождает на выходе по- 1) Для простоты допустим, что у нас только один тип арифметики. Если таких типов несколько, например арифметика с фиксированной и плавающей точкой, то перевод операции -у будет зависеть от информации об атрибутах имей В и С, записанной в таблице имен. 205
ГЛ. 9. ПЕРЕВОД И ГЕНЕРАЦИЯ КОДА следовательность команд построения синтаксического дерева (или многоадресного кода) для w. 9.1.8. Сгенерируйте программы на языке ассемблера наиболее знакомой Вам машины для программ из упр. 9.1.1. *9.1.9. Разработайте алгоритмы для генерации программ на языке ассемблера наиболее знакомой Вам машины, соответствую- щих промежуточным программам, представляющим арифмети- ческие действия и присваивания, когда промежуточная программа является (а) программой в постфиксной польской записи, (б) программой в многоадресном коде с явно именуемыми результатами, (в) программой в многоадресном коде с неявно именуемыми результатами, (г) некоторым представлением синтаксического дерева. *9.1.10. Сконструируйте язык, удобный для представления некоторого подмножества Фортрана (или ПЛ/I, или Алгола). Это подмножество должно включать операторы присваивания и некоторые операторы управления. В нем должны допускаться переменные с индексами. **9.1.11. Постройте генератор кода, отображающий промежу- точную программу из упр. 9.1.10 в машинный код наиболее знакомой Вам машины. Замечания по литературе К сожалению, даже для простых конструкций входного языка нельзя точно определить наилучший объектный код. Тем не менее существует ряд книг и статей, посвященных переводу различных языков программирования. Бэкус и др. [1957] подробно описали ранний компилятор Фортрана. Ренделл и Рассел [1964|, Грау и др. [1967] изучили задачу реализации Алгола 60. Некоторые детали реализации языка ПЛ/I приведены в ИБМ [1969J. Во многих работах излагаются методы, полезные при генерации кода. Кнут [1968а] исследовал различные методы распределения памяти. Элсон и Рейк [1970] рассмотрели вопрос о генерации кода для древовидных структур промежуточного языка. Уилкокс [1971] представил несколько общих моделей для процесса генерации кода. 9.2. СИНТАКСИЧЕСКИ УПРАВЛЯЕМЫЕ ПЕРЕВОДЫ В настоящем разделе мы рассмотрим модель компилятора, в которой синтаксический анализ и генерация кода объединены в одну фазу. Такую модель можно представлять себе как компи- лятор, в котором операции генерации кода совмещены с опера- циями разбора. Для описания компиляции такого типа часто употребляется термин синтаксически управляемая компиляция. 206
9.2. СИНТАКСИЧЕСКИ УПРАВЛЯЕМЫЕ ПЕРЕВОДЫ Описываемые здесь методы можно применять также при гене- рации промежуточного, а не только объектного кода, или кода на языке ассемблера. Мы приводим один пример перевода в про- межуточный код, остальные примеры относятся к коду на языке ассемблера. Нашим отправным пунктом будет схема синтаксически управ- ляемого перевода (СУ-схема), описанная в гл. 3. Мы покажем, как осуществить синтаксически управляемый перевод с помощью детерминированного МП-преобразователя, выполняющего нисхо- дящий или восходящий анализ. В этом разделе будем считать, что ДМП-преобразователь использует специальный символ § в качестве ограничителя правого конца входной цепочки. Кроме того, чтобы сделать СУ-схему более гибкой, мы наделим се до- полнительными свойствами. Прежде всего, разрешим существо- вание семантических правил, в которых определяется более одного перевода в различных вершинах дерева разбора. В фор- мулах для этих переводов разрешим повторения и условные выражения. Затем рассмотрим переводы, не являющиеся цепоч- ками; полезные дополнительные типы переводов — целые и логи- ческие переменные. Наконец, разрешим, чтобы переводы опре- делялись другими переводами, найденными ие только в прямых потомках рассматриваемой вершины, но и в ее прямом предке. Сначала покажем, что всякую простую СУ-схему, заданную на LL-грамматике, можно реализовать детерминированным пре- образователем. Затем исследуем, какие простые СУ-схемы на LR-грамматике можно реализовать таким способом. Мы изучим расширение ДМП-автомата, называемое МП-процессором, кото- рое служит для реализации всего класса СУ-переводов, вход- ными грамматиками которых являются LL- или LR-грамматики. После этого вкратце рассмотрим синтаксически управляемые переводы в связи с алгоритмами разбора с возвратом. 9.2.1. Простые синтаксически управляемые переводы В гл. 3 мы видели, что простую СУ-схему можно реализо- вать недетерминированным МП-преобразователем. В настоящем разделе мы исследуем детерминированные реализации некоторых простых СУ-схем. -Переводы, определяемые для языка L(G), и эффективность, с которой их можно непосредственно реализовать, могут зави- сеть от входной грамматики G. Пример 9.1. Пусть требуется отобразить выражения, порож- даемые грамматикой G с правилами Е—► а-\-Е | а* Е | а, в пре- фиксные польские выражения, в предположении что операция * 207
ГЛ <> ПЕРЕВОД И ГЕНЕРАЦИЯ КОДА имеет более высокий приоритет, чем 4-, т е. префиксным выражением для а*а + а будет + »ааа, а не »а-\-аа. Не существует СУ-схемы, для которой грамматика G была бы входной грамматикой и которая определяла бы такой пере- вод. Причина состоит в том, что выходная грамматика такой СУ-схемы должна быть линейной КС-грамматикой. В то же время нетрудно показать, что множество префиксных польских выра- жений в алфавите { + , *, а], соответствующих инфиксным выра- жениям языка L(G), не является линейным КС-языком. Тем не менее этот конкретный перевод можно определить, пользуясь простой СУ-схемой, у которой входной грамматикой служит Go (без правила F—□ В теореме 3.14 было доказано, что если (х,у)—элемент про- стого синтаксически управляемого перевода, то выход у можно построить по левому разбору цепочки х с помощью детермини- рованного МП-преобразователя. Отсюда следует, что если грам- матику G удается естественным образом разобрать детермини- рованно сверху вниз с помощью ДМП-преобразователя М, то М легко модифицировать так, чтобы реализовать любую простую СУ-схему, входной грамматикой которой служит G. Если G — ЕЕ(/г)-грамматика, то любой простой СУ-п^ревод, определенный на G, реализуется ДМП-преобразователем следующим образом. Теорема 9.1. Пусть Т = (N, 2, A, R, S)—семантически одно- значная *) простая СУ-схема, входной грамматикой которой служит ЪЦ^-грамматика. Тогда перевод {(a j, у) | (х, у) £ т (Т)} можно осуществить детерминированным МП-преобразователем. Доказательство. Доказательство вытекает из дока- зательств теорем 3.14 и 5.4. Если G — входная грамматика схемы Т, то но алгоритму 5.3 для G можно построить /г-пред- сказывающий алгоритм разбора. Реализуем этот /г-предсказы- вающий анализатор на ДМП-преобразователе М с концевым маркером и выполним перевод следующим образом. Пусть Д' = (а'|а£Д}, причем Д'(12 — 0, и Н(а) — а' для всех а£Д. Анализатор, сконструированный по алгоритму 5.3, поочередно заменяет нетерминалы правыми частями правил, используя для этого ЕЬ(/г)-таблицы, содержащие нетерминалы. Автомат М делает по существу то же самое. Предположим, что левый анализатор заменяет А на . Bmwm (к нетермина- Авторы используют понятие, определение которого дается несколько позже —в разд. 9.3. Однозначная СУ-схема — это сбычная СУ-схема.— Прим. ред. 20Л
9.2. СИНТАКСИЧЕСКИ УПРАВЛЯЕМЫЕ ПЕРЕВОДЫ лам добавляются некоторые ЬЬ(^)-таблицы, не показанные здесь). Пусть Д - -щДау .. . х„В1Х1 ... Втхт — правило из R. Тогда М заменит А на w„h(xa)B,wlh(x1)... Bmwmh(xm). Как и в алгоритме 5.3, всякий раз, когда символ из X по- является в верхушке магазина, он сравнивается с текущим входным символом, и если они совпадают, то символ удаляется из магазина, а входная головка сдвигается па одну ячейку вправо. Когда в верхушке магазина оказывается символ а' из Д', М порождает а и удаляет а' из верхушки магазина, не сдвигая при этом входной головки. М не порождает номеров правил. Более формальное построение автомата М оставляем чита- телю. □ Пример 9.2. Пусть Т — простая СУ-схема с правилами S — aSbSc, 1S2S3 S — d, 4 Входная грамматика является простой БЬ(1)-грамматикой. По- этому не обязательно запоминать в магазине LL-таблицы. Пусть М —детерминированный МП-преобразователь ((?, S, Д, Г, S, q, S, {допуск}), где Q = {<?, допуск, ошибка} S = {а, Ь, с, d, $} r='.S, $} и S и Д Д = {1, 2, 3, 4} Так как 2АД = 0, положим Д' = Д, Функцию 6 зададим равен- ствами S (9, a, S) = (q, Sb2Sc3, 1) *) <5(9. d, S) = (9, е, 4) 6 (9, b, b) = (9, e, e) 6 (q, c, c) = (9, e, e) 6 (q, e, 2) = (9, e, 2) 6(9, e, 3) = (9, e, 3) 6 (9, $, $) = (допуск, e, e) В остальных случаях &(q, X, Y) = (ошибка, e, e) J) Здесь мы отказываемся от ограничений, сформулированных при дока- зательстве теоремы 9.1 и заключающихся в том, что операции порождения выходного символа и сдвига входной цепочки после распознавания правила грамматики должны выполняться в разных тактах. 209
ГЛ 9. ПЕРЕВОД И ГЕНЕРАЦИЯ КОДА Легко проверить, что т(/И)= {(х$, у) | (х, у) £ т (Г)]. □ Рассмотрим теперь простую СУ-схему, входной грамматикой которой служит ЬК(/г)-грамматика. Поскольку класс LR(^)-rpaM- матик шире класса ЬЦ/г)-грамматик, интересно исследовать, какой класс простых СУ-схем, входными грамматиками которых служат ЬК(й)-грамматики, можно реализовать на ДМП-преобра- зователях. Оказывается, существуют семантически однозначные простые СУ-схемы, имеющие в качестве входных грамматик ЬК(^)-грамматики и не реализуемые ни на каком ДМП-прсоб- разователе. Неформально это объясняется тем, что элемент пере- вода может требовать порождения выхода задолго до того, как выяснится, что правило, которому приписан этот элемент пере- вода, действительно было применено. Пример 9.3. -Рассмотрим простую СУ-схему Т с правилами S—>Sa, aSa S^Sb, bSb S —► e, e Входная грамматика является СР(1)-грамматикой, но по лемме 3.15 не существует ДМП-преобразователя, определяю- щего перевод {(х $, у) | (х, у) ё т(Г)}. Неформально это объясняется тем, что, согласно первому правилу этой СУ-схемы, символ а должен порождаться раньше, чем выяснится, что было применено правило S—► Sa. □ Однако, если простая СУ-схема, входная грамматика кото- рой является ЬР(й)-грамматикой, не требует, чтобы выход порождался до того, как будет установлено, какое правило при- менялось, такой перевод можно реализовать на ДМ11-преобразо- вателе. Определение. СУ-схему Т = (N, 2, A, R, S) будем называть постфиксной, если каждое правило из R имеет вид Д'— где 6£N*A!>. Иными словами, каждый элемент перевода пред- ставляет собой цепочку из нетерминалов, за которыми следует цепочка выходных символов. Теорема 9.2. Пусть Т = (N, 2, A, R, S)— семантически одно- значная простая постфиксная СУ-схема, входной граммати- кой которой служит ].[)[1г)-грамматика. Тогда перевод {(.с $, у) | (х, у) ё т(7’)} можно осуществить детерминированным МП-преобразователем. Доказательство. Применяя алгоритм 5.11, можно для входной ЬК(&)-грамматики сконструировать детерминированный 210
9.2. СИНТАКСИЧЕСКИ УПРАВЛЯЕМЫЕ ПЕРЕВОДЫ правый анализатор М с концевым маркером. Однако, вместо того чтобы порождать номер правила, М порождает цепочку выходных символов элемента перевода, связанного с этим пра- вилом. Иными словами, если А—► a, fix — правило из /?, где fig У* и xgA‘, то всякий раз, когда анализатор порождает номер правила А—их, автомат М порождает цепочку х. Работая таким образом, автомат М определяет перевод {(%$, г/)|(х, у)е-г(Т)}. □ В качестве упражнения предлагаем доказать утверждение, обратное теореме 9.2, а именно: любое детерминированное МП- преобразование можно выразить в виде постфиксной простой СУ-схемы, заданной на ЬК(1)-грамматике. Пример 9.4. Постфиксные переводы полезнее, чем это может показаться на первый взгляд. Мы рассмотрим расширенный ДМП-преобразователь, отображающий арифметические выраже- ния языка Z.(G0) в машинный код специальным образом выбран- ной машины. Машина имеет магазин при сумматоре. Команда LOAD X помещает значение, записанное в ячейке X, в верхушку мага- зина; все остальные элементы магазина проталкиваются вниз. Команды ADD и MPY соответственно складывают и перемножают содержимое двух верхних ячеек, убирая эти ячейки и помещая результат в магазин. Для разделения команд служит точка с запятой. Наша СУ-схема имеет вид Е—> Е + Т, ЕТ ‘ADD; Е-> т. Т T*F, TF ‘MPY; Т-+ F, F F— (Е), Е F—> а, ‘LOAD а; ’ В этом и во всех последующих примерах мы будем пользовать- ся обозначениями Снебола, заключая цепочки букв и цифр в правилах перевода в кавычки. Кавычки не являются частью выходной цепочки. Получив на вход цепочку ДМП-преобразователь проходит следующую последовательность конфигураций (здесь ЬК(й)-таблицы из магазина выброшены; в последовательности опущены, кроме того, некоторые очевидные конфигурации, а также 211
ГЛ. 9. ПЕРЕВОД И ГЕНЕРАЦИЯ КОДЛ очевидные состояния и маркер, содержащийся в самой нижней ячейке магазина): [е, а + (а*й)$, е] h [а, +(а*а)$, е] Н [F, +(а*й)$, LOAD а;] Нг[Е, +(а»а)$, LOAD а ;] |— 8[£ + (а, *я)$, LOAD а;] I- [E + (F, *я)$, LOAD а ; LOAD а;] [£ + (Г, *а) $, LOAD а ; LOAD а;] г|Е + (Т * а, )$, LOAD а ; LOAD а ;] Н- [£ + (Г»£, )$, LOAD а; LOAD а; LOAD а ;] Н [£ + (Т, ) $, LOAD а; LOAD а ; LOAD а ; MPY;] I- [Е + (£, ) $, LOAD а; LOAD а ; LOAD а; MPY ;] |Е 4- (£), $, LOAD а ; LOAD а ; LOAD а ; MPY ;] Н|£ + Т, S, LOAD а ; LOAD а ; LOAD а ; MPY ;] h [£, 5, LOAD а; LOAD а ; LOAD а ; MPY ; ADD ;] Заметим, что если буквы а, представляющие идентификаторы, снабжены индексами так, что входное выражение имеет, напри- мер, вид аг -|- (а,» аг), то выходным кодом будет LOAD а, LOAD а2 LOAD а3 MPY ADD На нашей машине эта программа вычисляет исходное выраже- ние. □ Хотя модель вычислительной машины, описанная в приме- ре 9.4, предназначалась только для демонстрации синтаксически управляемого перевода весьма простых выражений, постфикс- ная схема способна определить полезные классы переводов. В оставшейся части главы мы покажем, как получается объект- ный код в других моделях вычислительных машин, работающих подобно МП-преобразователям над тем, что является по существу простой постфиксной СУ-схемой, у которой входной граммати- кой служит LR-грамматика. Предположим, что у нас есть простая, но не постфиксная СУ-схема, входная грамматика которой является LR(A)-rpaM- матикой. Как выполнить такой перевод? Один из возможных методов состоит в использовании следующей многопроходной схемы перевода. Этот метод иллюстрирует каскадную связь 2)2
9.2. СИНТАКСИЧЕСКИ УПРАВЛЯЕМЫЕ ПЕРЕВОДЫ ДМП-преобразователей. Правда, на практике такой перевод можно было бы осуществить и за один проход, если методы следующего раздела применить к произвольным СУ-схемам. Пусть T = (N, S, А, 7?, S) — семантически однозначная про- стая СУ-схема с входной ЬК(£)-грамматикой G. Для нахождения Уровень 1 л, правый раэоор Зря w Рис. 9.4. Простой СУ-перевод над ЬИ(й)-грамматикой. т(7') можно построить четырехуровцевую схему перевода. Пер- вый уровень занимает ДМП-преобразователь. Его входом слу- жит входная цепочка и>$. Выходом является правый разбор л цепочки w, соответствующий входной грамматике G. На втором уровне л обращается — получается обратный правый разбор л®1). Входом для третьего уровня будет л4. Выходом —перевод, определяемый простой СУ-схемой 7,' = (N, S', A, R', S), где R’ содержит правило Л ... Bt, утВт ... ytBtya тогда и только тогда, когда А —-x^Xj . .. ВиХ^у^В^.. .Втуа — правило из Р, а А —... Втхя — правило с номером I вход- ной ЬК(£)-грамматики. Легко доказать, что (nfi, ук) gr(T') тогда и только тогда, когда (S, S) ля(ш, у). г) Напомним, что правый разбор л—это последовательность щэавил в пра- вом выводе, записанная в обратном порядке. Таким образом, л# начинается с первого примененного правила и заканчивается последним. Для построения л^ достаточно прочитать буфер, в котором записана последовательное]ь л, в об- ратном порядке. 213
ГЛ. 9. ПЕРЕВОД И ГЕНЕРАЦИЯ КОДЛ Т' — это простая СУ-схема, основанная на И-(1)-грамматике, и, следовательно, ее можно реализовать на ДМП-преобразова- теле. На четвертом уровне просто обращается выход третьего уровня. Если выход третьего уровня записывается в магазин, то на четвертом уровне символы выталкиваются из магазина и по мере выталкивания пишутся в выходную цепочку. Эта процедура представлена на рис. 9.4. Число основных операций, выполняемых на каждом из этих уровней, пропорционально длине цепочки ш. Таким образом, получаем следующий результат: Теорема 9.3. Любую простую СУ-схему с входной ^(^-грам- матикой можно реализовать за время, пропорциональное длине входной цепочки. Доказательство. Доказательство представляет собой формализацию изложенного выше. □ 9.2.2. Обобщенный преобразователь С помощью МП-преобразователя хорошо описываются все простые СУ-схемы над LL-грамматиками и некоторые простые СУ-схемы над LR-грамматиками, но для реализации (1) непростых СУ-схем, (2) непостфиксных простых СУ-схем над LR-грамматиками, (3) простых СУ-схем над грамматиками, не являющимися LR-грамматиками, (4) синтаксически управляемого перевода в случае, когда разбор проводится недетерминированным образом и не за один проход (как в гл. 4 и 6), нам потребуется более гибкая модель транслятора. Определим теперь новое устройство, называемое МП-процес- сором. С его помощью можно будет определить синтаксически управляемые переводы, отображающие цепочки в графы. МП-про- цессор—это МП-преобразователь, выходом которого служит помеченный ориентированный граф, представляющий собой в об- щем случае дерево или часть дерева, которое строит процессор. Основная особенность МП-процессора состоит в том, что в его магазине, помимо магазинных символов, могут содержаться ука- затели па вершины выходного графа. Подобно расширенному МП-автомату, МП-процсссор может исследовать верхние k ячеек своего магазина для любого ко- нечного k и произвольным образом обрабатывать их содержи- мое. Если эти k ячеек содержат указатели на выходной граф, то в отличие от МП-автомата МП-процессор может видоизменять выходной граф, добавляя или выбрасывая направленные дуги, 214
9.2. СИНТАКСИЧЕСКИ УПРАВЛЯЕМЫЕ ПЕРЕВОДЫ соединяющие вершины, на которые указывают эти указатели. МП-процессор может также создавать новые вершины, помечать их, создавать указатели на них и строить дуги, соединяющие эти вершины с теми вершинами, на которые указывают указа- тели, содержащиеся в верхних ячейках магазина. Из-за трудностей, возникающих при выработке компактной и ясной формальной записи для описания таких операций, будем пользоваться словесным описанием работы МП-процессора. Так как на каждом шаге работы МП-процессора обрабатывается лишь конечное число указателей, вершин и дуг, такой форма- лизм в принципе возможен, однако мы считаем, что он только заслонил бы идейную простоту рассматриваемых алгоритмов. Начнем сразу с примера. Пример 9.5. Построим МП-процессор Р, отображающий ариф- метические выражения языка L(G„) в синтаксические деревья. В этом случае синтаксическое дерево будет деревом, в котором внутренние вершины помечены знаками 4- или», а листья—бук- вами а. На рис. 9.5 и 9.6 перечислены операции разбора и вы- дачи, выполняемые МП-процессором для всех возможных ком- бинаций текущего входного символа и символа, содержащегося в верхушке магазина. Р сконструирован на основе SLR(l)-aHa- лизатора для G„, показанного на рис. 7.37. Правда, в данном случае таблица Т, исключена из рис. 7.37 и правило F—>а рассматривается как цепное; таблицы пере- именованы следующим образом: Старое имя Г„ 7 t Ta Тв Т, Т„ Т, Т1а Тг1 Новое имя Г, 7; ( + * Т3 Ts Tt ) Кроме того, правым концевым маркером служит символ $. Опе- рации разбора и выдачи процессора Р приведены на рис. 9.5 и 9.6. Для того чтобы определить нужное действие, Р исполь- зует ЬК(1)-таблицы. Помимо этого, когда таблицы Т\, Тг, Т3 и Т, помещаются в магазин, Р прикрепляет к ним указатели ). Эти указатели относятся к порождаемому выходному графу. Однако указатели не влияют на процесс разбора. При разборе символы грамматики в магазин не записываются. Тем пе менее имена таблиц указывают, что эго должны быть за символы. Последний столбец на рис. 9.5 содержит имя новой LR(1)- таблицы, которую нужно поместить в магазин после свертки. Пустые элементы обозначают ошибочные ситуации. Новый вход- г) На практике эти указатели можно запоминав в магазине непосредст- венно под таблицами. 215
ГЛ. 9. ПЕРЕВОД И ГЕНЕРАЦИЯ КОДА ной символ считывается только после переноса. Числа в таб- лице относятся к действиям, приведенным на рис. 9.6. Действие Пере- ход То Ti Тг То То + * ( ) 4 5 6 7 перенос 4- перенос-}- 2 3 перенос * перенос * перенос * 3 перенос ( перенос ( перенос ( перенос ( перенос 2 3 допуск 2 3 ‘ з 7*4 Т2 7 7 Рис. 9.5. МП-процессор Р. (1) Построить новую вершину п с меткой а. Поместить в верхушку магазина символ [7\, р], где р —указатель па п. Прочитать новый входной сим- вол. (2) На этом этапе в верхушке магазина записана цепочка из четырех сим- волов вида X [Г/, PiJ + 17*/, р2], где Pi и Pz~указатели на вершины и п2 соответственно. Построить новую вершину п с мешой • Сделать пг и п2 левым и правым прямыми потомками вершины п. Заменить (Г/» P1J+ [?’/» Pel на Pb где 7 — переход (X), а р — указатель на вер- шину п. (3) То же, что и (2), но вместо 4- стоит *. (4) То же, что и (1), но вместо стоит 73. (5) То же,, что и (1), но вместо 7\ стоит 74. (6) То же, что и (1), но вместо 7\ стоит’7а. (7) Магазин теперь содержит Х([7, р]), где р—указатель на некоторую вер- шину п. Заменить ([7, р]) на \Т', р], где Т' = переход(Х). Рис. 9.6. Действия процессора по построению выхода. Проследим за поведением процессора Р, на вход которого поступает цепочка аг * (й2 +й3) $• Для ясности буквы а снабжены 216
9.2. СИНТАКСИЧЕСКИ УПРАВЛЯЕМЫЕ ПЕРЕВОДЫ индексами. Р выполняет такую последовательность тактов: (1) т„ а1*(а2 + а,)$ (2) Л [Л, Pi] »(а2 + ая)$ (3) Л ЕЛ. pJ* (а2 + а3)$ (4) Та{7\, Р1]*( @2 4- я3) $ (5) Л [Л, pxX[Ts, рг] + аз)$ (6) То [т1’ Pl]* (ЕЛ. Pa] + аз) $ (7) T„[Tt, Pi]* (ЕЛ. Ра] + [Л. Pa] )$ (8) Л [Л. Pi]*([Л, p4] )$ (9) Л ЕЛ. Р1]*(1Л. pJ) -$ (Ю) ЛЕЛ. Р1]*ЕЛ. Pi] $ (П) T’oET’i, Ра] $ Здесь левый столбец представляет содержимое магазина, пра- вый— входную цепочку. Исследуем некоторые интересные такты из этой последова- тельности. Переходя из конфигурации (1) в конфигурацию (2), Р создает вершину nlt помеченную символом а, и устанавливает указатель р, на эту вершину. Указатель запоминается в ма- газине вместе с ЬК(1)-таблицей Тг. Аналогично, переходя из конфигурации (4) в конфигурацию (5), Р создает новую вер- шину пг, помеченную символом а2, и помещает в магазин ука- затель />, на эту вершину вместе с ЬК(1)-таблицей Т2. В кон- фигурации (7) образуется еще одна вершина п„, помеченная символом а3, и устанавливается указатель ps на эту вершину. Рис. 9.7. Выход после достижения конфигурации (8). Перейдя в конфигурацию (8), Р создает выходной граф, изо- браженный на рис. 9.7. Здесь р4 —указатель на вершину п,. После того как процессор попадает в конфигурацию (11), выход- ной граф имеет вид, показанный на рис. 9.8. Здесь — указатель на вершину п5. В конфигурации (11) действием таблицы 7\ на 217
ГЛ. 9. ПЕРЕВОД И ГЕНЕРАЦИЯ КОДА входе $ служит допуск, и, следовательно, дерево, изображенное на рис. 9.8, является окончательным выходом. Это синтаксичес- кое дерево для выражения а1*(а2 + йз)- □ 9.2.3. Детерминированный однопроходный восходящий перевод Это первый из трех разделов, в которых показывается, как можно обобщить различные алгоритмы анализа для реализации СУ-схемы с помощью детерминированного МП-процессора вместо МП-преобразователя. Начнем с того, что дадим алгоритм реали- зации произвольной СУ-схемы с входной LR-грамматикой. Алгоритм 9.1. Реализация СУ-схемы над LR-грам- матикой. Вход. Семантически однозначная СУ-схема Т = (N, 5, A, Р, S) с входной 1_Р(/г)-грамматикой G = (N, S, Р, S) и входная це- почка S*. Выход. Выходное дерево, крона которого служит переводом w. Метод. Дерево строится МП-процессором М, моделирующим КК(/г)-анализатор Л для грамматики G. Как и Л, М запоминает в магазине (верхушка которого расположена справа) символы из NU2 и КР(А)-таблицы. Кроме того, М записывает под каж- дым нетерминалом указатель на порождаемый выходной граф. Действия перенос, свертка и допуск процессора М описываются так: 218
9.2. СИНТАКСИЧЕСКИ УПРАВЛЯЕМЫЕ ПЕРЕВОДЫ (1) Когда Л переносит символ а в магазин, М делает то же самое. (2) Если Л свертывает Х\ . . . Хт в нетерминал А, то М делает следующее: (а) Пусть А —» X. ... Х,„, w„B.w. . .. Brwr — правило СУ-схемы, где символы В взаимно однозначно соответст- вуют тем символам X, которые являются нетерминалами, (б) М удаляет из магазина X, . . . Х,„ вместе с промежу- точными указателями Ы?(А:)-таблиц и, если ука- затель, расположенный непосредственно под Хг (в) М создает новую вершину п, помечает ее символом А и помещает указатель на нее в магазин непосредствен- но под Д. (г) Метки прямых потомков вершины п читаются слева направо: №„6^ . . . Brwr. Для всех символов цепочек w создаются вершины. Вершина для Bh пред- ставляет собой вершину, на которую указывает указа- тель, расположенный в магазине процессора М непо- средственно под Xf, где X., -нетерминал, соответствую- щий В, в данном конкретном правиле СУ-схемы. (3) Если входная цепочка исчерпана (достигнут правый кон- цевой маркер) и в магазине процессора М содержатся только pS и две ЕК(й)-таблицы, то М допускает тогда, когда допускает Л; р указывает на корень выходного дерева процессора М. □ Пример 9.6. Пусть алгоритм 9.1 применяется к СУ-схсме S — а5Д, 0Д5 S-*b, 1 Д- Л;Д.$, 15Д А —► а, О а входной цепочкой служит abbab. Входная грамматика яв- ляется БЕК(1)-грамматикой. Мы не будем рассматривать LR(1)- таблицы, считая, что они правильно управляют разбором. Будем последовательно выписывать цепочки, содержащиеся в магазине МП-процессора, а затем приведем древовидную структуру, на которую указывает каждый из указателей. ЕК(1)-таблицы, со- держащиеся в магазине, опускаем. (е, abbab \—2 (ab, bab$) (apjS, babi) |—2 (ap.Sba, b$) (—(ap.Sbp.A, &$) I- (ap.Sbp.Ab, $) (-(ap.Sbp.ApsS, $) Н (ар^р.А, $) Н (P„S, $) 219
ГЛ. 9. ПЕРЕВОД И ГЕНЕРАЦИЯ КОДА Деревья, построенные к моментам, когда процессор прошел третью, пятую, седьмую, восьмую и девятую конфигурации, изображены на рис. 9.9. Рио. 9.9. Перевод с помощью МП-процессора. Заметим, что когда bp3Ap3S свертывается в А, поддерево, на которое вначале указывал указатель р3, появляется слева от поддерева, на которое указывает р2, так как элемент пере- вода, связанный с А—<-bSA, переставляет справа символы S и А. Аналогичная перестановка .происходит при последней свертке. Можно видеть, что результатом работы процессора на рис. 9.9, д будет 01101. □ Теорема 9.4. Алгоритм 9.1 правильно выполняет перевод вход- ной цепочки в соответствии с данной СУ-схемой. 220
9.2. СИНТАКСИЧЕСКИ УПРАВЛЯЕМЫЕ ПЕРЕВОДЫ Доказательство. Элементарная индукция по порядку, в котором образуются указатели в алгоритме 9.1. □ Добавим, что если мы „реализуем" МП-процессор на обычной вычислительной машине с прямым доступом, то один такт МП- процессора осуществляется за конечное число шагов такой машины. Следовательно, время, затрачиваемое алгоритмом 9.1, является линейной функцией длины входной цепочки. 9.2.4. Детерминированный однопроходный нисходящий перевод Предположим, что перед нами предсказывающий (нисходя- щий) анализатор. Превращение такого анализатора в транслятор требует подхода, несколько отличного от того, который приме- нялся в случае восходящего анализатора. Допустим, что у нас есть СУ-схема с входной LL-грамматикой. В процессе разбора дерево строится сверху вниз, и на каждом этапе можно считать, что построено частичное дерево. Листья этого частичного де- рева, помеченные нетерминалами, соответствуют нетерминалам, содержащимся в магазине предсказывающего анализатора, по- строенного алгоритмом 5.3. Развертка нетерминала эквивалентна созданию потомков для соответствующего листа дерева. Стратегия при переводе состоит в том, чтобы хранить ука- затель на каждый лист „текущего" дерева с нетерминальной меткой. При обычном LL-разборе этот указатель хранится в ма- газине непосредственно под нетерминалом, соответствующим вершине, на которую указывает указатель. При развертке нетерминала по некоторому правилу для соответствующего эле- мента перевода создаются новые листья и на вершины с нетер- минальными метками устанавливаются вновь созданные указа- тели, записанные в магазине. Указатель, записанный непосред- ственно под развертываемым нетерминалом, исчезает. Поэтому необходимо хранить где-то вне МП-процессора указатель на корень образующегося дерева. Например, если магазин содержит Ар и для развертки А применяется правило А—шВЬСс с эле- ментом перевода 0С1В2, то МП-процессор заменит Ар на aBp-JiCp.fi. Если указатель р до развертки указывал на лист с меткой А, то после развертки А будет корнем поддерева где рг указывает на вершину В, а рг— на вершину С. 221
ГЛ 9. ПЕРЕВОД И ГЕНЕРАЦИЯ КОДА Алгоритм 9.2. Нисходящая реализация СУ-схемы н ад LL-r р а мм а т и к о й. Вход. Семантически однозначная СУ-схема Т — (N, S, A, R, S) с входной 1_Ц/г)-грамматикой G = (N, 2, A, Р, S). Выход. МП-процессор, порождающий дерево, крона которого служит переводом для ш, где ш — любая цепочка из ЦО). Метод. Построим МП-процессор (И, моделирующий LL(fe)- анализатор Л для грамматики G.. М моделирует Л следующим образом. Какие алгоритме 9.1, мы опускаем операции работы с таблицами. Для М они те же, что и для Л. (1) Первоначально в магазине процессора М (верхушка на- ходится слева) записана цепочка Spr, где рг — указатель на корневую вершину пг. (2) Если в верхушке магазина анализатора Л содержится терминал и он сравнивается с текущим входным символом, после чего и тот и другой стираются, то в М происходит то же самое. (3) Предположим, что Л развертывает нетерминал А (воз- можно, вместе с соответствующей ЕЬ(й)-таблицей) по правилу А —>• . Хт с элементом перевода уаВ1у1 ... Вгуг н указатель, расположенный непосредственно под А (легко показать, что он всегда существует), указывает на вершину п. Тогда М делает следующее: (а) Для п он образует прямых потомков, помеченных слева направо символами цепочки УиВ^у^ . . . Вгуг. (б) В магазине он заменяет А и расположенный под ним указатель на . . . Хт, причем под теми из символов Xi . Хт, которые являются нетерминалами, записыва- ются указатели. Указатель, расположенный под Xj, указывает на' вершину, образованную для В,-, если X/ и В, соответствуют друг другу в правиле А ► Хг ... Xт, yQBLyг ... Вгуг (4) Если магазин процессора М становится пустым к мо- менту достижения конца входной цепочки, то процессор допу- скает; выходом служит построенное к этому моменту дерево с корнем пг. □ Пример 9.7. Рассмотрим пример из области перевода естест- венного языка. Известно, что СУ-схема дает точную модель перевода с английского языка на другой естественный язык — распространенный жаргон „пиг лэтин“'). Перечислим правила, ') В оригинале pig Latin.— Прим, ред. 222
9,2. СИНТАКСИЧЕСКИ УПРАВЛЯЕМЫЕ ПЕРЕВОДЫ которые неформально определяют перевод английского слова в соответствующее слово на „пиг лэтин": (1) Если слово начинается с гласной, добавляем к нему суф- фикс YAY. (2) Если слово начинается с непустой цепочки согласных, помещаем все согласные до первой гласной в конец слова и добавляем суффикс AY. (3) Однобуквенные слова не изменяем. (4) Буква U, стоящая после Q, считается согласной. (5) Буква Y в начале слова считается гласной, если за ней не следует гласная. Приведем СУ-схему, включающую только правила (1) и (2). В качестве упражнения предлагаем учесть и остальные правила. Правила СУ-схемы таковы: <слово> —> <согласные> <гласная> <буквы>, <гласиая> <буквы> <согласные> ‘AY’ <слово> —>• <гласная> <буквы>, <гласная> <буквы> ‘YAY’ <согласные>—► <согласная> <согласные>, <согласная> <согласные> <согласные>—> <согласная>, <согласная> <буквы> —► <буква><буквы>, <буква><буквы> <буквы> —> е, е <гласная> —► ‘А’, ‘А’ <гласная> —>• ‘Е’, ‘Е’ <гласная> —► ‘U’, ‘U’ <согласная>—► ‘В’, ‘В’ <согласная>—► ‘С’, ‘С’ <согласная>—>‘2’, *Z’ <буква> —>• <гласная>, <гласпая> <буква> —> <согласная>, <согласная> Легко видеть, что входная грамматика является LL(2)-rpaM- матикой. Найдем перевод, соответствующий входному слову “THE”. Как и в предыдущих двух примерах, сначала выпишем конфигурации процессора, а затем- покажем, как выглядит де- рево на различных этапах его построения. Верхушка магазина все время находится слева. 223
ГЛ. 9. ПЕРЕВОД И ГЕНЕРАЦИЯ КОДА (1) ТНЕ$ <СЛОВО>р1 (2) ТНЕ$ <согласные>р2<гласная>р3<буквы>р4 (3) ТНЕ$ <согласпая>р6<согласпые>ре<гласная>р3<буквы>р4 (4) ТНЕ$ Т<согласные>рв<гласная>рз<буквы>р4 (5) НЕ$ <согласныс>рй<гласная>ря<буквы>р4 (6) НЕ$ <согласнаяур7<гласная>р3 <буквы>р4 (7) НЕ$ Н<гласная>р3<буквы>р4 (8) Е$ <гласвая>р3<буквы>р4 (9) Е$ Е<буквы>р4 (10) $ <буквы>р4 (И) $ е Здесь левый столбец означает входную цепочку, правый — содержимое магазина. Структура дерева после шагов 1, 2, 6 и 11 представлена соответственно на рис. 9.10, а—г. □ Как и в предыдущем разделе, легко доказать, что рассмат- риваемый алгоритм выполняет правильный перевод и что на обычной машине с прямым доступом его можно реализовать так, чтобы он работал за время, линейно зависящее от длины входной цепочки. Зафиксируем изложенное в следующей теореме. Теорема 9.5. Алгоритм 9.2 строит МП-процессор, порожда- ющий в качестве выхода дерево, крона которого служит переводом входной цепочки. Доказательство. Индукцией можно доказать, что вход- ная цепочка w вызывает стирание нетерминала А и указателя р в магазине тогда и только тогда, когда (A,A)=^>‘T(w,x), где х — крона поддерева, корнем которого служит вершина, на ко- торую указывает р (после стирания символа А, указателя р и символов, в которые развертывается Д). Детали доказательства оставляем в качестве упражнения. □ 9.2.5. Перевод при наличии возвратов Центральные идеи МП-процессора можно применить также и к алгоритмам разбора с возвратом. Для определенности рас- смотрим, как можно обобщить анализирующую машину из разд. 6.1, чтобы она строила дерево. Основная новая идея за- ключается в том, что процессор должен обладать способностью „разрушать" поддеревья, которые он построил. Иными словами, некоторые поддеревья могут становиться недостижимыми (н, хотя здесь мй не будем разбирать детали реализации, на прак- тике использованные для представления таких поддеревьев ячейки памяти возвращаются в общую доступную память). Модифицируем анализирующую машину из разд. 6.1 так, чтобы предоставить ей возможность помещать в магазин указа- тели на вершины графа. (Напомним, что в анализирующей ма- 224
9.2. СИНТАКСИЧЕСКИ УПРАВЛЯЕМЫЕ ПЕРЕВОДЫ шине уже есть указатели на ее вход; они хранятся в одной ячейке памяти с информационным символом.) Правила работы Т <согласная> Н Рис 9.10. Перевод на «пиг лэтин». с этими указателями те же, что и в случае МП-процессора, поэтому мы пе будем здесь подробно на них останавливаться. Прежде чем описать алгоритм перевода, связанный с анали- зирующей машиной, посмотрим, как переносится понятие СУ - 8 д. Ахо, Дж, Ульман, т. 2 225
ГЛ. 9. ПЕРЕВОД И ГЕНЕРАЦИЯ КОДА перевода на ОЯНРОВ-программы (программы, написанные на Обобщенном Языке Нисходящего Разбора с Ограниченными Возвратами) из разд. 6.1. Разумно предположить, что перевод связан с „вызовом" нетерминала тогда и только тогда, когда этот вызов успешен. Пусть P = (N, 2, R, S) —ОЯНРОВ-программа. Будем интер- претировать ОЯНРОВ-оператор Аа, где agSuje), как по- пытку применить правило А—>а в КС-грамматике. Тогда по аналогии с СУ-схемой можно было бы ожидать, что найдется связанная с этим правилом цепочка выходных символов. Иными словами, все правило будет иметь вид А—>а, w, где ш£Д*; здесь Д— „выходной алфавит". Единственным другим ОЯНРОВ-оператором, способным поро- дить перевод, будет А —» В[С, £>], где А, В, С и D принадлежат N. Можно считать, что здесь участвуют два правила КС-грамма- тики, а именно А—-ВС и А—-D. Если В и С приводят к успеху, то желательно, чтобы перевод для А включал пере- воды для В и С. Поэтому представляется естественным связать с правилом А—>-В[С, D] элемент перевода вида wBxCy или wCxBy, где W, х и у принадлежат Д*. (Если В = С, то должно быть точно определено соответствие между нетерминалами пра- вила и нетерминалами элемента перевода.) Однако, если В приводит к неудаче, хотелось бы, чтобы перевод для А вызывал перевод для D. Поэтому второй элемент перевода, имеющий вид uDv, должен быть связан с правилом А—>• В[С, D], Дадим формальное определение такого метода описания перевода и посмотрим, как можно обобщить анализи- рующую машину, чтобы она выполняла такие переводы. Определение. ОЯНРОВ-програжжой с выходом назовем пятерку P = (N, 2, Д, R, S), где N, 2 и S те же, что для произвольной ОЯНРОВ-программы, Д — конечное множество выходных символов, a R — множество правил вида: (1) A~,f, е, (2) А—► а, у, где a£2u{e} и i/gA’, (3) (а) А В[С, D], yfiyfy,, ytDy„ (б) 4—>В[С, D], y,CyJiy3, yj)y,,, где yt ё Д’. Для каждого нетерминала существует не более одного из этих правил. Определим отношения =3" между нетерминалами и тройками вида (и) v, у, г), где и и v принадлежат 2*, у £ Д* и г — это либо s, либо [. Здесь первая компонента— входная цепочка, в которой отмечено положение входной головки, вторая компо- 226
9.2 СИНТАКСИЧЕСКИ УПРАВЛЯЕМЫЕ ПЕРЕВОДЫ нента — выходная цепочка, а третья — выход, означающий успех или неудачу. (1) Если для А есть правило А—уа, у, то A =>' (a f и, у, s) для всех и б 2*. Если и принадлежит S*, по не начинается с а, то А =>' (| v, е, [). (2) Если для А есть правило А—<-S[C, D], yrEy2Fys, ytDy5, где Е = В и F— С или наоборот, то справедливо следующее: (а) Если В=>“> (Uj | u2u3, X;, s) и С =>"> (u21 u3, х2, s), то А=$"^+1(и2и2\'иг, у^у^у,, s) при Е = В, F = С и А =>»+».11 (и,ц2» и„ ухх2у2х,у2, s) при F. = С и F — B. В случае В —С будем предполагать, что соответствие между Е и F, с одной стороны, и по- зициями, в которых стоят В и С, с другой стороны, указывается с помощью верхних индексов; например, Л ./К1'[/К2*, £»], у.В^у.В'у,, у,Dy,. (б) Если /!=>"' (u, t и,, х, s) и C=:>',i (| и2, е, f), то Л=>’‘.+щ+1(|М1и2, е, [) (в) Если В=^"< (J UjW2, е, [) и D ==>"> (u21 «2, х, s), то Л=>-,+->,+1(и1|и2, ytxyh, s) (г) Если В =»"'(!«, е, [) и D =^>"> (t и, е, f), то Л=ф’>1+'>.+фц, е, [) Заметим, что если А =5>п (и t v, у, f), то и—е и у = е. Иными словами, при неудаче входной указатель не сдвигается и не порождается никакого перевода. Следует также подчеркнуть, что в случае (26) перевод символа В „аннулируется", если С приводит к неудаче. Обозначим через =>+ объединение отношений =^п для njsl. Переводом т(Р), определяемым программой Р, назовем множество {(ш, х) |S=»+ (w f, х, s)}. Пример 9.8. Напишем ОЯНРОВ-программу с выходом, осу- ществляющую перевод на „пиг лэтин", описанный в примере 9.7. Выход будем записывать строчными буквами. При переводе используются нетерминалы, связь которых с предыдущим при- мером показана в табл. 9.1. X и С3 означают здесь цепочки нетерминалов. Кроме того, мы будем пользоваться нетерминалами S и F с правилами S — e и F—yf. Наконец, правила для С\, V и L должны быть такими, чтобы они соответствовали любой соглас- ной, гласной или букве, определяя перевод, который является 8* 227
ГЛ. 9. ПЕРЕВОД И ГЕНЕРАЦИЯ КОДА Таблица 9.1 Пример 9.8 Пример 9.7 и/ Ст с2 ^3 1-2 V X <слово> <согласная> <согласные> <согласпая>* <буква> <буквы> <гласная> <гласная> <буквы> соответствующей буквой. В эти правила входят дополнительные нетерминалы, и мы их опускаем. Существенными правилами будут №-Щ[Х, X], ХСг ‘ay’, X ‘уау’ С2->С,[С3, F], С,С3, F C3—^CI[C„S], С£3, S A. *^]> X ->-V[L2, F], VL2, F Например, если рассматривается входная цепочка ‘and’, то легко видеть, что V =»+ (a f nd, a, s) и L3=S>+ (nd f, nd, s). Поэтому X=»+(and j, and, s). Так KaKCj=>+ (f and, e, f), то С2=Ф+(f and, e, f). Таким образом, W =Ф+ (and f, andyay, s). □ Подобный перевод можно осуществить с помощью модифи- цированной анализирующей машины из разд. 6.1. Действие такой машины основано на следующем наблюдении. Если вызывается процедура А с правилом А—> В[С, £>], то А порождает пере- вод, только если В и С приводят к успеху или В приводит к неудаче, a D — к успеху. Опишем поведение модифицирован- ной анализирующей машины в виде алгоритма. Алгоритм 9.3. Реализация ОЯНРОВ-п р о г р а м м ы с выходом. Вход. ОЯНРОВ-программа P = (N, S, Д, R, S) с выходом. Выход. Модифицированная анализирующая машина М, по- рождающая для любой входной цепочки w дерево с кроной х тогда и только тогда, когда (w, х) принадлежит т(Р). Метод. Если не учитывать элементов перевода, отвечающих правилам из Р, то можно считать, что у нас ОЯНРОВ-программа 228
9 2 СИН'1 АКСИЧЕС'К’И УПРАВЛЯЕМЫЕ ПЕРЕВОДЫ Р' в смысле разд. 6.1. Тогда можг10 п0 лемме 6.6 построить анализирующую машину ,ЛГ, распозн:а1°ЩУю L(P'). Опишем неформально! изменения . которые нужно внести в машину М' для получе.:ния модифит-1НРС1ванной анализирующей машины М. Модифицированная маши^3 моделирует ЛГ и тоже образует вершины в выходном дереве^ помещая в магазин ука- затели на эти вершины. Получив на вход цепсочку w, М. начинает работу в конфи- гурации (начало, (ш, (S„0)pr)- Здес£ Рг указатель на корне- вую вершину пг. (1) (а) Пусть А ->-В[С, £>], у^у^ГУя, У^у-,~правило для А. Предположим, чтсо А1 выполн:яет следующую последова- тельность тактов, реализующуУ10 вызов процедуры А ио правилу А—>В[С, £>]: (начало, ux f u2us, (A, i) у> (начале»» ui t “А, (5, /)(Л, /) у) * (успех, uiui t us, (21, i)f) H (начало». “A t «а. (С, i)y) Затем И выполняют такую последовательность тактов, соответствующую послсдовате;ПЬ11ости тактов, выполнен- ных ранее машинсон М’: (9-2.1) (начало,, f usua, (Л. ОРАу') (9.2.2) (— (начало,, аг f u2us< (Р, /) Рв (А, 0 рврАу') (9.2.3) (успех, jWjM2 f и3, (А • РиРлУ') (9.2.4) j— (начало,, UjU,, ( “а, ((?» () Рс?') В конфигурации (9.2.1) указа»тель Рл на лист пл рас- положен непосредсственно под -Е (Указатели на входную цепочку мы опускаем.) При переходе в конфигурацию (9.2.2) М. образует новую ве;РшинУ Ид. которая стано- вится прямым потгомком вери.1ИНЫ ПА, и помещает ука- затель р,> на пв непосредствен1510 П°Д и над А. Затем М помещает В в верхушке ипазина. В конфигурации (9.2.3) М возвращается к в состоянии успех. При переходе в конфигураций» (9.2.4) М создает пря- мых потомков вершшны пл дЛя всех символов цепочки ytEy,Fy3 и упорядочивает их слева направо. Вершина Ид становится вершиной для или для F (для того символа, который соответствуй7 Е). Обозначим вершину для другого из си'мволов Е и F через пс, В конфигура- ции (9.2.4) М заменяет Ар „pi на Срс, где рс —указа- тель па пс. Таюим образом,- если Е=С и F = то 229
ГЛ 9, ПЕРЕВОД И ГЕНЕРАЦИЯ КОДА в конфигурации (9.2.4) вершина пл является корнем поддерева (б) Если, с другой стороны, В вырабатывает неудачу в правиле А—►BfC, D], то /И выполняет такую после- довательность тактов: (9.2.1) (начало, и,]иги3, (А,1)рАу") (9.2.2) J- (начало, Mj f иги3, (В,/)РвИ, ОРвРл/) (9.2.5) J- ’(неудача, игиг, (А, I)рврАу') (9.2.6) (— (начало, иг f иаи3, (D, i) рд?') При переходе из (9.2.5) в (9.2.6) М. сначала удаляет из выходного дерева вершину пв и всех ее прямых потом- ков, используя для запоминания пя указатель ря, запи- санный под А. Затем для всех символов цепочки в порядке слева направо /И образует прямых потомков вершины пл и заменяет в верхушке магазина АрврА на DpD, где pD—указатель на вершину, построенную для D. (2) Если А —♦ а, у — правило а £ 2 (J {е}, то М выполняет один из следующих тактов: (а) (начало, и f av, (Л, i)pAy)\— (успех, ua\v, у). На этом шаге для каждого символа цепочки у создается прямой потомок вершины пА (вершина, на которую ука- зывав! рА). Если у = е, то прямым потомком станет одна вершина, помеченная символом е. (б) (начало, u\v, (Л, i) рАу) -- (неудача, и' f v', у), где | и' | = I и v не начинается с а. (3) Если Л —► [, е— правило, то М выполняет такт (26). (4) Если М' прочитывает всю входную цепочку w и стирает все символы в магазине, то переводом цепочки w будет построен- ное к этому моменту дерево с корнем пг. □ Теорема 9.6. Алгоритм 9.3 определяет модифицированную анализирующую машину, порождающую для входной цепочки w дерево, крона которого является переводом цепочки w. Доказательство. Доказательство представляет собой простую индукцию по числу тактов, совершаемых машиной М. 230
9,2. СИНТАКСИЧЕСКИ УПРАВЛЯЕМЫЕ ПЕРЕВОДЫ Предположение индукции состоит в том, что если М, начав работу в состоянии начало и имея в верхушке магазина сим- вол А и указатель р на вершину п и цепочку uv справа от входной головки, исчерпывает вход и, в результате удаляя из магазина А и р, и заканчивает работу в состоянии успех, то вершина, на которую указывает р, будет корнем поддерева с такой кроной у, что А =>* (и f v, у, s). □ Пример 9.9. Посмотрим, как анализирующая машина осу- ществляет перевод, описанный в примере 9.8. Мы примем сле- дующую форму записи (табл. 9.2). За конфигурациями будет Таблица 9.2 Состояние Входная цепочка Содержимое магазина начало t and IFpi начало f and (.2р31Гр=Д1 начало f an d С1Р3С2РЯР2 WP2P1 неудача f and начало t and FPiWp.1Pt неудача t and Vp2P1 начало t and Xp„ начало * and VpuXpKpb успех a t nd Х-РъРъ начало a t nd L2p7 начало a f nd ^iPs^iPsPi успех an f d ^iPsPy начало an t d f-sPs начало an f d LiPnAPioPi» успех and f L2PtnP„ начало and f L2P11 начало and f ^IP12^2P12P11 неудача and t AsPiaPll начало and t i’PBI успех and f e 231
ГЛ. 9. ПЕРЕВОД И ГЕНЕРАЦИЯ КОДА следовать построенное к этому моменту дерево. Такты, пред- ставляющие опознание согласных, гласных и букв (нетерминалы С,, V и Z.J, опускаем. Выходное дерево после каждой четвертой конфигурации пока- зано па рис. 9.11. □ Не вдаваясь в подробности, отметим только, что методы, представленные в алгоритме 9.3, применимы и к другим алго- ритмам нисходящего разбора, таким, как алгоритм 4.1 и построе- ние перевода в виде ОЯНРОВ-программы. УПРАЖНЕНИЯ 9.2.1. Постройте МП-преобразователь, реализующий простую СУ-схему Е-.Е--Т, ЕТ ‘ADD’; Е—>Т, Т Т —*T*F, TF ‘MPY’; T .F, F FF f P, FP ‘EXP’; F—>P, P P-»(E), E P —♦ a, ‘LOAD a;’ Преобразователь должен опираться на 8ЬР(1)-алгоритм разбора. Напишите последовательности выходных цепочек, возникающих при обработке выражений (a) a f а» (а-у а), (б) а-\-а*а j а. 9.2.2. Сделайте упр. 9.2.1 для случая МП-процессора, исполь- зующего ЬЕ(1)-алгоритм разбора. Если понадобится, видоизме- ните входную грамматику. 9.2.3. Покажите, каким образом МП-преобразователь, рабо- тающий как LL(1 (-анализатор, будет выполнять перевод следу- ющих цепочек в соответствии с простой СУ-схемой; Е-*ТЕ', ТЕ' Е'-^ + ТЕ', Т ‘ADD’; Е' Е'—>е, е T—>FT', FT' Т' F ‘MPY;’ Т' Т' ->е, е F(Е), Е Fa, ‘LOADa;’ 232
Рис. 9.11. Перевод с «пиг лэгин» с помощью анализирующей машины. (Здесь е — пустая цепочка, перевод символа S.)
ГЛ. 9. ПЕРЕВОД И ГЕНЕРАЦИЯ КОДА (а) о# (а4-я), (б) ((а + а)*а)+а. 9.2.4. Покажите, как МП-процсссор будет выполнять пере- вод цепочки abbbaaaa в соответствии с СУ схемой 3 —* аДа"Дг|, ОД<2>лч'1 S ^Ь, 2 Д ^yS'i’S12’, IS'i'S^'O Д — а, е если разбор проводится с помощью (а) СЦ1)-алгоритма, (б) ЬР(1)-алгоритма. 9.2.5. Покажите, что не существует СУ-схемы для перевода, описанного в примере 9.1, если язык порождается грамматикой Е - at- Е\а * F. \а. 9.2.6. Опишите формально построение МП-преобразователя М из теоремы 9.1. *9.2.7. Докажите, что каждый ДМП-преобразователь опреде- ляет постфиксный простой синтаксически управляемый перевод языка, порождаемого Ы?(1)-грамматикой. Указание: Покажите, что каждый ДМП-преобразователь можно преобразовать к нор- мальной форме, аналогичной той, которая была определена в разд. 8.2.1. *9.2.8. Покажите, что существуют такие переводы Т = = {(%S, i/)}, что Т можно определить ДМП-нреобразователем, но {(х, у) | (х$, у) С Т\ нельзя определить никаким ДМП преобразо- вателем. Сопоставьте этот результат с упр. 2.6.20(6). 9.2.9. Проведите формальное доказательство теоремы 9.3. 9.2.10. Докажите теорему 9.4. 9.2.11. Расширьте СУ-схему из примера 9.7 так, чтобы вклю- чить в нее правила (3) — (5) из определения перевода на „пиг лэтин“. 9.2.12. Можно ли заменить СУ-схему из примера 9.7 простой СУ-схемой, если принять, что в английском языке нет слов, начинающихся более чем с четырех согласных? Изменится ли число правил СУ схемы? 9.2.13. Покажите, как анализирующая маплша с указателями будет выполнять перевод цепочки abb согласно ОЯНРОВ про- 234
УПРАЖНЕНИЯ грамме с выходом S —>• 4 [В, С], ОВД, ПС А —* а, О В-.8’[С, 4], OCS, 14 С- Ь, 1 **9.2.14. Напишите такую ОЯНРОВ программу с выходом, что т(Р) = {(х, у) | х -цепочка, содержащая п символов а и п символов b, n^s() и у = а"Ь"). Постройте по Р модифицирован- ную анализирующую машину Л1, для которой т(/И) = т(Р). Существует ли (а) ЯНРОВ-программа с выходом, (б) СУ-схема, определяющая тот же перевод? 9.2.15. Докажите теорему 9.5. 9.2.16. Докажите теорему 9.6. *9.2.17. Обобщите понятие процессора с указателями на граф и дайте алгоритмы перевода для СУ-схем, основанные на сле- дующих алгоритмах: (а) алгоритм 4.1, (б) алгоритм 4.2, (в) алгоритм Кока — Янгера — Касами, (г) алгоритм Эрли, (д) двухмагазинный анализатор (разд. 6.2), (е) анализатор Флойда—Эванса. Проблема для исследования 9.2.18. При реализации перевода мы часто заинтересованы в его эффективности. Разработайте методы оптимизации, анало- гичные методам гл. 7, позволяющие находить эффективные трансляторы для полезных классов синтаксически управляемых переводов. Упражнения на программирование 9.2.19. Напишите программу, которая получает на вход про- стую СУ-схему над LL(1 (-грамматикой и выдает транслятор, реализующий эту СУ-схему. 9.2.20. Напишите программу, строящую транслятор, который реализует постфиксную простую СУ-схему над I АЫ?(1)-грам- матикой. 9.2.21. Напишите программу, которая строит транслятор, реализующий произвольную СУ-схему над LALK(1 (-грамматикой. 235
ГЛ. 9. ПЕРЕВОД И ГЕНЕРАЦИЯ КОДА Замечания по литературе Впервые возможность реализации простой СУ-схемы с входной LL(&)- грамматикой на МП-прсобразователе была доказана в работе Лыоиса и Стирпза [1968]. Они также показали, что простую постфиксную СУ-схсму над ЕН(£)-грамматикой можно реализовать ла ДМП-преобразователе и любой перевод, выполняемый ДМП-преобразователем, можно эффективно описать простой постфиксной СУ-схемой над ЬК(А)-грамматикой (упр. 9.2.7). Поня- тие МП-процессора введено Ахо и Ульманом [1969а]. Во многих компиляторах компиляторов и системах построения компиля- торов выходной компилятор описывается аналогично тому, как описывается схема синтаксически управляемого перевода. Синтаксис языка, для которого строится компилятор, определяется с помощью контекстно-свободной грамма- тики. Вводятся и семантические программы, связанные с каждым правилом. Полученный выходной компилятор можно промоделировать МП-процессором' входная цепочка анализируется компилятором, а для вычисления выхода вызываются семантические программы. ЯНРОВ с выходом представляет собой упрощенную модель системы построения компиляторов TMG [Мак-Клюр, 1965]. Мак-Илрой [1972] реализовал расширение TMG, в котором допускаются правила разбора типа ОЯНРОВ-правил и возможно моделирование поведения восходящих анализаторов. ОЯНРОВ с выходом — это упрощенная модель семейства компиляторов компиляторов МЕТА [Шорре, 1964]. Два класса простых СУ-схем, каждый из которых включает в себя про- стые СУ-схемы над LL-граммагиками и постфиксные простые СУ-схемы над LR-грамматиками, упоминаются Льюисом и Стирнзом [1968], а также Ахо и Ульманом [1972ж]. Каждый из этих классов можно реализовать на ДМП- преобразователе. 9.3. ОБОБЩЕННЫЕ СХЕМЫ ПЕРЕВОДОВ В этом разделе мы рассмотрим, как можно естественным образом расширить обсуждаемые ранее схемы перевода с тем, чтобы получить возможность выполнять более широкий и более полезный класс переводов. Будем считать, что в общем случае элементом перевода, связанным с правилом, может быть любой тип функции. Основные расширения заключаются в следующем: допускаются несколько переводов в каждой вершине дерева разбора, используются переменные, принимающие в качестве значений не только цепочки, разрешается зависимость перево- дов в вершине от переводов не только в ее прямых потомках, но и в ее прямом предке. Мы обсудим также важный вопрос,о разбиении на фазы при выполнении переводов в различных вершинах. 9.3.1. Мультисхемы переводов Наше первое расширение СУ-схемы будет допускать в каж- дой вершине дерева разбора несколько переводов, имеющих значениями цепочки. Как и в СУ-схеме, каждый перевод зави- сит от переводов прямых потомков рассматриваемой вершины. Однако элементами перевода могут быть произвольные цепочки выходных символов и символов, представляющих переводы в по- томках. Таким образом, символы перевода могут повторяться. 236
9.3. ОБОБЩЕННЫЕ СХЕМЫ ПЕРЕВОДОВ Определение. Обобщенной схемой синтаксически управляемого перевода (ОСУ схемой) называется шестерка Т = (N, 2, \, Г, R, S), где N, 2 и Л — соответственно конечные множества нетермина- лов, входных символов и выходных си'мволов, а Г — конечное мно- жество символов перевода вида Ар, зд.есь AgXn i — целое число. Мы будем полагать, что S, g Г. S— начальный символ, элемент множества N. Наконец, R— множегство правил перевода вида А —> a, Л, = ₽,, Л2 = рда, •••> =₽«,, удовлетворяющих следующим условиям: (1) Лу£Г для 1 (2) каждый символ, входящий в Pi, • "Щ, либо принадле- жит Д, либо является таким символом Bk § Г, что В—нетер- минал, появляющийся в а, (3) если а имеет более одного вхождения символа В, то каждый символ ВЛ во всех р соотнесен верхним индексом с кон- кретным вхождением В. Мы будем называть А—ю. входным правилом вывода, А: — переводом нетерминала А и Л; = рг—элементом перевода, свя- занным с этим правилом перевода . Если через Р обозначить множество входных правил вывода всех правил перевода, то G = (N, S, Р, S) будет входной грамм’атикой для Т. Если в ОСУ- схеме Т нет двух правил перевода с одинаковым входным пра- вилом вывода, то ее называют семантически однозначной. Выход ОСУ-схемы определим снизу вверх. С каждой внут- ренней вершиной п дерева разборга (во входной грамматике), помеченной А, свяжем одну цепочку для каждого Л( из Г. Эта цепочка называется значением (или /переводом) символа А, в вер- шине п. Каждое значение вычисляется подстановкой значений символов перевода данного элемен-ла перевода Л(. — р(, опреде- ленных в прямых потомках вершин!Ы п. Например, пусть А^ВаС, Al = bBlC201, А.^'АсВ, — правило перевода в ОСУ-схеме и в вершине А дерева вывода используется входное правило выеводэ А —»ВаС (рис. 9.12). 237
ГЛ. 9. ПЕРЕВОД И ГЕНЕРАЦИЯ КОДА Тогда, если значения символов В,, В2 в вершине В и Ct, С2 в вершине С таковы, как указано иа рис. 9.12, то значением символа At, определенным в вершине А, будет bxLy2xlt а значе- нием символа /12 в этой же вершине будет угсх2. Переводом х(Т), определяемым ОСУ-схемой Т, назовем мно- жество {(х, г/) |х имеет дерево разбора во входной грамматике для Т и у — значение символа перевода в корне этого дерева}. Пример 9.10, Пусть T = ({S}, ja}, {a}, {.S\, SJ, R, S) — ОСУ- схема, в которой R состоит из правил .8>aS, Sj = S1S2S2a, S2 = S2a S—>a, S, = a, S2 = a Тогда т(Т) = ((a", a"!) | n > 1}. Например, а1 имеет дерево раз- бора, изображенное на рис. 9.13, а. Значения двух переводов в каждой внутренней вершине показаны на рис. 9.13, б. Рис. 9.13. Обобщенная схема синтаксически управляемого перевода. Например, для того чтобы вычислить значение символа .8; в корне, надо подставить в выражение S^S^a значения для S, и S, в вершине под корнем. Этими значениями являются соответственно а9 и а3. Для доказательства того, что х(Т) отобра- жает а" в а" , достаточно заметить, что (п + I)2 = пг -ф2п Ц- 1. □ Пример 9.11. Приведем пример формального дифференциро- вания выражений, включающих константы 0 и 1, переменную х и функции синус, косинус, -ф и *. Такие выражения порождает 238
9.3. ОБОБЩЕННЫЕ СХЕМЫ ПЕРЕВОДОВ грамматика Е^Е + Т\Т T-+T*F\F F —> (£) | sin (£) | cos (£) | x 1011 Свяжем с каждым из E, T и F два перевода, обозначенные индексами 1 и 2. Индекс 1 указывает, что выражение не диф- ференцировано; 2 указывает, что выражение продифференциро- вано. Интересующий нас перевод—это £2. Законы дифференци- рования таковы: d (f (х) + g (x)) = df (х) + dg (х) d (f(x) g (x)) = f (x) dg (x) + g (x) df (x) d sin (f (x)) = cos (f (x)) df (x) d cos (f (x)) = — sin (f (x)) df (x) dx = 1 d0 = 0 dl =0 Эти законы реализуются ОСУ-схемой £^E+T £, = £> + £, ^2 = ^2 + ^2 E^T £, = 7^ £2 = Л T-+T*F T1=Tl^F1 7'! = r,»f,+(7'!).Fi T -,F F^E F, = (E.t) F —► sin (£) Ft = sin (£,) F2 — Cos (£,) * (£2) F —► cos (£) Ft = cos (£,) f2 = —sin (£,)*(£2) F-,x £, = x ^2=1 F, —0 F, = 0 f2=o F 1 F, = l Л = о 239
ГЛ. 9. ПЕРЕВОД И ГЕНЕРАЦИЯ КОДА В качестве упражнения предлагаем доказать, что если (а, Р) € т(Т), то р — производная от а. Цепочка 0 может содер- жать избыточные скобки. Дерево вывода для sin (cos (х)) 4-х изображено на рис. 9.14. Значения символов перевода в каждой внутренней вершине перечислены в табл. 9.3. □ Таблица 9.3 Вершины £\, Tt или Fj Elt Tt или Ft «3- «2 «12, «11, «10 «9’ «8, «7 «8» «5» «4 «1 X X cos (х) sin (cos (x)) sin (cos (x)) -h x 1 1 — sin (x) * (1) cos (cos (x)) * (— sin (x) * (1)) cos (cos (x)) * (— sin (x) * (1)) 4- 1 Реализация ОСУ-схемы не сильно отличается от реализации СУ-схемы с помощью алгоритмов 9.1 н 9.2. Обобщим теперь алгоритм 9.1 так, чтобы на выходе иметь не дерево, а ориен- тированный ациклический граф. Тогда можно будет „проходить" по ориентированному ациклическому графу так, чтобы полу- чался нужный перевод. Алгоритм 9.4. Выполнение ОСУ-с х е мы снизу вверх. Вход. Семантически однозначная ОСУ-схема T = (N, S, А, Г, R, S) с входной LR (й)-грамматикой G и входная цепочка xg2’. Выход. Ориентированный ациклический граф1), из которого можно получить такой выход у, что (х, i/)gT(T). Метод. Пусть Л—LR (й)-анализатор для G. Построим МП- процессор М с концевым маркером, который будет моделиро- вать Л и строить граф. Если ,4 содержит в своем магазине нетер- минал А, то М поместит под А по одному указателю для каждого символа перевода А, СГ. Таким образом, в графе будет столько вершин, соответствующих вершине А в дереве разбора, сколько существует переводов для А, т. е. символов Л.: в Г. Действия М таковы: (1) Если ,4 выполняет перенос, то М делает то же самое. (2) Предположим, что ,4 собирается выполнить свертку в соответствии с правилом А —» а с элементами перевода At = pit. . . . .., А,„--0,л. В этот момент в верхушке магазина процессора М находится а, а непосредственно под каждым нетерминалом в а б Для краткости мы до конца раздела будем писать просто „граф-1, опус- кая слова „ориентированный ациклический11.— Прим, перев. 240
9.3. ОБОБЩЕННЫЕ СХЕМЫ ПЕРЕВОДОВ находятся указатели на каждый из переводов этого нетерми- нала. Когда М делает свертку, сначала порождаются т вершин, по одной на каждый символ перевода At. Прямые потомки этих вершин определяются символами из |зп ..., fim. Порождаются новые вершины для выходных символов. Вершиной для символа перевода В^Г служит вершина, отмеченная тем указателем под нетерминалом В в а, который представляет k-й перевод для В. (Как обычно, если В входит в а более чем один раз, то каждое его конкретное появление будет помечено в элементе перевода дополнительным верхним индексом.) При свертке М 241
ГЛ 9. ПЕРЕВОД И ГЕНЕРАЦИЯ КОДА заменяет цепочку а и ее указатели символом Лит указателями на переводы для А. Например, допустим, что Л выполняет свертку в соответствии с входным правилом вывода правила перевода Л —► ВаС, А1 = ЬВ1С2В1, А2 = С1сВ2 Тогда в верхушке своего магазина М имеет цепочку ря^раВарСгрсС (С—самый верхний символ), где р — указатели на вершины, представляющие переводы. При свертке М заменяет эту цепочку цепочкой рА.рАЛ, где рА< и — указатели на первый и второй переводы для Л. После свертки получается граф, изображенный Рис 9.15. Часть выходного ориентированного ациклического графа. на рис. 9.15. Предполагается, что рх. указывает на вершину для Л (3) Если МП-процессор М достиг конца входной цепочки и его магазин содержит S и некоторые указатели, то указателем па вершину для .S, является корень нужного выходного графа. □ Подробный пример мы рассмотрим после того, как обсудим интерпретацию графа. Очевидно, что каждая вершина графа „представляет" значение символа перевода в некоторой вершине дерева разбора. Но как это значение можно получить из графа? Из определения перевода, связанного с графом, должно быть ясно, что значение, представляемое вершиной п, должно быть конкатенацией слева направо значений, представляемых прямыми потомками вершины п. Отметим, что в действительности два или более прямых потомков могут быть одной и той же вершиной. В этом случае значение вершины должно повториться. Учитывая все сказанное, можем заключить, что нужный выход порождается следующим методом прохождения по графу. Алгоритм 9.5. Перевод графа. Вход. Граф с помеченными листьями и единственным корнем. Выход. Последовательность символов, помечающая листья. Метод. Мы будем использовать рекурсивную процедуру В(п), где п — вершина графа. Сначала вызывается где пи — корень. 242
9 3. ОБОБЩЕННЫЕ СХЕМЫ ПЕРЕВОДОВ Процедура R (п). (1) Пусть а,, аг, .... а,„—дуги, исходящие из п в порядке записи. Совершаем шаг (2) для а,, а2, . .., а„ по порядку. (2) (а) Пусть а,. — текущая дуга. Если az входит в лист, выдаем метку этого листа. (б) Если а,- входит во внутреннюю вершину п', выпол- няем R(n'). □ Теорема 9.7. Если алгоритм 9.5 применяется к графу, по- строенному алгоритмом 9.4, то выходом алгоритма 9.5 является перевод цепочки х, подаваемой на вход алгоритма 9.4. Доказательство. Каждая вершина п, вырабатываемая алгоритмом 9.4, очевидным образом соответствует значению сим- вола перевода в данной вершине дерева разбора для х. Индук- цией по высоте вершины можно показать, что процедура R (п) вырабатывает значение этого символа перевода. □ Пример 9.12. Применим алгоритмы 9.4 и 9.5 к ОСУ-схеме из примера 9.10, задав на входе цепочку аааа. Последовательность конфигураций процессора приведена в табл. 9.4 (как обычно, ЬР(1)-таблицы опущены). Таблица 9.4 Содержимое магазина Входная цепочка (1) (> аааа$ (2) а ааа$ (3) аа аа$ 0) ааа и$ (5) аааа $ 16) aaapjp2S $ (7) aap^tS $ (8) ap2p„S S (9) P-iPkS $ Графы, построенные после шаюв 6, 7 и 9, приведены на рис. 9.16. Вершины слева соответствуют значениям для 5’,, а справа—для 5’,. Применение алгоритма 9.5 к графу на рис. 9.16, в требует много вызовов процедуры R(n). Работа алгоритма начинается с вершины поскольку опа соответствует Sr Выпишем после- довательность вызовов R (п) и генераций выходного символа а (обращение к Я (п/) обозначено просто как п(): nyign^angan^an^gaangn^aaanyiyi^aaanyigngaaaa □ 243
Рис. 9.16. Граф, построенный алгоритмом 9.4;
9.3. ОБОБЩЕННЫЕ СХЕМЫ ПЕРЕВОДОВ 9.3.2. Разновидности переводов До сих пор мы рассматривали в схеме перевода переменные, принимающие в качестве значений только цепочки. Те же прин- ципы, что привели к определению СУ-схем и ОСУ-схем, позво- лят определить и реализовать схемы перевода, содержащие также логические и арифметические переменные. Цепочки, вырабатываемые в процессе генерации кода, можно разбить на несколько различных классов: (1) Машинные коды, или команды ассемблера, которые должны быть выходом компилятора. (2) Сообщения об ошибках; это также выход компилятора, но не в том выходном потоке, что (1). (3) Команды, указывающие, что некоторые операции должны производиться над данными, с которыми имеет дело сам ком- пилятор. К классу (3) относятся команды, осуществляющие операции по организации информации, арифметические операции над пере- менными, используемыми компилятором не в механизме синтак- сического анализа, и операции по распределению памяти и гене- рации новых меток для выходных операторов. Обсуждение того, когда выполняются эти операции, мы отложим до следующего раздела. Вот еще несколько примеров типа переводов, которые могут оказаться полезными при генерации кода: • (1) элементы конечного множества видов (вещественный, це- лый и т. д.), указывающие на вид арифметического выражения, (2) цепочки, представляющие метки некоторых операторов при компиляции структур управления (например, if — then—else), (3) целые, указывающие высоту вершины в дереве разбора. Мы обобщим типы формул, которые можно применить в СУ схеме для вычисления перевода. Разумеется, работая с числами или логическими переменными, мы будем употреблять для нахождения переводов логические и арифметические опера- торы. Удобно использовать также условные выражения вида if В then £, else £2, где В — логическое выражение, а и Е2 — произвольные выражения, включая условные. Например, в правиле вывода А —> ВС нетерминал В мог бы иметь логический перевод Blt а С — два перевода С2 и С2 с це- почками в качестве значений. Формулой перевода для Аг могла бы быть if В, then С, else С2. Это означает, что если левый прямой потомок вершины, перевод Л, которого вычисляется, имеет перевод В,=истина, то в качестве надо взять первый перевод С, правого прямого потомка; иначе надо взять С2. Дру- гой сдучай: Егетерминал В мог бы иметь перевод В2, принимаю- щий целое значение, и формулой для Аа могла бы быть if В2 = 245
ГЛ. 9. ПЕРЕВОД И ГЕНЕРАЦИЯ КОДА = 1 then С1 else С'2. Э.о приведет к тому, что значение А2 будет то же, что и у С2, если значение В2 не 1. Мы увидим, что не трудно обобщить алгоритм 9.4, работаю- щий снизу вверх, так, чтобы в качестве переводов допускались числа, логические значения или элементы некоторого конечного множества. В схеме рабо.ы снизу вверх формулы для этих переменных (и для переменных, имеющих значениями цепочки) вычисляются только тогда, когда известны все аргументы. В самом деле, часто все связанные с вершиной переводы, кроме одного, будут логическими, целыми или элементами конеч- ного множества. Если этот один (имеющий значением цсио-.ку) перевод можно получить с помощью правил перевода, являю- щихся по существу правилами простой постфиксной СУ-схемы (возможно, с условиями), то можно выполнить весь перевод на ДМП-преобразователе, храпящем в своем магазине переводы раз- ного типа, в том числе и не цепочки. Эги переводы легко „свя- зать" с ятейками магазина, хранящими нетерминалы; это будет очевидная связь между нетерминалами в магазине и внутрен- ними вершинами дерева разбора. Если некоторый перевод имеет целое значение, мы выходим за пределы описания ДМП-преоб- разователя, что, впрочем, нс может составить проблемы при реализации транслятора на вычислительной машине. Однако обобщение алгоритмов 9.2 и 9.3, работающих сверху вниз, не столь просто. В случае когда должны быть сформи- рованы только цепочки, мы допускали возможность неявного развертывания формул, т. е. формулы могли содержать указа- тели на вершины, которые в конечном счете представляют нуж- ную цепочку. Но может оказаться, что трактовать таким же образом арифметические формулы или формулы с условиями невозможно. Что касается алгоритма 9.2, можно сделать следующую модификацию. Если развертывается нетерминал А, находящийся в верхушке магазина, то указатель остается в магазине непо- средственно под А. Он указывает на вершину п, представляю- щую это вхождение А. После того как А развернут, указатель снова будет в верхушке магазина и будут вычислены переводы для всех потомков вершины я. (Мы покажем это индуктивно.) Затем можно вычислять перевод вершины п точно так, как мы делали бы, если бы анализ шел снизу вверх. Детали этого обобщения предлагаем в качестве упражнения. Закончим раздел несколькими примерами более общих схем перевода. Пример 9.13. Опишем детально генерацию кода для арифме- тических выражений, о которой шла речь в разд. 1.2.5, для машины с одним сумматором и произвольным доступом к памят. 246
9.3. ОБОБЩЕННЫЕ СХЕМЫ ПЕРЕВОДОВ Будем предполагать, что язык ассемблера содержит команды ADD а МРУ а LOAD а STORE а имеющие очевидный смысл. Перевод будет основан на грамматике G„. Каждый из нетер- миналов Е, Т и F содержит по два элемента перевода. Первый вырабатывает цепочку выходных символов, представляющую последовательность команд, после выполнения которой значение соответствующего входного выражения будет размещено на сум- маторе. Второй перевод будет целым числом, представляющим высоту вершины в дереве разбора. Однако при определении высоты мы не будем считать правила Е—>Т, Т> F и F Поскольку измерение высоты необходимо только для определе- ния имени ячейки, хранящей промежуточную информацию, эти правила можно не учитывать. Перечислим шесть правил и соответствующие им элементы перевода: (1) Е^Е + Т E, — T, STORE $’ E, £3 = max(£a, 7,) -- 1 £, ADD $’ Ег № Е—+Т E,=T, *) £г -= T, (3) Т ^T*F T,=F, ‘STORE S’ 7\, Тг - max(7 „ + 1 ’ T, ; MPY $’ T3 (4) T—-F = (5) F-^(E) F, = E, f2 = e (6) F ->-a F, = ‘LOAD’ NAME(a) F3=l Для определения цепочек в элементах перевода мы вновь принимаем соглашения языка Снобол. Цепочки, заключенные в кавычки, представляют сами себя. Символы без кавычек обо- значают текущее значение символа, которое надо вместо него подставить. Таким образом, в правиле (1) элемент перевод/ J) При обработке синтаксического дерева, а не дерева разбора, нет свер- ток в соответствии с правилами вывода R Т, Т —• F и F —» (£"). Поэтому с реализации нет необходимости отражать тривиальные правила перевода, соответствующие этим правилам вывода. 247
ГЛ. 9. ПЕРЕВОД И ГЕНЕРАЦИЯ КОДА для А, построен так, что значением Ег должна быть конкате- нация (1) значения нетерминала Т\, за которым следует точка с запятой; (2) команды STORE с адресом Sn, где п — высота вершины для Е (в правой части правила вывода), за которой следует точка с запятой; (3) значения нетерминала Ег (левого аргумента операции -(-), за которым следует точка с запятой; (4) команды ADD $л, где п то же, что и в (2). Здесь $п служит рабочей ячейкой, и перевод для Е, (в пра- вой части элемента перевода) эту ячейку использовать не будет из-за способа обработки £2, Т2 и F2. 248
9.3. ОБОБЩЕННЫЕ СХЕМЫ ПЕРЕВОДОВ В правиле (6) применяется NAME(a), где NAME—функция, участвующая в организации информации и дающая внутреннее (для компилятора) имя идентификатора, представленного лек- семой а. Напомним, что терминальные символы всех наших грамматик — это лексемы. Если лексема представляет идентифи- катор, то она будет содержать указатель на позицию в таблице имен, в которой хранится информация об этом идентификаторе. Эта информация говорит как о том, какой именно идентифика- тор представляет данную лексему, так и о том, каковы атри- буты этого идентификатора. На рис. 9.17 показано дерево разбора цепочки (а + а) (а4-а) и даны значения некоторых символов перевода. Мы предполагаем, что NAME(o) для четырех идентификаторов, представленных символом а, дает значения а3, а2, а3 и at. □ Пример 9.14. Код, вырабатываемый в примере 9.13, никоим образом не оптимален. Его можно значительно улучшить, если заметить, что когда правый операнд — просто идентификатор, нет необходимости читать его и запоминать в рабочей ячейке. Поэтому мы добавим третий перевод в правилах Е, Т и F, являющийся логической переменной и принимающий значение истина тогда и только тогда, когда выражением, соответствую- щим данной вершине, является просто идентификатор. Первым переводом для Е, Т и F вновь будет код, вычисляю- щий выражение. Однако если выражение—идентификатор, то переводом будет только „NAME" этого идентификатора. Таким образом, схема перевода не „трудится" над одиночным иденти- фикатором. Это приводит, впрочем, к некоторым неудобствам, поскольку можно считать, что грамматика для выражений со- ставляет часть грамматики для оператора присваивания, а перевод для таких операторов присваивания, как А^-В, осуществляется на более высоком уровне. Новые правила таковы: (1) Е—гЕ^-Т Е3 — if Тг then if Es then ‘LOAD’ E, ‘;ADD’7'i else ‘;ADD’ 7, else if E3 then *;STORE$1; LOAD’Ef ‘; ADD$1’ else 7\ ‘-.STORES’ E, E, ‘;ADD$’Ea £2 = max (E2, 7a) + 1 E, = ложь (2) £->7 E1 = T1 ^s~T3 249
ГЛ. 9. ПЕРЕВОД И ГЕНЕРАЦИЯ КОДЛ (3) T-+T*F 7\ = if F, then if Г, then‘LOAD’Г, ‘;MPY’F, else 7", ‘;MPY’f, else if T, then Ft STORE $1; LOAD’ Tt MPY $1’ else/7, STORES’T, T, ‘;MPYs’7’, T, — max (7\, p2) + 1 T3 = ложь (4) T —> F 1\ = F, t\ — f2 T- -= F (5)E —(£) /2-E.2 F, = E„ (6) F —> a Ft = NAME(a) Л=1 F3 = истина В правиле (1) формула для Е, проверяет, является ли один из аргументов или оба просто идентификаторами. Если правый аргумент—идентификатор, то генерируется код для вычисления левого аргумента и сложения правого аргумента с содержимым сумматора. Если левый аргумент — идентификатор, то генерируе- мый код будет именем идентификатора. В этом случае ему должно предшествовать ‘LOAD’. Отметим, что тогда Е2 1, так что в качестве рабочей можно взять J1, а не ячейку *$’Е, (кото- рая в этом случае все равно была бы $1). Код, вырабатываемый для (й + й) * (а-J-а), имеет вид LOAD а3- ADD й,; STORE S2; LOAD а,; ADD а2; MPY $2 В этих правилах перевода не предполагается, что операции + и * коммутативны. □ Наш следующий пример снова связан с арифметическими выражениями. Он показывает, как с помощью ОСУ-схемы можно описать процесс, в основе которого лежит простая СУ-схема, но детерминированный МП-преобразователь, реализующий эту схему, способен хранить в ячейках своего магазина некоторую допол- нительную информацию. В качестве промежуточного языка выбран трехадресный код. Пример 9.15. Будем переводить Ц0„) в последовательность трехадресных операторов вида А<--у ВС и А*—* ВС, означаю- щих, что переменной А надо присвоить сумму или соответственно 250
9.3. ОБОБЩЕННЫЕ СХЕМЫ ПЕРЕВОДОВ произведение В и С. В этом примере А будет цепочкой вида $i, где i — целое. Основные переводы Е3, 7\ и F1 будут последо- вательностями трехадресных операторов, вычисляющими значе- ние выражения, соответствующее рассматриваемой вершине; Ег, '1\ и F3— целые числа, указывающие, как и в предыдущем примере, уровни; £3, Т3 и F, — имя переменной, которой при- сваивается упомянутое выше значение выражения. Этим именем будет программная переменная, если выражение — просто иден- тификатор, и имя рабочей ячейки в противном случае. Схема перевода такова: £ —► Е Т Е1 = E-J\ ‘S’ max (£2, Т2) —|- ’ Е3Т3 £3^-max(£2, TJ-Fl £, = max (£2, T3) E — T E,=T, e.-t, E^T, T —‘TnF Tt = TlFl max(7\, F.2)‘ <— * ’ T3F3 7, = max (T,, FJ + l T3 = ‘$’ max (7,, FJ T—> F T1 — F1 T,-F, T3- E, F->(E) F1 = El F.-E., F, = E, F—>a F3—e f2= 1 f3 = NAME(a) Например, переводом для a1»(a2 + a3) будет $ 1 * F ^2^3- $2-<—«OjSl; Предоставляем читателю проследить, что правила перевода для £\, 7\ и Fl образуют простую постфиксную СУ-схему в предположении, что входными символами являются значения второго и третьего переводов для Е, Т и F. Практически пере- вод можно осуществить с помощью ДМП-преобразователя, хра- нящего в своем магазине значения второго и третьего переводов и выполняющего разбор грамматики G„ методом LR(1). Таким образом, каждая ячейка магазина, содержащая Е, будет также содержать значения Ег и Е3 для соответствующих вершин дерева разбора (аналогично для ячеек, содержащих 'Г и F). 251
ГЛ. 9. ПЕРЕВОД И ГЕНЕРАЦИЯ КОДЛ Перевод осуществляется выдачей ‘S' max Tt) ‘«—|- ’ Е3Т3 при каждой свертке Е + Т в Е-, здесь Л',, Е3, Т, и Т3— значе- ния, приписанные ячейкам магазина, участвующим в свертке. При свертке T--<-T*F производятся аналогичные действия, а при остальных свертках не выдается ничего. Следует отметить, что, поскольку второй и третий переводы для Е, Т и F могут принимать бесконечное число значений, устройство, осуществляющее перевод, не является, строго говоря, ДМП-преобразователем. Однако на практике это расширение легко реализуется на вычислительной машине с произвольным доступом. □ Пример 9.16. Будем генерировать код на языке ассемблера для условных операторов вида if —then — else. Предполагается, что нетерминал 3 представляет оператор и одно из правил вы- вода— это 3 —>• if В then S else 3. Предполагается также, что 3 имеет перевод 3,, являющийся кодом для выполнения этого оператора. Если для 3 используется правило вывода, отличное от приведенного выше, будем считать, что перевод 3, вычислен правильно. Условимся также, что В представляет логическое выраже- ние и переводы и В2 для В вычисляются по другим прави- лам системы перевода. В частности, В,— код, вызывающий переход на ячейку В2, если логическое выражение принимает значение ложь. Для генерации требуемого кода необходимо, чтобы у нетер- минала 3 был еще один перевод Зг, являющийся именем ячейки, на которую будет передано управление после того, как закон- чится выполнение оператора 3. Будем предполагать также, что в вычислительной машине есть команда JUMP а, осуществляю- щая передачу управления па ячейку с именем а. Для генерации имен этих ячеек применяется функция NEWLABEL, при обращении к которой генерируется имя для метки, никогда раньше не встречающееся. Например, компиля- тор может хранить глобальную переменную с целым значением i. Каждое обращение к NEWLABEL может приводить к тому, что i будет увеличиваться на 1, а в качестве значения будет выдаваться имя $$i. На самом деле функция NEWLABEL в ука- занном выше правиле вывода для 3 не вызывается, а вызывается в некоторых других правилах вывода для 3 и В. Мы будем использовать также удобную псевдооперацию, по- добную которой можно найти в большинстве языков ассемблера. Эта команда ассемблера имеет вид EQUAL а, р 252
9.3. ОБОБЩЕННЫЕ СХЕМЫ ПЕРЕВОДОВ Она не генерирует никакого кода, а в результате ее выполне- ния ассемблер рассматривает а и [3 как имена одной и той же ячейки. Команда EQUAL нужна потому, что каждое из вхождений S в правой части правила вывода S —>• if В then S else S содержит имя команды, которая должна быть выполнена следующей. Мы должны быть уверены, что ячейка, участвующая в одном из них, та же, что и в другом. Элементы перевода для этого правила вывода таковы: S - if В then S’1’ else S™ S, = ‘EQUAL’ Si1’ Si® Bi Si1’ JUMP’ S'1’ B2 S<® S2-S<” Таким образом, перевод S состоит из конкатенации (1) команды, означающей, что S”’ и S)3’ представляют одну и ту же ячейку; (2) объектного кода для логического выражения (В^, вызыва- ющего переход на ячейку В,, если его значением является ложь; (3) объектного кода для первого оператора (S)1’), за которым следует переход па ячейку, помеченную Si” (ячейка с этой мет- кой находится вне компилируемого оператора); (4) объектного кода для второго оператора (S{3’). Первая ячейка этого кода помечена Вг. Перевод 32 для данного оператора тот же, что и перевод 32 для первого подоператора. Таким образом, независимо от того, истинно или ложно В, управление на ячейку Si1’ (совпадающую теперь с SJ3’) будет передано. Рассмотрим сложный оператор if В'1’ then if В'21 then S’1’ else S’2’ else S'3’ возникающий в результате двух применений рассматриваемого правила вывода (строго говоря, верхних индексов здесь не должно быть; они приведены для удобства ссылок). Объектным кодом, генерируемым для этого оператора, будет EQUAL S'1’, S'8’ код для В'1’ EQUAL Si1’, S?’ код для В”” код для S'1’ JUMP S’” В)3’: код для S’2’ JUMP S’” Bi1’: код для S’3’ 2»
ГЛ. 9 ПЕРЕВОД И ГЕНЕРАЦИЯ КОДА (Здесь точки с запятой заменены переходами на новую строку.) □ Пример 9.17. В качестве последнего примера этого раздела рассмотрим генерацию кода для вызовов вида call XfE11', .. ., £<'”) Предположим, что в языке ассемблера есть команда CALL X, которая передает управление на ячейку X и запоминает в спе- циальном регистре адрес текущей ячейки для последующего возврата из обращения к функции. Будем переводить call Х(ЕШ, .... Еш) в код, который вычисляет значения каждого из выражений А111, ...,ЕМ и запоминает их в рабочих ячейках /,....t„. За этими вычислениями идет команда ассемблера CALL X и п команд ARG Ц ARG t„, осуществляющих „хранение значений" и использующихся как указатели на аргу- менты этого вызова X. Основные правила вывода, описывающие оператор вызова, таковы: S —>call аА A-^el(L) Е—^Е, Е{Е Таким образом, оператором является ключевое слово call, за которым следует идентификатор и список аргументов (А). Спис- ком аргументов может быть либо пустая строка, либо список выражений, заключенный в скобки (А). Предполагается, что каждое выражение Е имеет два перевода Ег и Е2, причем Е, — объектный код, помещающий в сумматор значение Е, а Аз —имя рабочей ячейки для запоминания значения Е. Имена для рабо- чих ячеек порождаются функцией NEWLABEL. Требуемый перевод осуществляется следующими правилами: A -► call аА S, = A. ‘;CALL’ NAME (а) А» A—-(A) А, = Е, А.,— , Е, А —*е А, =е А2 = е Е—-Е,Е А, = STORE’ £г At A2 = ‘ARG’ Ег L2 LЕ L1 = E1 STORE’ Е, A2 = ‘ARG’ Е, Например, оператор call АВ (А111, А12’) переводится (в пред- положении, что рабочими ячейками для А’11 и А121 являются 254
9.3. ОБОБЩЕННЫЕ СХЕМЫ ПЕРЕВОДОВ- $$1 и $$2 соответственно) в код для Е'11 STORE SS1 код для Ет STORE $$2 CALL АВ ARG $$1 ARG $$2 Для реализации вызова можно было бы запоминать значения выражений Е111, ...,ЕШ непосредственно в ячейках, следующих за командой C.ALL(X). Построение схемы перевода, генерирую- щей такой код, оставляем читателю в качестве упражнения. □ 9.3.3. Наследственный и синтезированный переводы Существует другое обобщение синтаксически управляемого перевода, которое может оказаться полезным в некоторых при- ложениях. До сих пор мы рассматривали переводы нетермина- лов как функции только переводов прямых потомков вершины. Однако можно допустить, чтобы значение перевода было функ- цией значений переводов не только прямых потомков вершины, но и ее предков. Дадим следующее определение. Определение. Перевод нетерминала в схеме перевода будем называть синтезированным, если он зависит только от перево- дов вершины, в которой вычисляется, и переводов ее прямых потомков. Перевод будем называть наследственным, если он зависит только от переводов вершины, в которой вычисляется, и переводов ее прямого предка. Все переводы, рассмотренные до сих пор, были синтезированными и, более того, не содержали формул, включающих переводы в самой вершине. Элементы перевода, связанные с правилом вывода, определим обычным образом, если определяемый перевод—синтезированный. Однако наследственные переводы, связанные с правилом вывода, могут использовать в качестве аргументов переводы левой части правила вывода, вычисляя при этом перевод для некоторого конкретного символа в правой части. Значит, необходимо отли- чать нетерминал слева от любого его вхождения справа. Как обычно, для этой цели мы будем употреблять верхние индексы. Пример 9.18. Рассмотрим правила перевода Л,2|А,3> А^‘— аА'р А^'Ь - Л)11 Л‘3|-аЛф 255
ГЛ. 9 ПЕРЕВОД И ГЕНЕРАЦИЯ КОДА Здесь А имеет два перевода: синтезированный перевод А: и наследственный перевод Аг. Правило для А, относится к знако- мому нам типу. Правила для А^’ и Д”1 служат примерами правил перевода для наследственных атрибутов. Исследуем часть дерева на рис. 9.18. числить в каждой Правило для Да2’ говорит о том, что пере- вод Д2 в вершине па должен совпадать с переводом А, в и,. Поскольку At вл, выражается через Д2 в па, это пример зацикленного определения, и в такой форме это правило недопустимо. □ Схема перевода, содержащая как на- следственный, так и синтезированный пе- реводы, реализуется не просто. В самом общем случае сначала надо полностью построить дерево разбора, а затем вы- вершине все переводы, которые можно вычислить в терминах уже вычисленных переводов в потомках и предках. Прежде всего надо начать с синтезированных атри- бутов в вершинах высоты 1. При перевычислении перевода все переводы, от него зависящие, как наследственные, так и синте- зированные, также должны вычисляться снова. Тем самым может оказаться, что процесс перевычисления переводов никогда не закончится. Такую схему перевода называют зацикленной. Проб- лема распознавания, является ли схема перевода зацикленной, разрешима, хотя ее решение сложно, и мы предлагаем ее в качестве упражнения. Приведем пример, в котором для любого дерева разбора существует естественный порядок вычисления всех переводов. Пример 9.19. Скомпилируем для вычисления арифметических выражений код, который должен выполняться на машине с двумя быстрыми регистрами, обозначенными через А и В. Будут использоваться команды LOADA а LOADВ а STOREA а STOREB а ADDA а ADDB а MP4 а АТОВ Смысл первых шести команд очевиден: можно считывать, за- поминать и складывать в любом регистре. Предполагается, что 2Я
9.3. ОБОБЩЕННЫЕ СХЕМЫ ПЕРЕВОДОВ команда MPY берет левый операнд из регистра В и заносит результат в регистр А. Последняя команда, АТОВ, передает содержимое регистра А в регистр В. Как и в примере 9.13, построим перевод на основе грамма- тики G„. Переводы £n 7\ и Fa будут представлять код для вы- числения значения соответствующего входного выражения, зано- сящий результат либо в регистр А, либо в регистр В. Однако перевод £, для корня дерева разбора всегда будет помещать значение выражения в регистр А. Как и в примере 9.13, £„, Т2 и F, будут целыми числами, равными высотам вершин. Переводы Е3, Т3 и F„ будут логическими выражениями, прини- мающими значение истина тогда и только тогда, когда значение выражения должно остаться в регистре А. Этн переводы — на- следственные, а первые шесть — синтезированные. Методы улуч- шения кода, данные в примере 9.14, здесь не применены. Пра- вила перевода таковы: £ч>_„Ет + Т EJ11 = if Е®’then 7\ ‘;STOREA $’ Е® ‘;ADDA S’ Е‘» else 7\ ‘;STOREA S’ E® Е\г> ‘;ADDB $’ ES*> E'1’= max (E™, TJ + l *) Ta = истина E—*T Е3 = Т3 Е„=тг T3 = E3 pu pm * p 74D = jf pm then F3 ‘jSTOREA $’ T? T?> ‘;MPY $’ T® else Et‘jSTOREA $’ TV’ T? ;MPY $’ T?’ ‘;ATOB’ 7T>=max(7T, F3) + l T‘a2' = ложь F3 — истина T—tF T1 = Fl T3 = F3 F3 = T3 ’) Предполагается, что вначале все логические переводы имеют значение истина. Таким образом, если Ej1’ ссылается на корень, считается, что-перевод для него уже определен. 9 А. Ахо, Дж. Ульман, т. 2 257
ГЛ. 9. ПЕРЕВОД И ГЕНЕРАЦИЯ КОДЛ f->(£) F1 = El F2 ” А 2 £s = F3 F—-a Fr = if F3 then ‘LOADA’ NAME(a) else ‘LOADB’ NAME(a) Стратегия заключается в том, чтобы вычислять все правые операнды в регистре А. Левый операнд для * всегда вычисляется в В, левый операнд для 4- вычисляется либо в А, либо в В в зависимости от того, где желательно его разместить. Таким образом, элемент перевода для Е{1>, связанный с правилом вы- вода Е—>-Е-\- Т, дает перевод, который вычисляет Т в регистре А, запоминает его в рабочей ячейке, затем вычисляет Е либо в А, либо в В в зависимости от того, где желательно, и выполняет сложение. Правило перевода для Л* 1 * 3’, связанное с правилом вывода Т—>-T*F, вычисляет F в регистре А, запоминает его, вычисляет Т в регистре В, умножает и, если надо, передает результат в регистр В. Дерево разбора для (а4-а)*а показано на рис. 9.19, на ко- тором некоторым внутренним вершинам присвоены имена. На- следственные и синтезированные атрибуты переносятся без из- менений вверх и вниз по цепям Е —>Т —> F. В табл. 9.5 приведена последовательность вычисления переводов (перенос переводов из Е в Т, из Т в F и обратно в таблице не указан). □ Таблица 9.5 Перевод В вершине Значение истина ложь ложь истина LOADA at 1 LOADB Qi 1 LOADA a2; STOREA $1 ; LOADB ; ADDB $1 истина LOADA ag 1 LOADA a3 ; STOREA $2 ; LOADA a2 ; STOREA $1 ; LOADB аг; ADDB $1 ; MPY$2 3 258
9.3. ОБОБЩЕННЫЕ СХЕМЫ ПЕРЕВОДОВ Рис. 9.19. Дерево разбора. 9.3.4. Замечание о разбиении на фазы Мы обрисовали компилятор так, как будто каждый из его шагов — лексический анализ, синтаксический анализ и генера- ция кода — выполнялся отдельно в указанном порядке. Однако такое деление на последовательные шаги служит скорее мето- дическим целям представления и па практике может и не соблюдаться. Во-первых, фаза лексического анализа вырабатывает лексемы постольку, поскольку они необходимы для разбора. Реально же 9» 259
ГЛ. 9. ПЕРЕВОД И ГЕНЕРАЦИЯ КОДА входной цепочки лексем, которая была показана для демонстра- ции действий при разборе, может и не быть. Лексемы разыски- ваются только по мере того, как они требуются при разборе. Конечно, эта разница никоим образом не влияет на процесс разбора. Как мы уже отмечали выше, разбор и генерация кода могут осуществляться одновременно. Таким образом, три фазы могут работать комбинированно. Обращение к лексическому анализа- тору происходит тогда, когда процесс разбора не может идти дальше. После каждой свертки (при разборе снизу вверх) или развертки нетерминала (при разборе сверху вниз) фаза гене- рации кода обрабатывает вершину или вершины дерева разбора, сформированные только что. Если бы вырабатываемым переводом была одна цепочка, то было бы не столь существенно, когда именно вырабатываются различные ее части. Однако напомним, что отдельные части вы- рабатываемого перевода могут быть различных типов: объектным кодом, диагностикой, командами, выполняемыми самим компи- лятором (такими, например, как команды по вводу информации в механизмы ее хранения). Если перевод осуществляется МП-преобразователем или ана- логичным устройством с одним выходным потоком, то проблем с разбиением перевода иа фазы не возникает. Символы считаются выходными по мере того, как они вырабатываются устройством. Если предположить, что различные виды выходных потоков от- деляются друг от друга метасимволами, то выходной поток можно разделять по мере его образования. Например, промежуточный код передается на фазу оптимизации, диагностика размещается в собственный список, чтобы затем быть напечатанной, а команды по организации информации выполняются немедленно. Предположим, что для обобщенного синтаксически управляе- мого перевода применяется один из наиболее общих вариантов алгоритмов 9.1—9.4. Можно было бы дождаться, когда будет полностью сконструировано дерево или ориентированный аци- клический граф, а затем сформировать единый выходной поток. Деление потока на объектный код и команды могло бы осущест- вляться точно так же, как и для МП-преобразователя. Это оз- начает, что команды по организации информации пе выполнялись бы до тех пор, пока не был бы полностью сформирован выход- ной поток, и что команды выполняются по мере обработки вы- ходного потока. Такая организация требует дополнительного прохода и большой памяти с произвольным доступом, но может оказаться наиболее приемлемой, если требуется мощность самых общих схем синтаксически управляемого перевода. С другой стороны, можно принять, что команды по органи- зации информации и другие команды компилятора связаны с от - 260
УПРАЖНЕНИЯ дельными вершинами дерева разбора и выполняются сразу, как только вершина образована. Однако, если алгоритм разбора требует возвратов, надо быть осторожным, чтобы не выполнить команды, связанной с вершиной, не являющейся частью дерева разбора. В этой ситуации необходим механизм для отмены ре- зультата такой команды. УПРАЖНЕНИЯ 9.3.1. Найдите ОСУ-схемы для следующих переводов: (а) {(а”, ап’) | п > 1}, (б) {(ап, аг")|п> 1}, (в) {(а», ют) |w С (0 + 1)*}- 9.3.2. Покажите, что существуют переводы, определяемые ОСУ-схемой, но не определяемые никакой СУ-схемой. **9.3.3. Пусть Т — семантически однозначная ОСУ-схема с бес- конечной областью определения, входная КС-грамматика которой является приведенной. Покажите, что в этом случае должно удовлетворяться одно из следующих условий: (1) Существуют константы с2 и с2, большие 1 и такие, что если (х, у)Ст(Т’), то | у\^с[х' и для бесконечного числа цепо- чек х найдутся такие пары (х, у) Ст (Г), что | у| >4Х1. (2) Существуют константы с1 и с2, большие 0, и целое число 1 > 1, такие, что если (х, у) g т (Г) и х += е, то | у | Д с21 х ]' и для бесконечного числа цепочек х найдутся такие пары (х, у) Ст(Т), что | у | > И | х I'. (3) Множество значений схемы Т конечно. 9.3.4. Покажите, что перевод {(a", am) |т — целая часть числа Уп} нельзя определить никакой ОСУ-схемой. 9.3.5. Для переводов из упр. 9.3.1 (а) — (в) постройте ориен- тированные ациклические графы, вырабатываемые алгоритмом 9.4 для входов а3, а1 и 011 соответственно. 9.3.6. Укажите последовательность вершин, по которой про- ходит алгоритм 9.5, примененный к ориентированным ацикли- ческим графам из упр. 9.3.5. *9.3.7. Дополните пример 9.16, включив правило вывода 3—► while В do S, смысл которого должен заключаться в том, что проверяется выражение В, а затем выполняется оператор S до тех пор, пока значением В не станет ложь. 261
ГЛ. 9. ПЕРЕВОД И ГЕНЕРАЦИЯ КОДА 9.3.8. Следующая грамматика порождает объявления, подоб- ные объявлениям в ПЛ/1: D — (L) М L—»-a, L\D, L | a | D M —... \mk Терминал а изображает идентификатор; mlt ...,mk— это k воз- можных атрибутов идентификатора в языке. Терминальными символами являются также запятая и скобки. L представляет список идентификаторов и объявлений; D — это объявление, со- стоящее из заключенного в скобки списка идентификаторов и объ- явлений. Атрибут, выведенный из М., должен применяться ко всем идентификаторам, выведенным из L в правиле вывода D—даже если идентификатор находится внутри слож- ного объявления. Например, объявление (а,, (а2, а3)т1)тг на- значает идентификаторам а2 и а:, атрибут т1, а идентификато- рам alt а_ и а3 атрибут т2. Используя любые типы перевода, постройте схему перевода, переводящую цепочки, выведенные из нетерминала D, в k списков, причем список i должен содер- жать в точности те идентификаторы, которым придан атрибут т;. 9.3.9. Измените пример 9.17 так, чтобы в команду ARQ за- носились не указатели на значения выражений, а сами эти зна- чения. 9.3.10. Рассмотрим схему перевода N—+L L-+LB L—*B В-^0 A1 = L<i>+Z,<2>/2l™ L1 = 2Li + B1 Li = Bi £a = 1 B1 = 0 Bt=l В 1 Во входной грамматике из нетерминала А выводятся двоичные числа (возможно, с двоичной точкой). Нетерминал L представ- ляет список битов, а нетерминал В—бит. Элементами перевода являются арифметические формулы. Элемент перевода А, пред- ставляет рациональное число—значение двоичного числа, вы- веденного из N. Элементы перевода Lit L2 и Вк принимают целые значения. Например, 11.01 имеет перевод З1/^ Покажите, что т(7’) = {(6, d) | b—двоичное целое, d — его значение}. 262
УПРАЖНЕНИЯ *9.3.11. Рассмотрим следующую схему перевода с входной грамматикой, как в упр. 9.3.10, но содержащую как синтези- рованные, так и наследственные атрибуты: N —N^L^' + L^ Д1’=0 J <2> __________ _ Г 12) 1^2 — N-+L N^L, L2 = 0 L{"=L^+Bt b2=l?> L<®=L‘« + 1 В?’=Ц2’ + 1 L~>B L1 = Bl B2 — L2 L3=l B-^0 B,=0 В — 1 Bx = 2s. Дерево разбора для 11.01 co значениями элементов перевода, соответствующих каждой вершине, изображено на рис. 9.20. 263
ГЛ. 9. ПЕРЕВОД И ГЕНЕРАЦИЯ КОДА Отметим, что для того, чтобы вычислить элемент перевода надо сначала вычислить снизу вверх все L3 справа от разделительной точки, затем сверху вниз все Е2 и, наконец, снизу вверх все Lt. Покажите, что эта схема определяет тот же перевод, что и схема из упр. 9.3.10. *9.3.12. Покажите, что всякий перевод, который можно вы- полнить с помощью наследственного и синтезированного пере- водов, можно выполнить с помощью только синтезированного перевода. Указание: На структуру перевода ограничений нет. Таким образом, перевод, определяемый в некоторой вершине, может быть целым поддеревом. 9.3.13. Можно ли любой перевод, использующий синтезиро- ванные переводы, выполнить только с помощью наследственного перевода? **9.3.14. Приведите алгоритм для проверки, является ли дан- ная схема перевода, содержащая наследственные и синтезиро- ванные атрибуты, зацикленной. 9.3.15. Видоизмените пример 9.18 так, чтобы ввести возмож- ности улучшения кода из примера 9.14. *9.3.16. Алгоритм дифференцирования примера 9.11 позволяет генерировать такие выражения, как l»cos(x) или 0*х + (1)*1 (формальная производная от 1»х). Можно выявить и исключить выражения, явно равные 0 или 1, где явно определяется сле- дующим образом: (1) 0 явно равен 0; 1 явно равна 1. (2) Если £, явно равно 0, а Е2— некоторое выражение, то Ej* Е„ и Е.» £, явно равны 0. (3) Если Ег и Еа явно равны 1, то Ej* Е2 явно равно 1. (4) Если £, явно равно 0, а Е2 явно равно 1, то Et4-E2 И Е2 + Е3 явно равны 1. (5) Если £, и Е2 явно равны 0, то Е> + £2 явно равно 0. Измените ОСУ-схему (в том числе, возможно, и входную грамматику) так, чтобы в переводе не появлялись выражения, явно равные 0, а в качестве множителей чтобы не появлялись выражения, явно равные 1. 9.3.17. Рассмотрим следующую грамматику для оператора присваивания, включающего переменные с индексом: 264
УПРАЖНЕНИЯ А--!-. =Е Е —< Е <знсл> Т | Т Т —► Т <знумн> F | F F—(E)\I I ~^а\ a (L) L—>а, L\a <знсл> —<• + I — <знумн> — * I / Примером оператора, генерируемого этой грамматикой, может служить а (а, а):=а(а + а, <1»(а + а))4-а Здесь а—лексема, представляющая идентификатор. Сконструи- руйте схему перевода, основанную на этой грамматике и гене- рирующую необходимые команды языка ассемблера или много- адресного кода для операторов присваивания. 9.3.18. Покажите, что ОСУ-схема из примера 9.11 правильно вырабатывает выражение для производной входного выражения. **9.3.19. Покажите, что перевод {(al...a„bi...b„, a-,bx...ar:bj | п > 1, а, £ {0, 1}, bji {2,3} для 1 <1 <«} ие определяется никакой ОСУ-схемой, Проблема для исследования 9.3.20. Перевод арифметических выражений становится до- вольно сложным, если допустить в качестве операндов элементы многих различных типов данных. Например, значениями могут быть логические переменные, цепочки, целые, вещественные или комплексные числа — в последних трех случаях они могут иметь одинарную, двойную или, возможно, более высокую точность. Кроме того, некоторые значения могут лежать в динамически рас- пределяемой памяти, а некоторые размещаться статически. Число комбинаций вполне может быть настолько большим, что элементы перевода, связанные с таким правилом вывода, как Е—>Е-[-Т, станут весьма громоздкими. Можете ли Вы по данному переводу, перечисляющему желаемые коды для каждого случая, приду- мать способ автоматического упрощения записи? Скажем, в при- мере 9.19 части перевода E[v для then и else отличаются только одним символом А или В в конце команды ADD. Таким обра- зом, если использовать более изощренные механизмы, описание можно сократить почти вдвое. 265
ГЛ. 9. ПЕРЕВОД И ГЕНЕРАЦИЯ КОДА Упражнение на программирование *9.3.21. Сконструируйте схему перевода, отображающую под- множество Фортрана в промежуточный язык, как в упр, 9.1.10. Напишите программу, реализующую эту схему перевода. Реа- лизуйте генератор кодов, построенный в упр. 9.1.11. Скомби- нируйте эти программы с лексическим анализатором, чтобы получить компилятор с этого подмножества Фортрана. Сконст- руируйте тестовые цепочки, на которых можно было бы прове- рить правильность работы каждой программы. Замечания по литературе Обобщенные схемы синтаксически управляемого перевода описаны в ра- боте Ахо и Ульмана [1971]; там же можно найти решение упр. 9.3.3. В ра- боте Кнута [1968 б) определяются схемы перевода с наследственными н сни- тез^ированными атрибутами; там же обсуждаются ОСУ-схемы из упр. 9.3.10 Решение упр. 9.3.14 дали Бруно и Беркхард [1970] и Кнут [1968 6]; упр. 9.3.12 взято из работы Каута [1968 6].
Ю ОРГАНИЗАЦИЯ ИНФОРМАЦИИ В этой главе рассматриваются методы, с помощью которых информацию можно быстро запомнить и найти в таблицах. Наиболее важное применение этих методов — хранение инфор- мации о лексемах, полученных в процессе лексического анализа, и нахождение ее при генерации кода. Мы разберем два подхода: простые методы нахождения информации и формализм грамматик свойств. Последний заключается в том, что атрибуты и иден- тификаторы связываются между собой по мере того, как появ- ляется уверенность, что для каждого идентификатора доступна вся необходимая для целей перевода информация. 10.1. ТАБЛИЦЫ ИМЕН Таблицы, хранящие имена и информацию, связанную с этими именами, называются таблицами имен. Таблицы имен исполь- зуются практически во всех компиляторах. Таблица имен изо- Имя Данные I целое LOOP метка X вещественный массив Рис. 10.1. Таблица имен. бражена на рис. 10.1. Элементами полей имен являются обычно идентификаторы. Если имена могут быть различной длины, то удобнее, чтобы элементы полей имен были указателями на об- ласть памяти, фактически хранящую эти имена. 267
ГЛ. 10. ОРГАНИЗАЦИЯ ИНФОРМАЦИИ Элементы полей данных, называемые иногда дескрипторами, дают информацию, которую надо собрать о каждом имени. В некоторых ситуациях с данным именем можно связать дюжину или более элементов информации. Например, возможно, что надо знать тип данных (вещественный, целый, строковый и т. д.) идентификатора; был ли он меткой, именем процедуры или фор- мальным параметром процедуры; должен ли он распределяться в статической или динамической области памяти; был ли он идентификатором, имеющим структуру (например, массивом), и если да, то какую структуру (например, размерность массива). Если число элементов информации, связанной с данным именем, переменно, то снова удобно хранить в поле данных указатель на эту информацию. 10.1.1. Хранение информации о лексемах Компилятор использует таблицу имен для хранения инфор- мации о лексема!, в частности об идентификаторах. Эта инфор- мация используется затем для двух целей. Во-первых, для про- верки семантической правильности исходной программы. Напри- мер, если в исходной программе есть оператор вида GOTO LOOP то компилятор должен проверить, что идентификатор LOOP встречается в программе в качестве метки соответствующего оператора. Такую информацию можно найти в таблице имен (хотя и не обязательно во время обработки оператора перехода). Во-вторых, информация в таблице имен используется при гене- рации кода. Например, если в исходной программе па Форт- ране есть оператоф вида А = В + С то генерированным для операции -|- код зависит от атрибутов идентификаторов В н С (скажем, имеют ли они фиксированную или плавающую точку, находятся ли внутри или вне области COMMON и т. д.). Лексический анализатор заносит имена и информацию в таб- лицу имен. Например, всякий раз, когда лексический анализатор обнаруживает идентификатор, он проверяет в таблице имен, встречалась ли ранее такая же лексема. Если нет, то лекси- ческий анализатор! заносит в таблицу имя этого идентификатора вместе с соответствующей информацией. Если идентификатор уже есть в некоторой ячейке I таблицы имен, то лексический ана- лизатор вырабатывает на выходе лексему (<идентификатор>, /). Таким образом, лексический анализатор обращается в таб- лицу имен каждый раз, когда он находит лексему, и чтобы скон- 268
10.1. ТАБЛИЦЫ ИМЕН струировать эффективный компилятор, надо уметь по данному вхождению идентификатора быстро определить, отведена ли для этого идентификатора ячейка в таблице имен. Если этого эле- мента нет, то надо иметь возможность быстро вставить иден- тификатор в таблицу. Пример 10.1. Предположим, что при компиляции языка типа Фортран для всех имен переменных используется единственная лексема типа <идентификатор>. Когда (прямой) лексический анализатор впервые обнаруживает идентификатор, он может занести в таблицу имен информацию о том, имеет ли соответ- ствующая переменная фиксированную или плавающую точку. Лексический анализатор получает эту информацию по первой букве идентификатора. Конечно, если в силу предыдущего объ- явления идентификатор является функцией либо подпрограммой или не подчиняется обычному соглашению о фиксированной или плавающей точке, то информация для него уже содержится в таблице имен, и это приводит к тому, что лексический анали- затор не заносит информацию о ием в таблицу. □ Пример 10.2. Предположим, что разрабатывается компилятор с языка, в котором объявления массивов определяются правилами <оператор массива>—»• массив <список массивов> <список массивов> —»• Определение массивах <список массивов> | Определение массива) Определение массива)—► <идентификатор) (<целое>) Примером объявления массива в этом языке служит (10.1.1) массив ЛВ(10), С£>(20) Для простоты мы здесь предполагаем, что массивы одномерны. Дерево разбора для оператора (10.1.1) изображено на рис. 10.2, на котором идентификаторами являются АВ и CD, а целыми — 10 и 20. На этом дереве разбора лексемы Идентификатору, Иден- тификатору, <целоеу и <целое>2 представляют соответственно АВ, CD, 10 и 20. Естественно, оператор объявления массивов не выполняется; он не компилируется в машинный код. Однако имеет смысл рас- сматривать его перевод как последовательность шагов по орга- низации информации, которые должны выполняться непосред- ственно компилятором. Таким образом, если переводом иденти- фикатора является указатель на отведенное для него место в таблице имен, а перевод целого — оно само, то синтаксически управляемым переводом вершины, помеченной Определение 269
ГЛ. 10. ОРГАНИЗАЦИЯ ИНФОРМАЦИИ массивах могут быть команды для механизмов организации информации, предназначенные для того, чтобы запомнить, что идентификатор — это массив, а его размер — это соответствующее целое. □ Способы применения информации, запомненной в таблице имен, многочисленны. Простой пример: для каждого подвыра- жения в арифметическом выражении может требоваться инфор- мация о его виде, чтобы знать, над какими числами выполнять арифметические операции — над числами с фиксированной или плавающей точкой, комплексными числами и т. д. Эта инфор- мация выбирается из таблицы имен для листьев, помеченных как константы или идентификаторы, и передается вверх по де- реву в соответствии с такими, например, соглашениями, что число с фиксированной точкой -(-число с плавающей точкой = число с плавающей точкой, а число с плавающей точкой-(-комп- лексное число = комплексное число. С другой стороны, язык, а следовательно и компилятор, может запрещать выражения со смешанными видами (как это делается, например, в некоторых версиях Фортрана). 10.1.2. Механизмы запоминания Из сказанного можно заключить, что компилятору нужны методы организации информации, способные быстро запоминать и выдавать информацию о большом числе различных объектов 270
10.1. ТАБЛИЦЫ ИМЕН (например, идентификаторах). Кроме того, в то время как число объектов, реально появляющихся в программе, может быть и велико (скажем, для типичной программы порядка 100 или 1000), число всех возможных объектов имеет порядок несравненно более высокий; большинство из возможных идентификаторов в данной программе не появляется. Изложим кратко возможные способы запоминания информа- ции в таблицах, чтобы обосновать использование таблиц рас- становки, или распределенной памяти, которые будут изучаться в следующем разделе. Основную проблему можно сформулировать так. Есть большой набор объектов, которые могут встретиться. Объект здесь может рассматриваться как имя, состоящее из цепочки символов. Объекты встречаются нам в непредсказуемом порядке,и точное число объектов, которые могут встретиться, заранее неизвестно. Как только объект встретился, надо проверить в таблице, по- являлся ли он раньше, и если нет, внести его имя в таблицу. Помимо этого, будет еще и другая информация об объекте, ко- торую нам надо будет запомнить в таблице. Сначала разберем использование для запоминания информа- ции об объектах таблиц с прямым доступом. В такой таблице для каждого возможного объекта резервируется отдельная ячейка. В ней запоминается информация относительно этого объекта, и нет необходимости запоминать в таблице его имя. Если число возможных объектов мало и для каждого объекта действительно можно выделить отдельную ячейку, такая таблица — таблица с прямым доступом—дает очень быстрый механизм запоминания и извлечения информации об объектах. Однако в большинстве случаев идею применения таблицы с прямым доступом прихо- дится отвергнуть, поскольку размер таблицы был бы недопус- тим, а большая ее часть не использовалась бы. Например, число идентификаторов Фортрана (буква, за которой следует до пяти букв или цифр) равно примерно 1,33x10“. Другой возможный метод запоминания — использование мага- зина. Когда встречается новый объект, его имя и указатель на информацию, относящуюся к этому объекту, помещаются в вер- хушку магазина. В этом случае размер таблицы пропорционален числу действительно встретившихся объектов, а новые объекты можно вставить очень быстро. Но извлечение информации об объекте требует просмотра магазина до тех пор, пока объект не будет обнаружен. Таким образом, в среднем поиск требует времени, пропорционального числу объектов в магазине. Этот метод часто бывает удобен для небольшого числа объектов. Кроме того, он имеет преимущества при компиляции языков с блочной структурой, так как, помимо старого объявления переменной, в таблицу можно поместить и новое. Когда блок закончен, все 271
ГЛ. 10. ОРГАНИЗАЦИЯ ИНФОРМАЦИИ его объявления выталкиваются из магазина, а старые объяв- ления переменных остаются. Третий метод, более быстрый, чем использование магазина, заключается в применении дерева двоичного поиска. В дереве двоичного поиска у каждой вершины может быть левый прямой потомок и правый прямой потомок. Предполагается, что объекты данных можно линейно упорядочить некоторым отношением <, например отношением „предшествовать в алфавитном порядке". Объекты запоминаются как метки в вершинах дерева. Когда встречается первый объект, скажем а,, порождается корень, который помечается at. Если <х2—следующий объект и то к дереву добавляется лист, помеченный а2, и он становится левым прямым потомком корпя. (Если <Zj < а2, то этот лист становится правым прямым потомком.) Появление каждого нового объекта приводит к тому, что к дереву добавляется новый лист в такой позиции, что дерево всегда обладает следующим свой- ством. Пусь #—вершина дерева, помеченная р. Если N имеет левое поддерево, содержащее вершину, помеченную а, то а < р; если N имеет правое поддерево с вершиной, помеченной у, то Для внесения объектов в дерево двоичного поиска можно применить следующий алгоритм. Алгоритм 10.1. Внесение объектов в дерево дво- ичного поиска. Вход. Последовательность объектов а,, ...,«„ из множества объектов А с линейным порядком < на А. Выход. Двоичное дерево, каждая из вершин которого поме- чена одним из элементов с^, ..., и такое, что если вершина N помечена а и некоторый ее потомок N' помечен р, то р < а тогда и только тогда, когда N'— левое поддерево вершины N. т
I 10.1. ТАБЛИЦЫ ИМЕН Метод. (1) Создать одиночную вершину (корень) и пометить ее ax. (2) Предположим, что ах, .... а,._, уже размещены в дереве, I > 0. Если i = л + 1, остановиться. В противном случае внести <хг в дерево, выполняя шаг (3) начиная с корпя. (3) Пусть этот шаг выполняется в вершине М с меткой р. (а) Если а(<р и ДО имеет левого прямого потомка выполнить шаг (3) в вершине N,. Если N не имеет левого прямого потомка, создать его и пометить <х;. Вернуться к шагу (2). б) Если р < <zz и N имеет правого прямого потомка Nr, выполнить шаг (3) в вершине Л1Г. Если А не имеет правого прямого потомка, создать его и пометить а(. Вернуться к шагу (2). □ Метод поиска объекта по существу совпадает с методом вне- сения, за исключением того, что на шаге (3) в каждой вершине надо проверять, является ли ее метка требуемым объектом. Пример 10.3. Пусть на вход алгоритма 10.1 подается после- довательность объектов XY, М, QB, АСЕ и ОР. Упорядочение предполагается алфавитным. Построенное дерево изображено на рис. 10.3. □ 273
ГЛ. 10. ОРГАНИЗАЦИЯ ИНФОРМАЦИИ Можно показать, что, после того как в дерево двоичного поиска помещено п объектов, ожидаемое число вершин, которые надо просмотреть для поиска одного объекта, пропорционально log п. Эта цена приемлема, хотя таблицы расстановки, которые мы теперь обсудим, дают меньшее ожидаемое время поиска. 10.1.3. Таблицы расстановки Наиболее эффективный и широко применяемый в компиля- торах метод при работе с таблицами имен дают таблицы рас- становки. Таблица имен, организованная на принципе расста- новки, схематически изображена на рис. 10.4. Функция расстановки Рис. 10.4. Схема памяти, использующей расстановку: а —таблица расстановки, б — таблица данных. Механизм расстановки состоит из функции расстановки h, таблицы расстановки и таблицы данных. Таблица расстановки содержит п элементов, где п фиксировано заранее. Каждый эле- мент в таблице расстановки имеет два поля: поле имени и поле указателя. Предполагается, что вначале все элементы в таблице расстановки пусты1). Если ранее встретился объект а, то в не- которой ячейке таблицы расстановки, обычно h (а), есть элемент, поле имени которого содержит а (или, возможно, указатель па ячейку в таблице имен, где хранится а) и поле указателя ко- торого содержит указатель на часть таблицы данных, содержа- щую информацию, связанную с а. х) Иногда вначале удобно помещать в таблицу расстановки зарезервиро- ванные слова и имена стандартных функций. 274
10.1. ТАБЛИЦЫ ИМЕЙ Таблица данных физически может совпадать с таблицей рас- становки. Например, если для каждого объекта нужно k слов информации, то можно использовать таблицу расстановки раз- мером kn. Каждый объект, запомненный в таблице расстановки, занимал бы часть из k последовательных слов памяти. Ячейку таблицы расстановки, соответствующую объекту а, легко найти, умножая адрес h(a) расстановки для а на /г и беря полученный адрес в качестве первой ячейки набора слов для а. Функция расстановки h— это фактически набор функций ha, hlt ..., hm, каждая из которых отображает набор объектов в множество целых чисел {0, 1, .... п—1}. Функцию h„ будем на- зывать первичной функцией расстановки. Когда встречается новый объект а, для вычисления h(a) можно воспользоваться следую- щим алгоритмом. Если объект уже встречался ранее, то h(a) — ячейка в таблице расстановки, в которой хранится а. Если объект а ранее не встречался, то h(a) —пустая ячейка, в которой можно запомнить а* 2). Алгоритм 10.2. Вычисление адреса таблицы рас- становки. Вход. Объект а, функция расстановки h, состоящая из по- следовательности функций /г0, Лц .. ., Нт, каждая из которых отображает множество объектов в множество целых чисел {0, 1, ... ...,п—1}, и (не обязательно пустая) таблица расстановки с п ячейками. Выход. Адрес расстановки /г(«) и указание, встречался ли объект а ранее. Если а уже есть в таблице расстановки, то /г(а) — ячейка, отведенная для а. Если объект а ранее не встре- чался, то h(a) — пустая ячейка, в которой а запоминается. Метод. (1) Вычисляем по порядку /|„(<х), h^a), .... /:,„(«), выполняя шаг (2) до тех пор, пока не возникнет „конфликт". Если /1„(<х) дает конфликт, останавливаемся и сообщаем о неудаче. (2) Вычисляем /г,(а): (а) Если ячейка /|,(а) в таблице расстановки пуста, по- лагаем /|(а) = /|;(а), сообщаем, что объект а ранее не встречался, и останавливаемся. (б) Если ячейка /г,(а) не пуста, проверяем поле ее име- ни2). Если именем является а, полагаем /г(а) =/1Да), со- Строго говоря, при таком определении h не функция, поскольку один и тот же объект может отображаться в различные позиции таблицы. В дей- ствительности h—функция двух аргументов: а и самой таблицы.— Прим, не рев. 2) Если поле имени содержит указатель на таблицу имен, надо проверить по этой таблице действительнее имя. 275
ГЛ. 10. ОРГАНИЗАЦИЯ ИНФОРМАЦИИ общаем, что объект а уже встречался, и останавливаемся. Если именем является не а, то возник конфликт; повто- ряем шаг (2) для вычисления другого адреса. □ Каждый раз, когда проверяется ячейка /г,(а), мы говорим, что осуществляется так называемая проба таблицы. Когда таблица расстановки слабо заполнена, конфликты бывают редко и для нового объекта а значение h(a) можно вы- числить очень быстро. Обычно для этого достаточно вычислить значение первичной функции расстановки h0(a). По мере запол- нения таблицы растет вероятность того, что для каждого но- вого объекта а ячейка h0(a) будет уже содержать другой объект. Таким образом, конфликты становятся тем более частыми, чем больше объектов внесено в таблицу, так что число проб, тре- буемых для определения /г(а), увеличивается. Однако можно так конструировать таблицы расстановки, что они по всем ха- рактеристикам будут значительно превосходить деревья двоич- ного поиска. В идеале хотелось бы иметь такую первичную функцию расстановки /г„, чтобы она давала различные положения в таб- лице расстановки для любых двух различных объектов. Разу- меется это, вообще говоря, невозможно, поскольку общее число возможных объектов обычно значительно больше числа п пози- ций в таблице. На практике п делают несколько больше ожи- даемого числа различных объектов. Однако необходимо преду- сматривать некоторые действия на тот случай, если таблица будет переполнена. Для того чтобы запомнить информацию об а, сначала вычис- ляется h(a). Если объект а ранее не встречался, то его имя запоминается в поле имени позиции /г(а). (Если используется отдельная таблица имен, то а запоминается в следующей ее пустой позиции, а указатель на эту позицию помещается в поле имени ячейки /1(a).) Затем в таблице данных отводится очеред- ной подходящий участок памяти, а указатель на него поме- щается в поле указателя ячейки h(a). Потом информация раз- мещается в этом участке памяти таблицы данных. Точно так же, чтобы иайти информацию об а, можно вычис- лить h(a) с помощью алгоритма 10.2 (если а есть в таблице). Для локализации в памяти таблицы данных информации, относящейся к а, используется указатель в поле указателя. Пример 10.4. Возьмем п = 10, и пусть объектами будут про- извольные цепочки прописных латинских букв. Определим CODE(a), где а—цепочка букв, как сумму „числовых значений'1 каждой буквы в а, считая, что А имеет числовое значение 1, В — числовое значение 2 и т. д. Определим /гДа) для OgJ/^9 276
10.1. ТАБЛИЦЫ ИМЕН как (CODE(a) 4-/') mod 10'). Внесем в таблицу расстановки объекты A, W и EF. Вычисляем Л„(А) = (1 mod 10) = 1, так что А вносим в пози- цию 1. Объект W вносим в позицию /i„(W) = (23 mod 10) = 3. Затем встречается EF. Вычисляем /i0(EF) = (5 -)-6) mod 10 = 1. Поскольку позиция 1 уже занята, пробуем /j1(EF) (5 + 6+ + 1) mod 10 = 2. Таким образом, для EF отводится позиция 2. Рис. 10.5. Содержимое таблицы расстановки. Содержимое таблицы расстановки к этому моменту приведено на рис. 10.5. Предположим, что мы хотим выяснить, есть ли в таблице объект НХ. Находим й0(НХ) = 2. С помощью алгоритма 10.2 проверяем позицию 2 и видим, что возник конфликт, поскольку позиция 2 занята, но не объектом НХ. Проверяем затем пози- цию /г!(НХ) = 3 и снова получаем конфликт. Наконец, вычисляем /гг(НХ) = 4 и находим, что позиция 4 пуста. Приходим, таким образом, к выводу, что объекта НХ в таблице нет. □ 10.1.4. Функции расстановки Желательно пользоваться такой первичной функцией расста- новки /г„, которая распределяла бы объекты равномерно по всей таблице расстановки. Надо избегать функций, которые отобра- жают не на все множество позиций или выбирают одни позиции *) amodd — это остаток от деления а иа Ь. 277
ГЛ. 10. ОРГАНИЗАЦИЯ ИНФОРМАЦИИ чаще, чем другие, а также функций, требующих больших вы- числений. Перечислим наиболее широко используемые первичные функ- ции: (1) Если а занимает в машине несколько слов, можно вы- числить арифметическую (или логическую) сумму этих слов, чтобы получить представление а в виде единственного слова. Это слово теперь можно трактовать как число, извлечь квадратный корень и взять в качестве Л„(а) средние loga п битов результа- та. Поскольку средние биты квадратного корня зависят от всех символов объекта, различные объекты в среднем будут давать различные адреса независимо от того, имеют ли объекты общие префиксы или суффиксы. (2) Единственное слово, представляющее а, можно разбить на несколько частей фиксированной длины (обычно по log2п. битов). Затем можно просуммировать эти части и взять в ка- честве /<„(«) младшие log2 п битов суммы. (3) Единственное слово, представляющее а, можно разделить на размер п таблицы и взять в качестве Л0(а) остаток от деле- ния (в этом случае п должно быть простым числом). Рассмотрим теперь методы разрешения конфликтов, т. е. по- строения дополнительных функций hlt h2, ..., hm. Прежде всего отметим, что значение /гДа) должно отличаться от /гу(а) для всех t j. Когда /iz(a) дает конфликт, бессмысленно пробовать ht+r(a), если /1,-+,(а) = /i,.(a). В большинстве случаев хотелось бы, чтобы было т = п — 1, поскольку всегда желательно найти в таблице пустую позицию, если она есть. В общем случае метод разрешения конфликтов оказывает сильное влияние на эффективность всей системы с распределенной памятью. Простейшим, но, как мы увидим, одним из самых худших, набором функций hlt h2, .... ha_2 является /г,.(<х) = (Л0(а) +1) mod п —1 В этом случае мы движемся вперед относительно значения h0(a) первичной позиции до тех пор, пока не исчезнет конфликт. Если достигнута позиция п—1, переходим на позицию 0. Метод прост для выполнения, однако если уже возник конфликт, то занятые позиции имеют тенденцию скапливаться. Например, если из- вестно, что h0(a) вызывает конфликт, то вероятность того, что /1а(а) также вызывает конфликт, выше средней. Более эффективный метод получения вторичных адресов за- ключается в выборе /1,(<х) = (/г0(а) 4-г,) mod/г 1 i п—1 где г(—псевдослучайное число. Часто для этой цели достато- чен самый элементарный генератор случайных чисел, дающий 278
10.1. ТАБЛИЦЫ ИМЕН все числа в диапазоне от 1 до п—1 в точности по одному разу (см. упр. 10.1.8). Каждый раз, когда используются вторичные функции, генератор случайных чисел устанавливается в одно и то же состояние. Таким образом, каждый раз, когда происхо- дит обращение к h, генерируется одна и та же последователь- ность r\, г2, ..., и, следовательно, поведение генератора „слу- чайных" чисел вполне детерминировано. В качестве вторичных функций можно взять также А,- (a) = [t (А„(а) 4-1)] mod п и ht (а) = [/г„(а) + ар 4- Ы] mod п где а и b—подходящие константы. Несколько отличный от этого метод разрешения конфликтов, называемый методом цепочек, разбирается в упражнениях. 10.1.5. Эффективность таблиц расстановки Сколько требуется в среднем времени для внесения и поиска данных в таблице расстановки? С этим вопросом связан сле- дующий: даны вероятности появления различных объектов; как выбрать функции й„, ..., h„.lt чтобы оптимизировать работу с таблицей расстановки? Интересно, что здесь есть ряд нерешен- ных вопросов. Как мы уже отмечали, было бы неразумно иметь повторе- ния в последовательности позиций ..., hn.l(a) для како- го-нибудь объекта а. Будем считать, что хорошая система функ- ций расстановки не допускает повторений. Например, последо- вательность .......ht из примера 10.4 такова, что ни для какого объекта одна и та же позиция не будет проверяться дважды. Если п — размер таблицы расстановки с позициями, зануме- рованными от 0 до п—1, и h„......h„^i — функции расстановки, то каждому объекту а можно поставить в соответствие переста- новку Пя множества {0, ...,п—1}, а именно Па = [/10(а), ..., А„_х(а)]. Таким образом, первая компонента перестановки П« дает первичную позицию, отводимую для а, вторая компонента— следующую возможную позицию и т. д. Если для каждого объекта а известна вероятность ра его появления, то можно определить вероятность перестановки П как г-'1е сумма берется по всем таким объектам а, что Па = П1). Отныне будем полагать, что вероятности всех перестановок даны. *) Иными словами, это сумма вероятностей появления объектов, которые образуют данную перестановку П.—Прим, перев. 279
ГЛ, 10. ОРГАНИЗАЦИЯ ИНФОРМАЦИИ Ясно, что ожидаемое число позиций, которые надо проверить при внесении или поиске объекта, можно вычислить, зная толь- ко вероятности перестановок. Для вычисления эффективности конкретной функции расстановки не обязательно знать реаль- ные функции /:0, .... В этом разделе мы изучим свойства функций расстановки, определяемые вероятностями перестановок. Основываясь на сказанном выше, можно дать следующее определение, которое сводит задачу построения таблицы рас- становки к вопросу о том, каков желательный набор вероят- ностей перестановок. Определение. Системой расстановки назовем пару, состоя- щую из размера таблицы п и функции вероятности р, опреде- ленной на перестановках целых чисел от 0 до п — 1. Систему расстановки будем называть случайной, если р(П) = l/nl для каждой из перестановок П. Укажем важные функции, связанные с системой расстановки: (1) Р(11г2-•-У — вероятность того, что некоторый объект имеет ц в качестве первичной позиции, г2 в качестве первой вто- ричной, t8 в качестве следующей вторичной и т. д. (здесь каж- дое i, — это целое между 0 и п—1), (2) р({й, Ц, ...,/*})— вероятность того, что последователь- ность k объектов заполнит в точности множество позиций • • • » 1ft}* Легко вывести следующие формулы: (10.1.2) p(il...ill)= p(t\.. .tftt), если fe <п ...(ft) (10.1.3) р(1\.../„)=р(П) где П—перестановка [t'i, .... („]. (Ю.1.4) p(S) = 2 P(S — {i})2p(“’1') i € 6’ W где S—произвольное подмножество множества {0, .. , п—1}, состоящее из k элементов, а правая сумма берется по всем цепочкам w из k—1 или менее различных позиций в S — {<}. Полагаем, что р(0) = 1. Формула (10.1.2) позволяет вычислять по вероятностям пе- рестановок вероятность любой последовательности вторичных позиций. Формула (10.1.4) позволяет вычислять вероятность того, что позициями, отведенными для k объектов, являются в точности те, которые составляют множество S. Эта вероятность равна сумме, взятой по всем tgS, вероятностей того, что пер- вые k—1 объектов займут все позиции в S, кроме позиции I, а последний объект займет позицию I. 280
10.1. ТАБЛИЦЫ ИМЕН Пример 10.5. Пусть п = 3, а вероятности шести перестано- вок приведены в табл. 10.1. Таблица 10.1 Перестановка Вероятность [0, 1. 2] 0.1 [0, 2, 1] 0.2 [1, 0, 2] 0.1 11 . 2, 0] 0.3 [2, 0, 1] 0.2 [2, 1, 0] 0.1 По (10.1.3) вероятность того, что в результате применения функции расстановки к некоторому объекту будет выработана цепочка позиций 012, равна просто вероятности перестановки [0,1,2]. Таким образом, р(012) = 0.1. По (10.1.2) вероятность того, что вырабатывается 01, равна р(012). Аналогично /?(02)— вероятность перестановки [0, 2, 1], равная 0.2. Применяя фор- мулу (10.1.2), получаем, что р(0) = р(01) + р(02) = 0.3. Вероят- ность появления каждой цепочки длины 2 или 3 — это вероят- ность той единственной перестановки, префиксом которой слу- жит данная цепочка. Вероятности появления цепочек 1 и 2 равны соответственно р(10) + р(12) = 0.4 и р(20) +р(21) = 0.3. Вычислим теперь вероятности заполнения различных мно- жеств позиций. Для множеств S, состоящих из одного элемента, (10.1.4) сводится к p(]t[)—p(i). Вычислим р({0, 1}) по формуле (10.1.4). Прямая подстановка дает р({0,1}) = р({0})[р(1) + р(01)] + р({1[)[р(0) + р(10)] = 0.3[0.4 + 0.1] + 0.4[0.3 +0.1] = 0.31 Аналогично находим р(]0,2}) = 0.30 и р({ 1,2}) = 0.39 Для вычисления р(]0,1,2}) по формуле (10.1.4) подсчитываем р(]0,1})[р(2) + р(02) + р(12) + р(012)+р(102)] + р(]0,2})[р(1) + р(01) + р(21) + р(021) + р(201)] + р({1,2})[р(0) + р(10) + р(20) + р(120) + р(210)] что, конечно, равно 1. □ Основной величиной, которая нам понадобится для оценки системы расстановки, будет ожидаемое число проб, необходимых Для того, чтобы внести объект а в таблицу, в которой k пози- 281
ГЛ 10. ОРГАНИЗАЦИЯ ИНФОРМАЦИИ ций из п заполнены. Успех достигается при первой же пробе, если /г0(а) = / и i — одна из п—k пустых позиций. Таким обра- зом, вероятность того, что успех будет достигнут при первой пробе, равна £ Р<0 Sp(5) z i = 0 s ' где правая сумма берется по всем множествам S из k позиций, не содержащим i. Если /t0(a)gS, но ht(a)$S, то успех будет достигнут при второй попытке. Поэтому вероятность того, что первая попытка будет неудачной, а вторая — удачной, равна 2* "2p(«7)Sp(S) I - о I = о 5’ где правая сумма берется по всем множествам S из k позиций, содержащим i и не содержащим /. Отметим, что p(i/) = 0 при i = i- Продолжая в том же духе, получаем формулу ожидаемого числа E(k, п) проб, требуемых для внесения объекта в таблицу, в которой k из п позиций заняты, k<n: k + 1 (10.1.5) E(k, n)= jj m 2p(u>) S p(S) m = 1 n i где (1) средняя сумма берется по всем цепочкам w различных позиций длины т, (2) правая сумма берется по всем таким множествам S, со- стоящим из k позиций, что в w все символы, кроме последнего, принадлежат S (последний символ цепочки w не принадлежит S). Предполагается, что в первой сумме для вычисления пер- вичной позиции и первых т—1 вторичных позиций требуется т шагов. Отметим, что при k < п пустая позиция всегда отыс- кивается не более чем за /г+1 попыток. Пример 10.6. Используем вероятности примера 10.5 для вы- числения Е(2, 3). По формуле (10.1.5) £(2, 3)= S т 2 P(^)Sp(S) т = 1 | со | =т = р(0)р({1, 2}) + р(1)р({0, 2}) + р(2)р({0, 1}) 4-2[р(01)р({0, 2}) + р(10)р({1, 2}) + р(02)р({0, 1}) + р(20)р({1, 2}) + р(12)р({0, 1})+р(21)р({0, 2}) + 3[р(012)р({0, 1})+р(021)р({0, 2})+р(102)р({0, 1}) + р(120)р({1, 2}) + р(201)р({0, 2}) +р(210)р({1, 2}) = 2.008 282
10.1. ТАБЛИЦЫ ИМЕН Правая сумма берется по всем множествам S из двух элемен- тов, содержащим все символы цепочки ш, кроме последнего. □ Для оценки систем расстановки нам пригодится также ожи- даемое число R(k, п) проб, требуемых для поиска объекта в таб- лице, в которой k из п позиций заняты. Однако этот показа- тель легко выразить через E(k, п). Можно предположить, что каждый из k находящихся в таблице объектов отыскивается с равной вероятностью. Следовательно, ожидаемое время поиска равно среднему числу проб, которые раньше потребовались на то, чтобы внести эти k объектов в таблицу. Таким образом, 6-1 R(k, n) = -^^E(i, п) 1=0 Поэтому основным показателем мы будем считать E(k, п). Естественно думать, что случайная система расстановки лучше всех остальных, поскольку любая неслучайность может привести только к тому, что вероятность заполнения для одних позиций будет больше, чем для других, и при попытке внести новые объекты эти позиции будут чаще проверяться. Однако мы покажем, что это не совсем так, и точный оптимум не известен. Мы полагаем, что случайная расстановка оптимальна в смысле минимального времени поиска, а другие используемые системы расстановки существенно ей уступают. Поэтому вычислим E(k, п) для случайной системы расстановки. Лемма 10.1. Если система расстановки случайна, то (1) для всех последовательностей ш позиций, для которых 1 igg | ш |^п, p(w) = (n — |w|) !/п! (2) для всех подмножеств S множества {0, 1, ...,п—1} P<S) = (±) Доказательство. (1) Это доказывается элементарной индукцией по (п — |ц'|), начиная | оу | = п и кончая |ш| = 1, с уче- том формулы (10.1.2). (2) Простые рассуждения с использованием симметрии при- водят к выводу, что значение p(S) одинаково для всех подмно- жеств S из k элементов. Поскольку число множеств мощности k равно , утверждение (2) доказано. □ k Лемма 10.2. Если п k, то У (”~0 = *) 1 = 0 Доказательство. Упражнение. □ 283
ГЛ. 10. ОРГАНИЗАЦИЯ ИНФОРМАЦИИ Теорема 10.1. Если система расстановки случайна, то E(k, п)= = (п+ 1)/(п+ 1 — k). Доказательство. Предположим, что в таблице расста- новки k из п позиций заполнены. Требуется внести (& + 1)-й объект а. Из леммы 10.1(2) следует, что для любого множества из k позиций вероятность быть заполненным одинакова. Таким образом, E(k, п) не зависит от того, какие именно k позиций заполнены. Поэтому без потери общности можно считать, что заполнены позиции 0, 1, 2, .... k—1. При вычислении ожидаемого числа проб, требуемых для вне- сения а, нас интересует последовательность адресов, получаемых при применении h к а. Пусть этой последовательностью будет h„(a), h^a), ..., hn_l(a). По определению все такие последова- тельности из п позиций равновероятны. Пусть qj — вероятность того, что первые /—1 позиций в этой последовательности принадлежат {0, 1, ...,k — 1}, а позиция / не принадлежит. Ясно, что ожидаемое число £(fe, п) проб, необхо- 4+1 димых для внесения а, равно 2/'?/• Заметим, что fe+1 А + 1 т k + l k + 1 (10.1.6) 2/?/=2 2?» /=1 +1 = 11 = 1 1=1 т = 1 4 + 1 Но 2'Ли —это как Раз вероятность того, что первые /—1 «=/ позиций в последовательности /гв(а), Ьг(а), .... /:„_,(«) лежат между 0 и k — 1, т. е. что для внесения (&-|-1)-го объекта тре- буется по крайней мере / проб. По лемме 10.1 (1) эта величина равна М-/ + Ц /_4 \ /4—П / 4 — _ k I (я —/4-1) 1 _ {k — j+lj \ п J \п— 1/ ' ' '\л— / 4-2/ — (4 — / -1- 1) ! л! / л \ \ * У Тогда, применяя лемму 10.2, получаем '=1 k) \k) Из теоремы 10.1 видно, что при больших п и k функция E(k, п) зависит только от отношения k/n и приблизительно равна 1/(1—р), где p = k/n. График этой функции приведен на рис. 10.6. Отношение k/n называется коэффициентом загрузки. Когда коэффициент загрузки мал, время внесения как функция числа k заполненных позиций растет медленнее, чем log k, и расста- 284
10.1. ТАБЛИЦЫ ИМЕН новка предпочтительнее двоичного поиска. Конечно, при прибли- жении к п, т. е. по мере заполнения таблицы, внесение становится дорогим, а при k = n вообще невозможным, если нет специаль- ных механизмов обработки переполнений. Один метод, связан- ный с переполнением, предлагается в упр. 10.1.11 и 10.1.12. Рис. 10.6. E(k, п) как функция коэффициента загрузки для случайной расстановки. Ожидаемое число попыток при внесении объекта является не единственным критерием качества схемы расстановки. Жела- тельно также, чтобы вычисление функций расстановки было простым. В схемах расстановки, которые мы до сих пор рас- сматривали, вторичные функции hl(a), вычислялись не от а, а от /г0 (а), и это характерно для большинства схем расстановки. Такая организация эффективна, поскольку h0 (а) — целое число известной длины, в то время как а может иметь произвольную длину. Этот метод мы будем называть расстанов- кой по позициям. Частный случай этого метода, еще более лег- кий с точки зрения выполнения,—линейная расстановка, где hj(a) вычисляется как (h„ (а) 4-1) mod п. В этом случае переби- раются последовательные ячейки, пока ие отыскивается пустая; если достигнут конец таблицы, переходим на ее начало. Линей- ная расстановка используется в примере 10.4. Приведем теперь пример, показывающий, что по ожидаемому числу попыток вне- сения линейная расстановка может быть хуже случайной. Затем 285
ГЛ. 10. ОРГАНИЗАЦИЯ ИНФОРМАЦИИ рассмотрим расстановку по позициям и покажем, что по край- ней мере в одном случае она также хуже случайной расстановки. Пример 10.7. Рассмотрим систему линейной расстановки с и = 4 и вероятностью Ч, для каждой из четырех перестановок [0123], [1230], [2301] и [3012]. Читатель может убедиться в том, что если вероятности сделать неравными, то система станет только хуже. Для случайной расстановки теорема 10.1 дает £(2,4) = 7з- По формуле (10.1.4) можно вычислить вероятности того, что заполнено множество из двух позиций. Эти вероятности таковы: р({0, 1}) = р({1, 2}) = р({2, 3}) = p({s, 0}) = з/18 р({0, 2})=р([1, 3}) = 7, Затем по формуле (10.1.5) находим, что для линейной рас- становки £(2,4) = 27/16, а это больше 5/3— стоимости случайной расстановки. □ Сравним теперь расстановку по позициям со случайной рас- становкой в частном случае, когда в таблицу вносится третий объект. Отметим, что при расстановке по позициям для каждой позиции i точно одна перестановка П( начинается с i и имеет ненулевую вероятность. Вероятность перестановки П, обозначим через р;. Второй элемент в IT,-, т. е. первую вторичную пози- цию для t, обозначим через at. Если р(=1/л для всех 1, то си- стему будем называть случайной расстановкой по позициям. Теорема 10.2, При всех п > 3 £(2, я) для случайной расста- новки меньше, чем для случайной расстановки по позициям. Доказательство. По теореме 10.1 для случайной рас- становки £(2, п) =(п +1)/(я— 1). Найдем нижнюю границу функ- ции £(2, п) для расстановки по позициям. Предположим, что первые три объекта, вносимые в таблицу, имеют перестановки П(, Пу и Щ соответственно. Рассмотрим отдельно случаи i—j и <>#/• Случай 1: i=/=j. Это происходит с вероятностью (п—1)/п. Ожидаемое число попыток при внесении третьего объекта оказы- вается равным 1 (2/п) 4- (2/я) [1/(л— 1)] = (л 4-1 )/(п— 1) Случай 2: i= j. Это происходит с вероятностью \/п. Тогда третий объект вносится с первой попытки с вероятностью (п— 2)/п\ при этом и k-Фа, (а; — вторая заполненная по- зиция). Вероятность того, что/г - о,-, равна 1//г; нужны по край- ней мере две попытки. Вероятность того, что k—i, также равна 1/л, и надо сделать три попытки. (Это вытекает из того, что 286
УПРАЖНЕНИЯ вторая попытка делается для позиции а,-, которую занимает /.) Таким образом, в этом случае ожидаемое число проб не менее [(л—2)/я] + (2/л) + (3/л)=(л+3)/л. Взвешивая эти два случая в соответствии с их вероятно- стями, получаем для случайной расстановки по позициям ' ’ \ п— I / \ п п ) \ п ) пг Последнее выражение превосходит («4-1)/(л—1) для п > 3. □ Основное в предыдущем примере и теореме заключается в том, что многие простые схемы расстановки не удовлетворяют требованиям определения случайной расстановки. Интуитивно это объясняется тем, что при использовании неслучайных схем стремятся пробовать одну и ту же позицию снова и снова. Даже если коэффициент загрузки мал, некоторые позиции с боль- шой вероятностью испытываются многократно. При использова- нии такой схемы, как расстановка по позициям, каждый раз, когда заполняется первичная позиция йДа), все вторичные по- зиции для /г0(а), которые уже испытывались, будут испытывать- ся снова, а это ведет к плохим характеристикам. Из сказанного вовсе не следует, что не стоит пользоваться такими схемами, как расстановка по позициям, особенно если затраты во времени на одну попытку занесения компенсируются за счет простоты реализации. В действительности весьма вероятно, что случайная расста- новка— не самое лучшее из всего, что можно применить. Сле- дующий пример показывает, что при применении случайной рас- становки E(k, п) не всегда достигает минимума. Мы, однако, думаем, что случайная расстановка дает минимум R(k, п) — ожи- даемого времени поиска объекта. Пример 10.8. Пусть перестановки [0123] и [1032] имеют веро- ятности 0.2, [2013], [2103], [3012] и [3102] имеют вероятнос- ти 0.15, а все остальные имеют нулевые вероятности. Можно вычислить £(2,4) непосредственно по формуле (10.1.5) и получить 1.665. Это значение меньше, чем % для случайной расста- новки. □ УПРАЖНЕНИЯ 10.1.1. С помощью алгоритма 10.1 внесите в дерево двоич- ного поиска последовательность объектов Т, D, Н, F, А, Р, О, Q. W, ТО, TH. Считайте, что объекты упорядочены по алфавиту. 10.1.2. Разработайте алгоритм, на вход которого подается дерево двоичного поиска и который перечисляет по порядку все 287
ГЛ. 10. ОРГАНИЗАЦИЯ ИНФОРМАЦИИ элементы, запомненные в дереве. Примените этот алгоритм к де- реву, построенному в упр. 10.1.1. *10.1.3. Покажите, что ожидаемое время внесения (или поис- ка) одного объекта в дерево двоичного поиска составляет 0(log п), где п — число вершин в дереве. Каково максимальное значение времени, требуемого для внесения одного произвольного объекта? *10.1.4. Какая информация о переменных и константах Форт- рана необходима в таблице имен для генерации кода? 10.1.5. Опишите механизм хранения таблицы имен для языка с блочной структурой, такого, как Алгол, в котором область действия переменной X ограничена данным блоком и всеми теми блоками, содержащимися в данном, в которых переменная X не переобъявлена. 10.1.6. Выберите размер таблицы и первичную функцию рас- становки Л„. Вычислите Л0(сс), где а берется из множества (а) ключевых слов Фортрана, (б) ключевых слов Алгола и (в) клю- чевых слов ПЛ/I. Каково максимальное число объектов с одина- ковым значением первичного адреса расстановки? Можете про- вести эти вычисления на ЭВМ. Саммет [1969] дает необходимые наборы ключевых слов. *10.1.7. Покажите, что функция R(k, п) для случайной рас- становки приблизительно равна (—l/p)log(l—р), где p = k/n. Начертите график этой функции. Указание: Аппроксимируйте 6-1 (n/й) J (n+l)/(n —z + 1) интегралом. 1 = 0 *10.1.8. Рассмотрим следующий генератор псевдослучайных чисел. Этот генератор вырабатывает последовательность rt, г2, . . . . . . , чисел, которые можно использовать для вычисления /;,•(«) = [/;„(«) + г,] mod п при 1<Д'<л — 1. Каждый раз, когда должна генерироваться последовательность чисел, целому R присваи- вается значение 1. Предполагается, что /г —2г. Для того чтобы получить очередное число, надо выполнить такие шаги: (1) R = 5*R, (2) A’ = A’mod4n, (3) выдать в качестве значения г = [7?/4]. Покажите, что для любого i все разности ri+k— г,-для й>1 и i-| 1г<'.п—1 различны. **10.1.9. Покажите, что если /г,- — |/г„ 4-ai2 4-W]modп для —1, то различны не более половины позиций в после- довательности hlt h,, ..., /Д-р При каком условии в этой по- следовательности будет в точности половина различных позиций? 288
УПРАЖНЕНИЯ **10.1.10. Каково число различных позиций в последователь- ности Л„, hlt ... , если для 1 С г <р/2 + mod р h2l = h„ — + «'] 2mod p и p — простое число? Определение. Методом разрешения конфликтов, более эффек- тивным (чем описанный в разд. 10.1.4) с точки зрения внесения и поиска, является метод цепочек. В этом методе каждый эле- мент таблицы расстановки имеет дополнительное поле, содержа- щее указатель на дополнительные элементы с тем же, как у него самого, первичным адресом. Все элементы с одинаковым первич- ным адресом соединены в последовательный список, начиная с этой первичной позиции. Существует несколько способов реализации метода цепочек. В одном из них, называемом прямым методом цепочек, для хранения всех объектов используется сама таблица расстановки. Для того чтобы внести объект а, проверяется позиция Л0(а). (1) Если эта позиция пуста, а помещается в ней. Если она занята и с нее начинается цепочка, находим некоторым подхо- дящим способом пустой элемент таблицы расстановки и поме- щаем его в цепочку, начинающуюся с h„(a). (2) Если позиция h0(a) занята, но не началом цепочки, то перемещаем текущий элемент р, находящийся в h„(a), в пустую позицию таблицы расстановки и вносим а в h0(a). (При этом надо заново вычислить /г(р), чтобы хранить Р в соответствующей це- почке.) Это перемещение элементов составляет главный недостаток прямого метода цепочек. Тем не менее метод довольно быстр. Другое его достоинство в том, что в переполненную таблицу с помощью той же стратегии внесения и поиска можно поместить дополнительные объекты. 10.1.11. Покажите, что если вторичные позиции выбираются случайно, то ожидаемое время поиска Д(й, п) для прямого метода цепочек равно 1 +р/2, где р = kjn. Сравните эту функцию с R(k, п) в упр. 10.1.7. В другом методе цепочек, не требующем перемещения объек- тов, перед таблицей расстановки применяется таблица индексов. Первичная функция расстановки h„ вычисляет адрес в таблице индексов. Элементами таблицы индексов служат указатели на таблицу расстановки, элементы которой заполняются по порядку. Для того чтобы при этой схеме внести объект а, вычисляется Ло(«), т. е. адрес в таблице индексов. Если позиция Л0(а) пуста, 10 А. Ахо, Дж. Ульман, т, 2 289
ГЛ. 10. ОРГАНИЗАЦИЯ ИНФОРМАЦИИ занимаем очередную доступную позицию в таблице расстановки и вносим в иее а. Указатель на эту позицию размещаем затем в Ло(«)- Если Л0(а) уже содержит указатель на позицию в таблице рас- становки, обращаемся в эту позицию. Затем просматриваем на- чинающуюся с нее цепочку. Достигнув конца цепочки, выбира- ем очередную доступную позицию в таблице расстановки, вно- сим в нее а и присоединяем эту позицию к концу цепочки. Если таблица расстановки заполняется сверху вниз, то очеред- ную доступную позицию можно иайти очень быстро. В этой схе- ме нет необходимости перемещать объекты, поскольку каждый элемент таблицы индексов всегда указывает на начало цепочки. Кроме того, легко обрабатывать переполнения, добавляя мес- то к концу таблицы расстановки. *10.1.12. Каково ожидаемое время поиска объекта для метода цепочек с таблицей индексов? Считайте, что первичные позиции распределены равномерно. 10.1.13. Рассмотрим систему случайной расстановки с п пози- циями, как в разд. 10.1.5. Покажите, что если множество S состоит из k позиций и i#S, то (tw') = l/(n — k), где сумма W берется по всем цепочкам w из k или менее различных пози- ций в S. *10.1.14. Докажите тождества , \ V М+* + 1 (d) J < k 1=0 , , V . М + h (и + '1 Лг+^ +1 (в) 2- ‘ ( i ) = k ( k /г-1 i = о 4 *10.1.15. Предположим, что объектами являются цепочки длины от одной до шести латинских букв. Пусть CODE—функ- ция, определенная в примере 10.4, а объект а имеет вероят- ность (1/6)26-|а|. Вычислите вероятности перестановок мно- жества {0, 1, .... п— 1}, если (а) /1;(а) = (CODE(a) + i) mod п, — 1, (б) Л((а) = (i(/i0(a) + 1)) mod п, 1 С? i C n—1, где /i„(a) =CODE(«) mod n. **10.1.16. Покажите, что для линейной расстановки со слу- чайно распределенной первичной позицией /г0(а) предел функ- 290
УПРАЖНЕНИЯ ции E(k, п) при k и п, стремящихся к оо, и k/n = p равен 1 +[р(1—р/2)/(1—р)2]. Как это соотносится с соответствующей функцией от р для случайной расстановки? Определение. Систему расстановки назовем k-равномерной, если для любого множества Ss{0, 1,2........п—1}, состоящего из k элементов, вероятность того, что последовательность из k различных позиций образована в точности позициями из S, / /и. \ равна 1/(^1 (наиболее существенно здесь то, что вероятность не зависит от S). * 10.1.17. Покажите, что если система расстановки й-равпо- мерна, то, как и для случайной расстановки, E(k, п) = (п + 1)/(п + 1 —k) * 10.1.18. Покажите, что для любой системы расстановки, для которой существует такое число k, что E(k, п) < < (n + 1)/(« + 1—k), существует такое k' < k, что E(k', n) > (п + 1)/(п + 1 —k') Таким образом, если для некоторого k данная система расста- новки лучше случайной, то существует меньшее число k', для которого эта система хуже случайной. Указание: Покажите, что если система расстановки (k—1)-равномерна, но не й-равно- мерна, то E(k, п) > (п + 1)/(п—£ + !) * 10.1.19. Приведите пример системы расстановки, А-равно- мериой для любого k, но не случайной. * 10.1,20. Обобщите пример 10.7 на случай неравных вероят- ностей для циклических перестановок. * 10.1.21. Усильте теорему 10.2 с тем, чтобы включить системы, осуществляющие расстановку по позициям, но имеющие не- равные вероятности рг. Открытые проблемы 10.1.22. Оптимальна ли в смысле ожидаемого времени поиска объекта случайная расстановка. Другими словами, верно ли, что функция R(k, п) всегда ограничена снизу величиной 4-1 (1 /k) S (п + 1 )Цп + 1 — i) < = 0 Мы думаем, что случайная расстановка оптимальна. 10.1.23. Найдите наибольшую нижнюю границу функции E(k, п) для систем, осуществляющих расстановку по позициям. to* 291
ГЛ. 10. ОРГАНИЗАЦИЯ ИНФОРМАЦИИ Любая нижняя граница, превышающая (и 1 )/(n 4- 1—/г), пред- ставляет интерес. 10.1.24. Найдите наибольшую нижнюю границу функции E(k,n) для произвольной системы расстановки. В примере 10.8 мы видели, что (п + 1 )/(n + 1—k) такой границей не является. Проблема для исследования 10.1.25. В некоторых применениях таблиц расстановки вво- димые объекты известны заранее. Примерами служат библиотеки стандартных подпрограмм или таблицы кодов операций языка ассемблера. Если известно, что именно размещается в таблице расстановки, то можно выбрать систему расстановки так, чтобы минимизировать ожидаемое время просмотра. Можете ли Вы привести алгоритм, который принимает на вход список объек- тов, подлежащих запоминанию, и выдает систему расстановки, эффективно реализуемую и требующую мало времени при поиске для этой конкретной загрузки таблицы расстановки? У пражнения на программирование 10.1.26. Запрограммируйте систему расстановки, осуществ- ляющую расстановку по позициям. Проверьте поведение системы на ключевых словах Фортрана и общеупотребительных именах функций. 10.1.27. Запрограммируйте систему расстановки, использую- щую для разрешения конфликтов метод цепочек. Сравните пове- дение этой системы и системы из упр. 10.1.26. Замечания по литературе Таблицы расстановки известны также как таблицы с распределенной памятью, ключевые трансформационные таблицы, случайные таблицы и таб- лицы с вычисляемыми элементами. Таблицы расстановки применялись про- граммистами с начала 50-х годов. Самая ранняя работа по адресам рас- становки написана Петерсоном [1957]. Хороший обзор методов расстановки приводен Моррисом [1968]. У него же можно найти ответ на упр. 10.1.7. Методы вычисления вторичных функций для уменьшения ожидаемого числа конфликтов обсуждаются Маурером [1968], Радке [1970] и Беллом [1970]. Ответ на упр. 10.1.10 можно найти у Радке [1970]. В работе Ульмана [1972] изучаются ^-равномерные системы расстановки. Хорошим справочником по деревьям двоичного поиска и таблицам рас- становки является работа Кнута [1973]. 10.2. ГРАММАТИКИ СВОЙСТВ Интересный конструктивный метод присваивания свойств идентификаторам в языке программирования основан па фор- мализме „грамматик свойств". Это контекстно-свободные грам- матики с дополнительными механизмами передачи информации »2
10.2. ГРАММАТИКИ СВОЙСТВ об идентификаторах и обработки некоторых не контекстно-сво- бодных аспектов синтаксиса языков программирования (таких, как требование, чтобы идентификаторы были описаны раньше их использования). В этом разделе мы дадим введение в теорию грамматик свойств и покажем, как с помощью грамматики свойств смоделировать синтаксический анализатор, соединяющий в себе разбор с некоторыми аспектами семантического анализа. 10.2.1. Мотивировка Попробуем попять сначала, почему не всегда бывает доста- точно объявления идентификатора для того, чтобы установить все его свойства и поместить их в ячейки таблицы имен, отве- денные для этого Идентификатора. Если мы рассмотрим язык ------начало io ока 1 А ------начало io ока 1 В Е начало блока 3 конец блока 3 О ------конец блока 2 В -----начало блока 4 -----конец блока 4 S ------конец блока 1 с блочной структурой (например, Алгол или ПЛ/1),то увидим, что свойства иден- тификатора могут многократно меняться, Рис. 10.7. Блочная струн- Рис. 10.8. Представление блочной структуры в тура программы. виде дерева. поскольку его можно определить в охватывающем блоке и переоп- ределить во внутреннем. Когда внутренний блок заканчивается, свойства становятся снова такими, какими оии были в охваты- вающем блоке. Рассмотрим, например, диаграмму на рис. 10.7, изображаю- Щую блочную структуру программы. Буквы обозначают области Действия в программе. Эту блочную структуру можно предста- вить деревом на рис. 10.8. Предположим, что идентификатор I определен в блоке 1 этой программы и помещен в таблицу имен сразу, как только встретился. Предположим, что после этого I переопределен 293
ГЛ. 10. ОРГАНИЗАЦИЯ ИНФОРМАЦИИ в блоке 2. В областях В, С и D этой программы для I дейст- вует новое определение. Таким образом, встретив определение I в блоке 2, надо внести это новое определение в таблицу имен. Однако нельзя просто заменить определение, которое было у / в блоке 1, новым определением в блоке 2, поскольку в области Е надо будет вернуться к первоначальному определению I. Один из путей решения этой проблемы заключается в том, что с каждым определением идентификатора связываются два числа: номер уровня и индекс. Номер уровня — это глубина вло- женности, и всем блокам с одним и тем же номером уровня даются различные индексы. Например, идентификаторы в об- ластях В и D блока 2 имеют номер уровня 2 и индекс 1. Идентификаторы в области F блока 4 имеют иомер уровня 2 и индекс 2. Если ссылка на идентификатор осуществляется в блоке с уровнем 1 и индексом /, то в таблице имен разыскивается определение этого идентификатора с тем же номером уровня и тем же индексом. Если, однако, в блоке с номером уровня i идентификатор не определен, то его определение надо искать в блоке с номером уровня i—1, содержащем блок с номером уровня i и индексом /, и т. д. Если определение появлялось на нужном уровне, но индекс слишком мал, можно отбросить опре- деление, так как оно уже больше неприменимо. Таким образом, для запоминания определений каждого идентификатора по мере их появлений полезен магазин. Описанный поиск облегчается, если индекс текущего активного блока доступен на каждом уровне. Например, если идентификатор Д встречается в области С, но его определения там нет, надо взять его определение в Й (или D, если допускаются объявления после использования). Если же определения К- нет ни в В, ни в D, надо взять ’его в областях А, Е или G. Но нельзя искать определение /< в об- ласти F. Метод „уровень — индекс" работы с определениями годится для языков с принципом строгой вложенности областей дейст- вия определений (например, для Алгола и ПЛ/I). В этом раз- деле, однако, мы изучим более общий формализм, называемый грамматиками свойств, допускающий произвольные соглашения об области действия определений. Грамматикам свойств присущи общность и элегантность, вытекающие из единообразной трак- товки идентификаторов и их свойств. Кроме того, обработку с их помощью можно осуществить за время, линейное относи- тельно длины входного потока. Константа пропорциональности может быть велика, но мы излагаем эту концепцию в надежде на то, что будущие исследования сделают использование грам- матик свойств практически приемлемым. 294
10.2. грамматики свойств 10.2.2. Определение грамматики свойств Неформально грамматику свойств можно определить как входную КС-грамматику, нетерминальным и терминальным сим- волам которой приписываются „таблицы свойств". Таблицу свойств можно рассматривать как абстракцию таблицы имен. При разборе снизу вверх в соответствии с входной грамма- тикой таблицы свойств, приписанные нетерминалам, представ- ляют в данной точке разбора информацию, хранящуюся обычно в таблице имен. Таблица свойств Т — это отображение множества индексов I в множество свойств V. Множеством индексов у нас будет мно- жество неотрицательных целых чисел. Каждое целое число в множестве индексов можно интерпретировать как указатель на таблицу имен. Таким образом, если указываемый элемент таблицы имен представляет идентификатор, то целое можно трактовать как имя этого идентификатора. Множество V—это множество „свойств", или „значений", и им у нас будет конечное множество целых чисел. Одно из них (обычно 0) выделяется как „нейтральное" свойство. Остальные можно связать с различными свойствами, представляющими инте- рес. Например, число 1 можно связать со свойством „на этот идентификатор была ссылка", 2 — со свойством „объявленное вещественное" и т. д. В таблицах, связанных с терминалами, все индексы, кроме одного, отображаются в нейтральное свойство. Этот один индекс может отображаться в любое свойство (в том числе и нейтраль- ное). Однако если терминалом является лексема «(идентификатору, то индекс, представляющий имя конкретной лексемы (а именно, компонента данных этой лексемы), должен отображаться на свой- ство типа „это идентификатор, упоминаемый здесь". Например, если в программе встретилось объявление real В, то эту цепочку можно разобрать так: <Мпя6лыше> [112] real <иЗентшримтор> [id] где компонента данных лексемы «(идентификатору ссылается иа цепочку В. С терминалом «(идентификатору связана таблица [1:1], отображающая индекс 1 (который соответствует теперь цепочке В) в свойство 1 (возможно, „упоминаемый"), а остальные индексы — в нейтральное свойство. Терминальная лексема real связана с таблицей, отображающей все индексы в нейтральное свойство. Обычно такая таблица явно не представлена. 295
ГЛ. 10. ОРГАНИЗАЦИЯ ИНФОРМАЦИИ С нетерминалом <объявление> в дереве разброса связывается таблица, получаемая слиянием по некоторому правилу таблиц прямых потомков этого нетерминала. В приведенном примере это таблица [1:2], отображающая индекс 1 в свойство 2, а все другие индексы—в нейтральное свойство. Тогда ее можно трак- товать так, что идентификатор, связанный с индексом 1 (а именно, В), обладает свойством „объявленное вещественное11. Вообще говоря, если в дереве разбора есть структура А А Z, х2 Л тг ...т„ то свойство индекса I в таблице Т является функцией только свойства индекса i в таблицах Т\,Т2, ..., Тk. Иными словами, каждый индекс трактуется независимо от всех остальных. Дадим теперь формальное определение грамматики свойств. Определение. Грамматикой свойств называется восьмерка G = (N, S, Р, S, V, F, р), где (1) (N, S, Р, S)—входная КС-грамматика, (2) V—конечное множество свойств, (3) —нейтральное свойство, (4) F = V—множество допустимых свойств, всегда при- надлежит F, (5) р— такое отображение из РхР в V, что (а) если значение р(р, s) определено, то длина правой части правила вывода р та же, что и у s, где s — цепочка свойств; (б) значение р(р, .. . ц„) равно v0, если длина цепочки из нейтральных свойств та же, что и у правой части правила вывода р, и не определено в противном случае. Функция р говорит о том, как выбирать свойства в табли- цах, связанных с внутренними вершинами дерева разбора. В зависимости от правила вывода, использованного в этой вер- шине, свойство, связанное с каждым целым числом, вычисляется независимо от свойств всех других целых чисел. Условие (56) констатирует, что таблица в некоторой внутренней вершине может обладать не нейтральным свойством для некоторого целого числа, только если один из ее прямых потомков обладает не нейтральным свойством для этого числа. 296
10.2. ГРАММАТИКИ СВОЙСТВ Выводимой цепочкой в G называется цепочка Х1Т1Х2Тг. . . ХпТ„, где символы X принадлежат N IJ2, а Т — таблицы свойств. Пред- полагается, что каждая таблица связана с символом непосред- ственно слева от нее и представляет собой такое отображение множества индексов в V, что все индексы, кроме конечного числа, отображаются в Определим на выводимых цепочках отношение =>0 (или =ф, если ясно, о какой грамматике идеть речь). Пусть aATf}— выводимая цепочка в G и А—► Х1 .. . —правило вывода р£Р. Тогда аЛГр => аХ1Т1 .. . ХкТ$, если для всех индексов i р(р, л(0Л(0---Л(‘'))=д;) Обозначим через =з>’в (или =>*, если G подразумевается) рефлек- сивное и транзитивное замыкание отношения =>0. Языком L(G), определяемым грамматикой G, называется множество всех таких цепочек . апТп, что для некоторой таблицы Т (1) ST акТ ,агТг . а„Тп, (2) для всех /, (3) T(i)£F для всех I, (4) Tj для каждого j отображает все индексы, кроме, быть может, одного, в п„. Следует заметить, что хотя определение вывода дается сверху вниз, определение грамматики свойств скорее основано на раз- боре снизу вверх. Если можно определить таблицы, связанные с терминалами, то можно детерминированно построить таблицы, связанные с каждой вершиной дерева разбора, так как р— функция таблиц, связанных с прямыми потомками вершины. Должно быть ясно, что если G — грамматика свойств, то множество {а1а2 ... а„ | а1Т1а2Т2... апТ„ 6 ЦО) для некоторой последовательности таблиц Т1: Т2, . . ., Т„} является контекстно- свободным языком, поскольку любую цепочку, выводимую во входной КС-грамматике, можно вывести и в грамматике свойств, считая при этом все таблицы нейтральными. Соглашение. Мы и дальше будем придерживаться принятого соглашения относительно обозначений для контекстно-свободных грамматик, по которому а, Ь, с, ... принадлежат 2 и т. д. Кроме того, будем считать, что символ v обозначает свойство, а сим- вол s — цепочку свойств. Если Т отображает все целые числа в нейтральное свойство, то вместо ХТ будем писать X. Пример 10.9. Приведем довольно длинный пример применения грамматик свойств для обработки объявлений в языке с блоч- ной структурой. Покажем, как в ходе разбора можно детер- 297
ГЛ. 10. ОРГАНИЗАЦИЯ ИНФОРМАЦИИ мииироваино строить таблицы, если входная КС-грамматика допускает детерминированный разбор снизу вверх1). Пусть G = (N, 2, Р, S, V, 0, {0}, |.Г)— грамматика свойств, в которой (i) К = {<блок>, <оператор>, <список объявлений>, <список операторов;», <список перемеиных>}. Нетерминал <список пере- менных> вырабатывает список переменных, используемых в опе- раторе. Оператор мы представим только переменными, действи- тельно используемыми в операторе, а не заданием его полной структуры. Эта абстракция позволяет выделять основные осо- бенности грамматик свойств, ие загромождая пример подробно- стями. (ii) 2 = {begin, end, declare, label, goto, а}. Терминал declare служит для объявления одного идентификатора. Объявленные идентификаторы ие изображаются, поскольку эта информация будет в таблице свойств, связанной с declare. Аналогично label устанавливает, что идентификатор употребляется как метка опе- ратора. Сам идентификатор явно не изображается. Терминал goto заменяет goto <метка>, но метка снова явно не изображается, поскольку она будет в таблице свойств, связанной с goto. Тер- минал а представляет переменную. (ill) Р состоит из следующих правил вывода: (1) <блок>—> begin <список объявлеиий> <список операто- ров> end (2) <список операторов>—>-<список операторов> <оператор> (3) <список операторов>—>-<оператор> (4) <оператор>—>-<блок> (5) <оператор>—> label <список переменных> (6) <оператор>—>-<список переменных> (7) <оператор>—«-goto (8) <список переменных>—><список переменных>а (9) <список перемеиных>—>е (10) <список объявлений>—► declare <список объявлений> (11) <список объявлений;»е Неформально правило (1) говорит, что блок — это список объяв- лений и список операторов, охваченные begin и end. Правило (4) говорит, что оператором может быть блок, (5) и (6) — что опе- ратор— это список использованных внутри него переменных, перед которым, возможно, стоит метка. Правило (7) говорит, что оператором может быть оператор перехода, (8) и (9) — что список переменных — это цепочка из 0 или более терминалов а, а (10) и (11) — что список объявлений —это цепочка из 0 или более терминалов declare. ') Грамматика этого примера неоднозначна, но это не мешает иллюстри- ровать основные понятия. 298
10.2. ГРАММАТИКИ СВОЙСТВ (iv) И={0, 1,2, 3,4} — множество свойств, имеющих такой смысл: О — идентификатор не появляется в цепочке, выводимой из данной вершины (нейтральное свойство), 1—идентификатор объявлен как переменная, 2—идентификатор является меткой оператора, 3 — идентификатор используется как переменная,но (постоль- ку, поскольку речь идет о потомках рассматриваемой вершины) еще не объявлен, 4 — идентификатор используется как метка в операторе пе- рехода, по еще не было объявления этой метки. (v) Определим на свойствах функцию ц, преследуя такие цели: (а) если обнаружено недопустимое использование пере- менной или метки, то нельзя строить таблицы дальше, так что процесс вычисления таблиц „зайдет в тупик" (можно было бы для этой цели ввести свойство „ошибка"), (б) идентификатор, использованный в операторе goto, должен быть меткой некоторого оператора того блока, в котором ои используется1), (в) идентификатор, использованный как переменная, дол- жен быть объявлен внутри этого же блока или блока, в ко- торый данный блок вложен. Зададим значение ц (р, w) для каждого правила вывода по порядку и прокомментируем наши действия. (1) <блок>—► begin <список объявлений)) <список операто- ров> end S у (1, S) 0 0 0 0 0 0 10 0 0 0 13 0 о 0 0 3 0 3 0 0 2 0 0 Единственным возможным свойством для всех целых чисел, связанных с begin и end, является 0; этим и объясняются два столбца нулей. В списке объявлений каждый идентификатор будет иметь свойство 0 (не объявлен) или 1 (объявлен). Если ’) Это отличается от соглашений Алгола. Например, Алгол допускает переходы в блок, охватывающий данный. Мы принимаем наше соглашение потому, что хотим, чтобы обработка меток отличалась от обработки иденти- фикаторов. 299
ГЛ 10. ОРГАНИЗАЦИЯ ИНФОРМАЦИИ идентификатор объявлен, то внутри тела блока, т. е. в списке операторов, он либо может использоваться только как перемен- ная (3), либо не использоваться (0). В любом случае идентифи- катор не объявлен, коль скоро это касается программы вне данного блока, так что идентификатору придается свойство 0. Так появляются строки вторая и третья. Если идентификатор не объявлен в данном блоке, он все- таки может использоваться либо как метка, либо как перемен- ная. Если он используется как переменная (свойство 3), то это надо передать за пределы блока, чтобы можно было проверить, объявлен ли он в соответствующем месте (строка 4). Если иден- тификатор определен как метка внутри данного блока, то это не передается за пределы данного блока (строка 5), поскольку на метку внутри данного блока нельзя перейти извне его. Поскольку функция р не определена для остальных значе- ний $, грамматика свойств вылавливает использование меток, не найденных внутри данного блока, а также и использование объявленных переменных в качестве меток внутри данного блока. Метка, использованная как переменная, будет выловлена в дру- гом месте. (2) <список операторов> <список операторов> <оператор> р. (2, s) О 3 о 3 4 о 4 4 2 0 О 3 3 о 4 4 0 2 4 2 О 0 3 3 3 4 4 4 2 2 2 2 Строки 2—4 говорят, что идентификатор, использованный как переменная в <списке операторов> или в <операторс> в пра- вой части правила вывода, используется как переменная, коль скоро это касается <списка операторов> слева. Строки 5—7 говорят то же самое о метках. Строки 8—II говорят, что метка, определенная либо в <списке операторов>, либо в <операторе> в правой части, определена для <списка операторов> слева, независимо от того, использовалась метка или нет. В этом месте вылавливается использование идентификатора в качестве переменной и в качестве метки внутри одного блока 300
10.2. ГРАММАТИКИ СВОЙСТВ (3) (список операторов>—> (оператору S 11 (3, S) 0 2 3 4 0 2 3 4 Свойства передаются естественным образом. Свойство 1 для оператора невозможно. (4) (оператору—-(блоку s и. {4, s) 0 0 3 3 Все рассуждения, относящиеся к правилу (3), применимы также и к правилу (4). (5) <оператор>—-label (список переменныху s р (5, s) 0 0 о 0 3 3 2 0 2 Использование идентификатора в качестве метки в label или переменной в (списке переменных> передается в (оператору в левой части. (6) <оператор>—> (список переменныху S (1. (6, S) 0 О 3 3 Здесь использование переменной в (списке переменныху пе- редается в (оператору. (7) <оператор> —>goto S Ц (7, S) 0 0 4 4 301
ГЛ. 10. ОРГАНИЗАЦИЯ ИНФОРМАЦИИ Использование метки в goto передается в <оператор>. (8) <список переменных>—► <список переменных> а I М (8, S) 0 3 0 3 0 о 3 3 о 3 3 3 Любое использование переменной передается в <список пе- ременных/ (9) <список переменных>—<-е М(9, s) Единственным значением, для которого функция р опреде- лена, является s = e. Свойством должно быть число 0 по опре- делению нейтрального свойства. (10) <список объявлений>—►declare <список объявленийу i.i (10, S) 0 0 Объявленные идентификаторы передаются в <список объяв- лений/ (11) <список объявлений>—>1 р(1 1, S) Здесь та же ситуация, что и в правиле (9). Теперь приведем пример построения таблиц снизу вверх на дереве разбора. Таблицу, которая индексу i, присваивает свой- ство о, для 1 а всем остальным индексам — нейтраль- ное свойство, будем обозначать [i/Ox, 1„:пя]- 302
10.2. ГРАММАТИКИ СВОЙСТВ Рассмотрим входную цепочку begin declare [1:1] declare [2:I] begin label [1:2] a [2:3] goto [1:4] end a [1:3] end Таким образом, во внешнем блоке идентификаторы 1 и 2 объявлены посредством символов declare [1:1] и declare [2:1] как переменные. Затем во внутреннем блоке идентификатор 1 по- средством символов label [1:2] и goto [1:4] соответственно объявлен и используется как метка (что законно), а идентифи- катор 2 посредством символа а[2:3] используется как переменная. На рис. 10.9 приведено дерево разбора с таблицами, свя- занными с каждой вершиной. □ Понятие грамматики свойств можно обобщить. Например, (1) отображение р можно сделать недетерминированным, т. е. допустить, что р (р, w) — подмножество множества V, (2) можно не предполагать наличия нейтрального свойства, (3) можно наложить ограничения на класс таблиц, связанных с символами; например, можно не допускать наличия полностью нейтральных таблиц. Некоторые теоремы о грамматиках свойств в этой более общей формулировке изложены в упражнениях. 10.2.3. Реализация грамматик свойств Рассмотрим реализацию грамматики свойств для случая, когда входная КС-грамматика допускает детерминированный восходя- щий разбор с помощью алгоритма типа „перенос — свертка". Нис- ходящий разбор или применение других алгоритмов разбора, из- ложенных в этой книге, приводит к тем же проблемам согла- сования при конструировании таблиц, что и при построении цепочек переводов в СУ-переводе. Поскольку их решение в основном то же, что и в гл. 9, мы рассмотрим только восхо- дящий разбор. В нашей модели компилятора вход для лексического ана- лизатора не имеет таблиц, связанных с его терминалами. Бу- дем предполагать, что лексический анализатор сигнализирует о том, является ли выбранная лексема идентификатором или 303
<4лОК> becjin < список объявлений > [1:1, 2:1] < список операторо8> [1:3, 2:3] declare < список ооъяВлений> [1:1] [2:1] declare end < список операторо8> [2:3] < оператор > £1=3] < список объявлении^ <оператор> <список переменных > [1-4] [Г-2,2:3] Рис. 10.9. Дерево разбора с таблицами.
10 2. ГРАММАТИКИ СВОЙСТВ нет. Таким образом, каждая лексема, будучи входом при раз- боре, имеет одну из двух таблиц—либо полностью нейтральную, либо таблицу, в которой один индекс обладает не нейтральным свойством. Поэтому мы будем считать, что еще необработанный вход вообще не имеет таблиц, и они строятся, когда символ передается в магазин. Будем также предполагать, что таблицы не влияют на раз- бор, пе считая случая ошибки, когда разбор надо прервать. Таким образом, механизмом разбора будет нормальный механизм типа „перенос—свертка", причем к каждому символу магазина будет добавляться указатель на таблицу свойств этого элемента. Пусть в верхушке магазина находится [В, TJ[С, Т2] и вы- полняется свертка в соответствии с правилом А —► ВС. Наша задача заключается в том, чтобы быстро и просто по 7\ и Тг построить таблицу, связанную с А. Поскольку большинство индексов в таблице отображается в нейтральное свойство, же- лательно помещать в нее только те индексы, которые обладают не нейтральным свойством. Схема обработки таблиц будет реализована так, чтобы все операции по обработке таблиц и запросы о свойстве данного индекса можно было выполнить за время, фактически пропор- циональное числу операций и запросов. Естественно предполо- жить, что число запросов в таблицы пропорционально длине входа. Предположение корректно, если разбор детерминирован- ный, поскольку число выполняемых сверток (а следовательно, и число слияний таблиц) в этом случае пропорционально длине входа. В то же время разумный алгоритм перевода не должен осуществлять запросы свойств более чем фиксированное число раз на одну свертку. Далее мы будем считать, что в нашей грамматике свойств входная КС-грамматика имеет нормальную форму Хомского. Обобщения алгоритма вынесены в упражнения. Будем предпо- лагать, что в любой таблице свойств каждый индекс (идентифи- катор), обладающий не нейтральным свойством, занимает пози- цию в таблице расстановки, и что можно создавать структуры данных из элементарных единиц, называемых ячейками. Каждая ячейка имеет форму ДАННОЕ! данное™ УКАЗАТЕЛЬ] УКАЗАТЕЛЬ/! т. е. состоит из одного или может содержать некоторые ячейку. Ячейки понадобятся более полей, каждое из которых данные или указатель на другую при построении связных списков. 305
ГЛ. 10. ОРГАНИЗАЦИЯ ИНФОРМАЦИИ Предположим, что V состоит из k свойств. Таблица свойств, связанная с символом грамматики, расположенным в магазине, представляется структурой данных, состоящей не более чем из k списков свойств и из списка пересечений. Каждый список свойств начинается с заголовка списка свойств. Список пересечений на- чинается с заголовка списка пересечений. Эти заголовки связаны так, как это показано на рис. 10.10. Элемент магазина Заголовок списка пересечений Заголовки списков свойств Рис. 10.10. Элемент магазина со структурой, представляющей таблицу свойств. Заголовок списка свойств имеет три поля: СВОЙСТВО РАЗМЕР СЛЕДУЮЩИЙ ЗАГОЛОВОК Заголовок списка пересечений содержит только указатель на первую ячейку списка пересечений. Каждая ячейка списков свойств и списков пересечений называется индексной ячейкой. Индексная ячейка состоит из четырех полей с указателями: НА СВОЙСТВО НА СПИСОК ПЕРЕСЕЧЕНИЙ К ТАБЛИЦЕ РАССТАНОВКИ ОТ ТАБЛИЦЫ РАССТАНОВКИ Предположим, что Т — таблица свойств, связанная с символом в магазине. Тогда Т будет представляться р списками свойств, где р — число различных свойств в Г, и одним списком пересе- чений. Для каждого индекса в Т, обладающего не нейтральным свойством /, есть одна индексная ячейка в списке свойств, на- чинающемся с заголовка списка свойств для свойства /. 306
10.2. ГРАММАТИКИ СВОЙСТВ Индексные ячейки, обладающие одинаковым свойством, объ- единены в дерево 1), корнем которого служит заголовок для этого свойства. Первый указатель в индексной ячейке—это указатель па ее прямого предка в этом дереве. Если индексная ячейка принадлежит списку пересечений, то вторым указателем в ней является указатель на следующую ячейку списка пересечений. Если ячейка не принадлежит списку пересечений, то этот указатель пуст. Два остальных указателя связывают индексные ячейки, пред- ставляющие один и тот же индекс, но в различных таблицах свойств. Предположим, что 6Т,р/Т$Тга представляет такую це- почку таблиц в магазине, что каждая из таблиц Тг, Т2 и 1\ содержит индекс i с не нейтральным свойством и все таблицы в а, р, у и 6 дают индексу i нейтральное свойство. Если ближе всех к верхушке магазина расположена таб- лица Т1: то индексная ячейка С1Г представляющая i в 7\, будет содержать в третьем поле указатель на позицию таблицы имен для г. Четвертое поле в С1 содержит указатель на ячейку С2 в Т2, представляющую i. В С2 третье поле содержит указатель на Cj, а четвертое поле содержит указатель на ячейку в Тг, представляющую i. Таким образом, на индексные ячейки налагается дополни- тельная структура: все индексные ячейки, представляющие один и тот же индекс во всех таблицах в магазине, помещаются в двунаправленный список, начинающийся с элемента таблицы расстановки для этого индекса. Ячейка размещается в списке пересечений таблиц тогда и только тогда, когда какая-нибудь таблица, расположенная над пей в магазине, имеет индексную ячейку, представляющую тот Же индекс. В приведенном выше примере ячейка С2 будет в списке пересечений для Т2. Пример 10.10. Предположим, что в магазине находятся сим- волы грамматики В и С, причем С — в верхушке магазина. Пусть с этими элементами связаны соответственно таблицы 7"; = [1 : vlt 2 : v2, 5 : v2, 6 : vif 8 : п2] T2 = [2 :vlt 3: vlr 4: с,, 5 : р1, 7:v2, 8 :v,] Возможная реализация этих таблиц показана на рис. 10.11. Кружочками указаны индексные ячейки. Число внутри кружоч- ка—это индекс, представляемый ячейкой. Связи списка пересе- чений указаны пунктиром. Отметим, что список пересечений самой верхней таблицы пуст по определению, а список пересе- чений таблицы 7\ состоит из индексных ячеек для индексов 2, х) Структура этого дерева будет ясна из алгоритма 10.3. — Прим, перец. 307
ГЛ. 10. ОРГАНИЗАЦИЯ ИНФОРМАЦИИ 5 и 8. Ссылки на таблицу расстановки и на ячейки, представ- ляющие один и тот же индекс в других таблицах, указаны штриховыми линиями. Во избежание путаницы они показаны только для индексов 2 и 3. □ магазин Рис. 10.11. Реализация таблиц свойств. Предположим, что в процессе разбора надо в магазине свер- нуть ВС в А. Надо вычислить таблицу Т для А по таблицам Т\ и Т3 для В н С соответственно. Поскольку С — верхний сим- вол магазина, список пересечений таблицы Г, содержит в точ- ности те индексы, которые обладают не нейтральным свойством в обеих таблицах 7\ и Т2 (отсюда и название „список пересе- чений"). Эти индексы мы рассмотрим позднее. Индексы, не принадлежащие списку пересечений Tlt обладают нейтральным свойством по крайней мере в одной из таблиц 7\ или Тг. Таким образом, их свойство в Т есть функция только 308
10.2, ГРАММАТИКИ СВОЙСТВ их одного не нейтрального свойства. Если отвлечься от индек- сов из списка пересечений, то структуру данных, представля- ющую таблицу Т, можно построить, комбинируя различные деревья из Т1 и Т2. После того как это сделано, каждый эле- мент списка пересечений для Тг рассматривается отдельно, и из него делается ссылка на соответствующую ячейку таблицы Т. Прежде чем формализовать эти идеи, отметим, что хотелось бы, чтобы на практике свойства можно было разбить на непе- ресекающиеся подмножества так, чтобы V можно было пред- ставить в виде Vt х V2 х . . . X К„ для некоторого относительно большого пг. Различные компоненты Vlt Ка, ... были бы, вообще говоря, небольшими. Например, множество V, могло бы содер- жать два элемента, обозначающие „вещественное" и „целое"; V2 — два элемента, обозначающие „одинарная точность" и .двойная точность"; 1'3— „динамически размещаемые" и „статически раз- мещаемые" и т. д. В каждом из множеств V,, . . . один элемент можно рассматривать как условие отсутствия остальных, а про- изведение таких элементов отсутствия — как нейтральное свой- ство. Наконец, можно ожидать, что различные компоненты свойств идентификатора могут определяться независимо от ос- тальных. Если происходит именно так, то можно создавать один за- головок свойств для каждого элемента из V,, кроме элемента отсутствия, один для каждого элемента из Ка, кроме элемента отсутствия, и т. д. Каждая индексная ячейка связана с несколь- кими заголовками свойств, но не более чем с одним из каждого множества К(. Если ссылки на заголовки для Vt отличаются от ссылок на заголовки для Vt при i , то идеи этого раздела можно с тем же успехом применить и к этой ситуации; общее число заголовков свойств будет близко к сумме мощностей мно- жеств Vt, а не к их произведению. Дадим формальный алгоритм реализации грамматики свойств. Для простоты изложения ограничимся грамматиками свойств с входной КС-грамматикой в нормальной форме Хомского. Алгоритм 10.3. Обработка таблиц при реализа- ции грамматик свойств. Вход. Грамматика свойств G = (N, 2, Р, S, V, v„, F, у) с вход- ной КС-грамматикой в нормальной форме Хомского. Будем пред- полагать, что не нейтральное свойство никогда не отображается в нейтральное, т. е. если р(р, v1v2) = v0, то о1 = о2 = о1). (Это ус- ловие приемлемо, поскольку если у (i, но или не равно v„, то в правой части можно заменить v„ на новое не нейтральное свойство v'o и ввести правила, которые делали бы Vv „похожим" на о„.) Входом для данного алгоритма служит 309
ГЛ. 10. ОРГАНИЗАЦИЯ ИНФОРМАЦИИ также алгоритм разбора типа „перенос—свертка" для входной КС-грамматики. Выход. Модифицированный алгоритм разбора типа „перенос — свертка" для входной КС-грамматики, вычисляющий в процессе разбора таблицы, связанные с теми вершинами дерева разбора, которые соответствуют символам магазина. Метод. Предположим, что каждая таблица имеет формат, как на рис. 10.10, т. е. не более одного списка пересечений и списка заголовков для каждого свойства, а в ее дереве индексов с каж- дым заголовком связано данное свойство. Описание работы ме- ханизма построения таблиц мы разобьем на две части в зави- симости от того, свертывается один терминал или два нетерми- нала. (Напомним, что входная грамматика задана в нормальной форме Хомского.) Часть 1: Предположим, что терминальный символ а перено- сится в магазин и свертывается в нетерминал А. Пусть таблицей, требуемой для А, будет [i : о]. Для того чтобы выполнить эту операцию, поместим А непосредственно в магазин и следующим образом выработаем таблицу [г : о] для А. (1) При элементе А в верхушке магазина поместим указа- тель на единственный заголовок свойства, обладающий свойст- вом v и размером 1. Этот заголовок свойства указывает на за- головок списка пересечений с пустым списком пересечений. (2) Создадим индексную ячейку С для I. (3) В первом поле ячейки С поместим указатель на заголовок свойства. (4) Второе поле ячейки С будет пустым. (5) В третье поле ячейки С поместим указатель на элемент таблицы расстановки для i и в этот элемент таблицы расста- новки поместим указатель на С. (6) Если другая ячейка С уже была связана с элементом таблицы расстановки для I, поместим С' в список пересечений таблицы, в которую она входит. (Для этого в заголовок списка пересечений поместим указатель на С, а во второе поле ячейки С' поместим указатель па прежнюю первую ячейку списка пере- сечений, если она была.) (7) В четвертое поле ячейки С поместим указатель на С'. (8) В третье поле ячейки С поместим указатель на С. Часть 2: Предположим теперь, что два нетерминала свер- тываются в один, скажем, по правилу А—*BD. Пусть таблицами, связанными с В и D, будут Тг и Т2 соответственнв. Тогда для вычисления таблицы Т для А сделаем следующее. (1) Рассмотрим каждую индексную ячейку в списке пересе- чений для 7\. (Напомним, что у Тг нет списка пересечений.) Каждая такая ячейка дает элемент для некоторого индекса 1, который есть как в 7\, так и в Т2. Свойства данного индекса 310
10,2. ГРАММАТИКИ СВОЙСТВ в этих таблицах можно найти с помощью алгоритма 10.41). Пусть этими свойствами будут vx и v2. Вычисляем t> = p(p, vxv2), где р— правило вывода А— BD. Строим список из всех индексных ячеек списка пересечений вместе с их новыми свойствами и старым содержимым ячеек таблиц Тх и Т2. (2) Рассмотрим заголовки свойств таблицы Тх. Изменим свой- ство заголовка со свойством v на свойство р(р, vv0). Таким об- разом, мы предполагаем, что все индексы со свойством v в 7\ обладают нейтральным свойством в Т2. (3) Рассмотрим заголовки свойств в Т2. Изменим свойство заголовка со свойством v на р(р, п0о). Таким образом, мы пред- полагаем, что все индексы со свойством v в Т2 обладают нейт- ральным свойством в Тх. (4) Теперь некоторые из заголовков свойств, ранее принад- лежащие Тх и Т2, могут обладать одинаковым свойством. Их слияние осуществляется в результате выполнения следующих шагов, объединяющих два дерева в одно: (а) заменяем заголовок свойства с меньшим размером (произвольно нарушая связи) на фиктивную индексную ячейку, не соответствующую никакому индексу, (б) помещаем в эту новую индексную ячейку указатель на заголовок свойства с большим размером, (в) полагаем размер оставшегося заголовка равным сумме размеров этих двух заголовков плюс 1, так что оно от- ражает число индексных ячеек в дереве, включая фиктив- ные ячейки. (5) Рассмотрим теперь список индексов, созданный на шаге (1). Для каждого такого индекса (а) создаем новую индексную ячейку С, (б) в первое поле ячейки С помещаем указатель на за- головок свойства с исправленным свойством, а скоррек- тированное значение размера помещаем в этот заголовок, (в) в третье поле ячейки С помещаем указатель на пози- цию таблицы расстановки для этого индекса, а из этой позиции таблицы расстановки — на С, (г) в четвертое поле ячейки С помещаем указатель на первую индексную ячейку, лежащую под ней (в магазине) и имеющую тот же индекс, (д) рассмотрим теперь две исходные ячейки С\ и С2, пред- ставляющие этот индекс в 7\ и Т2. Делаем Сх и С2 „фиктив- ными", сохраняя указатели в их первых полях (ссылки J) Очевидно, что свойство данного индекса можно найти, идя из ячеек, соответствующих ему в двух таблицах, по направлению к корням деревьев, на которых эти ячейки находятся. Однако, чтобы обработка таблиц в целом была линейной во времени, необходимо, чтобы движение к корню осуществля- лось специальным образом. Этот метод мы опишем ниже в алгоритме 10.4. 311
ГЛ. ю. ОРГАНИЗАЦИЯ ИНФОРМАЦИИ на их предков в деревьях), но удаляя укиазатели в треть- их и четвертых полях (их ссылки на таблицу расстановки и на ячейки в других таблицах, имеющие тот же индекс). Таким образом, вновь созданная индексная ячейка С играет роль двух ячеек С, и С„, сделанных тепефь фиктивными. (6) Оставшиеся в результате фиктивные ячейкги можно вернуть в свободную память. □ Пример 10.11. Исследуем две 10.10 (рис. 10.11). Пусть р(р, st) таблицы свойсств из примера задается табл.. 10.2. Таблица 10.22 |х (р, st) с» с» v2 Согласно части 2 алгоритма 10.3, сначала надо рассмотреть список пересечений для Т1, состоящий из индексных ячеек 2, 5 и 8 (рис. 10.11). Из табл. 10.2 видно, что в новой таблице свойств Т эти индексы будут обладать свойствами v„ vs и v2 соответственно. Рис. 10.12. Слившиеся деревья. Затем рассмотрим заголовки свойств для Тг ш Т2. Свойства в заголовках остаются теми же, поскольку р<(р, v„V/) = о,, и р(р, = Теперь дерево для и, в Tf „вливаем" в дерево для vt в Т2, так как последнее больше. Полученное дерево изобра- жено на рис. 10.12, а. Затем дерево для v, в Г'г „вливаем" в 312
10.2. ГРАММАТИКИ СВОЙСТВ дерево для о2 в Ту (рис. 10.12,6). Замеетим, что на рис. Ю-12, а вершина 5 стала прямым потомком заголовка, в то врем:Я как на рис. 10.11 она была прямым потомком вершины с номером 3. Эго происходит при анализе списка перресечений для Тг в алго- ритме 10.4. Вершина 2 на рис. 10.12,6.6 переместилась ПО той же причине. В качестве последнего шага исследуУем индексы в списке пе- ресечений для Ту. Для этих индексов < создаются новые индекс- ные ячейки; новые ячейки указывают пррямо на соответству ющии Рис. 10.13. Новая табли11ца заголовок. Все остальные ячейки для оттого индекса в таблице Т делаются фиктивными. Затем удаляютс:;я фиктивные ячейки без потомков. Полученная таблица Т показана на рис. 10.13. Таб- лица имен не приведена. Отметим, что с список пересечений Д1ЛЯ Т пуст. Предположим теперь, что входной с!имвол переносится ма- газин и свертывается в £>[2:^]. Тогда индексная ячейка для 2, которая па рис. 10.13 указывает на о»8, включается в список пересечений своей таблицы. Изменениия отражены на рис. 10.14. □ Дадим теперь алгоритм, с помощью которого из таблигцы выбирается свойство индекса 1. Этот аллгоритм используемся в алгоритме 10.3 для нахождения свойства индексов в списке .пере- сечений. 313
ГЛ. 10. ОРГАНИЗАЦИЯ ИНФОРМАЦИИ Рнс 10.14. Таблицы после переноса. Алгоритм 10.4. Нахождение свойства индекса. Вход. Индексная ячейка некоторой таблицы Т. Предполагаем, что таблицы имеют ту же структуру, что и в алгоритме 10.3. Выход. Свойство этого индекса в таблице Т. Метод. (1) Проходим по указателям из данной индексной ячейки до корня дерева, в которое она входит. Формируем список всех ячеек, встретившихся на этом пути. (2) Помещаем в каждую ячейку на этом пути, кроме корня, ссылку прямо на этот корень. (Конечно, ячейка на этом пути, непосредственно предшествующая корню, уже ссылается на него). □ Отметим, что наиболее важен шаг 2 алгоритма 10.4, являю- щийся по существу „побочным эффектом" алгоритма. Именно шаг (2) гарантирует, что общее время, потраченное на обра- ботку таблицы, в целом будет пропорционально длине входа. 10.2.4. Анализ алгоритма обработки таблиц Оставшаяся часть этой главы посвящена анализу временной сложности алгоритмов 10.3 и 10.4. Определим сначала две функ- ции F и G, которые нам понадобятся в этой главе. 314
10.2. ГРАММАТИКИ СВОЙСТВ Определение. F (п) определим рекуррентно: F(n) = 2F<'"~I> Некоторые значения F (м) приведены в табл. 10.3. Таблица 10.3 п F (п) 1 2 3 4 5 1 2 4 16 ч 65536 Определим G (п) как наименьшее из целых чисел I, для кото- рых F (1) > п. Функция G растет так медленно, что реально G(n)=C6 для всех п, представимых одним машинным словом, даже с плавающей точкой. С другой стороны, G (м) можно опре- делить как количество применений log2 к п для того, чтобы получить число, меньшее или равное 0. Оставшаяся часть главы посвящена доказательству того, что алгоритм 10.3 требует 0(nG(n)) шагов вычислительной машины с произвольным доступом при длине входной цепочки, равной п. Покажем сначала, что, если не считать время, затрачиваемое на алгоритм 10.4, временная сложность алгоритма 10.3 состав; ляет 0(м). Лемма 10.3. Если не считать обращений к алгоритму 10.4, то алгоритм 10.3 можно реализовать на вычислительной маши- не с произвольным доступом за время 0(м), где п—длина разби- раемой входной цепочки. Доказательство. Каждое выполнение части 1 требует фиксированного количества времени, а таких выполнений в точ- ности п. Отметим, что шаги (1) и (5) в части 2 требуют времени, про- порционального длине списка пересечений. (Напомним еще раз, что время работы алгоритма 10.4 не учитывается.) Но единст- венный способ поиска по индексной ячейке пути в списке пере- сечений заключается в выполнении части 1. Каждое выполнение части 1 размещает не более одной индексной ячейки в списке пересечений. Таким образом, во все списки пересечений всех таблиц помещается не более п индексов. После выполнения части 2 все индексные ячейки удаляются из списка пересечений, 315
ГЛ. 10. ОРГАНИЗАЦИЯ ИНФОРМАЦИИ так что общее время, затрачиваемое на шаги (1) и (5) части 2, составляет 0(п). Легко видеть, что остальные шаги части 2 требуют постоян- ного количества времени на одно выполнение части 2. Поскольку часть 2 выполняется в точности п--1 раз, можно заключить, что общее время, затрачиваемое алгоритмом 10.3, не считая вызовов алгоритма 10.4, составляет 0(п). □ Поставим теперь некоторую абстрактную задачу и дадим ее решение, отражающее идеи алгоритмов 10.3 и 10.4, в терми- нах, более абстрактных и легче поддающихся анализу. Определение. Для оставшейся части главы определим задачу слияния множеств как (1) набор объектов ait (2) набор имен множеств, включающий А1: А2, . . ., Ап, (3) последовательность команд /4, 12...I т, причем каждая команда It имеет форму (а) слить (Я, В, С) или (б) найти (а), где А, В и С — имена множеств, а а—объект. (Имена множеств можно мыслить как пары, состоящие из таб- лицы и свойства, а объекты — как индексные ячейки.) Команда слить(Я, В, С) формирует объединение множеств А и В и получающемуся множеству дает имя С. При этом не генерируется никакого выхода. Команда найти (а) печатает имя множества, элементом кото- рого является а. Вначале предполагается, что каждый объект а{ принадлежит множеству Я,-, т. е. Я; = {а,}. Ответом последовательности команд It, /2, . . ., 1т называется последовательность выходов, генери- руемая при последовательном выполнении команд. Пример 10.12. Пусть заданы объекты а(, а2, ...,ав и после- довательность команд слить (Я„ Аг, Я2) слить (Я3, Я4, ЯД слить (Я5, As, Ае) слить (Я2, Я4, Я4) слить (Я„ Ае, Яв) найти (а3) После выполнения первой команды множеством Я2 будет {а,, а2). После второй команды Я4 = (а3, а4}. После третьей множеством Яв станет {а,, а8}. Затем после команды слить (Я2, Я4, Я4) множест- вом Я4 станет {а4, аг, а3, а4}. После последней команды слияния 316
10.2. ГРАММАТИКИ СВОЙСТВ A» = {at, а„, Затем команда найти (а3) печатает имя Ае, являющееся ответом на эту последовательность команд. □ Теперь дадим алгоритм выполнения любой последователь- ности команд длины 0 (п) за время 0(nG(n)), где п — число объ- ектов. Относительно способа доступа к объектам и множествам будут сделаны некоторые допущения. Сразу пе очевидно, что реализация грамматики свойств алгоритмами 10.3 и 10.4 этим условиям удовлетворяет. Однако достаточно простых рассужде- ний, чтобы увидеть, что в действительности при необходимости определить свойства объектов (индексных ячеек) или слить мно- жества (заголовки свойств) они (объекты и множества) будут доступны. Алгоритм 10.5. Вычисление ответа на последова- тельность команд. Вход. Набор объектов (а,, .... ап} и последовательность команд Ц, ..., /га описанного выше типа. Выход. Ответ на последовательность /1Г ..., 1т. Метод. Множество запоминается в виде дерева, каждая вер- шина которого представляет один элемент множества. Корень дерева имеет метку, дающую (1) имя множества, представляемого деревом, и (2) число вершин этого дерева (размер). Предполагается, что за конечное число шагов можно найти вершину, представляющую объект, или корень дерева, пред- ставляющего множество. Это можно сделать, например, исполь- зуя два таких вектора OBJECT и SET, что OBJECT (а) — ука- затель на вершину, представляющую a, a SET (А) — указатель на корень дерева, представляющего множество А. Сначала строим п вершин, по одной для каждого объекта а;. Вершина для а,- — это корень дерева с одной вершиной; корень помечен А,- и имеет размер 1. (1) Для выполнения команды слить (А, В, С) определяем местоположение корней деревьев для А и В (с помощью SET (А) и SET (В)). Сравниваем размеры деревьев, указываемых с по- мощью А и В. Корень меньшего дерева становится прямым по- томком корня большего дерева (связи нарушаются произвольно). Большему корню дается имя С, а его размером становится сумма размеров А и В1). Указатель на корень С помещается в ячейку SET (С). ') Аналогия между этим шагом и процедурой слияния алгоритма 10.3 очевидна. Различие в способе подсчета заключается только в том, считается ли корень или нет. В данном случае считается, в алгоритме 10.3 нет. 317
ГЛ. 10. ОРГАНИЗАЦИЯ ИНФОРМАЦИИ (2) Для выполнения команды найти (а) определяем с помощью OBJECT (а) вершину, представляющую а. Затем проходим из нее в корень г этого дерева. Печатаем имя, найденное в г. Все вершины на этом пути, кроме г, делаем прямыми потом- ками гх). □ Пример 10,13. Рассмотрим последовательность команд из примера 10.12. После выполнения первых трех команд слияния ^2 ^4 ^6 получаются три дерева, изображенные на рис. 10.15. Корни помечены именем множества и размером. (Размер не показан.) Затем, выполнив команду слить (Л2, А4, Л4), приходим к струк- туре на рис. 10.16. После последней коман- ды слить (Л4, Ав, Ла) Ряс. 10.16. Деревья после очередной ко- Рис. 10.17. Дерево после по- манды слить. следней команды слить. получаем рис. 10.17. Выполняя далее команду найти (а3), печа- таем имя Ав, а вершины as и а4 делаем прямыми потомками корня (а4 уже является прямым потомком). Окончательная структура приведена на рис. 10.18. □ 1) Аналогия с алгоритмом 10.4 должна быть очевидна. 318
10.2. ГРАММАТИКИ свойств Покажем теперь, что алгоритм 10.5 может работать за время 0(nG(n)) при разумном предположении, что выполнение команды слить требует одной единицы времени, а команды вида найти (а) — времени, пропорционального длине пути от вершины, представ- ляющей а, до корня. Все последующие результаты выведены при этом предположении. Начиная отсюда, будем считать, что число объектов п фиксировано и последовательность команд имеет длину 0(м). Определение. Определим ранг вершины в структуре, выра- батываемой алгоритмом 10.5: (1) лист имеет ранг 0, (2) если у вершины N когда-либо появляется прямой потомок ранга i, то N имеет ранг по крайней мере i+1, (3) ранг вершины—это наименьшее целое число, удовлетво- ряющее условию (2). Сразу не ясно, что это определение корректно. Однако если вершина М становится прямым потомком вершины в алго- ритме 10.5, то у М уже никогда больше не будет прямых по- томков. Таким образом, в этот момент можно зафиксировать ранг Л1. Например, на рис. 10.17 ранг вершины ае можно за- фиксировать равным 2, поскольку а, имеет одного прямого по- томка ранга 1, а новых потомков уже больше иметь не будет. Три следующие леммы устанавливают некоторые свойства ранга вершины. Лемма 10.4. Пусть N—корень ранга I, созданный алгорит- мом 10.5. Тогда N имеет по крайней мере 21' потомков. Доказательство. Базис, 1 = 0, очевиден, поскольку вер- шина тривиально является собственным потомком. Для дока- зательства шага индукции предположим, что /V— корень ранга i. Тогда в некоторый момент у вершины N должен появиться пря- мой потомок М ранга i—1. Кроме того, вершина М должна была стать прямым потомком вершины W на шаге (1) алгоритма 10.5, поскольку иначе ранг вершины W был бы не менее i + 1. Отсюда 31?
ГЛ. 10. ОРГАНИЗАЦИЯ ИНФОРМАЦИИ следует, что вершина Л1 была корнем и по предположению ин- дукции имела в тот момент по крайней мере 2'-1 потомков, а на шаге (1) алгоритма 10.5 в тот момент вершина W имела по крайней мере 2'-1 потомков. Таким образом, после слияния W имеет по крайней мере 2‘ потомков. До тех пор пока W остается корнем, она не может потерять потомков. □ Лемма 10.5. Если вершина N в какой-то момент работы алгоритма 10.5 имеет прямого потомка М, то ранг N больше ранга М. Доказательство. Прямая индукция по числу выполняе- мых команд. □ Следующая лемма дает границу числа вершин ранга I. Лемма 10.6. Существует не более п2~‘ вершин ранга i. Доказательство. Структура, создаваемая алгорит- мом 10.5, представляет собой набор деревьев. Поэтому никакая вершина не может быть потомком двух различных вершин ранга i. Поскольку в структуре п вершин, результат вытекает непосредственно из леммы 10.4. □ Следствие. Никакая вершина не имеет ранга, большего log.pi. □ Определение. При фиксированном числе п объектов определим группы рангов. Будем говорить, что целое i принадлежит группе /, тогда и только тогда, когда log?1 (п) > I > log?+n (и) где log?1’(я) = loga п и log?+" («) = log£fe> (log, («)). Таким образом, log?’—это функция, представляющая собой последовательное применение k раз функции |oga. Например, log?' (65 536) = log.® (16) = loga (4) = 2 Говорят, что ранг г принадлежит группе рангов j, если г принадлежит группе /. Поскольку log?’ (F (1г)) = 1 и никакая вершина не имеет ранга, большего loga п, заключаем, что никакая вершина не принадлежит группе рангов, более высокой, чем G (я). Группы рангов при п = 65 536 приведены в табл. 10.4. Таблица Ю.4 Ранг вершины Группа рангов 0 5 1 4 2 3 3, 4 2 5, 6,..., 16 1 320
10.2. ГРАММАТИКИ СВОЙСТВ Теперь мы готовы доказать, что временная сложность алго- ритма 10.5 равна 0(/гС(н)). Теорема 10.3. Любая последовательность о, состоящая из 0 (п) команд, выполняется за время 0(nG(n)). Доказательство. Ясно, что общее время выполнения команд слить в о равно 0 (м). Длины путей, проходимых коман- дами найти в о, подсчитаем в два этапа. Предположим, что при выполнении команды найти мы поднимаемся вверх от вершины М к вершине IV. Если М. и N принадлежат разным группам ран- гов, то увеличим цену команды найти на одну единицу времени. Если /V — корень, увеличим цену еще на одну единицу. Поскольку вдоль любого пути не более G (п) различных групп рангов, никакой из команд найти не будет назначена цена, большая, чем G (п) единиц. Если, с другой стороны, М и N принадлежат одной группе рангов и W не корень, то вершине М набавим цену на 1 еди- ницу времени. Отметим, что в этом случае вершина М должна быть перемещена. По лемме 10.5 ее новый прямой предок имеет более высокий ранг, чем предыдущий прямой предок. Таким образом, если вершина М принадлежит группе рангов /, то ей можно набавлять цену не более чем log?' (п) раз, прежде чем ее прямой предок попадет в более низкую группу рангов. На- чиная с этого момента, цена для М уже больше не будет ме- няться; цена перемещения М будет порождаться выполненной командой найти, как это описано выше. Ясно, что цена для всех команд найти составляет О(/гС(/г)). Чтобы найти верхнюю границу общей цены для всех объектов, просуммируем по всем группам рангов максимальную цену для каждой вершины в группе, умноженную на максимальное число вершин в группе. Пусть gj— максимальное число вершин в группе рангов /, а с,—цена для всех вершин в группе /. Тогда по лемме 10.6 юй.у> (п) (10.2.1) k =log </+1) (п) Слагаемые в формуле (10.2.1) образуют геометрическую про- грессию со знаменателем */2, так что их сумма не превосходит удвоенного первого члена. Таким образом, g}-^2n2~ioe^+l‘(n) — 2n/log2'’ (п). Так как цена с, ограничена сверху величиной g. loga” (н), то Cf^2n. Поскольку j может меняться только от 1 до G (п), видим, что вершинам назначена цена в 0 (nG (п)) единиц времени. Следовательно, общая стоимость работы алгоритма 10.5 равна 0(пС(/г)). □ 11 А. Ахо, Дж. Ульман, т. 2 321
ГЛ. 10. ОРГАНИЗАЦИЯ ИНФОРМАЦИИ Применим теперь абстрактные результаты к грамматикам свойств. Теорема 10.4. Предположим, что механизм разбора и обработки таблиц, разработанный в алгоритмах 10.3 и 10.4, применяется ко входной цепочке длины п. Предположим также, что число за- просов относительно свойств индекса в таблице составляет ве- личину 0 (п) и эти запросы относятся только к верхней таблице магазина, для которой индекс обладает не нейтральным свойст- вом1). Тогда общее время, затраченное на обработку таблицы на машине с произвольным доступом, равно 0 (nG («)). Доказательство. Заметим прежде всего, что предполо- жения о нашей модели выполняются, а именно, что время, тре- буемое в алгоритме 10.3 для достижения любой вершины, которую нужно обработать, фиксировано и не зависит от п. Заголовков свойств (корней деревьев) можно достичь за фиксированное время, поскольку их конечное число на одну таблицу и они связаны. Индексные ячейки (вершины для объектов) непосредственно достижимы либо из таблицы расстановки, когда нам надо узнать нх свойства (вот почему мы предполагали, что запросы осущест- вляются только для индексов верхней таблицы), либо в процессе спуска по списку пересечений. Теперь достаточно показать, что каждый индекс и ячейку заголовка, которые порождаются, можно смоделировать как объектные вершины, что их всего 0 (п) и что все манипуляции можно выразить в точности как некоторую последовательность команд слить и найти. Приведем полный список всех возможных порождаемых ячеек. (1) 2п „объектов" соответствуют п ячейкам заголовков и п индексным ячейкам, создаваемым в процессе операции переноса (часть 1 алгоритма 10.3). С помощью операции слить можно сде- лать так, чтобы индексная ячейка указывала на ячейку заго- ловка. (2) Новым индексным ячейкам, порожденным на шаге (5) части 2 алгоритма 10.3, соответствует самое большее п объек- тов. С помощью подходящей операции слить можно сделать так, чтобы эти ячейки указывали на правильный корень. Таким образом, существует не более Зп объектов (п в алго- ритме 10.5 означает Зп здесь). Кроме того, число команд, необ- ходимых для обработки множеств и объектов при „моделирова- нии" алгоритмов 10.3 и 10.4 алгоритмом 10.5, равно 0(п). Уже 0 Если речь идет о типичном использовании этих свойств (например, когда при свертке а в F в грамматике Go желательно знать свойства конкрет- ного идентификатора а), то это предположение кажется вполне правдоподобным. 322
УПРАЖНЕНИЯ было отмечено, что для инициализации таблиц после переноса [(1) выше] и для сопоставления новых индексных ячеек с заго- ловками [(2) выше] достаточно не более 'Зп команд слить. Кроме того, на шаге (4) части 2 алгоритма 10.3, когда два множества индексов, обладающих одним и тем же свойством, сливаются, достаточно 0 (п) команд слить. Это следует из того, что число различных свойств фиксировано и что можно сделать только п— 1 сверток. Из леммы 10.3 вытекает, что для проверки свойств индексов в списке пересечений [шаг (1) части 2 алгоритма 10.3] доста- точно 0 (п) команд найти. Наконец, по условию теоремы для определения свойств индексов (подразумевается использование в процессе перевода) требуется 0(п) дополнительных команд найти. Если разместить все эти команды в порядке, определяе- мом анализатором и алгоритмом 10.3, получим последователь- ность из 0(п) команд. Настоящая теорема следует, таким обра- зом, из леммы 10.3 и теоремы 10.3. □ УПРАЖНЕНИЯ 10.2.1. Пусть G — КС-грамматика с правилами Е->-Е + Т\Е<&Т\Т Т--(Е)\а где а — идентификатор, 4- представляет сложение с фиксиро- ванной точкой, ф—сложение с плавающей точкой. Образуйте из G грамматику свойств, в которой (1) каждый символ а имеет таблицу с одним не нейтральным элементом, (2) если в вершине п дерева разбора применяется правило Е—►Е'4-7’, то все а, вершины которых находятся ниже п, об- ладают свойством „используются в сложении с фиксированной точкой", (3) если, как и в (2), применяется правило Е—>Е®Т, то все а, находящиеся ниже п, обладают свойством „используются в сложении с плавающей точкой", (4) осуществляется разбор в соответствии с грамматикой G, при этом ведется контроль за тем, чтобы идентификатор, ис- пользованный в сложении с плавающей точкой, не использовался затем (выше в дереве разбора) в сложении с фиксированной точкой. 10.2.2. С помощью грамматики свойств из примера 10.9 по- стройте дерево разбора, если оно существует, для каждой из следующих входных цепочек: 11 323
ГЛ. 10. ОРГАНИЗАЦИЯ ИНФОРМАЦИИ (a) begin declare [1:1] declare [1:1] begin a[l:3] end label begin declare [3:1] a[3:3] end goto [2:4] end (6) begin declare [1:11 a [1 :3] begin declare [2:1] goto [1:4] end end Определение. Недетерминированная, грамматика свойств определяется так же, как грамматика свойств, за исключением того, что (1) значениями функции р являются подмножества множе- ства V, и (2) не требуется наличия нейтрального свойства. В соответствии с соглашениями этого раздела мы пишем аЛТр=> аЛ',7'1. . . Х„Т„‘д, если А —» Xj. • . Л'„ — некоторое правило вывода, скажем р, и для каждого i таблица Т (г) принадлежит множеству р (р, Отношение =>* и порождаемый язык определяются в точности так же, как и в детерминиро- ванном случае. *10.2.3, Докажите, что для каждой недетерминированной грамматики свойств G найдется грамматика свойств G' (воз- можно, без нейтрального свойства), порождающая тот же язык, в которой р является функцией. 10.2.4. Покажите, что если грамматика G из упр. 10.2.3 обла- дает нейтральным свойством (т. е. все, кроме конечного числа, це- лые числа обладают этим свойством в каждой таблице каждого вывода), то G'— грамматика свойств с нейтральным свойством. 10.2.5. Обобщите алгоритм 10.3 для грамматик нс в нормаль- ной форме Хомского. Обобщенный алгоритм должен иметь ту же временную сложность, что и исходный. 324
УПРАЖНЕНИЯ *10.2.6. Изменим определение грамматики свойств, потребо- вав, чтобы ни у какого терминального символа не было полно- стью нейтральной таблицы. Если G — такая грамматика свойств, то пусть L' (G) = {а4.. ,ап | а1Т1.. .а,.Т„ 6 L (G) для некоторых (не полностью нейтральных) таблиц Т1, .., Тп\. Покажите, что L' (G) может не быть КС-языком. Указание'. Покажите, что таким способом порождается язык {a'bV1 i -С /' -С/г). **10.2.7. Покажите, что для „грамматики свойств" G, модифи- цированной в упр. 10.2.6, неразрешима проблема пустоты мно- жества L' (G), даже если входная КС-грамматика для G право- линейная. 10.2.8. Пусть G — входная КС-грамматика из примера 10.9. Предположим, что терминал declare связывает с индексом одно из двух свойств: либо „объявлен как вещественное", либо „объяв- лен как целое". Определите на G такую грамматику свойств, что если реализуется алгоритм 10.3, то самая верхняя таблица в магазине, имеющая конкретный индекс i с не нейтральным свойством (т. е. таблица с ячейкой для i, на которую указывает элемент таблицы расстановки для i), будет Иметь в качестве свойства для i текущее объявление идентификатора i. Таким образом, решить, вещественный ли или целый идентификатор, можно сразу же, как только он обнаружен во входном потоке. 10.2.9. Найдите выход алгоритма 10.5 и окончательное де- рево при данном множестве объектов {а4....а12} и следующей последовательности команд. Предположите, что в случае ра- венства размеров корень для А,- становится потомком корня для Aj при i < /. слить (А4, Д2, Ах) слить (As, At, Ах) слить (Д4, А6, AJ слить (А„ Аа, Д4) слить (А,, Ав, А7) слить (As, Л7, А7) слить (А10, Ах1, Ахо) слить (А12, А1о, Ахи) найти (а4) слить(Ах, Д4, А,) слить (А,, А1о, А2) найти (а,) слить (А,, Д2, Ах) найти (а3) найти (а4) 325
ГЛ. 10. ОРГАНИЗАЦИЯ ИНФОРМАЦИИ **10.2.10. Предположим, что алгоритм 10.5 модифицирован так, что при выполнении слияний каждый корень может стать потомком другого. Покажите, что временная сложность такого алгоритма не лучше O(rilogrt). Открытые проблемы 10.2.11. Действительно ли алгоритм 10.5, как это утверж- дается в нашей книге, имеет сложность 0(nG(n)), или его слож- ность равна 0 (/г), или, возможно, лежит где-то между этими величинами? 10.2.12. Составляет ли временная сложность модифицирован- ного алгоритма из упр. 10.2.10 величину 0 (п log л)? Проблема для исследования 10.2.13. Исследуйте или охарактеризуйте разновидности свойств идентификаторов, которые можно правильно обработать грамматиками свойств. Замечания по литературе Грамматики свойств впервые были определены Стирнзом и Льюисом [ 1969]. В их работе можно иайти ответы к упр. 10.2.6 и 10.2.7. Метод реализации грамматик свойств за «log log п обсуждался Стиризом и Розенкранцем [1969]. Насколько нам известно, впервые алгоритм 10.5 предложили Моррис и Мак-Илрой, но они не опубликовали его. Анализ алгоритма проведен Хоп- крофюм и Ульманом [1972]. Упр. 10.2.10 взято у Фишера [1972].
ОПТИМИЗАЦИЯ КОДА Одной из самых трудных и непонятных проблем, возникаю- щих при построении компиляторов, является генерация „хоро- шего" объектного кода. Два наиболее широко распространенных критерия, по которым определяют качество программы, заклю- чаются в оценке времени се выполнения и размера. К сожалению, для данной конкретной программы, вообще говоря, невозможно установить время выполнения самой быстрой эквивалентной программы или длину самой короткой эквивалентной програм- мы. Как уже указывалось в гл. 1, если программа имеет цик- лы, мы вынуждены довольствоваться только улучшением кода, а не его истинной оптимизацией. Большинство алгоритмов улучшения кода можно рассматри- вать как приложение различных преобразований к некоторому промежуточному представлению исходной программы с целью привести промежуточную программу к форме, из которой можно получить более эффективный объектный код. Эти преобразова- ния по улучшению кода могут применяться в любой точке про- цесса компиляции. Один из широко распространенных методов заключается в применении этих преобразований к программе на промежуточном языке, появляющейся после синтаксического анализа, но перед генерацией кода. Преобразования по улучшению кода можно разделить на машинно-независимые и машинно-зависимые. Примером машин- но-независимой оптимизации может служить удаление из про- граммы бесполезных операторов, т. е. таких, которые никаким образом не влияют на выход программы1). Такие машинно- независимые преобразования были бы полезны во всех компи- ляторах. С помощью машинно-зависимых преобразований можно по- пытаться привести программу к форме, в которой могут ска- ’) Поскольку обычно такие операторы ие должны появляться в программе, весьма вероятно, что в программе ошибка, и потому компилятору следовало бы информировать пользователя о бесполезности оператора, 327
ГЛ. 11. ОПТИМИЗАЦИЯ КОДА заться преимущества, связанные с машинными командами спе- циального вида. Как следствие этого машинно-зависимые преобразования трудно охарактеризовать в общем виде, и по- тому мы их рассматривать не будем. В настоящей главе мы изучим различные машинно-независи- мые преобразования, применимые к промежуточной программе, появляющейся внутри компилятора после синтаксического ана- лиза, но перед генерацией кода. Начнем с того, что покажем, как генерировать оптимальный код для простого, но важного класса линейных программ. Затем расширим этот класс, вклю- чив в программы циклы, и исследуем некоторые методы улуч- шения кода, которые можно применить к этим программам. 11.1. ОПТИМИЗАЦИЯ ЛИНЕЙНОГО УЧАСТКА Рассмотрим сначала схему программы, представляющей со- бой последовательность операторов присваивания, каждый из которых имеет вид А <—f (Вг, ..., Вг), где А и Вг, ..., Вг — скалярные переменные, а f—функция от г переменных для не- которого г. Для этого ограниченного класса программ мы разработаем множество преобразований и покажем, как исполь- зовать их для нахождения программы, оптимальной относительно некоторой оценки. Поскольку действительная оценка программы зависит от природы машинного кода, который в конечном итоге будет выработан, мы рассмотрим, какие части процедуры оп- тимизации машинно-независимы и как зависят оставшиеся от реально выбранной машины. 11.1.1. Модель линейного участка Начнем с определения блока. Блок моделирует часть про- граммы на промежуточном языке, которая содержит только операторы присваивания. Определение. Пусть S — счетное множество имен переменных, а 0 — конечное множество операций. Предположим, что каждая операция 0^0 имеет известное фиксированное количество опе- рандов. Предположим также, что 0 и S не пересекаются. Оператором называется цепочка вида А^вВх...В, где А, ВТ, ..., Вг—переменные из S, а 0—это r-местная опе- рация из 0. Будем говорить, что оператор осуществляет при- сваивание переменной А и ссылается на В ..., Вг. Блок S — это тройка (Р, I, U), где (1) Р — список операторов Sjj Ss; ...; S„ (п>0), 328
II.1. ОПТИМИЗАЦИЯ ЛИНЕЙНОГО УЧАСТКА (2) I—множество входных переменных, (3) U — множество выходных переменных. Будем предполагать, что если оператор ссылается на Л, то либо А— входная переменная, либо осуществлено присваи- вание ей значения некоторым оператором до .3, (т. е. не- которым оператором S,-, I < /). Таким образом, внутри блока все переменные, на которые ссылаются, к этому моменту опре- делены либо внутренним образом как переменные, которым присвоены значения, либо внешним как входные переменные. Аналогично будем предполагать, что каждая выходная перемен- ная либо является входной переменной, либо ей присвоено значение некоторым оператором. Типичным можно считать оператор Л1------}гВС, который есть не что иное, как префиксная запись более привычного опера- тора присваивания Д « — ВЦ-С. Если оператор осуществляет присваивание переменной А, то с этим присваиванием можно связать некоторое „значение". Последнее представляет собой формулу для А в терминах (неизвестных) первоначальных зна- чений входных переменных. Эту формулу можно записать как префиксное выражение, включающее входные переменные и опе- рации. Начиная отсюда, будем предполагать, что входные перемен- ные имеют неизвестные значения и их надо рассматривать как алгебраические неизвестные. Кроме того, значения операций и множества, на которых они определены, не конкретизированы, так что в качестве значения мы можем рассматривать лишь формулу, а не некоторую величину. Определение. Пусть (Р, /, U) — блок, P = S1\ ... ;S„. Опре- делим значение vf(A) переменной А непосредственно после мо- мента времени /, 0 / <лг, как следующее префиксное выра- жение: (1) Если Agf, то и„(А) = А. (2) Если оператором .8’, является А*—QB1.. ,ВГ, то (a) vt(A)^Qvi_1(B1). (б) vt(C) — vt_1(C) для всех С^А, при условии что . щ.ДС) определено. (3) Для всех А £2, если о((А) не определено по (1) или (2), то оно не определено. Отметим, что поскольку у каждой операции известное число операндов, каждое выражение, имеющее значение, либо является одиночным символом из 2, либо допускает единственное пред- ставление в виде 0Е'1...£'Г, где 0 — это r-местная операция, а Ех......Ег -выражения, имеющие значения. (См. упр.3.1.17.) 329
ГЛ. II. ОПТИМИЗАЦИЯ КОДА Значением v(53) блока S = (P, I, V) называется множество {и„(Л)|A g V, п — число операторов в В} Два блока считаются (топологически) эквивалентными (==), если они имеют одно и то же значение. Отметим, что цепочки, обра- зующие префиксные выражения, равны тогда и только тогда, когда они тождественны. Таким образом, пока мы не будем предполагать никаких алгебраических тождеств. В разд. 11.1.6 мы изучим эквивалентность блоков относительно некоторых алгебраических законов. Пример 11.1. Пусть / = {Д, В), U — (F, G} и Р состоит из операторов') Т--А-В S^—A — B Т- Т;Т S- S-S F- T S G^-T-S Сначала t>„ (Д) = А и v0(B) = B. После первого оператора oJ(7') = -4 + B (в префиксной записи (Т) = 4- АВ), р1('4) = Д и v,(B) — B. После второго оператора р2(3) = Д — В, а значения остальных переменных прежние. После третьего оператора v3 (Т) = (А -|- В)х(А А-В). Последние три оператора приводят к следующим значениям (остальные значения переносятся с пре- дыдущего шага): v„ (S) = (A — В)»(А-В) vt (F) = (4 +В) * (А + В) + (А—В) * (Л — В) и, (G) = (4 + В) * (4 + В) — (4 — В)»(А - В) Поскольку ve (F) = (F), значением блока будет {(Д4-В)*(Д4-В)4-(Д-В)*(Д-В), (4 4-В)* (4 4-В) — (Д — В)* (4 — В)}* 2) Напомним, что мы не учитываем никаких алгебраических зако- нов. Если применить обычные законы алгебры, то можно было бы записать F = 2(Д2 4- В2) и G = 44B. □ 4 При изображении списка операторов мы часто пользуемся переходом на новую строку вместо точки с запятой в качестве разделителя между опе- раторами. В примерах для бинарных операций мы будем употреблять инфик- сную запись. 2) В префиксной записи значение блока таково: {--* 4-ЛВ4-ЛВ * — АВ, — АВ, — * А-АВА АВ * — АВ —АВ) 330
11.1. ОПТИМИЗАЦИЯ ЛИНЕЙНОГО УЧАСТКА Во избежание излишней сложности мы не будем на этот раз рассматривать операторы, включающие структурированные пе- ременные (массивы и т. д.). Один из путей обработки массивов заключается в следующем. Если А — массив, то рассматриваем оператор присваивания А (/) = J так, как если бы А была скаляр- ной переменной, которой было присвоено значение некото- рой функции от /, J и предыдущего значения. Другими словами, можно написать А-—MIJ, где 0 — операция, симво- лизирующая присваивание массиву. Аналогично такой оператор, как J = A(I), можно выразить в виде J<—фА/. Сделаем, кроме того, еще несколько предположений, в ре- зультате чего наши построения потеряют некоторую общность. Например, будем пренебрегать операторами проверки, констан- тами, операторами присваивания вида А-—В. Однако снятие этих ограничений приведет к аналогичной теории, и мы делаем эти предположения прежде всего для удобства — чтобы привести пример теории такого типа. Наши основные предположения: (1) Важным фактором, касающимся блока, является набор функций входных переменных (переменных, определенных вне блока), вычисляемых внутри блока. Сколько раз вычисляется конкретная функция, несущественно. Такой подход основан на том, что различные блоки программы передают друг другу значения переменных и что нет необходимости передавать две копии одного и того же значения из одного блока в другой. (2) Имена переменных, участвующих в вычислениях, несу- щественны. Это предположение неудовлетворительно, если блок составляет часть цикла и функция вычисляется повторно. Напри- мер, если вычисляется /«—/ -f- I, то недопустимо заменять это вычисление на .!•—/4-1, а затем повторять блок, ожидая, что результаты будут такими же. Тем не менее мы принимаем это предположение, поскольку оно ведет к некоторой симметрии решения и часто оказывается справедливым. В упражнениях предлагается сделать модификации, необходимые для того, чтобы допустить, что некоторым выходным значениям даны фиксиро- ванные имена. (3) Мы не включаем операторы вида Х->—У. Если такой оператор встречается, то при условии, что предположение (2) выполнено, можно вместо X подставить У, исключив всюду X. И вновь это предположение вносит симметрию в модель, и чи- тателю предлагается модифицировать теорию так, чтобы такие операторы можно было включать. 331
ГЛ. И. ОПТИМИЗАЦИЯ КОДА 11.1.2. Преобразования блоков Заметим, что если даны два блока 331 и ®2, то можно уста- новить, эквивалентны ли они, вычислив их значения 0(53^ и а(33г) и выяснив, выполняется ли равенство v = v (332). Однако можно указать бесконечное число блоков, эквивалентных любому данному. Например, если ® = (Р, /, U) — блок, X — переменная, на которую пет ссылки в S3, А— входная переменная, а 9 — опера- ция, то к Р можно любое число раз присоединять оператор X <—ОД...4, не меняя значения 53. Если выбрать подходящую оценку, то не все эквивалентные блоки будут одинаково эффективны. При данном блоке 33 су- ществуют различные преобразования, применимые для отобра- жения его в эквивалентный и, возможно, более желательный блок 53'. Пусть ST — множество всех преобразований, сохраняю- щих эквивалентность блоков. Мы покажем, что любое преобра- зование из S' можно осуществить с помощью конечной после- довательности четырех простейших преобразований блоков. Затем опишем последовательности преобразований, которые приводят к блоку, оптимальному относительно некоторой ра- зумной оценки. Определение. Пусть® — (Р, I, U) — блок, Р = 3,; S2; ...; S„. Для единообразия обозначений примем, что все элементы входного множества Z приписаны к некоторому нулевому оператору .S„, а все элементы выходного множества — к некоторому («+1)-у оператору S„ + i. Переменная А называется активной после момента времени t, если (1) ей присвоено значение некоторым оператором St, (2) ей не присвоены значения операторами S/+1, Sz+2, (3) на нее ссылается оператор 3/+1, (4) Если число /, о котором идет речь выше, имеет максимально возможное значение, то последовательность операторов S!+1, Sz+2, .... S/+1 называют областью действия оператора S, и обла- стью действия этого присваивания переменной А. Если А — вы- ходная переменная и после Sz ей не присваивается значение, то j = п ф- 1, и говорят, что U лежит в области действия опера- тора 3,- (это следует из принятого выше соглашения; здесь мы лишь подчеркиваем это). Если блок содержит такой оператор S, что переменная, кото- рой присваивается значение в S, не является активной после этого оператора, то область действия оператора S пуста, и говорят, что S—бесполезный оператор. Другими словами, S — 332
11.1. ОПТИМИЗАЦИЯ ЛИНЕЙНОГО УЧАСТКА бесполезный оператор, если он присваивает значение перемен- ной, которая не является выходной и на которую нет ссылки в последующих операторах. Пример 11.2. Рассмотрим блок, в котором а, 0 и у — списки из нуля или более операторов: а А ₽ £>*— А*Е У Если переменной А не присваивается значение в последова- тельности операторов р и на нее нет ссылки из у, то область действия оператора Л-—В-|-С включает полностью р и опе- ратор D <—А*Е. Если в у нет операторов, ссылающихся на D, и О не является выходной переменной, то оператор D <—А-у. Е бесполезен. □ Определим теперь четыре простейших преобразования бло- ков, сохраняющие эквивалентность. Пусть 33 = (Р, /, U) — блок и P = S1; S2; . . . ;S„. Как и выше, предположим, что всем вход- ным переменным присваиваются значения в операторе и все выходные переменные входят в оператор 3„ + 1. Преобразования определим в терминах их воздействия на данный блок S3. Пер- вое из преобразований интуитивно желательно, а именно из блока удаляются все те входные переменные или операторы, которые не оказывают влияния на выходные переменные. Тр. Удаление бесполезных присваиваний Если оператор Sh O^i^n, присваивает значение перемен- ной А и она не активна после момента I, то (1) при i > 0 можно удалить S, из Р, (2) при (=0 можно удалить А из /. Пример 11.3. Пусть S3 = (P, I, U), где / — pl, В, С}, U — {F, G} и Р состоит из F^~ А + А G*—F*C F+-A + B G<— А * В Второй оператор бесполезен, так как его область действия пуста. Таким образом, одно применение преобразования 1\ 333
ГЛ. 11. ОПТИМИЗАЦИЯ КОДЛ отображает S3 в S3i = (P1, I, U), где Рг состоит из F — А + А F А — В G *— А * В Теперь в S3, бесполезны входная переменная С и первый опера- тор. Поэтому 7'1 можно применить дважды и получить S3, = = (Р2, {А, В}, U), где Р2 состоит из F+-AA-B G <— А* В Отметим, что S32 получается независимо от того, удаляется сначала переменная С или первый оператор из Pt. П Для того чтобы можно было систематически удалять из блока 3 = (Р, I, U) все бесполезные операторы, надо определить мно- жество полезных переменных (тех, которые явно или неявно используются в вычислении выхода) после каждого оператора блока, начиная с последнего оператора в Р и поднимаясь затем вверх. Ясно, что Un — U— множество переменных, полезных после последнего оператора Sn. Предположим, что оператором 3£- является А «—6В1 . .. Вг и U) — множество переменных, полезных после 3£-. (1) Если A^Ut, то .3,-—полезный оператор, так как пере- менная А используется для вычисления выходной переменной. Тогда множество Uполезных переменных после Sl_1 нахо- дится заменой А в IJ, на переменные В1( ..., Вг (т. е. Ul_l =- = (U-{A})U{Bj, .... Bf}). (2) Если A^U;, то оператор Вг бесполезен, и его можно удалить. В этом случае = (3) После вычисления U 0 можно удалить из / все входные переменные, которых нет в Второе преобразование блоков сливает общие выражения. Т2. Исключение избыточных вычислений Предположим теперь, что 3 = (Р, I, U) —блок, где Р имеет вид а А вс,... Сг в^-вс,...с, Т причем ни одна из переменных С,, .. ., Сг не есть А и ни одной из них не присваивается значение ни в каком операторе в 0. 334
11.1. ОПТИМИЗАЦИЯ ЛИНЕЙНОГО УЧАСТКА Преобразование Т, отображает 53 в S3' ~(Р', I, U'), где Р' есть а D^QC1...Cr ₽' т' и (1) р' — это список р, в котором все ссылки на переменную А в области действия данного изображения этой переменной заме- нены ссылками на D, (2) у'—это список у, в котором все ссылки на А и В в облас- тях действия данных изображений А и В заменены ссылками на D. Если область действия переменной А или В распростра- няется на S„+l, то U' — это множество U, в котором А или В заменена на D. В противном случае U’— U. D может быть любым именем, не меняющим значения блока. Подходит любой символ, на который нет ссылки в Р; кроме того, могут использоваться и некоторые символы, на которые есть ссылки в Р. Пример 11.4. Пусть ЙЗ = (Р, {Д, В}, {F, 6}), где Р состоит из в^д + в В — Д*В R — B-B T*—A*S G^T*R Второй и четвертый операторы дают избыточные вычисления, так что к S3 можно применить преобразование Тг, в результате чего получится 53'=(Р', {Л, BJ-, \D, G}), где Р' состоит из S+-A+B D- -A-.S R — B--B G*—D*R Выходным множеством становится {D, G}. D может быть любым новым символом или одной из переменных В, A, S или Т. Легко проверить, что если в качестве D взять В, R или G, то изменится значение программы. □ Т3: Переименование Ясно, что поскольку речь идет о значении блока 33 ~(Р, /, U), имена переменных, которым присваиваются значения, несущест- венны. Предположим, что оператором 3,- в Р является — 335
ГЛ. 11. ОПТИМИЗАЦИЯ КОДЛ 9В1 ... В, и переменная С не активна в области действия оператора В,-. Тогда можно положить S' = (P', I, U"), где Р'—это Р, в котором оператор В,- заменен на —0В, . .. Вг, а все вхождения А в области действия оператора В,- заменены на С. Если (7 лежит в области действия оператора В,., то U'— это U, в котором переменная А заменена на С. В противном случае U' = U. Преобразование Ts отображает S3 в S3'. Пример 11.5. Пусть ® = (Р, {4, В}, {В}), где Р состоит из Т — Ау.-В Т --Т А F-Т-/.Т Одно применение Ts позволяет изменить имя переменной Т, которой присваивается значение первым оператором, на В. Таким образом, 7', отображает S3 в S3'— {Р', {А, В}, {В}), где Р' состоит из В^4*В T+-S + A F->—Т »Т Отметим, что переменная Т заменена на В только в первом операторе присваивания. □ Г4: Перестановка Пусть S3 = (Р, I, U) — блок, в котором оператором В,- является А-—9В1...ВГ, оператором В,-+1 являетсяС<—фО,...О5,4 не со- впадает ни с одной из переменных С, ,... , D, и С не совпадает ни с одной из переменных 4,В,,.. . , Вг. Тогда преобразование В4 отображает блок S3 в 33' —(Р', /, U), где Р' — это Р, в кото- ром В,- и В,+1 переставлены. Пример 11.6. Пусть S = (P, {4, В}, {В, G}), где В состоит из В<-4 + В G-—4*В Можно применить Tt и отобразить 33 в (В', {4, В}, {F, G}), где Р' состоит из G^4 *В В--4 ‘ В Однако с помощью Т, нельзя отобразить блок 531 = (Р1, {4, В}, {В, G}), где состоит из F — А-'-В G-—F*A 336
11.1. ОПТИМИЗАЦИЯ ЛИНЕЙНОГО УЧАСТКА в блок .'В, = (Р2, {А, В}, {В, 6}), где В2 состоит из G — F. А F+-A+B В самом деле, в этом случае 332 даже не блок, потому что пере- менная F используется, не будучи предварительно определен- ной. □ Определим теперь некоторые отношения эквивалентности, связанные с действиями четырех определенных выше преобра- зований. Определение. Пусть 3 — подмножество множества {1, 2, 3, 4}. Будем писать 33t=>s 33,, если одно применение преобразования Т/ переводит в 332, причем i£S. Будем писать 33,^332, если s существует такая последовательность блоков 4?0, ..., что (1) = (2) (3) для каждого г, 0<д ign, либо 4?z =S>s4?г, либо Таким образом, — это наименьшее отношение эквивалент- s пости, содержащее =>s и отражающее идею о том, что преобра- зования могут применяться в любом направлении. Соглашение. Подмножества {1, 2, 3, 4} будем изображать без скобок, так что, например, =>{i,2} будем записывать =>12. Теперь мы хотим показать, что блоки ЗВ, и 332 эквивалентны тогда и только тогда, когда существует последовательность преобразований, включающая в себя только преобразования Т,— Tt, которая отображает S3, в 33,. Иными словами, 33,=Э32 тогда и только тогда, когда 33, 35 33г. Достаточность условия 1.2.3.4 проверяется легко: надо лишь показать, что каждое отдельное преобразование сохраняет значение блока. Теорема 11.1. Если 33,^>,t2t2<l332, то 33,-—ЗВ.. Доказательство. Упражнение. Читатель должен также показать, что для D в преобразовании Т2 можно выбрать любое новое имя, как это утверждалось в описании преобразова- ния. □ Следствие-. Если 33, 4=> 33 то 33, = 33.. □ 1.2,3,4 В разд. 11.1.4 будет доказано обращение этого утверждения. 337
ГЛ. 11. ОПТИМИЗАЦИЯ КОДЛ 11.1.3. Графическое представление блоков В настоящем разделе мы покажем, что для каждого блока Й9— (Р, I, U) можно найти ориентированный ациклический граф D, естественным образом представляющий S3. Каждый лист графа D соответствует одной входной переменной в /, а каждая его внутренняя вершина — оператору из Р. К ориентированным ациклическим графам легко применяются преобразования бло- ков, рассмотренные в предыдущем разделе. Определение. Пусть 33 — (Р. I, U) — блок. Построим из 3 помеченный упорядоченный граф1) D(/8): (1) Пусть P = S1; ... ;S„. (2) Для каждой переменной Д g / образуем вершину с мет- кой А и будем называть ее последним определением, для А. (3) Для i = 1, 2, . . ., п делаем следующее. Пусть оператором Sj является А «—0В] . .. Вг. Образуем новую вершину, помечен- ную 0, из которой выходят г ориентированных дуг. Пусть /-я дуга (при упорядочении дуг слева направо) указывает на последнее определение для BJt Новая вершина, помеченная 0, становится последним определением для А. Эта вершина соот- ветствует оператору Зг в Р. (4) После шага (3) вершины, являющиеся последними опре- делениями выходных переменных, в дальнейшем помечаются как „выделенные". Выделенные вершины будем изображать двойными кружками. Пример 11.7. Пусть ® = (Р, </1, В}, {К, G}) — блок, в кото- ром Р состоит из операторов Т^А + В Г^А'/..'Г T^B + F G*—B*T Граф D(33) изображен на рис. 11.1. Отметим, что на рис. 11.1 четыре оператора из 33 соот- ветствуют по порядку вершинам п.:, п2, п3, п3. Отметим также, что прямым потомком вершины является п3, а не nlt по- скольку при создании вершины п4 вершина п3 была последним определением для Т. □ Каждый граф естественным образом представляет класс экви- валентности отношения «Ф. Иными словами, если блок ЭЗг с по- s.4 мощью некоторой последовательности преобразований Т3 и 7’4 *) До конца этого и в следующем разделе под словом „граф11 будем под- разумевать „ориентированный ациклический граф“.— Прим. ред. 338
11.1. ОПТИМИЗАЦИЯ ЛИНЕЙНОГО УЧАСТКА можно отобразить в блок 332, то блоки 332 и 332 имеют один и тот же граф, и обратно. Одна часть этого утверждения состав- ляет приведенную ниже лемму, доказательство которой заклю- чается в использовании определений и предоставляется читателю. Лемма 11.1. Если 332, то D(.591) = B (®а). До к а з а т е л ь с т в о. Упражнение. □ Следствие. Если то D (33 — D(,332). □ Доказательство обратного утвержде- ния более трудно. Для него понадобятся еще одно определение и лемма. Определение. Блок 33 = (Р, 1, U) на- зывают открытым,, если (1) ни один из операторов в Р не имеет вида А<—а, где Xg/, Рис. 11 1. Пример ориен- тированного ацикличе- ского графа. (2) в Р нет двух операторов, присваи- вающих значение одной и той же пере- менной. В открытом блоке 33 = (Р, I, U) все операторы .S\ из Р при- сваивают значения различным переменным Xt, не входящим в /. В лемме 11.2 утверждается, что открытый блок всегда можно получить переименованием переменных с помощью только преобразования 7\. Лемма 11.2. Пусть 33 = (Р, I, U)— блок. Тогда существует такой эквивалентный открытый блок 33' = (Р', I, U'), что ЗЗ&ЗЗ' 3 Доказательство. Упражнение. □ Следующая теорема показывает, что два блока имеют один и тот же граф тогда и только тогда, когда один из них можно преобразовать в другой переименованием и перестановкой. Теорема 11.2. D(33^)^D(33^ тогда и только тогда, когда 331-^332. ' 3,4 Доказательство. Достаточность следует из леммы 11.1. Для доказательства необходимости рассмотрим два блока ®,= = (Рх, Д, С7Г) и 332 = (Ра, /2, U2), для которых D (332)-D. Поскольку графы одинаковы, входные множества должны совпа- 339
ГЛ. И. ОПТИМИЗАЦИЯ КОДА дать, так что можно положить = = Кроме того, число операторов в Pt и Р, должно быть одинаковым, так что можно положить Р, =St; . . . ; S„ и Рг = Р,; . .. ; Rn. С помощью переименования Т3 можно построить два откры- тых блока®; = (PJ, (/() и = (Р.;, U2) с одним и тем же мно- жеством переменных, которым присваиваются значения, причем (1) ®; А®!, (2) (3) если р; = SJS,' и Р'г = R', R'n, то S; и Р) осу- ществляют присваивание одной и той же переменной тогда и только тогда, когда им соответствует одна и та же вершина в D. (Из следствия леммы 11.1 видно, что D (®J) ~ D (33'2) = D.) При создании открытых блоков сначала всем переменным блоков и ®г даем новые имена. Затем можно снова восполь- зоваться переименованием, чтобы удовлетворить условию (3). Будем теперь строить такую последовательность блоков ....что (4) (5) п — ®3, (6) для О -С (-С п, 4 (7) операторами в rtS, являются Р,'; ... ; R't, за которыми сле- дуют операторы из SJ; . .. ; S'„, не осуществляющие присваива- ний тем переменным, которым уже присвоены значения одним из операторов Р(; ... ; Р;. Ясно, что D(’S1) = D и операторы, определяющие одни и те же переменные в и порождают одинаковые вершины в D. Начнем с Условие (7) удовлетворяется тривиально. Предположим, что мы уже построили 77, Список опера- торов из можно записать как Р,' ; ... ; Р; ; S’^ ; ... ; S; _t, и в нем операторы S’!t, .... S', удовлетворяют условию (7). По определению PJ и Р2 найдется оператор S'j , осуществляю- щий присваивание той же переменной, что и Р[+1. Поскольку и Р;+1 соответствуют одной и той же вершине в D, то S', ссы- лается только на переменные из / или па те, которым присваи- ваются значения операторами R[;...; Ri, и в действительности P, + 1=S;A. Таким образом, повторяя Tt, можно поставить S) перед всеми S; ;.. .; S'j . В результате будет блок g1+1; усло- вия (6) и (7) легко проверяются. 340
11.1. ОПТИМИЗАЦИЯ ЛИНЕЙНОГО УЧАСТКА Когда в условии (7) i = n, получаем условие (5). Итак, 3 4 3 откуда □ 3, 4 Следствие. Если D(®t) = D(SZ), то 33i = 332. Доказательство. Следует непосредственно из теорем 11.1 и 11.2. □ В силу этого следствия граф можно снабдить значением, а именно значением любого блока, имеющего данный граф. Пример 11.8. Рассмотрим два блока 131~(Р1, {Д, В}, {В}) и ®г-=(Р2, {Л, В}, jf}), множества Pt и Р2 для них приведены Таблица 11.1 Pt рг А * А С В *В D В * В D^- -А * А Е+— C — D Е+- -D+C F 4— С D с*- D—C F E/F F -С/Е в табл. 11.1. Блоки и имеют один и гот же граф, изображенный на рис. 11.2. С помощью Т3 можно отобразить 3, и в открытые блоки ®;=(в;, {л, в}, {х5}) и s2 = =- (Р'г, {Л, В}, {ХЕ}), при этом будет удовлетворяться условие (3) из дока- зательства теоремы 11.2. Р[ и /^при- ведены в табл. 11.2. Затем, начиная с блока у которого Р[ — список операторов, легко построить блоки 1?2, g3, '<?, и £5, упомянутые в доказательстве тео- ремы 11.2. Блок й, получается применением преобразования Tt, перемещающего второй оператор на первое место (см. табл. 11.3). Далее, U2 — "Si. Блок й, строится из с помощью преобразова- ния Та, ставящего четвертый оператор перед третьим (табл. 11.3); блоки 'Л4 и й’ь совпадают с <?,. □ 341
ГЛ. 11. ОПТИМИЗАЦИЯ КОДА Таблица 11.2 Таблица 11.3 Ао *— В* В 11.1.4. Критерий эквивалентности блоков Покажем теперь, что SjSsB, тогда и только тогда, когда * - <J=> ®2. На самом деле справедливо более сильное утверж- * дение, а именно: 33, = 332 тогда и только тогда, когда 93, <=> 332. Иными словами, преобразований Т, и Т2 достаточно, чтобы ото- бразить любой блок в любой эквивалентный ему. Доказательство этого более сильного утверждения предлагаем в качестве упраж- нения (упр. 11.9 и 11.10). Определение. Блок 33 называется приведенным, если не суще- ствует такого блока 33', что 33=i>,l233'. Приведенный блок не содержит ни бесполезных операторов, ни избыточных вычислений. Если дан блок 33, то можно найти эквивалентный ему приведенный блок, повторно применяя Т, и Т2. Поскольку каждое применение Т, или Т2 сокращает длину блока, в конце концов мы должны прийти к приведенному блоку. Наша цель заключается в том, чтобы показать, что для при- веденных блоков 33, = 332 тогда и только тогда, когда D(93,) — D(932). Таким образом, если дан блок 33, то можно найти единственный граф, соответствующий всем приведенным блокам, получаемым из 33, независимо от той конкретной последователь- 342
11.1. ОПТИМИЗАЦИЯ линейного участка яости преобразований 7\ и Тг, в результате которой был полу- чен приведенный блок. Какова бы ни была машинная модель, нахождение этого графа — важный шаг „оптимизации" блока. Определение. Пусть Р = ; ... ; S„— список операторов блока. Обозначим через £(Р) множество выражений, вычисляемых в Р. Формально Е (Р) = {р((А) | S( осуществляет присваивание переменной А, Выражение Г| вычисляется в Р k раз, если существуют ров- но k таких различных значений t, что ц((А) = Г| и присваи- вает значение А. Лемма 11.3. Если S3 = (P, I, U)— приведенный блок, mo Р не вычисляет никакого выражения более одного раза. Доказательство. Если два оператора вычисляют одно и то же выражение, находим „первое" вхождение выражения, вы- числяемого дважды. Иными словами, если S; и Sy, i < /, вычис- ляют одно и то же выражение т], будем называть (i, j) первым вхождением, если для всех пар Sk и S,, k < /, вычисляющих то же самое выражение, либо (<fe, либо одновременно t -k и j <1. В качестве упражнения предлагаем показать, что к S; и Sy можно применить в прямом направлении преобразование Тг, а это противоречит предположению о приведенности Р. □ Лемма 11.4. Если !Bl — (P1, flt UJ и S.1 = (Pt, /г, U2)—экви- валентные приведенные блоки, то Е(Р1) = Е(Р.а). Доказательство. Если Е(Р1)^Е(Ра), то без потери общности можно считать, что т] — последнее вычисляемое выра- жение в Е(Р1)^Е(Р2). Поскольку w(S1)=w(®2) и каждое выра- жение единственным образом можно разбить на подвыражения то Г| не является подвыражением никакого выражения из yp-JJ. Таким образом, оператор, вычисляющий т] в Рп бесполезен, и его можно удалить с помощью преобразования Г,, что противоре- чит предположению о приведенности 931. Подробное доказатель- ство оставляем в качестве упражнения. □ Теорема 11.3. Если 53, и S32 — два приведенных блока, то 53, —У32 тогда и только тогда, когда = D(Sa). Доказа гельство. Достаточность условия — частный слу- чай следствия теоремы 11.2. Докажем необходимость. Пусть Из предыдущих двух лемм вытекает, что существует J) Подвыражение — это префиксное выражение, являющееся операндом другого префиксного выражения.— Прим, перев. 343
ГЛ. 11. ОПТИМИЗАЦИЯ КОДА взаимно однозначное соответствие между операторами из S3, и 33г, вычисляющими одни и те же выражения. Предположим, что 0(3)^ =/= D(Si2). Попытаемся „сопоставить" вершины в D(S3^\ и в О('Й„) настолько „высоко" по графу, на- сколько это возможно. Ясно, что листья двух графов можно сопоставить—в противном случае входные множества блоков и 332 были бы различны. Затем можно найти входную пере- менную одного из блоков, на которую не было ссылки, и, при- меняя Т\, удалить ее. Поскольку 51, и 3)2 приведены, приходим к противоречию. Продолжаем сопоставлять вершины; если некоторая вершина в DISBJ имеет ту же метку (операцию), что и какая-то вершина в D(S32), если из них выходит одинаковое количество дуг и соот- ветствующие дуги (начиная слева) указывают на сопоставленные вершины, то рассматриваемые две вершины можно сопоставить. Если, продолжая в том же духе, мы сопоставим все вершины из D(S3,) и О(®2), то эти графы совпадут. В противном случае мы придем к некоторой вершине в 0(53,) или D(332), которой не соответствует никакая вершина в дру- гом графе. Без потери общности можно считать, что эта вер- шина принадлежит D(®,) и что обнаружена самая „нижняя" такая вершина, т. е. вершина, каждая выходящая дуга которой ука- зывает па сопоставленную вершину. Пусть этой вершиной будет /г,. Можно видеть, что сопоставленные вершины в 0(53,) и D(S32) порождаются операторами в S3, и 3)2, вычисляющими одни и те же выражения. Это легко показать простой индукцией по порядку сопоставления. Однако по лемме 11.3 никакую вершину нельзя сопоставить с двумя вершинами другого графа. По лемме 11.4 в £>(Э32) най- дется вершина я2, порождаемая оператором из 33 2, вычисляющим то же самое выражение, что и оператор из S3,, порождающий п1. Поскольку „разбор" выражений определен однозначно, прямые потомки вершин п, и п2 сопоставлены. Это следует из предпо- ложения, что вершина п, находится в D(S3,) настолько „низко", насколько возможно. Таким образом, вершины п, и п2 можно сопоставить вопреки предположению. Следовательно, 0(53,) = = О(ЗЭ2). □ Следствие. Все приведенные блоки, эквивалентные данному, имеют один и тот же граф. □ Соберем теперь вместе доказанные выше результаты и дока- жем, что четырех описанных преобразований достаточно для того, чтобы превратить блок в любой ему эквивалентный. Теорема 11.4.33^33гтогда и только тогда, когда 31, <—> ЗЭ2. 1, 2, 3, 4 344
11.1. ОПТИМИЗАЦИЯ ЛИНЕЙНОГО УЧАСТКА Доказательство. Достаточность условия — это следствие теоремы 11.1. Обратно, предположим, что 53, Тогда суще- ствуют такие приведенные блоки S3,' и S32, что S3, <=ь 3>'. и I. 2 332^33'г. Согласно следствию теоремы 11.1, .S3, = 33'2 и 332 ts332. 1. 2 Таким образом, S3,'—S3j. По теореме 11.3 D(S?() = О(332). По тео- реме 11.2 S3,'« 33г- Следовательно, S3, <=т> S32. □ 11.1.5. Оптимизация блоков Займемся теперь преобразованием блока S3 в блок S3', опти- мальный относительно некоторой оценки блока. На практике часто встречается ситуация, изображенная на рис. 11.3. Подан- ному блоку S3 мы хотим в конце концов получить программу Оптимизатор Генератор кода Рис. 11.3. Схема оптимизации. на объектном языке, оптимальную относительно некоторой опенки объектных программ, такой, например, как размер программы или скорость ее выполнения. Оптимизатор применяет к блоку S3 последовательность преобразований, чтобы построить блок S3', эквивалентный S3, из которого можно получить оптимальную программу на объектном языке. Таким образом, одна из задач заключается в нахождении оценки блоков, отражающей опенку вырабатываемой в конце концов объектной программы. Существует несколько оценок блоков, для которых идея опти- мизации даже не имеет смысла. Например, если мы будем гово- рить, что блок тем лучше, чем он длиннее, то вообще нет опти- мального блока, эквивалентного данному. Здесь мы ограничимся оценками блоков, отражающими наиболее широко применяемые критерии качества программ на объектном языке, такие, напри- мер, как скорость выполнения или объем используемой памяти. Определение. Оценка блоков — это функция, отображающая блоки в вещественные числа. Блок 33 называется оптимальным относительно оценки С, если C(S3) ^1C(S3') для всех S3', экви- валентных 53. Оценка называется приемлемой, если S3,=>,,2S3a влечет С (S32) C(S3t) и любой блок имеет эквивалентный блок, оптимальный относительное. Иными словами, оценка приемлема, если преобразования 7", и Т2, применяемые в прямом направле- нии, не увеличивают оценки блока. 345
ГЛ. 11. ОПТИМИЗАЦИЯ КОДА Лемма 11.5. Если С—приемлемая оценка, то любой блок имеет эквивалентный приведенный блок, оптимальный относительно С. Доказательство. Следует непосредственно из определе- ний. □ Лемма 11.5 устанавливает, что если дан блок Я, то поиски эквивалентного оптимального блока можно ограничить множест- вом приведенных блоков, эквивалентных 3?. В лемме 11.6 ниже утверждается, что в результате применения к данному приве- денному блоку 3 последовательности преобразований Г3 и Г4 получаются только приведенные блоки, эквивалентные Я. Лемма 11.6. Если Яг—приведенный блок и Я1^Я2,тоЯ2 — 3, 4 также приведенный блок. Доказательство. Упражнение. □ Наш следующий результат показывает, что если дан откры- тый блок, то последовательность переименований, за которой идет перестановка, можно заменить на перестановку, за которой следуют переименования. * Лемма 11.7. Пусть Яг — открытый блок и Я1<^Яг=^>1Я3. 3 Тогда существует такой блок Я'г, что Я1=;>ЛЯ2^Я:1. 8 Доказательство. Упражнение. □ Теперь мы готовы к тому, чтобы дать общую схему оптими- зации блоков в соответствии с любой приемлемой оценкой. Теорема 11.5 подводит базис для этой оптимизации. Теорема 11.5. Пусть Я — любой блок. Существует блок Я', эквивалентный Я и такой, что если С—приемлемая оценка, то найдутся такие блоки Я, и Я2, что (1) Я' 1 (2) Я,^Я2, 9 (3) Я, оптимален относительно С. Доказательство. Пусть Я" — любой приведенный блок, эквивалентный Я. Можно преобразовать Я" в открытый блок Я', эквивалентный Я", с помощью только Т3. По лемме 11.6 блок Я' приведен и открыт. 346
11.1. ОПТИМИЗАЦИЯ ЛИНЕЙНОГО УЧАСТКА Пусть ®2 — оптимальный приведенный блок, эквивалентный 33. По лемме 11.5 33t существует. Таким образом, D(332) = D(S3') в сил\' следствия теоремы 11.3. По теореме 11.2 33’ & 33г. Заме- 3. 4 тим, что Т, и Т, взаимно „обратимы", т. е. К =>314 тогда и только тогда, когда . Следовательно, найдется такая последовательность блоков ..., что 33'= ‘@г, 33.l = 'Sn и 1?,-4=>s, 4 для 1 ^t<n. Многократно применяя лемму 11.7, можно перенести все Т4 перед всеми Тг и найти такой блок 93г, что 33'^3), <&33г. □ 4 3 Если внимательно присмотреться к теореме 11.5, можно заме- тить, что она разбивает весь процесс оптимизации на три стадии. Допустим, мы хотим оптимизировать данный блок S: (1) сначала можно исключить из 33 лишние и бесполезные вычисления и переименовать переменные с тем, чтобы получить приведенный открытый блок 33', (2) затем в 53' можно переупорядочить операторы с помощью перестановки и делать это до тех пор, пока не сформируется блок 33ц в котором операторы расположены в наилучшем порядке, (3) наконец, в 53, можно переименовывать переменные до тех пор, пока не будет найден оптимальный блок 33г. Отметим, что шаг (1) можно выполнить эффективно (как функ- цию длины блока). Читателю предлагаем разработать алгоритм для шага (1), обрабатывающий блок из п операторов за время 00z log п). Один из шагов (2) или (3) часто оказывается тривиальным. Приведем пример, показывающий, как преобразовать операторы промежуточного языка в язык ассемблера, чтобы число выпол- няемых команд языка ассемблера было минимальным. Мы увидим, что этот алгоритм оптимизации не нуждается в шаге (3). Даль- нейшее переименование переменных не будет влиять на оценку. Пример 11.9. Наш пример содержит несколько интересных идей, которые не затрагиваются ни в какой другой части книги. Читателю настоятельно рекомендуем подробно разобраться в этом примере. Рассмотрим машинный код, генерируемый для блоков. Вычислительная машина имеет один сумматор и следующий набор команд языка ассемблера, смысл которых мы кратко расшифруем: (1) LOAD М. Содержимое ячейки памяти М помещается на сумматор. (2) STORE М. Содержимое сумматора запоминается в ячейке памяти М. (3) 0М2М, ... Мг. В этой команде 9—имя r-местной опера- ции. Ее первый аргумент — сумматор, второй — ячейка памяти/И2, 347
ГЛ II ОПТИМИЗАЦИЯ КОДЛ третий — ячейка памяти М3 и т. д. Результат применения опера- ции 0 к своим аргументам размещается на сумматоре. Генератор кодов должен переводить оператор вида А«—0S, ... В, в последовательность машинных команд LOAD В, е в,..........в, STORE А Однако если значение В; уже находится на сумматоре (г. е. перед этим был оператор, присваивающий значение BJ, то пер- вую команду LOAD генерировать не надо. Аналогично, если значение А не требуется нигде, кроме первого аргумента сле- дующего оператора, то заключительная команда STORE не нужна. Оценивать оператор А-—0В1...В„ можно числами 1,2 и 3. Оценка равна 3, если В1 нет на сумматоре и в дальнейшем есть ссылка на новое значение Л, отличная от первого аргу- мента следующего оператора (т. е. А надо запомнить). Оценка равна 1, если BL уже на сумматоре и нет ссылки на А, отлич- ной от первого аргумента следующего оператора. В остальных случаях оценка равна 2. Заметим, что такой способ оценки полностью исчерпывает все случаи, заслуживающие рассмотрения. Чтобы показать, что он правильно отражает число команд, требующихся для выпол- нения блока на нашей машине, надо сначала точно определить эффект последовательности команд языка ассемблера. Если это сделано должным образом, то каждую программу па языке ассемблера можно сопоставить с блоком на промежуточном языке путем отождествления команд языка ассемблера типа (3), т. е. операций, с операторами блока. Все эти детали мы пред- лагаем в качестве упражнения. В настоящем примере мы будем пользоваться оценкой блоков в том виде, как мы ее определили. Рассмотрим блок (Р, {А, В, С), {F, GJ-), который мог бы получиться, скажем, из операторов Фортрана F = (А + В)* (Л - В) G-(A-B)*(A — С)» (В—С) Список операторов в Рг таков: T — A-'--B S ^А — В F .-'1GS Т^-А — В S--A-C R+-B-C T<-T*S G<-T*R 348
11.1. ОПТИМИЗАЦИЯ ЛИНЕЙНОГО УЧАСТКА Бесполезных операторов здесь нет. Есть, однако, повторения — второй и четвертый операторы. Эту избыточность можно удалить, а затем переименовать во всех операторах переменные, которым присваиваются значения. В результате получится приведенный открытый блок 592 = (Рг, {Л, В, С}, {Х3, X,}). Он играет здесь роль блока 53' в теореме 11.5. Операторами в Рг будут Хг <~А + В Х. — А -В Х.^.Х, X., —/1-С Х„^В — С Ф'-- Х2 * ^1 Граф для изображен на рис. 11.4. Вершина н( соответ- ствует оператору списка Р2, присваивающему значение перемен- ной Х;. Мы видим, что существует много программ, в которые можно преобразовать ®2 с помощью только 7\. Предлагаем в качестве упражнения доказать, что их столько, сколько существует 34?
ГЛ 11. ОПТИМИЗАЦИЯ КОДА линейных порядков, в которых выполняется частичный порядок, представленный на рис. 11.4. Верхняя граница этого числа равна 71, т. е. число переста- новок из семи операторов. Но в действительности это число будет меньше, так как операторы из не могут располагаться в любом порядке. Например, третий оператор в Р2 всегда должен следовать за вторым, поскольку третий ссылается на перемен- ную X,, а второй определяет ее. Отметим, что применение Ts может изменить имя Х2, но то же отношение будет выполняться и с новым именем. Другая интерпретация ограничений на возможности Т, пере- упорядочивать блок заключается в том, что при любом таком переупорядочении каждая вершина в D(®2) будет соответство- вать некоторому оператору. Оператор, соответствующий внут- ренней вершине п, не может предшествовать никакому опера- тору, соответствующему внутренней вершине, являющейся потомком вершины п. Этот пример достаточно прост для того, чтобы просмотреть все линейные порядки в Р2, но для произвольного блока этого сделать нельзя, поскольку это связано с большими затратами времени. Для того чтобы быстро вырабатывать хорошее, но нс обязательно оптимальное упорядочение, нужна некоторая эври- стика Здесь мы предлагаем один такой способ. Следующий алгоритм дает линейное упорядочение вершин графа. В требуе- мом блоке операторы, соответствующие этим вершинам, распо- ложены в обратном порядке. (I) Строим список L. Вначале он пуст. (2) Выбираем вершину п графа так, что и, если сущест- вуют входящие в п дуги, они должны выходить из вершин, уже принадлежащих L. Добавляем п к L. Если такой вершины нет, то останавливаемся. (3) Если п1 — последняя вершина, добавленная к L, самая левая дуга, выходящая из nt, указывает на внутреннюю вер- шину п, не принадлежащую L, и все прямые предки п уже принадлежат L, то добавляем п к L и повторяем шаг (3). В противном случае переходим к шагу (2). Например, используя граф рис. 11.4, можно начать с L = n3. Согласно шагу (3), к L добавляем п1. Затем выбираем и добав- ляем к L вершину п7, а потом пе и п2. В результате еще двух применений правила (2) добавляются nt и п6, так что L имеет вид n8, nlt n„ nt, ti2, tit, пь. Вспоминая, что оператор, при- сваивающий значение X,-, порождает вершину п,- и что список L соответствует операторам в обратном порядке, получаем блок В, С}, {Х3, X,}). Легко проверить, что 4 350
11.1. ОПТИМИЗАЦИЯ ЛИНЕЙНОГО УЧАСТКА Список операторов в Ps таков: Х^В-С Хл--Л -С х,-- л—в х,—х2*х4 х. — x,*xs х, - - л в х:1- х,*х2 Программы на языке ассемблера, созданные из блоков 332 и 5Э3> приведены на рис. 11.5. □ LOAD A LOAD В ADD В SUBTR С STORE X STORE X, LOAD A LOAD A SUBTR В SUBTR с STORE x2 STORE xt LOAD LOAD A MULT xa SUBTR В STORE A'g STORE X2 LOAD A MULT xt SUBTR C MULT X. STORE x, STORE x7 LOAD в LOAD A SUBTR c ADD В STORE X, MULT x, LOAD Xa STORE X3 MULT Xt MULT X5 STORE x, а — Из 6 — Из <Й?д Рис. 11.5. Программы на языке ассемблера. 11.1,6. Алгебраические преобразования Известно, что во многих языках программирования некото- рые операции и операнды подчиняются определенным алгебраи- ческим законам. Учитывая эти законы, можно проводить такие улучшения программы, какие невозможно сделать с использова- нием лишь четырех рассмотренных выше типов преобразований. 351
ГЛ. И. ОПТИМИЗАЦИЯ КОДА Перечислим несколько полезных и распространенных алгеб- раических законов: (1) Бинарная операция 0 называется коммутативной, если аОр |т()с/. для всех выражений а и [3. Примерами коммутативных операций служат сложение и умножение целых чисел1). (2) Бинарная операция 0 называется ассоциативной, если а0 (р0у'| =•• (сс.О|3) Оу для всех а, [3 и у. Например, сложение ассоциативно, так как “ + (Р + Т) = (« + ₽) + У2) (3) Бинарная операция 0! называется дистрибутивной отно- сительно бинарной операции 0а, если ct01 ф02у) = (aSjP) 02 (а0]у). Например, умножение дистрибутивно относительно сложения, так как а * (0 4- у) = а * 04-а* у. Предосторожности здесь те же, что и в (1) и (2). (4) Унарная операция 0 называется идемпотентной, если 00а = а для всех а. Например, логическое не и унарный минус идемпотептпы. (5) Выражение е называется нейтральным относительно (бинарной) операции 0, если е0а = а0е = а для всех а. Вот при- меры нейтральных выражений: (а) Константа 0 нейтральна относительно сложения. Ней- трально и любое выражение, имеющее значение 0, такое, напри- мер, как а—а, а*0, (—а)4-а и т. д. (б) Константа I нейтральна относительно умножения. (в) Логическая константа истина нейтральна относительно конъюнкции (т. е, а Д истина = а для всех а). (г) Логическая константа ложь нейтральна относительно дизъюнкции (т. е. а\/ложь = а для всех а). Если Л — множество алгебраических законов, будем говорить, что выражение а эквивалентно выражению |1 относительно Л (и писать cts^0), если а можно преобразовать в 0, применяя только алгебраические законы из Л. Пример 11.10. Рассмотрим выражение С помощью ассоциативного закона умножения можно записать Л* (В* С) в виде (Л*В)*С. С помощью коммутативного закона ‘) Однако необходимо соблюдать осторожность, если операнды коммута- тивной операции — функции с побочным эффектом. Например, / Ое) может отличаться от g (г/) + / (х), если функция / меняет значение у. 2) Это преобразование также надо применять с осторожностью, Напри- мер, пусть х значительно больше у и г— — х, а вычисления осуществляются с плавающей точкой. Тогда (у4-х)4-г может в резулыате дать 0, в го время как </4-(х4-г) дает у. 352
ИЛ. ОПТИМИЗАЦИЯ ЛИНВИНОГО УЧАСТКА умножения можно записать В» А в виде А * В. Применяя дистри- бутивный закон, все выражение можно записать как (Л»В)»(С + О) + Л*£ Наконец, применяя ассоциативный закон к первому слагаемому, затем дистрибутивный закон, можно записать выражение как Л*(В*(С + О) + В) Таким образом, это выражение эквивалентно исходному относи- тельно ассоциативного, коммутативного и дистрибутивного зако- нов умножения и сложения. В то же время последнее выраже- ние вычисляется только двумя сложениями и двумя умножениями, в то время как для исходного требовалось пять умножений и два сложения. □ Определение эквивалентности относительно множества алгеб- раических законов Л можно распространить и на блоки. Будем говорить, что блоки и 39а эквивалентны относительно Л (и писать 53, если для любого выражения существует такое выражение (3g у (5Э2), что = и обратно. Каждый алгебраический закон приводит к соответствующим преобразованиям блоков (и графов). Пример 11.11. Если сложение коммутативно, то преобразо- вание блоков, соответствующее этому алгебраическому закону, позволяет заменить в блоке оператор вида Х<—Л+В на опера- тор X >— В + Л. Соответствующее преобразование графа позволяет заменить всюду в графе структуру Пример 11.12. Рассмотрим преобразование блоков, соответ- ствующее ассоциативному закону сложения. Последовательность из двух операторов вида Х^-В + С y — a + x можно заменить на три оператора X ^в + с Х'ч—А + В Y «- Х'+С 12 л, Ахо, Дж. Ульман, т. 2 353
ГЛ, И. ОПТИМИЗАЦИЯ КОДА где^Х' — новая переменная. Это преобразование имеет следую- щий аналог на графах: Отметим, что мы сохранили оператор X <— В + С, поскольку на переменную X может быть ссылка из последующего оператора. Однако, если оператор X*—В-\-С после этого преобразования становится бесполезным, его можно удалить, применяя 7\. Если, кроме того, можно удалить Х'ч—Лф-В с помощью Т.,, то использование ассоциативного закона принесло выгоду. □ Если дан конечный набор алгебраических законов и соответст- вующие преобразования блоков, то для нахождения оптималь- ного блока, эквивалентного данному, желательно было бы при- менить их вместе с четырьмя топологическими преобразованиями, описанными в разд. 11.1.2. К сожалению, для конкретного набора алгебраических законов может не быть эффективного способа применения этих преобразований для нахождения опти- мального блока. Обычный подход к решению этого вопроса заключается в том, что алгебраические преобразования применяют в ограниченном виде, надеясь сделать возможно больше „упрощений" выражений и выработать возможно большее число общих подвыражений. В типичной схеме |30сс заменяется на сс0р, если 9 — коммутатив- ная бинарная операция, а а предшествует р при некотором лексикографическом упорядочении имен переменных. Если 9 — ассоциативная и коммутативная бинарная операция, то сфНаф . . . 0ая можно преобразовать, располагая имена alt . . ., <х„ в лексикографическом порядке и группируя их слева направо. Закончим этот раздел примером, иллюстрирующим возмож- ный эффект алгебраических преобразований блоков. Пример 11.13. Рассмотрим блок S = (Р, /, {У}), где / = = {Л, В, С, D, Л} и Р — последовательность операторов Xj^-B—С Х2 А * X, X,--E*F Х4- О » Х3 Y ^X2*X4 354
11.1. ОПТИМИЗАЦИЯ ЛИНЕЙНОГО УЧАСТКА Блок S3 вычисляет выражение Y = (А * (В — С)) * (D* (Е * В)) Граф для S3 приведен на рис. 11.6. Предположим, что для 5Э генерируется программа на языке ассемблера, в которой участвуют команды языка ассемблера и функция оценки, описанные в примере 11.9. Если генерировать программу на языке ассемблера прямо из 33, то результирую- щая программа будет иметь оценку 15. Предположим теперь, что умножение коммутативно и ассоциа- тивно и мы хотим найти оптимальный блок для 33, эквивалент- ный 33 относительно ассоциативного и коммутативного законов умножения. Применим к S3 алгебраические преобразования, соответствующие этим двум законам. Мы хотим получить после- довательность операторов, в которой промежуточные результаты можно без запоминания немедленно использовать последующими командами. Предполагая, что умножение ассоциативно, можно заменить в S3 два оператора X, - - £ » F Х4«-£>*Х., на три оператора Х3 <— £ * F X’3<~D*E Х3<-Х’3*Р Теперь оператор Ха <—E*F бесполезен, и его можно удалить 12* 355
ГЛ. И. ОПТИМИЗАЦИЯ КОДА преобразованием Г,. Затем с помощью ассоциативного преобразо- вания можно заменить операторы X.-.-XXF Y Х2*Х4 на Х4 — X'3*F XJ — Xs * Х'3 Y *-X't*F Оператор Х4«—X;*F теперь бесполезен, и его можно удалить. К этому моменту у нас пять операторов Х,«- В — С Х3 <- А * Xf X'3-<—D»E x;^-x2*x; Y ^X'3*F Если применить ассоциативное преобразование еще раз к треть- ему и четвертому операторам, получим (после исключения бес- полезных операторов) блок Хх-^В—С X., - - Л * X, Х3" - X,» О х; <-• х; * е Y +-X’,*F Наконец, если предположить, что умножение коммутативно, можно переставить операнды второго оператора и получить блок 53': Хх —в-с Х2 — Xj * А X"3^-X.^D X't^X3*E Y ^-X'^F Граф для S3' приведен на рис. 11.7. Блок S3’ имеет оценку 7, самую нижнюю возможную оценку для блока, эквивалентного S3'. В следующем разделе мы изложим систематический способ опти- мизации арифметических выражений с использованием ассоциа- тивного и коммутативного алгебраических законов. □ 356
УПРАЖНЕНИЯ УПРАЖНЕНИЯ 11.1.1. Пусть 59 = (Р, {А, В, С}, {f, G}) — блок, в котором Р состоит из Т — А + В R+-A*T S+-B + С F+-R*S 'ГА ~ Л R*—A+B S<—A*R G--S-T (а) Что представляет собой v (53)? (б) Укажите область действия каждого оператора из Р. (в) Имеет ли Р бесполезные операторы? (г) Преобразование Т„ применимо к первому и шестому опера- торам. Какие значения может принимать D (см. определение D в разд. 11.1.2) при этом применении Та? 357
гл. 11. ОПТИМИЗАЦИЯ КОДА (д) Изобразите граф для S3. (е) Найдите для S3 эквивалентный приведенный блок. (ж) Сколько существует эквивалентных приведенных блоков для 33, не считая тех, которые получаются переименованием? ^Точнее, пусть S3’ — открытый приведенный блок, эквивалент- ный S3. Какова мощность множества 59'f ? ) I 4 I / (з) Найдите для S3 эквивалентный блок, оптимальный относи- тельно оценки из примера 11.9. 11.1.2. Докажите, что преобразования Т,, Т3 и Та сохраняют эквивалентность блоков (т. е. влечет v(33) =v(33') для 1 = 1,3 и 4). 11.1.3. Докажите, что если в преобразовании Т2 (разд. 11.1.2) D—любой символ, не употребляемый в Р, то v(S) —v(33’). *11.1.4. Дайте алгоритм определения множества допустимых имен для D в преобразовании Т2. 11.1.5. Докажите, что алгоритм, изложенный после при- мера 11.3, удаляет из блока все бесполезные операторы и вход- ные переменные. Покажите, что число шагов, требуемых для выполнения алгоритма, линейно зависит от числа операторов блока. *11.1.6. Приведите алгоритм удаления из блока всех лишних вычислений (преобразование Т2) за время 0(п logit), где п— число операторов блока1). (Это аналогично минимизации автоматов с конечным числом состояний с помощью алгоритма 2.6.) 11.1.7. Приведите алгоритм определения области действия оператора в блоке. 11.1.8. Определите преобразования графов, аналогичные пре- образованиям блоков 7\— Tt. # Упр. 11.1.9 и 11.1.10 показывают, что 3, <=> S3, влечет г 11. 2, з. 4 2 *11.1.9. Покажите, что если 39j=4>3®2, то существует такой блок 333, что 333^>г53.а и ‘j3.,—>aS3v. Таким образом, преобразо- вание Г, можно выполнить одним применением 1\ в обратном порядке с последующим применением Т,. Не надо забывать, что число возможных имен переменных бесконечно. Поэтому могут пригодиться методы организации информации, аналогичные упомянутым в разд. 10.1. 358
УПРАЖНЕНИЯ *11.1.10. Покажите, что если то существует такой блок что М,=>2 532 и S2=^>lSl. Определение. Множество S преобразований блоков называется X- полным, если »(®1) = С'(®2) влечет Множество 5 назы- вается минимально полным, если никакое его собственное под- множество не полно. Упр. 11.1.9 и 11.1.10 показывают, что множество {Г,, 7',} полно. Следующие два упражнения показывают, что Тг} минимально полно. *11.1.11. Покажите, что с помощью только преобразований Tt, Ts u'Tt нельзя преобразовать блок s = (P, {Л, В}, {С, DJ-) в ЗУ — IP', {А, В\, {С, D}), где Р и Р' таковы: Е *~-А +В D *— Е * Е Следовательно, множество {Тг, Те, 7\} не полно, и потому {Тх} не полно. *11.1.12. Покажите, что с помощью только преобразований Т2, Т3 и Tt нельзя преобразовать блок Si - (Р, {А, В}, {С}) в 33' = (Р', {Л, В}, {С}), где В и В' таковы: С*—А*В С >— А + В А+В 11.1.13. Приведите алгоритм, выясняющий, эквивалентны ли два данных блока. 11.1.14. Пусть В -..S,; S,S,, —последовательность опе- раторов присваивания, а I — множество входных переменных. Дайте алгоритм нахождения всех неопределенных (т. е. таких, иа которые есть ссылка до присваивания) переменных из В. *11.1.15. Пусть в качестве операторов блока, помимо данных выше в определении блока, допускаются также операторы вида 359
ГЛ. 11. ОПТИМИЗАЦИЯ КОДА Ач—В, имеющие очевидный смысл. Найдите для таких блоков полное множество преобразований. **11.1.16. Предположим, что сложение коммутативно. Пусть — преобразование, заменяющее оператор А*—В 4-С на Ач—С + В. Покажите, что Т„ вместе с и Т2 преобразуют два блока друг в друга тогда и только тогда, когда они экви- валентны относительно закона коммутативности сложения. **11.1.17. Предположим, что сложение ассоциативно. Пусть Тс—преобразование, заменяющее операторы Хч—А-уВ ; Уч—Х-|-С на Хч—А^-В-,Х'ч—В+С\Уч—Д-J-X' или операторы Х<-В+С;У^А.Х на X В+ С ; X’ А + В ;У X’ +С, где X' — новая переменная. Покажите, что Тв, 7\ и Т2 преобра- зуют два блока друг в друга тогда и только тогда, когда они эквивалентны относительно закона ассоциативности сложения. 11.1.18. Что представляет собой преобразование блоков, соответствующее закону дистрибутивности умножения относи- тельно сложения? Что представляет собой соответствующее преобразование графов? **11.1.19. Покажите, что существуют алгебраические законы, для которых рекурсивно неразрешима проблема эквивалентности двух выражений. Определение. Говорят, что алгебраический закон сохраняет операнды, если при одном его применении операнды не порож- даются и не исчезают. Например, коммутативный и ассоциатив- ный законы сохраняют операнды, а дистрибутивный нет. Говорят, что алгебраический закон сохраняет операции, если одно его применение не влияет на число операций. Алгебраи- ческий закон 09а = а (идемпотентность) не сохраняет операции, а закон (а—Р) — у = а—(р + у) сохраняет. Числа внутренних вершин и листьев в графе, связанном с блоком, сохраняются при применении к блоку преобразований, соответствующих алгебраическим законам, сохраняющим опера- ции и операнды. * 11.1.20. Покажите, что проблема эквивалентности двух бло- ков относительно алгебраических законов, сохраняющих опе- рации и операнды, разрешима. * 11.1.21. Обобщите теорему 11.5 так, чтобы можно было оп- тимизировать блоки, применяя как топологические преобразо- вания из разд. 11.1.2, так и произвольный набор алгебраических преобразований, сохраняющих операции и операнды. * 11.1.22. Рассмотрим блоки, в которых переменные могут представлять одномерные массивы. Рассмотрим операторы при- зы)
УПРАЖНЕНИЯ сваивания вида (1) А(Х)+- В, (2) В^Л(Х), где А— одномерный массив, а В и X — скаляры. Используя тот факт, что А — массив, найдите преобразования, применимые к блокам, в которых каждый оператор имеет вид (1), (2) или В*— 66, ... где В, Ci, .... С,—скаляры. 11.1.23. Докажите лемму 11.1. 11.1.24. Докажите лемму 11.2. 11.1.25. Закончите доказательство леммы 11.3, 11.1.26. Закончите доказательство леммы 11.4. *11.1.27. Дайте пример такой оценки С, что влечет C(33s) (SA, но не для каждого блока существует блок, оп- тимальный относительно С. 11.1.28. Докажите лемму 11.6. 11.1.29. Покажите, что если 331— открытый блок и S1=?>s®2=»4®3, то существует такой блок ,®, что ^Т=^4^=Ф3^3. 11.1.30. Докажите лемму 11.7. Указание-. Воспользуйтесь упр. 11.1.29. *11.1.31. Предположим, что у нас есть машина с N регист- рами, причем в этих регистрах можно разместить некоторые или все аргументы операции, а также ее результат. Покажите, что выходные значения блока можно вычислять на такой ма- шине, не прибегая к командам запоминания (результаты поме- щаются в регистры), тогда и только тогда, когда для этого блока существует эквивалентный блок, в котором в командах встречается не более N разных имен переменных. *11.1.32. Покажите, что если к данному блоку 33 в любом порядке применять преобразования 7\ и Т„ пока не получится приведенный блок, то результатом будет всегда один и тот же блок (с точностью до переименования). Проблемы для исследования 11.1.33. Используя оценку из примера 11.9 или какую-нибудь другую интересную оценку, постройте быстрый алгоритм нахож- дения оптимального блока, эквивалентного данному. 11.1.34. Укажите набор алгебраических преобразований, по- лезных при оптимизации широкого класса программ. Разрабо- тайте эффективные методы применения этих преобразований. 361
ГЛ 11. ОПТИМИЗАЦИЯ КОДА Упражнения на программирование 11.1.35. Используя подходящее представление графов, реали- зуйте преобразования Г, и Тг, описанные в настоящем разделе. 11.1.36. Реализуйте эвристику, предложенную в примере 11.9, для „оптимизации" кода машины с одним сумматором. Замечания по литературе Материал этого раздела излагается в соответствии с работой Ахо и Уль- мана [1972е]. Игараси [1968] дает преобразования аналогичных блоков, в ко- торых допускаются операторы А ч—5 и считаются существенными имена выходных переменных. Де Бэккер [1971] рассматривает блоки, в которых все операторы имеют вид Лч—В. Браха [1972] изучает линейные блоки с пере- ходами вперед. Ричардсон [1968] доказал, что не существует алгоритма „упрощения44 выражений, когда последние состоят из довольно простых операторов. В его работе можно найти ответ иа упр. 11.1.19. Кавинесс [1970] также рассматри- вает классы алгебраических законов, для которых проблема эквивалентности блоков неразрешима. Флойд [1961а] и Брюер [1969] представили алгоритмы нахождения общих подвыражений в линейных участках при выполнении определенных алгебраи- ческих законов. Ахо и Ульман [1972ж] исследовали эквивалентность блоков со структурированными переменными, как и в упр. 11.1.22. Некоторые методы, полезные для упр. 11.1.32, содержатся в работе Ахо и др. [1972]!). 11.2. АРИФМЕТИЧЕСКИЕ ВЫРАЖЕНИЯ Займемся теперь построением генератора кода, вырабаты- вающего для блоков код на языке ассемблера. Входом для гене- ратора кода служит блок, состоящий из последовательности операторов присваивания. Выходом служит эквивалентная про- грамма на языке ассемблера. Нам бы хотелось, чтобы результирующая программа на языке ассемблера была хорошей относительно некоторой оценки, такой, например, как число команд языка ассемблера или число обра- щений к памяти. К сожалению, как отмечено в предыдущем разделе, эффективный алгоритм, который давал бы оптимальный кол на языке ассемблера, не известен даже для простой машины с одним сумматором, такой, как в упр. 11.9. г) Авторы не упоминают работ советских авторов по методам оптимизации программ, хотя советскими учеными внесен значительный вклад в эту область автоматизации программирования, 3 работах Лаврова [1961] и Ершова |1962] применяются операторные схемы для решения задачи глобальной эко- номии памяти. В работе Ершова и др, [1965] эта теория используется для экономии памяти в АЛЬФА-трансляторе. Кроме того, в этой же работе вво- дится понятие линейного участка, употребляемого для построении оператор- ной схемы. См. также примечания переводчика к замечаниям по литературе в разд. 11.2— 11.4. — Прим, перее. 362
11.2. АРИФМЕТИЧЕСКИЕ ВЫРАЖЕНИЯ Здесь мы приведем эффективный алгоритм генерации кода на языке ассемблера для ограниченного класса блоков, а именно блоков, представляющих собой одно выражение без одинаковых операндов. Для этого класса блоков алгоритм будет генериро- вать код на языке ассемблера, оптимальный относительно раз- личных оценок, включая такие, как длина программы и число используемых сумматоров. Предположение об отсутствии одинаковых операндов, разу- меется, не реально, ио часто оно бывает хорошим первым при- ближением. Кроме того, это предположение весьма удобно, если мы собираемся генерировать код, применяя синтаксически управ- ляемый'перевод только с синтезированными атрибутами. Нако- нец, проблема генерации оптимального кода для выражений с одной только парой одинаковых операндов уже оказывается значительно более сложной. Блок, представляющий одно выражение, имеет только одну выходную переменную. Например, оператор присваивания F = Z* (X + У) можно представить блоком ЗА = (Р, {X, Y, Z}, {F}), где Р состоит из Г<~ Х + У F*-Z*R Ограничение, состоящее в том, что выражение не имеет оди- наковых операндов, эквивалентно требованию, чтобы граф для этого выражения был деревом. Для удобства будем предполагать, что все операции бинарные. Это ограничение несущественно, поскольку результаты этого раздела легко обобщаются на выражения с произвольными операциями. Код на языке ассемблера будем генерировать для машины с N сумматорами, где Х^1. Оценкой будет длина программы на языке ассемблера (т. е. число команд). Алгоритм впоследствии будет расширен, и во внимание будут приняты коммутативность и ассоциативность операций. 11.2.1. Модель машины Рассмотрим вычислительную машину с N > 1 универсальными сумматорами и командами четырех типов. Определение. Командой языка ассемблера называется цепочка символов одного из четырех типов: LOAD М, А STORE А, М ОР 9 А, М, В ОР 9 А, В, С 363
ГЛ. 11. ОПТИМИЗАЦИЯ КОДА В этих командах М — ячейка памяти, а А, В и С — имена сум- маторов (возможно, одинаковые). ОР0 — это код бинарной опе- рации 0. Предполагается, что каждой операции 0 соответствует машинная команда типа (3) или (4). Эти команды выполняют следующие действия: (1) LOAD М, А помещает содержимое ячейки памяти М на сумматор А. (2) STORE А, М помещает содержимое сумматора А в ячейку памяти М. (3) ОР 0 А, М, В применяет бинарную операцию 0 к содер- жимому сумматора А и ячейки памяти М, а результат помещает на сумматор В. (4) ОР 0 А, В, С применяет бинарную операцию 0 к содер- жимому сумматоров А и В, а результат помещает на сумматор С. Если сумматор только один, то множество команд сводится к множеству, приведенному в примере 11.9, но только теперь команды типа (4) превращаются в ОР 0 А, А, А. Возможности применения этой команды не используются, так что с этой точки зрения множество команд можно считать обобщением команд для одноадресной машины с одним сумматором. Программой на языке ассемблера (или для краткости просто программой) будем называть последовательность команд языка ассемблера. Если Р = Л ; /2; ... ; /„ — программа, то можно определить значение vt(R) регистра R после команды I (здесь под регистром понимается сумматор или ячейка памяти): (1) v^R) равно R, если R— ячейка памяти, и не определено, если R—сумматор, (2) если это LOAD М, А, то о((А) = t>t_1(AI), (3) если It—это STORE А, М, то t<t(M) = yt_1(A), (4) если I,—это ОР 0 A, R, С, то vt(C) — 0ct_j(A) (напомним, что R может быть сумматором или ячейкой памяти), (5) если vt(R) не определено по (2) —(4), a vt_j(R) опреде- лено, то vt(R) = Vf^AR)-, в противном случае vt(R) не определено. Таким образом, значения вычисляются именно так, как и следовало ожидать. Команды LOAD и STORE передают значения с одного регистра на другой, оставляя их в исходном регистре. Операции помещают вычисленное значение на сумматор, опре- деляемый третьим аргументом, не меняя значений остальных регистров. Будем говорить, что программа Р вычисляет выра- жение а, помещая результат на сумматор А, если после послед- него оператора из Р сумматор А имеет значение а. Пример 11.14. Рассмотрим программу на языке ассемблера с двумя сумматорами А и В, значения которых после каждой 364
11.2. АРИФМЕТИЧЕСКИЕ ВЫРАЖЕНИЯ Таблица 11.4 LOAD X, А ADD A, Y, А LOAD Z, В MULT В, А, А X X+Y X-Y Z* (Х+Г) не определено не определено Z Z команды приведены в табл. 11.4 в инфиксной записи, как обычно. Значение сумматора А в конце программы соответствует (ин- фиксному) выражению Z*(X + Y). Таким образом, эта программа вычисляет /«(Х + Н), помещая результат на сумматор А. Фор- мально вычисляется также и значение выражения Z. □ В настоящем разделе мы формально определим (арифмети- ческое) синтаксическое дерево как помеченное двоичное дерево Т, имеющее одну или более таких вершин, что (1) каждая внутренняя вершина помечена бинарной операцией 0£0, (2) все листья помечены различными именами переменных XgS. Для удобства будем предполагать, что множества 0 и 2 не пересекаются. На рис. 11.8 изображено дерево для /«(Х4-Г). Рнс. 11.8. Дерево для Z* (X-J-K). Вершинам дерева, начиная снизу, можно следующим образом приписать значения: (1) если п—лист, помеченный X, то п имеет значение X, (2) если п — внутренняя вершина, помеченная 0, и ее пря- мыми потомками являются п1 и п2 со значениями и с2, то и имеет значение Bopv Значением дерева будем считать значение его корня. Напри- мер, значением дерева па рис. 11.8 будет в инфиксной записи /*(Х + Г). 365
ГЛ. 11. ОПТИМИЗАЦИЯ КОДА Рассмотрим кратко связь между блоками на промежуточном языке (разд. 11.1) и программами на языке ассемблера, которые мы только что определили. Прежде всего если дан приведенный блок, в котором (1) все операции бинарные, (2) на каждую входную переменную делается одна ссылка, (3) есть в точности одна выходная переменная, то граф, связанный с этим блоком, является деревом. По нашей терминологии это дерево синтаксическое. Значение дерева — это в то же время и значение блока. Можно естественным образом, оператор за оператором, пре- образовать блок на промежуточном языке в программу на языке ассемблера. Оказывается, что если при этом преобразовании учесть возможность оставлять вычисленные значения на сумма- торах, то оптимальную программу на языке ассемблера можно получить из данного приведенного открытого блока, произведя сначала только преобразование Т4, как это предлагалось в тео- реме 11.5, и выполнив затем преобразование в язык ассемблера. Однако все это, быть может, не вполне очевидно; читатель должен сам проверить все эти утверждения. Именно в резуль- тате существенной переделки многих определений из разд. 11.1 для случая программ на языке ассемблера мы добиваемся воз- можности показать, что нет такой оптимальной программы на языке ассемблера, которая не была бы связана с блоком на промежуточном языке, получаемым из приведенного открытого блока, некоторым естественным пооператорным преобразованием и преобразованием Т4. 11.2.2. Разметка деревьев Основное в алгоритме генерации кода для выражений — это метод назначения дополнительных меток вершинам синтаксиче- ского дерева. Такими метками будут целые числа, и в даль- нейшем мы будем ссылаться на них как на метки вершин, несмотря на то, что каждая вершина помечена также операцией или переменной. Целочисленные метки определяют номера сум- маторов, нужных для оптимального вычисления выражения. Алгоритм 11.1. Разметка синтаксического дерева. Вход. Синтаксическое дерево Т. Выход. Помеченное синтаксическое дерево. Метод. Вершинами дерева Т рекурсивно, начиная снизу, назначаем целочисленные метки: 366
11.2. АРИФМЕТИЧЕСКИЕ ВЫРАЖЕНИЯ (1) Если вершина есть лист, являющийся левым прямым по- томком своего прямого предка, или корень (т. е. дерево состоит из одной этой вершины), помечаем эту вершину 1; если вершина есть лист, являющийся правым прямым потомком, помечаем ее 0. (2) Пусть вершина п имеет прямых потомков п1 и пг, поме- ченных /j и /2. Если 1х^ь12, берем в качестве ее метки большее из чисел /х и Z3. Если 1Х = 1г, берем в качестве ее метки число /1 + 1- □ Пример 11.15, Арифметическое выражение /1» (В — С)/(О » (£ —Л)) изображено в виде дерева на рис. 11.9, на котором проставлены целочисленные метки. □ Дадим теперь алгоритм, преобразующий помеченное синтак- сическое дерево в программу на языке ассемблера для машины с N сумматорами. Мы покажем, что для любого N получаемая программа оптимальна относительно различных оценок, включая такие, как длина программы. Алгоритм 11.2. Построение кода на языке ассемб- лера для выражений. Вход. Помеченное синтаксическое дерево 7' и ,V сумматоров Ах, Аг, ..., Аы, где 1. Выход. Программа Р на языке ассемблера, после, последней команды которой значением становится v(T); т. е. Р, вы- числяет выражение, представленное деревом Т, и помещает результат на сумматор Ах. 367
ГЛ. И. ОПТИМИЗАЦИЯ КОДА Метод. Предполагается, что дерево Т помечено в соответ- ствии с алгоритмом 11.1. Затем рекурсивно выполняется про- цедура code(n, i). Входом для code служит вершина п дерева Г и целое число i от 1 до N. Число i означает, что в данный момент для вычисления выражения в вершине п доступны сум- маторы А;, А/+1, .... AN. Выходом для code(n, Z) служит после- довательность команд языка ассемблера, которая вычисляет значение v(n) и помещает результат на сумматор А;. Сначала выполняется code(n0, 1), где п„— корень дерева Т. Последовательность команд, генерированных этим вызовом про- цедуры code, и будет нужной программой на языке ассемблера. Процедура code(n, i). Предполагается, что п — вершина де- рева Т, a i — целое число между 1 и N. (1) Если п—лист, выполняем шаг (2). В противном случае выполняем шаг (3). (2) Если вызвана процедура code(n, i), а п — лист, то п всегда будет левым прямым потомком (или корнем, если п— единствен- ная вершина дерева). Если с листом п связано имя перемен- ной X, то code(n, i) = ‘LOAD X, А/ (это означает, что выходом процедуры code(n, Г) служит команда LOAD X, А,). (3) В это место мы приходим, только если п — внутренняя вершина. Пусть с вершиной п связана операция 6 и ее прямыми потомками являются п, и п2 с метками Z, и Z2 (см. рисунок). Следующий шаг определяется значениями меток Zx и Z2: (а) если L--C1 (п2 — правый лист), выполняем шаг (4), (б) если 1 Zx < Z2 и выполняем шаг (5), (в) если 1 <Z2^ZX и 1г < N, выполняем шаг (6), (г) если N < Zx и AZ</2, выполняем шаг (7). (4) code(n, i) = code(nx, i) ‘OP 0 A(, X, a; Здесь X — переменная, связанная с листом п2, а ОР 0 — код операции 0. Выходом для code(n, i) служит выход для code(n1, Z), сопровождаемый командой ОР 0 Ah X, А;. 368
11.2. АРИФМЕТИЧЕСКИЕ ВЫРАЖЕНИЯ (5) code(n, i) = code(rt2, i) codepi,, i +1) ‘OP 0 Д; + 1, A;, A)’ (6) code(n, i) = code(ii1, i) codepi.,, i+1) ‘OP 0 A,, A!+1, A/‘ (7) codepi, i) = codepi2, i) T <—newtemp ‘STORE A,-, T’ code(nt, i) ‘OP 0 At, T, Ai' Здесь newtemp—функция, которая при обращении к ней вырабатывает новую временную ячейку памяти для запоминания промежуточных результатов. □ Позже мы увидим, что при выполнении шагов (5) —(7) алго- ритма 11.2 справедливы соотношения между ZI; Z2 и i, приведен- Таблица II.5 Шаг Соотношение (5) (6) (7) 1=1 ные в табл. 11.5. Отметим также, что для алгоритма 11.2 тре- буются команды типа (4) вида ОР 0 А, В, А ОР 0 А, В, В Несколько усложнив процедуру code на шаге (5), можно избе- жать использования команд вида ОР 0 А, В, В не входящих в определенный нами выше набор команд машин с многими регистрами (см. упр. 11.2.11). Можно рассматривать code(n, i) как функцию, вычисляющую перевод в каждой вершине выражения в терминах переводов и меток ее прямых потомков. Чтобы лучше понять алгоритм 11.2, разберем несколько примеров. Пример 11.16. Пусть Т—синтаксическое дерево, состоящее лишь из вершины X (помеченной 1). В соответствии с шагом (2) code — это единственная команда LOAD X, At. □ 369
ГЛ. 11. ОПТИМИЗАЦИЯ КОДА Пример 11.17. Пусть Т — помеченное синтаксическое дерево, изображенное на рис. 11.10. В табл. 11.6 показано, как выра- батывается алгоритмом 11.2 программа на языке ассемблера для Т при N = 2. Приведены вызовы процедуры code(n, () и со- Рис. 11.10. Помеченное синтаксическое дерево с переводами. ответствующие им шаги алгоритма 11.2. Вершина указывается при помощи связанной с ней переменной или операции. Таблица 11.6 Вызоь Шаг алгоритма 11 .2 code(*, 1) code(Z, 1) code(+, 2) code(X, 2) (Зв) (2) (За) (2) Вызов code(A', 2) генерирует команду LOAD X, Аг, являю- щуюся переводом, связанным с вершиной X. Вызов code(-|~, 2) генерирует последовательность команд LOAD X, А2 ADD А2, Y, А2 являющуюся переводом для вершины +. Вызов code(Z, 1) генерирует команду LOAD Z, Alt являющу- юся переводом для вершины Z. Вызов code(*, 1) генерирует 370
11.2. АРИФМЕТИЧЕСКИЕ ВЫРАЖЕНИЯ окончательную программу — перевод корня: LOAD Z, Аг LOAD X, А2 ADD Аг, Y, А2 MULT Alt Аа, At Эта программа аналогична (но не идентична) программе из при> мера 11.14. Очевидно, что в конце программы на сумматоре А( будет значение Z* (X -f-Y). □ Пример 11.18. Применим алгоритм 11.2 при N = 2 к синтак- сическому дереву рис. 11.9. Последовательность вызовов code(n, i) приведена в табл. 11.7. Здесь *Л — ссылка на левый потомок Таблица 11.7 Вызов Шаг code(/, 1) (3г) code(*#> 1) (Зв) code(D, 1) (2) code(—д, 2) code(£, 2) (За) (2) code(*£, 1) (Зв) code(A 1) (2) code(—i, 2) (За) code(5, 2) (2) вершины /, *я — на правый потомок вершины/, —Л — на правый потомок вершины *Л, а —я — на правый потомок вершины *я. Указаны также шаги алгоритма 11.2, выполняемые при каждом вызове. Процедура code(/, 1) генерирует программу LOAD D, A, LOAD E, A2 SUBTR A2, F, A2 MULT Aj, A2, A STORE Alr TEMPI LOAD A, A, LOAD B, a2 SUBTR a2, c, a2 MULT A,, A2, A; DIV A,, TEMPI, A( 371
ГЛ. И. ОПТИМИЗАЦИЯ КОДА Здесь TEMPI—ячейка памяти, генерированная функцией newtemp. □ Докажем, что значение метки корня помеченного синтакси- ческого дерева, построенного алгоритмом 11.1, равно наимень- шему числу сумматоров, необходимому для того, чтобы вычис- лить выражение, не прибегая к командам STORE. Начнем с нескольких замечаний по поводу алгоритма 11.2. Лемма 11.18. Программа, выработанная процедурой codejn, i) в алгоритме 11.2, правильно вычисляет значение вершины п, по- мещая его на i-й сумматор. Доказательство. Элементарная индукция по высоте вершины. □ Лемма 11.9. Если алгоритм 11.2 при N доступных сумма- торах применяется к корню синтаксического дерева, то при вызове процедуры code(ra, i) в вершине п с меткой I либо (1) l~^N и для этого вызова доступны N сумматоров (т. е. 1 = 1), либо (2/ / < Л7 и для этого вызова доступны по крайней мере I сумматоров (т. е. — /+!)• Доказательство. Снова элементарная индукция, на этот раз по числу вызовов code(n, Г), сделанных до рассматриваемого вызова. □ Теорема 11.6. Пусть Т—синтаксическое дерево, I—метка его корня, N— число доступных сумматоров. Программа, вычисляю- щая Т без использования команд STORE, существует тогда и только тогда, когда Icx.H. Доказательство. Достаточность. Если 1-^.N, то шаг (7) процедуры codeRz, i) никогда не выполняется. Действительно, вершина, прямые потомки которой помечены числом не менее N, сама помечена числом не менее Д'4-1. Команда STORE гене- рируется только на шаге (7). Поэтому при 1 st .'V программа, вы- рабатываемая алгоритмом 11.2, не содержит команд STORE. Необходимость. Пусть 1>N. Поскольку N > 1, должно быть /2^2. Предположим, что утверждение неверно. Тогда без потери общности можно считать, что дерево Т имеет программу Р, вычисляющую его с помощью .V сумматоров, Р не содержит команд STORE и не существует синтаксического дерева Т', имеющего меньше вершин, чем Т, и также не удовлетворяющего утверждению. Поскольку метка корня дерева Т превосходит 1, Т не может состоять из единственного листа. Пусть л — корень, а п, и пг — его прямые потомки с метками Z, и/а соответственно. 372
11.2. АРИФМЕТИЧЕСКИЕ ВЫРАЖЕНИЯ Случай 1: 1^ = 1. Значение п можно вычислить, только если значение п1 появится в некоторый момент на сумматоре, поскольку п, не может быть листом. Формируем из Р новую программу Р', удаляя операторы, следующие за вычислением значения пг. Тогда Р' вычисляет поддерево с корнем nt и не содержит команд STORE. Таким образом, утверждение неверно при числе вершин, меньшем, чем в Г, вопреки предположению относительно Т. Случай 2: 1г — 1. Этот случай аналогичен случаю 1. Случай 3: ^ = 1г = 1—1. Мы уже предполагали, что никакие два листа не имеют одинаковых имен связанных с ними пере- менных. Без потери общности можно считать, что программа Р „коротка, насколько возможно" в том смысле, что если удалить любой из операторов, то в конце программы значения п в том же сумматоре уже не будет. Таким образом, первым оператором программы должен быть LOAD X, А, где X— имя переменной, связанной с некоторым листом дерева Т, так как иначе первый оператор можно было бы удалить. Пусть X—значение листа, являющегося потомком вершины п2 (возможно, самой вершины nJ. Случай, когда X—значение по- томка вершины п2, аналогичен; мы его рассматривать не будем. До тех пор пока не вычислится значение nlt всегда по крайней мере один сумматор будет хранить значение, содержащее X. Этим значением нельзя воспользоваться в правильном вычисле- нии значения п2. Поэтому из Р можно получить программу Р', вычисляющую значение п2, помеченную I—1, не использующую команд STORE и требующую одновременно не более N— 1 сум- маторов. Читателю предлагаем показать, что для Р' можно построить эквивалентную программу Р", для которой никогда не понадобится более N—1 различных сумматоров. (Отметим, что в Р' могут употребляться все N сумматоров, даже если одновременно их используется не более N—1.) Таким образом, утверждение теоремы неверно для поддерева с корнем п2, а это противоречит предположению о минимальности дерева Т. Отсюда следует, что теорема справедлива. □ 11.2.3. Программы с командами STORE Выясним теперь, сколько команд LOAD и STORE требуется для вычисления синтаксического дерева, если пользоваться N сумматорами, когда корень помечен числом, превышающим N. Нам пригодятся следующие определения. Определение. Пусть Т — синтаксическое дерево, а АГ— число доступных сумматоров. Вершина из Т называется старшей, если каждый ее прямой потомок помечен числом, не меньшим чем AL Вершина называется младшей, если она является листом и левым 373
ГЛ- 11. ОПТИМИЗАЦИЯ КОДА прямым потомком своего прямого предка (т. е. это лист с мет- кой 1). Пример 11.19. Рассмотрим синтаксическое дерево, изобра- женное на рис. 11.9, при N = 2. Здесь одна старшая вершина — корень и четыре младших вершины — листья со значениями А, В, D и Е. □ Лемма 11.10. Пусть Т—синтаксическое дерево. Программа Р, вычисляющая Т и использующая т команд LOAD, существует тогда и только тогда, когда Т имеет не более т младших вершин. Доказательство. Если присмотреться к процедуре code(n, i) из алгоритма 11.2, то можно заметить, что оператор LOAD вставляется только на шаге (2). Поскольку шаг (2) при- меняется только к младшим вершинам, достаточность доказана. Необходимость доказывается, как в теореме 11.6, с учетом того, что значение на сумматоре может появиться только в ре- зультате команды LOAD, а левый аргумент любой операции должен быть на сумматоре. □ Лемма 11.11. Пусть Т—синтаксическое дерево. Программа Р, вычисляющая Т и использующая М команд STORE, существует тогда и только тогда, когда Т имеет не более М старших вершин. Доказательство. Достаточность. Исследуя снова про- цедуру code(n, /), видим, что команда STORE вставляется только на шаге (7), а он применяется только к старшим вершинам. Необходимость. Эта часть доказывается индукцией по числу вершин в Т. Базис индукции, т. е. случай, когда дерево имеет вершину, тривиален, так как вершина помечена 1 и, значит, старших вершин нет. Предположим, что утверждение верно для синтаксических деревьев с числом вершин вплоть до k — 1, и пусть Т имеет k вершин. Рассмотрим программу Р, вычисляющую Т, и обозначим через М число старших вершин в Т. Без потери общности можно считать, что Р содержит не больше команд STORE, чем любая другая программа, вычисляющая Т. При М = 0 нужный резуль- тат очевиден, поэтому будем считать, что Л4^1. Тогда Р со- держит хотя бы одну команду STORE, поскольку метка старшей вершины не меньше Ц-1, и если бы в Р не было команд STORE, теорема 11.6 была бы неверна. Значение, запомненное первой командой STORE, должно быть значением некоторой вершины п из Т, а иначе было бы легко найти вычисляющую Т программу, в которой команд STORE меньше, чем в Р. Кроме того, по той же самой причине можно считать, что п не лист. Пусть Т' — синтаксическое дерево, полу- 374
11.2. АРИФМЕТИЧЕСКИЕ ВЫРАЖЕНИЯ чающееся из Т, если сделать вершину п листом и дать ей в ка- честве значения некоторое новое имя X. Тогда у Т' будет меньше вершин, чем у Т, так что к нему можно применить предполо- жение индукции. Можно найти программу Р', вычисляющую Т' и использующую ровно на одну команду STORE меньше, чем Р. Программа Р' получается из Р, если удалить в точности те операторы, которые нужны для вычисления первого запомнен- ного значения, и затем заменить в Р ссылки на ячейку, участву- ющую в этой команде STORE, именем X, пока в этой ячейке ие будет запомнено новое значение. Если мы сможем показать, что Т' имеет не менее М — 1 старших вершин, то лемма будет доказана, поскольку по пред- положению индукции Р' имеет не менее М — 1 команд STORE и, значит, Р имеет не менее М команд STORE. Ясно, что ни один из потомков вершины п в Т не может быть старшим, поскольку в этом случае будет неверна тео- рема 11.6. Рассмотрим старшую вершину п' в Т. Если п не является ее потомком, то/г'—старшая вершина в Г'. Таким обра- зом, достаточно рассмотреть только старшие вершины пх,п2, ... на пути от п к корню дерева Т. В соответствии с рассужде- ниями, проведенными в случае 3 теоремы 11.6, сама вершина п не может быть старшей. Первая вершина /г,, если она сущест- вует, не может тогда быть старшей в Т’. Одн.ако метка вер- шины п1 в Т' не меньше чем N, потому что ее прямой пото- мок, не являющийся предком вершины п, должен иметь метку не менее N и в Т, и в Г'. Следовательно, п2, /г,, . . . остаются старшими вершинами в Т'. Отсюда можно заключить, что Т' имеет не менее М — 1 старших вершин. Индукция проведена полностью. □ Теорема 11.7, Алгоритм 11.2 всегда вырабатывает кратчай- шую программу для вычисления данного выражения. Доказательство. В соответствии с леммами 11.10 и 11.11 алгоритм 11.2 генерирует программу с минимально возможным числом команд LOAD и STORE. Поскольку ясно, что мини- мальное число команд операций равно числу внутренних вер- шин дерева, а алгоритм 11.2 дает по одной такой команде для каждой внутренней вершины, то . утверждение теоремы оче- видно. □ Пример 11.20. Как указывалось в примере 11.19, арифмети- ческое выражение па рис. 11.9 имеет одну старшую и четыре младших вершины (в предположении, что ,V~ 2). Оно имеет также пять внутренних вершин. Таким образом, для его вычис- ления требуется не менее десяти операторов. Программа из 375
ГЛ. И. ОПТИМИЗАЦИЯ КОДА примера 11.18 содержит как раз десять операторов. Отметим, что среди них одна команда STORE, четыре LOAD, а осталь- ные— команды операций. □ 11.2.4. Влияние некоторых алгебраических законов Определим оценку синтаксического дерева как сумму (1) числа внутренних вершин, (2) числа старших вершин, (3) числа младших вершин. Результаты предыдущего раздела показывают, что эта оценка служит разумной мерой „сложности" синтаксического дерева, поскольку число команд, необходимых для вычисления синтак- сического дерева, равно его оценке. Рис. 11.11. Ассоциативное преобразование синтаксических деревьев. Часто к некоторым операциям можно применить алгебраи- ческие законы и с их помощью уменьшить оценку данного синтак- сического дерева. Из разд. 11.1.6 известно, что каждый алгеб- раический закон индуцирует соответствующее преобразование синтаксического дерева. Например, если п — внутренняя вер- шина синтаксического дерева, связанная с коммутативной опе- рацией, то коммутативное преобразование меняет порядок пря- мых потомков вершины п. Аналогично, если 9 — ассоциативная операция (т. е. «9 (Р6у) ~ (сс9Р)9у), то, применяя соответствующее преобразование деревьев, можно перевести друг в друга два дерева, изображен- ные на рис. 11.11. Ассоциативное преобразование, приведенное 376
11.2. АРИФМЕТИЧЕСКИЕ ВЫРАЖЕНИЯ на рис. 11.11, соответствует преобразованию блоков х — вес х' <- лее Y^-Aex^ Y^x'ec В разд. 11.1.6 после применения преобразования слева направо оператор X -—В9С сохранялся. Однако теперь после преобра- зования этот оператор становится бесполезным, так что его можно удалить, не меняя значения блока. Определение. Если даио множество Л алгебраических зако- нов, то два синтаксических дерева Tt и Т2 будем называть эквивалентными относительно Л и писать если суще- ствует последовательность преобразований, выводимая из этих законов, переводящая 7\ в Г2. Через [Т]^ будем обозначать класс эквивалентности деревьев {T'\T=^T'}. Таким образом, если дано синтаксическое дерево Т и известно, что выполняются алгебраические законы из некоторого множе- ства законов Л, то для нахождения оптимальной программы для Т надо искать в [Tj^ дерево выражения с минимальной оценкой. Если дерево с минимальной оценкой найдено, то для нахожде- ния оптимальной программы можно применить алгоритм 11.2. Теорема 11.7 гарантирует, что получаемая программа будет оптимальной. Если каждый закон сохраняет число операций, как в слу- чае коммутативного и ассоциативного законов, достаточно мини- мизировать сумму чисел старших и младших вершин. В качестве примера приведем алгоритм этой минимизации сначала для случая, когда некоторые операции коммутативны, а затем для случая, когда некоторые коммутативные операции также и ассо- циативны. По данному синтаксическому дереву Т и множеству Л алгеб- раических законов приведенный ниже алгоритм будет строить синтаксическое дерево Т'б[Т]^ с минимальной оценкой при условии, что Л содержит только коммутативные законы, приме- нимые к определенным операциям. Затем к Т' можно будет при- менить алгоритм 11.2 и найти оптимальную программу для исходного дерева Т. Алгоритм 11.3. Построение дерева с минималь- ной оценкой, некоторые операции которого ком- мутативны. Вход, Синтаксическое дерево Т (с тремя или более вер- шинами) и множество Л коммутативных законов. Выход. Синтаксическое дерево из [Г]^ с минимальной оценкой. 377
ГЛ. 11. ОПТИМИЗАЦИЯ КОДА Метод. Ядро алгоритма составляет рекурсивная процедура commute(n), аргументом которой служит вершина п синтакси- ческого дерева, а результатом—модифицированное поддерево с вершиной п в качестве корня. Вначале вызывается commute),1„), где п„ — корень данного дерева Т. Процедура commute(n). (1) Если п — лист, полагаем commute(n) — п. (2) Если п — внутренняя вершина, рассмотрим два случая: а) Пусть вершина п имеет два прямых потомка п1 и па (в указанном порядке) и операция, связанная с п, ком- мутативна. Если /? ।— лист, а /га нет, то выход сот- mute(n)—дерево на рис. 11.12, а. б) Во всех других случаях выход commute(n)—дерево на рис. 11.12, б. □ Рис. 11.12. Результат процедуры commute. Пример 11.21. Рассмотрим рис. 11.9 и предположим, что коммутативно только умножение. Результат применения алго- 378
11.2. АРИФМЕТИЧЕСКИЕ ВЫРАЖЕНИЯ ритма 11.3 к этому дереву показан на рис. 11.13. Отметим, что корень на рис. 11.13 помечен 2 и что здесь две младшие вершины. Таким образом, если у нас два сумматора, то для вычисления этого дерева требуется только семь команд, а для дерева на рис. 11.9—десять. □ Теорема 11.8. Если допустимо применение одного только ком- мутативного для некоторых операций закона, то алгоритм 11.3 вырабатывает такое синтаксическое дерево из класса эквивалент- ности для данного дерева, которое имеет минимальную оценку. Доказательство. Легко видеть, что коммутативный закон не может изменить числа внутренних вершин. Простая индук- ция по высоте вершины показывает, что алгоритм 11.3 миними- зирует число младших вершин и метки, которые должны быть у вершин после применения алгоритма 11.1. Следовательно, минимизируется также число старших вершин. П Ситуация усложняется, когда некоторые операции одновре- менно коммутативны и ассоциативны. В этом случае уменьшить число старших вершин часто можно за счет существенного пре- образования дерева. Определение. Пусть Т — синтаксическое дерево. Множество S из двух или более его вершин называется кистью, если (1) все вершины в S внутренние и представляют одну и ту же ассоциативную и коммутативную операцию, 379
ГЛ. И. ОПТИМИЗАЦИЯ КОДА (2) вершины из S вместе с соединяющими их дугами обра- зуют дерево, (3) ни одно из собственных надмножеств множества S не обладает свойствами (1) и (2). Корнем кисти называется корень дерева, о котором идет речь в пункте (2). Прямыми потомками кисти S называются те вершины из Т, которые не принадлежат S, но являются пря- мыми потомками вершин из S. Пример 11.22. Рассмотрим синтаксическое дерево на рис. 11.14, в котором сложение и умножение коммутативны, а никакие Три кисти обведены штриховыми линиями. Кисть, включаю- щая корень дерева, имеет в качестве прямых потомков в порядке слева направо корень кисти 2, вершину, с которой сопостав- лена операция вычитания, и корень кисти 3. □ Заметим, что кисти синтаксического дерева Т определяются однозначно и не пересекаются. Для нахождения в [Т]^ дерева с минимальной оценкой, когда Л содержит законы, отражаю- щие тот факт, что одни операции коммутативны и ассоциа- тивны, а другие только коммутативны, вводится понятие ассоциа- тивного дерева, в котором кисти представляются одной вершиной. 380
11.2. АРИФМЕТИЧЕСКИЕ ВЫРАЖЕНИЯ Определение. Пусть Т — синтаксическое дерево. Ассоциатив- ным деревом Т' для Т назовем дерево, получающееся заменой каждой кисти S в Т на единственную вершину п с той же ассоциативной и коммутативной операцией, что и у вершины кисти S. Прямые потомки кисти в Т становятся прямыми потомками вершины п в Т'. Пример 11.23. Рассмотрим синтаксическое дерево на рис. 11.15. Предполагая, что сложение и умножение ассоциа- тивны и коммутативны, получаем кисти, обведенные на рис. 11.15 Рис. 11.15. Синтаксическое дерево с кистями. штриховыми линиями. Ассоциативное дерево для Т изображено иа рис. 11.16. Отметим, что ассоциативное дерево не обязано быть двоичным. □ Вершины ассоциативного дерева можно пометить целыми числами, начиная снизу, следующим образом: (1) Лист, являющийся самым левым прямым потомком своего предка, помечается 1. Все остальные листья помечаются 0. (2) Пусть п — внутренняя вершина, прямые потомки которой л1г па, ..., пт помечены llt I,, ..., l,„, (а) Если одно из чисел llt /2.1„ превосходит осталь- ные, берем его в качестве метки вершины п. (б) Если вершина п имеет коммутативную операцию и nt — внутренняя вершина с /, = 1, а остальные вершины 381
ГЛ. 11. ОПТИМИЗАЦИЯ КОДА «1, • /г,-,, п!+1, ...,пт — листья, то в качестве метки вершины п берем 1. (в) Если условие (б) не выполняется, lt = lj для неко- торых i =jt= j и /; не меньше остальных lk, в качестве метки вершины п берем /;+1. Рис. 11.16. Accoi нативное дерево. Рис. 11.17. Помеченное ассоциативное дерево. Пример 11.24. Рассмотрим ассоциативное дерево на рис. 11.16. Помеченное ассоциативное дерево изображено на рис. 11.17. 382
11.2. АРИФМЕТИЧЕСКИЕ ВЫРАЖЕНИЯ Отметим, что к третьему и четвертому прямым потомкам корня применяется условие (26) процедуры разметки, поскольку умножение коммутативно. □ Приведем теперь алгоритм, принимающий на вход данное синтаксическое дерево и вырабатывающий такое дерево из класса эквивалентности для данного дерева, которое имеет минималь- ную оценку. Алгоритм 11.4. Построение синтаксического де- рева с минимальной оценкой в предположении, что одни операции коммутативны, другие ком- мутативны и ассоциативны и больше никакие алгебраические законы не учитываются. Вход. Синтаксическое дерево Т и множество Л коммутатив- ных и коммутативно-ассоциативных законов. Выход. Синтаксическое дерево из [Т]^ с минимальной оценкой. Метод. Строим сначала помеченное ассоциативное дерево Т' для Т. Затем вычисляем acommute(n0), где acommute — процедура, определенная ниже, а — корень дерева Т'. Выходом acommute(/i0) служит синтаксическое дерево из [Т]^ с минимальной оценкой. Процедура acommiite(zi). Аргументом п служит вершина помеченного ассоциативного дерева. Если п--лист, полагаем acommute(n) — п. Если п — внут- ренняя вершина, рассмотрим три случая: (1) Пусть вершина имеет два прямых потомка п, и п2 (в ука- занном порядке) и операция, связанная с п, коммутативна (и, возможно, ассоциативна). (а) Если п,—лист, а пг нет, то выход acommute(n) — дерево на рис. 11.18, а. (б) В противном случае acommute(n) — дерево на рис. 11.18,6. (2) Предположим, что операция 9, связанная с п, коммута- тивна и ассоциативна и вершина п имеет прямых потомков пг, п2 tim, пг^З (в порядке слева направо). Пусть игаах— вершина из пг, ...,пт с наибольшей меткой. Если одной и той же наибольшей меткой помечены две или более вершин, то вершину игаах выбираем так, чтобы она была внутренней. Обозначим через pL, рг, , pm-i вершины в К, ..., —{игааХ} в любом порядке. Тогда выходом acommute(zr) служит двоичное дерево на рис. 11.19, где r, (l !) — новые вершины, связанные с коммутативной и ассоциативной операцией 9, соответствую- щей вершине п. 3S3
ГЛ. 11. ОПТИМИЗАЦИЯ КОДА (3) Если операция, связанная с п, не коммутативна и не рис. Рис. 11.18. Результат процедуры acommute. Пример 11.25. Применим алгоритм 11.4 к помеченному ассо- циативному дереву, изображенному на рис. 11.17. Применял acommute, а точнее случай (2) к корню, берем в качестве итах первого слева прямого потомка. Двоичное дерево, являющееся выходом алгоритма 11.4, показано на рис. 11.20. □ Закончим этот раздел доказательством того, что алгоритм 11.4 находит в [Т]^ дерево с минимальной оценкой. Централь- ной в нашем доказательстве будет следующая лемма. 0 В этом случае п имеет ровно два прямых потомка.— Прим, иерее. 384
11.2. арифметические выражения Лемма 11.12. Пусть Т — помеченное синтаксическое дерево, а S—кисть в Т1). Предположим, что метки г прямых потомков вершин из S больше или равны N, где N—число сумматоров. Доказательство. Будем доказывать лемму индукцией по числу вершин в Т. Базис, случай одной вершины, тривиален. Предположим поэтому, что утверждение верно для всех деревьев с числом вершин, меньшим, чем в Т. Пусть п — корень кисти S, и пусть п имеет прямых потомков п, и п2 с метками lL и /2. Пусть 7\ и Т.г — имена поддеревьев с корнями zi, и п2 соответ- ственно. Случай 1: ни zi£, ни п., не принадлежат S. Очевидно, что в этом случае утверждение верно. <) Доказательство буде! согласовано с формулировкой, если S —либо кисть, либо одиночная вершина, не входящая в кисть.— Прим, перев. 13 А. Ахо, Д-к. Ульман, т. 2 385
ГЛ. II. ОПТИМИЗАЦИЯ КОДА Случай 2: п1 принадлежит S, а п2 нет. Поскольку число вер- шин в дереве Т1 меньше, чем в 7", к нему применимо предпо- ложение индукции. Таким образом, в Т, множество 8— jn} содержит по крайней мере г—2 старших вершин, если и по крайней мере г—1 старших вершин, если /а < N. В послед- нем случае утверждение тривиально. В обоих случаях результат очевиден, если г 1. Поэтому рассмотрим случай г > 1 и N. Рис. 11.20. Выход алгоритма 11.4. Тогда 3— {/г} имеет по крайней мере одного прямого потомка, метка которого больше или равна ЛГ, так что l^N. Таким образом, п—старшая вершина и S содержит не менее г—1 старших вершин. Случай 3: аг принадлежит S, а п2 нет. Этот случай анало- гичен случаю 2. Случай 4: п1 и пг принадлежат 3. Пусть rt прямых потом- ков вершин из 3 с метками, не меньшими N, являются потом- ками вершины ni, а га из них являются потомками вершины п2. Тогда r1 + rs = r. По предположению индукции части кисти 3 336
11.2. АРИФМЕТИЧЕСКИЕ ВЫРАЖЕНИЯ в Tt и Т2 имеют соответственно не менее rt — 1 и не менее гг — 1 старших вершин. Если ни г2, ни гг не равны нулю, то N и 12 4- N, так что п — старшая вершина. Таким образом, S имеет по крайней мере (г1—1) + (т2—1)4-1 =г—1 старших вершин. Если г,--О, то г.2 = г, так что часть кисти S в Тг имеет не менее г—1 старших вершин. Случай г3 = 0 аналоги- чен. □ Теорема 11.9. Алгоритм 11.4 вырабатывает дерево из [Т]^ с минимальной оценкой. Доказательство. Прямая индукция по числу вершин в ассоциативном дереве А показывает, что в результате при- менения процедуры acornmute к его корню будет построено син- таксическое дерево Т, корень которого после разметки, описан- ной в алгоритме 11.1, помечен так же, как корень дерева А. Никакое дерево из не имеет корня с меткой, меньшей, чем у корня дерева А, и никакое дерево из [Т]^ не имеет мень- ше, чем в А, старших и младших вершин. Предположим, что это не так. Тогда пусть Т — наименьшее1) дерево, для которого одно из этих условий нарушается. Пусть О — операция в корне дерева Т. Случай 1: операция 9 не ассоциативна и не коммутативна. Любое ассоциативное или коммутативное преобразование дере- ва Т должно совершаться целиком внутри поддерева, корнем которого служит один из двух прямых потомков корня дерева Т. Таким образом, касается ли нарушение метки, числа старших или числа младших вершин, оно должно проявиться в одном из этих поддеревьев, что противоречит минимальности дерева Т. Случай 2: операция 0 коммутативна, но не ассоциативна. Этот случай аналогичен случаю 1, но теперь коммутативное пре- образование можно применить к корню. Но на шаге (1) про- цедуры acornmute уже учитывалась возможность применения этого преобразования, так что любое нарушение в дереве Т вновь приведет к нарушению в одном из его поддеревьев. ') Здесь «наименьшее» понимается в следующем смысле. По каждому дан- ному синтаксическому дереву Т( можно построить ассоциативное дерево А. В результате применения к А процедуры acornmute получается синтакси- ческое дерево Т, которому соответствует множество 1^1^- Выберем теперь из всех множеств [Т] для всевозможных деревьев 7\ все деревья, для ко- торых при сопоставлении с соответствующим деревом А нарушается одно из перечисленных выше условий. Размер (число вершин) этих деревьев ограничен снизу, и нижняя граница достигается. Выберем среди этих деревьев дерево с наименьшим числом вер- шин.— Прим, перев. 13* 337
ГЛ. И. ОПТИМИЗАЦИЯ КОДА Случай 3: операция 0 коммутативна и ассоциативна. Пусть S — кисть, содержащая корень. Можно считать, что ни в одном из поддеревьев, корнями которых служат прямые потомки вер- шин из S, не нарушается ни одно из указанных выше условий. Любое ассоциативное или коммутативное преобразование должно совершаться целиком внутри одного из этих поддеревьев или целиком внутри S. Если внимательно присмотреться к шагу (2) процедуры acommute, станет ясно, что число младших вершин, возникающих из S, минимально. По лемме 11.12 число стар- ших вершин, возникающих из S, минимально (для того чтобы это увидеть, надо вновь исследовать результат процедуры acom- mute), и значит, метка корпя минимальна. Наконец, видно, что изменения, вносимые алгоритмом 11.4, всегда можно совершить с помощью ассоциативных и коммута- тивных преобразований. □ УПРАЖНЕНИЯ 11.2.1. Предполагая, что не выполняются никакие алгебраи- ческие законы, найдите оптимальную программу на языке ассемб- лера при числе сумматоров Л'= 1, 2 и 3 для каждого из сле- дующих выражений: (а) А — В*С — D*(E-t-F), (б) Л + (В + (С*(О+Е/Е + <3)*Я)) + (/ +J), (в) (А * (В-С)) * (D * (Е » F)) + (G + {И + /)) + (J + {К + Е))). Вычислите оценку каждой из найденных программ. 11.2.2. Повторите упр. 11.2.1 в предположении, что сложе- ние и умножение коммутативны. 11.2.3. Повторите упр. 11.2.1 в предположении, что сложе- ние и умножение коммутативны и ассоциативны. 11.2.4. Пусть Е — бинарное выражение с k операциями. Ка- кое максимальное число скобок требуется для того, чтобы вы- разить Е без лишних скобок? *11.2.5. Пусть Т — двоичное синтаксическое дерево, корень которого после применения алгоритма 11.1 имеет метку N ^2. Покажите, что Т содержит не менее 3x2'v-2—1 внутренних вершин. 11.2.6. Пусть Т—дерево бинарного выражения с k внутрен- ними вершинами. Покажите, что Т может содержать не более k младших вершин. *11.2.7. Покажите, что при данном N > 2 дерево с М стар- шими вершинами содержит не менее 3(Л1 + 1)2Л"2 — 1 внутрен- них вершин. 388
УПРАЖНЕНИЯ *11.2.8. Какова максимальная оценка двоичного синтаксичес- кого дерева с k вершинами? *11.2.9. Каков максимальный выигрыш в оценке двоичного синтаксического дерева с k вершинами при переходе от маши- ны с N сумматорами к машине с А 4-1 сумматорами? **11.2.10. Пусть Л — произвольное множество алгебраических законов. Разрешима ли проблема эквивалентности относитель- но Л двух двоичных синтаксических деревьев? 11.2.11. Для алгоритма 11.2 определите процедуру code(rzг2, .... ;\]), которая вычисляет значение вершины п, пользуясь сумматорами A/t, Ait.....A!t, и помещает результат на сумматоре A(l. Покажите, что если взять в качестве шага (5) code(n,[Z1, I......................г\]) = code(ns,([t„ iit i3..г\]) codefrij^'t, i3, i„ ... ,г\]) ‘OP 0 ag, Аг>, a,; то алгоритм 11.2 можно модифицировать так, что все команды языка ассемблера типов (3) и (4) примут вид ОР 0 А, В, А 11.2.12. Пусть f |а| при 6>0 sign(a, Ь) = ? 0 при 6 = 0 I — |о| при b < 0 Покажите, что операция sign ассоциативна, но не коммутатив- на. Дайте примеры других операций, ассоциативных, но не коммутативных. *11.2.13. Каждая из команд LOAD Л4, А STORE А,М ОР 0 А, М, В использует одно обращение к памяти. Если В—сумматор, то ОР 0 А, В, С вообще не содержит обращений к памяти. Най- дите минимальное число обращений к памяти, генерируемое программой, вычисляющей двоичное синтаксическое дерево с k вершинами. *11.2.14. Покажите, что, алгоритм 11.2 вырабатывает про- грамму, требующую при вычислении данного выражения мини- мального числа обращений к памяти. *11.2.15. Взяв в качестве входной грамматики Go, постройте схему синтаксически управляемого перевода, переводящего ин- 13*А. Ахо. Дж. Ульман, т. 3 389
ГЛ. II. ОПТИМИЗАЦИЯ КОДА фиксные выражения в оптимальную программу на языке ассем- блера. Считайте, что имеется N сумматоров и (а) не выполняются никакие алгебраические законы, (б) сложение и умножение коммутативны, (в) сложение и умножение ассоциативны и коммутативны. 11.2.16. Приведите алгоритмы реализации процедур code, commute и acommute за линейное время. *11.2.17. Некоторые операции могут потребовать дополнитель- ных сумматоров (например, вызов подпрограмм или арифметика с кратной точностью). Модифицируйте алгоритмы 11.1 и 11.2 так, чтобы учитывать эту возможную потребность в дополни- тельных сумматорах со стороны операций. 11.2.18. Алгоритмы 11.1 —11.4 также можно применять к произвольному двоичному графу, если сначала с помощью расщепления вершин преобразовать его в дерево. Покажите, что алгоритм 11.2 в этом случае ие всегда будет генерировать оптимальную программу. Оцените, насколько плохим он может оказаться при этих условиях. 11.2.19. Обобщите алгоритмы 11.1 —11.4 так, чтобы они могли обрабатывать выражения, включающие операции с произволь- ным числом аргументов. *11.2.20. Арифметические выражения могут содержать также и унарные операции ф- и —. Постройте алгоритм генерации оптимального кода для этого случая. (Предполагается, что все операнды различны и что четыре бинарные арифметические опе- рации и унарные + и — связаны обычными алгебраическими законами.) *11.2.21. Постройте алгоритм генерации оптимального кода для одного арифметического выражения, в котором каждый операнд является либо отличной от других переменной, либо целой константой. Считайте, что для сложения и умножения выполняются ассоциативный и коммутативный законы и спра- ведливы следующие тождества: (1) а + 0 = 0-|-а = а, (2) а* 1 — 1 »а=а, (3) сфс^с,, где с3 — целое число, результат применения опе- рации 0 к целым числам сг и с2. 11.2.22. Найдите алгоритм генерации оптимального кода для одного логического выражения, в котором каждый операнд яв- ляется либо отличной от других переменной, либо логической константой (0 или 1). Считайте, что логическое выражение вклю- чает операции и, или, ие и они удовлетворяют законам булевой алгебры (см. том 1). 390
УПРАЖНЕНИЯ **11.2.23. В некоторых ситуациях две или более операции мо- гут выполняться параллельно. Алгоритмы из разд. 11.1 и 11.2 предполагают последовательное выполнение. Однако, если ма- шина способна выполнять параллельные операции, можно попы- таться так упорядочить выполнение, чтобы порождалось как можно больше одновременных параллельных вычислений. Пред- положим, например, что у нас есть машина с четырьмя реги- страми, в которой одновременно могут выполняться четыре опе- Рис. 11.21. Дерево для параллельных вычислений. можно представить так, как показано на рис. 11.21. На первом шаге нужно поместить Аг в первый регистр, А„ — во второй, At — в третий, А, — в четвертый. На втором шаге нужно при- бавить Л2 к содержимому регистра 1, Л,— к содержимому ре- гистра 2, Ав — к содержимому регистра 3, а Аа — к содержимому регистра 4. После этого шага регистр 1 будет содержать Л1 + Л2, регистр 2 будет содержать Л3 + Л4 и т. д. На третьем шаге прибавляем содержимое регистра 2 к содержимому реги- стра 1, а содержимое регистра 4 к содержимому регистра 3. На четвертом шаге прибавляем содержимое регистра 3 к содер- жимому регистра 1. Постройте машину с N регистрами, в ко- торой на одном шаге может выполняться до N параллельных операций. Модифицируйте алгоритм 11.1 так, чтобы он генери- ровал оптимальный код (в смысле минимального числа шагов) для одного арифметического выражения с различными операн- дами для такой машины. Проблема для исследования 11.2.24. Найдите эффективный алгоритм, который будет ге- нерировать оптимальный код того же типа, что и рассматривае- мый в этом разделе, но для произвольного блока. 13** 391
ГЛ. 11. ОПТИМИЗАЦИЯ КОДА Упражнение на программирование 11.2.25. Напишите программы, реализующие алгоритмы 11.1 — 11.4. Замечания по литературе Генерации хорошего кода дли арифметических выражений для конкретных машин или классов машин посвящено много статей. Флойд [1961а] описывает ряд методов оптимизации арифметических выражений, включая определение общих подвыражений. Он предлагает также, чтобы второй операнд некомму- тативной бинарной операции вычислялся первым. Андерсон [1964] дает алго- ритм генерации кода для машины с одним регистром, по существу совпада- ющий с кодом, вырабатываемым алгоритмом 11.1 при ,V=1. Наката [1967] и Мейерс [1965] приводят аналогичные результаты. Число регистров, требуемых для вычисления дерева выражения, иссле- довали Наката [1967], Редзиевский [1969], Сети и Ульман [1970]. Алгоритмы 11.1 —11.4 в том виде, в каком оии представлены здесь, разработаны Сети и Ульманом [1970]. Упр. 11.2.11 предложил Стокхаузен. Бити [1972] и Фрейли [1970] исследовали расширения, включающие операцию унарного минуса. Чен [1972] обобщил алгоритм 11.2 на некоторые ориентированные ациклические графы. Эффективный алгоритм генерации оптимального кода для произвольных выражений не известен. Один эвристический метод использования регистров в процессе вычисления выражения ссноваи на следующем алгоритме. Предположим, что должно вычисляться выражение а, а его значение должно запоминаться в быстром регистре (сумматоре). (1) Если значение а уже запомнено в некотором регистре i, то ие пере- вычисляем а. Регистр i находится теперь „в употреблении". (2) Если значение а ие запомнено ни в каком регистре, запоминаем его в очередном свободном регистре, скажем /. Регистр / находится теперь в упо- треблении. Если нет свободных доступных регистров, то содержимое некото- рого регистра k запоминаем в основной памяти, а значение а запоминаем в регистре k. Регистр k выбираем так, чтобы к его значению как можно дольше не было обращения. Бнледи [1966] показал, что в некоторых ситуациях этот алгоритм опти- мален. Однако этот алгоритм (разработанный для листования) предполагает модель, ие совпадающую в точности с моделью линейного кода. В частности, порядок вычислений считается фиксированным, в то время как в разд. 11.1 и 11.2 было показано, что, переупорядочивая вычисления, можно добиться значительного-выигрыша. Аналогичная задача распределения регистров исследуется в работе Хор- вица и др. [1966]. Там предполагается, что дана последовательность операций, обращающаяся к значениям и изменяющая их. Задача заключается в том, чтобы занести эти значения в быстрые регистры так, чтобы число записей и считываний из быстрых регистров в основную память было минимальным. Их решение сводится к выбору пути с минимальной оценкой иа ориентиро- ванном ациклическом графе возможных решений. Даются методы уменьшения размера графа. Дальнейшее исследование распределения регистров, когда по- рядок вычислений не фиксирован, проведено Кеннеди [1972] и Сети [1972]. Перевод арифметических выражений в код для параллельных машин из- лагается Аллардом и др. [1964], Хеллерманом [1966], Стоуном [1967], Бэром и Бове [1968]. Общая задача оптимального распределения задач между па- 392
11.3. ПРОГРАММЫ С ЦИКЛАМИ раллельными процессорами очень трудна. Некоторые ее интересные аспекты обсуждаются Грэхемом [1972]J). 11.3. ПРОГРАММЫ С ЦИКЛАМИ При рассмотрении программ, содержащих циклы, мы не можем осуществлять автоматическую оптимизацию. Основные трудности связаны с проблемами неразрешимости. Для двух произвольных программ не существует алгоритма, выясняющего, эквивалентны ли они в каком-нибудь смысле. Как следствие этого не сущест- вует алгоритма, который находил бы по данной программе эк- вивалентную ей и оптимальную относительно какой-нибудь оценки. Эти результаты становятся понятными, если вспомнить, что существует, вообще говоря, сколько угодно способов вычисле- ния одной и той же функции. Таким образом, существует бес- конечное множество алгоритмов, которые можно использовать для реализации функции, определяемой исходной программой. Если мы хотим получить полную оптимизацию, то компилятор должен быть способен найти наиболее эффективный алгоритм для функции, вычисляемой исходной программой, а затем сге- нерировать для него наиболее эффективный код. Излишне го- ворить, что как с теоретической, так и с практической точек зрения таких оптимизирующих компиляторов ие может быть. Тем не менее во многих ситуациях можно указать набор преобразований, применимых к исходной программе для умень- шения размера и/или увеличения скорости результирующей объектной программы. В этом разделе мы исследуем несколько таких преобразований. Благодаря их широкому распростране- нию, они стали известны как „оптимизирующие" преобразования. Точнее было бы называть их преобразованиями „улучшения кода". Однако мы будем следовать традиции и пользоваться более популярным, хотя и менее точным термином „оптимизирующее преобразование". Главной нашей целью будет уменьшение вре- мени выполнения объектной программы. Начнем с определения промежуточных программ с циклами. Эти программы будут весьма примитивными, так что основные концепции мы изложим, не вдаваясь в кучу мелких подробностей. Затем определим граф управления программы. Граф управле- ') Оптимизация арифметических выражений, включающая выделение общих подвыражений и такое преобразование программы, что эти общие подвыра- жения вычисляются только один раз, описана в работах: [Ершов, 19586], [Камынин, Любимский, Шура-Бура, 1958], [Ершов, 1958а], [Китов, Криницкий, 1959], [Ершова, Мостинская, Руднева, 1961], [Поттосин, 1965]. При этом полностью учитывалась коммутативность сложения и умножения. В работах Ершова [19586] и Поттосипа [1965] приведены алгоритмы экономии выраже- ний, работающие за линейное время. — Прим, перед. 393
ГЛ. И. ОПТИМИЗАЦИЯ КОДА ния — это двумерное представление программы, отражающее по- рядок выполнения операторов программы. Обычно двумерная структура дает более наглядное представление, нежели линейная последовательность операторов. В оставшейся части этого раздела мы опишем ряд важных преобразований, применимых к программе с целью уменьшить время выполнения объектной программы. В следующем разделе рассмотрим, как собрать вместе всю информацию, необходимую для применения некоторых из преобразований, описанных в этом разделе. 11.3.1. Модель программы Мы будем использовать для программ представление, про- межуточное между исходной программой и языком ассемблера. Программа состоит из последовательности операторов. Каждый оператор можно пометить идентификатором, за которым следует двоеточие. Существует пять основных типов операторов: при- сваивание, переход, условный, ввод-вывод и останов. (1) Оператор присваивания—это цепочка вида А <—OBj. ..Вг, где А— переменная, В1Г ..., Вг—переменные или константы, 0 — r-местная операция. Как и в предыдущих разделах, для бинарных операций обычно будем пользоваться инфиксной записью. Оператор вида А >—В также будем относить к этой категории. (2) Оператор перехода — это цепочка вида goto <метка> где <метка> — цепочка букв. Будем предполагать, что если в про- грамме употребляется оператор перехода, то метка, следующая за goto, появляется в качестве метки только одного оператора программы. (3) Условный оператор имеет вид if А <отношепие> В goto <метка> где А и В — переменные или константы, а <отношение> — бинар- ное отношение, такое, как <, =, (4) Оператор ввода-вывода—это либо оператор чтения вида read А где А — переменная, либо оператор записи вида write В 394.
11.3. ПРОГРАММЫ С ЦИКЛАМИ где В — переменная или константа. Для удобства последователь- ность операторов read А1 read Л2 read Ап будем изображать в виде read A,, А2, .... Ап Аналогичное соглашение у нас будет и для операторов записи. (5) Наконец, оператор останова—это команда halt. Интуитивный смысл операторов каждого типа должен быть ясен. Например, условный оператор вида if Л г В goto L означает, что если между текущими значениями Л и В выпол- няется отношение г, то управление должно передаваться на опе- ратор, помеченный L. В противном случае управление переходит к следующему оператору. Оператор определения (или просто определение) — это оператор вида read А или А <—6^. . ,ВГ. Про оба эти оператора говорят, что они определяют переменную А. Сделаем еще несколько предположений относительно программ. Переменные—это либо простые переменные, например Л, В, С, ..., либо переменные, индексированные одной простой переменной или константой, например Л(1), Л(2), Л(/) или Л(7). Далее будем считать, что все переменные, на которые в программе есть ссылки, либо должны быть входными переменными (т. е. появляться в предыдущем операторе чтения), либо должны ранее определяться с помощью оператора присваивания. Наконец, будем предполагать, что каждая программа содержит хотя бы один оператор останова и, если программа заканчивается, по- следний выполненный оператор—это оператор останова. Выполнение программы начинается с первого оператора про- граммы и продолжается, пока не встретится оператор останова. Предполагается, что каждая переменная имеет известный тип (например, целое, вещественное) и ее значение в любой момент в процессе выполнения либо не определено, либо представляет собой некоторую величину подходящего типа. (Будем считать, что все используемые операторы соответствуют типам перемен- ных, к которым они применяются, и, когда надо, происходит преобразование типов.) 395
ГЛ 11. ОПТИМИЗАЦИЯ КОДА Вообще говоря, входные переменные программы — это те, которые связаны с операторами чтения, а выходные — с опера- торами записи. Присваивание значения каждой входной пере- менной при каждом чтении называется входным присваиванием. Значение программы при некотором входном присваивании—это последовательность значений, записанных выходными перемен- ными в процессе выполнения программы. Две программы будем считать эквивалентными, если для каждого входного присваива- ния они имеют одинаковые значения1). Это определение эквивалентности обобщает определение экви- валентности блоков (разд. 11.1). Чтобы убедиться в этом, пред- положим, что два блока 33l = (Pl, и2) и ^2 = (Ра, /а, U2) эквивалентны в смысле разд. 11.1. Преобразуем очевидным об- разом блоки и ®2 в программы 3\ и 5%. Иными словами, поставим операторы чтения для переменных в 1г и /а перед Рг и Р2 соответственно, а операторы записи для переменных в U2 и U2—после Рг и Р2. Затем к каждой программе присоединим оператор останова. Операторы записи к Рг и Рг нужно добав- лять так, чтобы каждая выходная переменная печаталась хотя бы один раз и последовательности напечатанных значений для 3\ и 3\ были одинаковыми. Поскольку блоки и ®2 эквива- лентны, это всегда можно сделать. Легко видеть, что программы и 3\ эквивалентны незави- симо от того, что именно берется в качестве множества входных присваиваний и как интерпретируются функции, представленные операциями, входящими в и 3\. Например, можно взять в качестве входного множество префиксных выражений и считать, что применение операции 0 к выражениям ., ег дает 9е,.. ,ег. Однако, если 33г и 332 не эквивалентны, то всегда найдется множество типов данных для переменных и интерпретации для операций, приводящие к тому, что соответствующие блокам про- граммы и 3\ будут вырабатывать различные выходные по- следовательности. В частности, пусть „типом" переменных будут префиксные выражения, а результатом применения операции 9 к префиксным выражениям е17 ..., будет префиксное выра- жение 9ер . .в*. Ясно, что относительно типов данных и алгебры, связанной с функциями и знаками отношений, можно сделать такие пред- положения, что программы и 5!, окажутся эквивалентными. х) Предполагается, что смысл каждой операции и знака отношения, а также тип данных каждой переменной зафиксирован. Таким образом, это понятие эквивалентности отличается от понятия, введенного ранее, например Патерсоном [1968] или Лакхэмом и др. [1970], тем, что они требуют, чтобы две программы давали одинаковые значения не только для .каждого входного присваивания, ио и для каждого типа данных для переменных и каждого множества функций и отношений, которые мы подставляем вместо операций и знаков отношений. 396
11.3. ПРОГРАММЫ С ЦИКЛАМИ В таком случае блоки и будут эквивалентными относи- тельно соответствующего множества алгебраических законов. Пример 11.26. Рассмотрим следующую программу для алго- ритма Евклида, описанного в гл. О (том 1). Выходом должен быть наибольший общий делитель двух положительных целых чисел р и q. read р read q цикл: г <— remainder^, q) if r = 0 goto выход p^-q q^-r goto цикл выход: write q halt Если, например, входным переменным р и q присвоить зна- чения 72 и 56 соответственно, то при обычной интерпретации операций выходная переменная q к моменту выполнения опера- тора записи будет иметь значение 8. Таким образом, значением этой программы для входного присваивания р <—72, q >—56 слу- жит „последовательность" 8, вырабатываемая выходной пере- менной q. Если заменить оператор goto цикл на if q -/=< > goto цикл, то получим эквивалентную программу. Это следует из того, что оператора goto цикл нельзя достичь, если в четвертом операторе не выполняется условие г^ьО. Поскольку в шестом операторе q принимает значение г, то при выполнении седьмого оператора равенство q = 0 невозможно. □ Следует отметить, что преобразования, которые мы можем применять, в значительной степени определяются теми алгебраи- ческими законами, которые мы считаем справедливыми. Пример 11.27. Для некоторых типов данных можно считать, что а*а = 0 тогда и только тогда, когда ей). Если принять такой закон, то программе из примера 11.26 эквивалентна про- грамма read р read q цикл: г 1—remainder (р, q) 11— г * г if f = 0 goto выход q^r goto цикл выход: write q halt 3W
ГЛ. II. ОПТИМИЗАЦИЯ КОДА Конечно, при любых мыслимых обстоятельствах эта программа ничем не лучше, но если сформулированный выше закон неверен, то эта программа и программа из примера 11.26 могут оказаться и не эквивалентными. □ Если дана программа Р, то наша цель заключается в нахож- дении эквивалентной программы Р', для которой ожидаемое время выполнения в машинном языке меньше, чем для Р. Разумным приближением нашей задачи будет нахождение такой эквивалент- ной программы Р", что ожидаемое число команд машинного языка, которые предстоит выполнить в Р", меньше числа команд, вы- полняемых в Р. Эта задача является приближением, поскольку различные машинные команды могут выполняться за различное машинное время. Например, такая операция, как умножение или деление, обычно занимают больше времени, чем сложение или вычитание. Тем не менее мы сначала займемся уменьшением только числа выполняемых команд машинного языка. В большинстве программ одни последовательности операторов исполняются значительно чаще, чем другие. Кнут [1971] на боль- шом числе программ Фортрана обнаружил, что в типичной про- грамме около половины времени тратится менее чем на 4% про- граммы. Таким образом, на практике часто достаточно приме- нять оптимизирующие процедуры только к этим многократно проходимым участкам программы. В частности, оптимизация может состоять в том, что операторы перемещаются из много- кратно проходимых областей в области, редко проходимые, а число операторов в самой программе не меняется или даже увеличи- вается. Во многих случаях можно определить, какой кусок исходной программы будет выполняться чаще других, и вместе с исходной программой передать эту информацию оптимизирующему компи- лятору. В других случаях довольно просто написать подпро- грамму, подсчитывающую, сколько раз исполняется данный опе- ратор. С помощью такого счетчика можно получить „частотный профиль" программы и выявить те ее куски, на которые надо направить основные усилия по оптимизации. 11.3.2. Анализ потока управления Первый шаг на пути оптимизации программ заключается в определении потока управления внутри программы. Для того чтобы сделать это, разобьем программу на группы операторов так, чтобы внутри группы управление передавалось только на первый оператор, и если уж он выполнился, все остальные опе- раторы группы выполняются последовательно. Такую группу операторов будем называть линейным участком или просто участком. 398
11.3. ПРОГРАММЫ С ЦИКЛАМИ Определение. Оператор S в программе Р называется входом в линейный участок, если он (1) первый оператор в Р или (2) помечен идентификатором, появляющимся после goto в опе- раторе перехода либо в условном операторе, или (3) непосредственно следует за условным оператором. Линейный участок, относящийся к входу в участок S, состоит из S и всех операторов, следующих за .S', (1) вплоть до оператора останова и включая его или (2) вплоть до входа в следующий участок, но не включая его. Отметим, что программа, построенная из блока в смысле разд. 11.1, будет линейным участком в смысле настоящего раздела. Пример 11.28. Рассмотрим программу из примера 11.26. В ней четыре входа в участок, а именно первый оператор про- граммы, оператор, помеченный цикл, оператор присваивания р-<—q и оператор, помеченный выход. Таким образом, в этой программе четыре линейных участка: Участок 1 read р read q Участок 2 цикл: г<—remainder (р, q) if r = 0 goto выход Участок 3 р 1— q q^-r goto цикл Участок 4 выход: write q halt □ Из участков программы можно сконструировать граф, весь- ма похожий на блок-схему программы. Определение. Графом управления назовем помеченный ориен- тированный граф G, содержащий выделенную вершину п, из которой достижима каждая вершина в G. Вершину п назовем начальной. Граф управления программы—это граф управления, в кото- ром каждая вершина соответствует какому-нибудь участку про- граммы. Предположим, что вершины i и / графа управления соответствуют участкам i и j программы. Тогда дуга идет из вершины i в вершину /, если (1) последний оператор участка i не является ни операто- ром перехода, ни оператором останова, а участок j следует в программе за участком i, или 399
ГЛ. 11. ОПТИМИЗАЦИЯ КОДА (2) последний оператор участка i является оператором goto L либо оператором if . . . goto L, где L — метка первого операто- ра участка J. Участок, содержащий первый оператор программы, назовем начальной вершиной. Ясно, что любой участок, недостижимый из начальной вер- шины, можно удалить из данной программы, не меняя ее значе- ния. Отныне будем считать, что все такие участки рассматри- ваемой программы уже удалены. Пример 11.29. Граф управления программы1) примера 11.26 изображен на рис. 11.22. Начальной вершиной является учас- ток 1. □ Рис. 11.22. Граф управления. Многие оптимизирующие преобразования программ требуют знания тех мест в программе, где переменная определяется, и тех, где на ее определение есть ссылка. Эти связи между опре- делением и ссылкой зависят от последовательностей выполня- емых участков. Первым участком в такой последовательности будет начальная вершина, а в каждый последующий участок должна вести дуга из предыдущего. Иногда предикаты, исполь- зуемые в условных операторах, могут запрещать проход по некоторым путям в графе управления. Однако алгоритма для выявления всех таких ситуаций нет, и мы будем предполагать, что нет „запрещенных" путей. Удобно также знать, существует ли для участка S3 такой участок S3', что всякий раз, когда выполняется S3, перед ним Везде в дальнейшем граф управления программы будем называть для краткости просто графом управлении.— Прим, перев. 400
11.3. ПРОГРАММЫ С ЦИКЛАМИ выполняется 33'. В частности, если мы знаем это и если в обоих участках 93 и 33' вычисляется одно и то же значение, можно запомнить его после вычисления в 33' и избежать тем самым перевычисления его в 33. Формализуем теперь эти идеи. Определение. Пусть F— граф управления, имена участков которого выбираются из некоторого множества А. Последова- тельность участков из А* назовем путем вычислений (участков) в F, если (1) — начальная вершина в F, (2) для 1 существует дуга, ведущая из в 93;. Другими словами, путь вычислений 93;...33п— это путь в F из 33; в 33п, в котором 93; — начальная вершина. Будем говорить, что участок 93' доминирует над участком 33, если 93'^33 и каждый путь, ведущий из начальной вершины в 33, содержит 33'. Будем говорить, что прямо доминирует над .53, если (1) .53' доминирует над .53 и ' (2) если S3" доминирует над S3 и .53” ^=.53', то S3" доминиру- ет над 93’. Таким образом, участок S3' прямо доминирует над .53, если .53' — „ближайший" к S3 участок, доминирующий над S3. Пример 11.30. На рис. 11.22 последовательность 1232324 — это путь вычислений. Участок 1 прямо доминирует над участком 2 и доминирует над участками 3 и 4. Участок 2 прямо домини- рует над участками 3 и 4. □ Приведем некоторые алгебраические свойства отношения до- минирования. Лемма 11.13. Если 93; доминирует над 33.2, а 93, доминирует над 93,, то 33; доминирует над S3., (транзитивность). (2) Если 93; доминирует над 93„ то 332 не доминирует над 93; (асимметричность). (3) Если 93; и 93, доминируют над 93,,, то либо 93; домини- рует над 93,, либо S3, доминирует над S3;. Доказательство. Утверждения (1) и (2) оставляем в качестве упражнений. Докажем (3). Пусть ..i£„S33 — любой путь вычислений без циклов (т. е. i?;#=S33 и при i=£j). Один такой путь существует, так как мы предполагали, что все вершины достижимы из начальной вершины. По условию = и i?7 = S32 для некоторых i и /. Без потери общности можно считать, что i <3 j. Мы утверждаем, что 33; доминирует над 93г. 401
ГЛ. .11. ОПТИМИЗАЦИЯ КОДА Предположим противное, т. е. что 53, не доминирует над53а. Тогда найдется путь вычислений 30.,...30,,33,, в котором среди , @>т нет S3,. Отсюда следует, что £5,.. . S?mS32l?7 + 1... ...^„533— также путь вычислений. Но среди символов, пред- шествующих 333, нет 33lt а это противоречит предположению о том, что 33t доминирует над 533. □ Лемма 11.14. Каждый участок, кроме начальной вершины (не имеющей доминаторов), имеет единственный прямой доминатор. Доказательство. Пусть &—множество участков, доми- нирующих над некоторым участком S3. По лемме 11.13 отно- шение доминирования устанавливает (строгий) линейный поря- док на <Sf. Таким образом, <У” обладает наименьшим элементом, который должен быть прямым доминатором участка 33 (см. упр. 0.1.23). □ Изложим теперь алгоритм, вычисляющий отношение прямого доминирования для графов управления. Алгоритм 11.5. Вычисление прямого доминирова- ния. Вход. Граф управления р и множество А = {.Й?!, 53а, ...,33„} его участков. Предполагается, что 331— начальная вершина. Выход. Прямой доминатор DOM(S) участка S3 для каждого Й€Д, кроме начальной вершины. Метод. DOM($3) вычисляется рекурсивно для каждого 33 из Д — {S3J. В любой момент DOM(S3) будет участком, ближайшим к 33 среди всех участков, для которых уже известно, что они доминируют над 33. В конечном итоге DOM(S3) будет прямым доминатором участка 33. Вначале DOM(S3)— это 33, для всех 33 из Д—{S3J. Дляг = 2, 3, ..., п выполняем следующие два шага: (1) Исключаем участок S3s из F. С помощью алгоритма 0.3 находим все участки S3, ставшие теперь недостижимыми из на- чальной вершины в F. Участок Я,- доминирует над S3 тогда и только тогда, когда 33 становится недостижимым из начальной вершины после исключения 33t из F. Снова заносим 33, в F. (2) Предположим, что па шаге (1) обнаружено, что S3,- до- минирует над 33. Если DOM(S3) = DOM(S3(), берем 33j в качест- ве DOM(S3). В противном случае DOM(S3) не меняем. □ Пример 11.31. С помощью алгоритма 11.5 вычислим прямые доминаторы для графа управления рис. 11.22. Здесь А ={SBlt 313,, 333, 33t}. Последовательные значения DOM(S3) после иссле- дования участков 33h 2 <1 i 4, приведены в табл. 11.8. Вычис- лим строку 2. После исключения участка 33 г участки 333 и 33, становятся недостижимыми. Таким образом, 313, доминирует над 333 и 33Перед этим было DOM($3a) — DOM(,?33) = S3j, так что в 402
и 3. ПР0ГРА1У*МЫ C ЦИКЛАМИ DOM(^2) DOM($g) Таблица П.8 | Г>ом(^4) Вначале 2 3 4 <Й?2 соответствии с шагом (2) ал DOM(®3). Аналогично по.ъ °ри™д 11'5 ®еРем Л качестве участков и S3. не делаЭГаем ®a = DOM(S4), Исключение так что никаких изменений «Т никакой Участок ^«Достижимым, нии больше не требуется. □ Теорема 11.10. Поокончан,,,, „г,с < i к прямой доминатор участка работымгоРитма Доказательство За. вильно определяются те'v4,Me™M сначала- что на шаге (0 пра- 93h поскольку S3, домиии^™ над к°торыУ1И Доминирует когда любой путь в й из ДУет аад: 33 ™ГДа и только тогДа, рез 93,. ‘ачальнои вершины F пР°ходит че- участокУ«л, ” <™Ккото^’ йТО после шага (2) ^ОМ(®)~это рым в свою очередь доминиь, Доминирует над ? и над дето- нирующие над S. СуществгЙ^®06 S/’ 1 *’®аКЖе доми‘ непосредственно из леммы Л , □ такого участка вытекает Перейдем к доказательс? 3‘ БаЗИС’ f = 2’ три®иален. доминирует над ® то закл^Л^ шага индукции. Если SSt+l не предположения индукции. Учение вытекает непо<гРеДственно из существует такой участок 33 J'+i Доминирует наД 93, но а 93,., доминирует нап Й’1 < / < что ,®, дом*“1иРУет над .3, образом, DOM(.?-;) не меняет’ Т° Таким положению индукции. Есл/щ Что вполне соответствует пред- руется всеми 33,, доминируй'*1 доминнРУет на/* У3. и Домипн- этим шагом DOM.IS3) = DOAlr^ад Т0 пеРеД было не так, то нашелся 6h/+t)‘ В самом Дел/’ еСЛИ бы это ший над я,+, но не нал 5? Участок 93k, 1 Доминирую- Следовательно, DOMf.Sl Что невозможно по Лемм® 11.13(1). рема доказана. □ нимает именно значеяие ®<+i- Тео- Отметим, что если F стп„„^„ не более чем вдвое превос! И3 пР°гРаммы, ™ число дуг (1) алгоритма 11.5 выполз Т Число Участков/ Поэтому шаг квадрату числа участков кТ” За Время- пр^РЦИональное числу участков. ? ' ‘ребуемая емкость пр/опоРциональна 403
ГЛ. 11. ОПТИМИЗАЦИЯ КОДА Если 53и S32,.-.,S3n— участки программы (кроме началь- ного), то их доминаторы можно запоминать как последователь- ность где St— прямой доминатор для 331, 1 Все доминаторы для St легко выбрать из этой по- следовательности, вычисляя DOM(®,), DOM(DOM(®;)) и т. д, вплоть до начального участка. 11 .3.3. Примеры преобразований программ Займемся теперь преобразованиями, которые можно приме- нить к программе или ее графу управления, чтобы уменьшить время выполнения получающейся в конце концов объектной программы. В этом разделе мы рассмотрим примеры таких пре- образований. Хотя полного каталога оптимизирующих преобра- зований программ с циклами не существует, рассматриваемые здесь преобразования полезны для широкого класса программ. 1. Удаление бесполезных операторов Это — обобщение преобразования Т, из разд. 11.1. Без опе- ратора, не влияющего на значение программы, можно обойтись, так что его можно удалить. Линейные участки, недостижимые из начальной вершины, очевидно, бесполезны, и их можно уда- лить. Операторы, вычисляющие значения, не используемые в конечном итоге при вычислении выходной переменной, также попадают в эту категорию. В разд. 11.4 мы опишем технику применения этих преобразований к программам с циклами. 2. Исключение избыточных вычислений Это преобразование обобщает преобразование Т„ из разд. 11.1. Предположим, что у нас есть программа, в которой участок 53 доминирует над®', и что 59 и S3' содержат операторы А <— В + С и А'<—B-j-C соответственно. Если ни В, ни С не переопределены на каком-нибудь (не обязательно без циклов) пути из 53 в 53' (выяснить это нетрудно; см. упр. 11.3.5), то значения, вычис- ляемые этими двумя выражениями, совпадают. Тогда в S3 после А<—В + С можно вставить оператор X'—А, где X— новая переменная. Затем А'—В + С можно заменить на A'i—X. Кроме того, если А нигде на пути из.0 в®' не переопределяется, то оператор +—А не нужен, а А' <—В + С можно заменить на А+—А. Здесь предполагается, что выгоднее сделать два присваива- ния Х^-А и А'^—Х, чем вычислять А'«—В + С; это предпо- ложение справедливо для многих моделей машин. 404
11.3. ПРОГРАММЫ С ЦИКЛАМИ Пример 11.32. Рассмотрим граф управления, изображенный на рис. 11.23. В этом графе участок В2 доминирует над В2, S33 и В,. Предположим, что все операторы присваивания, в ко- торые входят переменные А, В, С и D, таковы, как показано на рис. 11.23. Тогда В + С принимает одно и то же значение Рнс. 11.23. Граф управления. при вычислениях в участках 333, В3 и ®4. Поэтому в З3 и не обязательно перевычислять выражение В + С. В В3 после оператора А<—В + С можно поместить оператор присваивания X <—А. Здесь X— новое имя переменной. Тогда в Я3 и В, опе- раторы А*—В + С и G-—В + С можно заменить на простые операторы присваивания —X и G «— X соответственно, и это не повлияет на значение программы. Отметим, что, поскольку А вычисляется в В2, вместо X нельзя использовать А. Преобра- зованный таким образом граф управления изображен на рис. 11.24. Теперь в В3 присваивание А*—X становится избыточным и его можно исключить. Отметим также, что если в В2 опера- тор F <—Л|-С заменить на В<—Л |-0, то в В, нельзя уже заменять G*—В + С на С<—X. □ Для исключения из программы избыточных вычислений (об- щих подвыражений) надо выявить вычисления, общие для двух 405
ГЛ. 11. ОПТИМИЗАЦИЯ КОДА или более участков программы. Избыточные вычисления, общие для участка и какого-нибудь из его доминаторов, мы уже рас- смотрели. Выражения типа Л-|-В могут вычисляться в несколь- ких участках, ни один из которых не доминирует над данным участком 33 (где также требуется выражение Л + В). Вообще Рнс. 11.24. Преобразованный граф управления. вычисление выражения Л + В считается избыточным в участ- ке ЙЗ, если (1) любой путь из начального участка в 33 (в том числе и проходящий через 53 несколько раз) проходит через вычисление Л + В, (2) вдоль любого такого пути между последним вычислением А + В и использованием Л + В в .53 не встречается определе- ния ни Л, пи В. В разд. 11.4 мы изложим некоторые методы определения этой наиболее общей ситуации. Отметим, что как и в линейном случае, применение алгеб- раических законов может увеличить число общих подвыражений. 406
11.3. ПРОГРАММЫ С ЦИКЛАМИ 3. Замена вычислений периода выполнения вычислениями периода компиляции Если это возможно, то имеет смысл выполнить вычисление один раз при компиляции, а ие повторять его многократно при исполнении объектной программы. Простой пример — размноже- ние констант, т. е. замена переменной на константу, когда значение переменной постоянно и известно. Пример 11.33. Рассмотрим участок read R PI 3.14159 Л - 4, 3 В =- А * PI C^R]3 V--B*C write V В четвером операторе вместо PI можно подставить значение 3.14159 и получить оператор В -— Л* 3.14159. Можно также вычи- слить 4/3 и, подставив найденное значение в В<—4*3.14159, по- лучить В*—1.33333* 3.14159. Можно вычислить 1.33333 * 3.14159 = = 4.18878 и, подставив 4.18878 в оператор В*С, получить V -—4.18878* С. Наконец, можно удалить получившиеся беспо- лезные операторы. В результате у нас будет более короткая эквивалентная программа read R C^R]3 V— 4.18878»С write V □ 4. Замена сложных операций Замена сложных операций представляет собой замещение одной операции, занимающей довольно много машинного времени, более быстрой последовательностью. Например, пусть исходная программа на ПЛ/I содержит оператор / = LENGTH (S1||S2) где S1 и S2—цепочки переменной длины. || означает конкате- нацию цепочек. Реализовать конкатенацию цепочек довольно сложно. Предположим-, однако, что мы заменяем этот оператор эквивалентным оператором 1 = LENGTH (SI) + LENGTH (S2) 407
ГЛ. II. ОПТИМИЗАЦИЯ КОДА Теперь мы должны дважды выполнить операцию определения длины и один раз сложение. Но эти операции занимают сущест- венно меньше времени, чем конкатенация цепочек. Другие примеры оптимизации такого типа: замена некоторых умножений сложениями и замена некоторых возведений в сте- пень повторными умножениями. Например, оператор —7?J3 можно заменить последовательностью С^Д.*Л! C*-C*R при условии, что дешевле вычислить 7? *7? *7?, чем вызывать подпрограммы для вычисления R3 как ANTILOG(3 * LOG(7?)). В следующем разделе мы изучим более интересную форму замены сложных операций в циклах, когда есть возможность заменять некоторые умножения сложениями. 11.3.4. Оптимизация циклов Грубо говоря, цикл в программе—это последовательность участков, которая может исполняться повторно. Циклы присущи большинству программ, а многие программы имеют циклы, исполняемые много раз. Во многих языках программирования есть конструкции, предназначенные специально для организации циклов. Часто можно добиться существенных улучшений в смысле времени исполнения программы, применяя преобразования, умень- шающие только оценку циклов. Универсальные преобразования, которые мы только что рассматривали, а именно удаление бес- полезных операторов, исключение избыточных вычислений, раз- множение констант, замена сложных операций, полезны, в част- ности, и в применении к циклам. Существуют, однако, и другие преобразования, ориентированные специально на циклы. Это вынесение вычислений из циклов, замена дорогих операций в циклах более дешевыми и развертывание циклов. Для того чтобы применить эти преобразования, цикл сначала надо выделить из данной программы. В случае циклов DO в Фортране или промежуточного кода, образуемого из цикла DO, найти цикл просто. Однако понятие цикла в графе управления * более общо, чем понятие цикла, возникающего из операторов DO Фортрана. Эти обобщенные циклы графов управления называют „сильно связными областями". Любой цикл графа управления *) с единственной точкой входа служит примером сильно связной области. Однако и более общие структуры циклов также слу- 1) Подчеркиваем: „цикл графа", т. е. замкнутый путь в графе.—Прим, ред. 408
11.3. ПРОГРАММЫ С ЦИКЛАМИ жат примерами сильно связных областей. Дадим определение сильно связной области. Определение. Пусть F—граф управления, а <9° — подмноже- ство его участков. Будем называть сильно связной областью (или, короче, областью) в F, если (1) в if существует такой единственный участок S3 (вход), что найдется путь из начальной вершины графа F в S3, не про- ходящий ни через какой другой участок из -F, (2) существует путь (ненулевой длины), лежащий целиком внутри if и ведущий из любого участка в if в любой другой участок в if. Пример 11.34. Рассмотрим абстрактный граф управления (рис. 11.25). {2, 3, 4, 5} — сильно связная область с входом 2. {4) — сильно связная область с входом 4. (3, 4, 5, 6}—область с входом 3. {2, 3, 7}—область с входом 2. Еще одна область с входом 2—{2, 3, 4, 5, 6, 7}. Последняя максимальна в том смысле, что любая другая область с входом 2 содержится внутри этой области. □ Важной особенностью сильно связной области, благодаря которой она н помогает улучшать код, является однозначность 409
ГЛ, II. ОПТИМИЗАЦИЯ КОДА определения входного участка. Например, одна из оптимизаций, выполняемых на графах управления, заключается в перемещении инвариантного в области вычисления в участки, предшествующие входному для данной области (можно также построить новый участок, содержащий инвариантные вычисления и предшествую- щий входу). Входные участки графов управления можно охарактеризо- вать в терминах отношения доминирования. Теорема 11.11. Пусть F—граф управления. Участок S3 в F является входным участком области тогда и только тогда, когда существует такой участок 33', что из него есть дуга в 33 и 93 либо доминирует над 33', либо совпадает с 33'. Доказательство. Необходимость. Предположим, что 33 — входной участок области if. Если ^ — {ЗЗ}, то результат три- виален. Если нет, пусть 93' g if, S3'^=33. Тогда Я доминирует надЗ', поскольку в противном случае найдется путь из началь- ной вершины в 33', не проходящий через 33, вопреки предположе- нию о том, что .53 — единственный входной участок. Таким образом, .входной участок области доминирует над любым другим участком. Поскольку в .53 ведет путь из любого элемента множества 3f, в if—{33} должен быть хотя бы один участок S', связанный не- посредственно с .53. Достаточность. Случай Зй—ЭЗ' тривиален, так что будем считать, что Определим if как объединение участка S с такими участками 33", что 33 доминирует над 33" и существует путь из .53" в 33, проходящий только через вершины, над кото- рыми доминирует S3. По предположению S3 и .53' оба принад- лежат 3f. Надо показать, что If — область с входом S3. Ясно, что условие (2) определения области удовлетворяется, поэтому мы должны показать, что существует путь из начальной вер- шины в 33, не проходящий ни через какой другой участок в if. Пусть ’S1...‘Sn33 — кратчайший путь вычислений, ведущий в S3. Если то найдется такое число i, 1-^.i-^.j, что £,- = S, поскольку .53 доминирует над i?y. Пришли к противоречию, так как тогда не будет кратчайшим путем вычислений, ведущим в 33. Итак, условие (1) определения сильно связной области удовлетворяется. □ Очевидно, что множество If, построенное в ходе доказатель- ства достаточности условия в теореме 11.11, является макси- мальной областью с входом S3. Было бы очень хорошо, если бы область с входом S была единственна, но, к сожалению, это не всегда так. В примере 11.34 три области с входом 2. Тем не менее теорема 11.11 полезна при построении эффектив- ного алгоритма, вычисляющего максимальную область, которая единственна. 410
11.3. ПРОГРАММЫ С ЦИКЛАМИ Если область не максимальна, входной участок может доми- нировать над участками, не принадлежащими области, а из них могут быть достижимы участки области. В примере 11.34, ска- жем, область {2, 3, 7} может быть достижима через участок 6. Поэтому говорят, что область имеет один вход, если каждая дуга, входящая в ее участок, отличный от входного, выходит из участка внутри области. В примере 11.34 область {2, 3, 4, 5, 6,7} имеет один вход. В дальнейшем будем предполагать, что области имеют один вход, хотя не трудно дать обобщение на любые области. 1 1. Перемещение кода Существует несколько преобразований, в которых для улуч- шения кода можно воспользоваться знанием областей. Одно из важнейших—перемещение кода. Вычисления, не зависящие от области, можно вынести за ее пределы. Пусть, скажем, внутри некоторой области с одним входом переменные Y и Z не меня- ются, но есть оператор Х<—Y + Z. Вычисление Y + Z можно переместить в заново образованный участок, связанный только с входным участком области1). Все связи вне области, ранее шедшие во входной участок, теперь идут в новый участок. Пример 11.35. Может показаться, что вычисления, инвариант- ные относительно области, появляются только в неаккуратно написанной программе. Рассмотрим, однако, следующий внутрен- ний цикл DO исходной программы на Фортране, где переменная определена вне цикла: К = 0 DO 3 / = 1,1000 3 7< = J + l+/+7< Промежуточная программа для этого фрагмента исходной про- граммы может быть такой: /ч-1 цикл Т1— J + 1 S+-T + I K^S + K if /=1000 goto выход 1 = 1 + 1 goto цикл выход halt Соответствующий граф управления изображен на рис. 11.26. *) Добавление такого участка может привести к графу управления, не получающемуся нн из какой программы. Но здесь нигде' не предполагается, что граф должен обязательно получаться нз программы. 411
ГЛ. И. ОПТИМИЗАЦИЯ КОДА Из рис. 11.26 видно, что {S2, 593} — область с входом ,В2. Оператор Г <— J 4- 1 инвариантен в области, так что его можно переместить в новый участок, как показано на рис. 11.27. Рнс. 11.26. Граф управления. Рис. 11.27. Преобразованный граф управления. Несмотря на то, что на рис. 11.26 операторов столько же, сколько на рис. 11.27, операторы в области будут, по-видимому, выполняться часто, так что ожидаемое время выполнения умень- шится . □ 2. Индуктивные переменные Другое полезное преобразование связано с удалением пере- менных, которые мы будем называть индуктивными. Определение. Пусть <9° — область с одним входом 3, а X — переменная, появляющаяся в некотором операторе, входящем в один из участков в if. Пусть . ..53„ 53®j... —такой путь вычислений, что принадлежит if, l^i^m, a 3in, если су- ществует, не принадлежит if. Обозначим через X,, Ха, ... зна- чения, присваиваемые X в последовательности Если Xn Xz, ... образуют арифметическую прогрессию (с положи- тельной или отрицательной разностью) для любого пути вычис- лений типа указанного выше, то будем называть X индуктивной переменной в <9°. Будем также называть X индуктивной переменной, если в первый раз она в 3 не определена и ее значения образуют арифметическую прогрессию. Тогда может понадобиться подхо- 412
11.3. ПРОГРАММЫ С ЦИКЛАМИ дящим образом инициализировать ее при входе в участок извне, чтобы выполнить разбираемые здесь оптимизации. Отметим, что задача нахождения всех индуктивных перемен- ных в области нетривиальна. На самом деле можно доказать, что алгоритма для этого вообще нет. Тем ие менее в общих ситуациях можно выявить достаточно много индуктивных пере- менных, так что это понятие заслуживает рассмотрения. Пример 11.36. На рис. 11.27 область {й2, йа} имеет вход Sj. Если вход в осуществляется из .53) и управление пов- торно передается от Sj к Sj и снова к ®2, то переменная / принимает значения 1, 2, 3......Таким образом, /— индуктив- ная переменная. Менее очевидно, но 5—также индуктивная переменная, поскольку она принимает значения 7’4-1, 7’4-2, 7’4-3......А вот переменная К, не индуктивная, так как она принимает значения Т 4- 1, 27’4-3, 37’4-6.... □ Важная особенность индуктивных переменных — их линейная связь друг с другом при передаче управления внутри области, которой они принадлежат. Например, на рис. 11.27 каждый раз при выходе из справедливы соотношения 5 = 7’4-/ и / = 5—7’. Если, как на рис. 11.27, какая-то индуктивная переменная используется только для управления в области (на это указы- вает тот факт, что ее значение не требуется за пределами об- ласти н что непосредственно перед входом в область ей присва- ивается всегда одна н та же константа), то ее можно исключить. Даже если за пределами области требуются все индуктивные переменные, внутри области можно использовать только одну, а остальные вычислять при выходе из области. Пример 11.37. Рассмотрим рис. 11.27. Исключим индуктив- ную переменную /, удовлетворяющую перечисленным выше критериям. Ее роль будет играть 5. Заметим, что после участ- ка .532 переменная 5 принимает значение 7’4-7, так что, когда управление возвращается от к 33а, должно выполняться со- отношение 5 = 7’-)-/—1- Таким образом, оператор 5«—T + I можно заменить на 5*—5 4-1. Но затем в S3) надо правильно инициировать 5, так что, когда управление перейдет из 53', в Э32, значением 5 после оператора 5«—5 4-1 будет T + I. Ясно, что в S3) после оператора 71 — J-J-1 надо ввести новый оператор S+-T. Затем мы должны исправить проверку /=1000? так, чтобы получить эквивалентную проверку относительно 5. При выпол- нении этой проверки 5 имеет значение T + I. Следовательно, эквивалентной проверкой будет R — 7’4- 1000 5 = /?? 413
ГЛ. 11. ОПТИМИЗАЦИЯ КОДА Поскольку 7? не зависит от области, вычисление Ri—Т 4-1000 можно вынести в участок Тогда можно полностью избавиться от /. Новый граф управления изображен на рис. 11.28. Рнс. 11.28. Дальнейшее преобра- зование графа управления. Рнс. 11.29. Окончательный граф управления. Из рис. 11.28 видно, что участок 533 исключен полностью, а область укорочена на один оператор. Конечно, размер участ- ка .Ж увеличился, но, по-видимому, области исполняются зна- чительно чаще, чем участки вне области. Таким образом, рис. 11.28 представляет ускоренный вариант рис. 11.27. Шаг S-—Т в 53'2 можно исключить, если отождествить S и Т. Это возможно только потому, что значения переменных S и Т никогда не будут различными, но несмотря на это обе они будут „активными" в том смысле, что обе будут использоваться в даль- нейших вычислениях. Иными словами, в 332 активна только пе- ременная S, ни одна из них не активна в a bSJ обе активны между операторами —Т и R<—Т4- 1000. В этот момент они, разумеется, принимают одно и то же значение. Если Т заменить иа S, получим граф управления на рис. 11.29. Для того чтобы понять, чем граф на рис. 11.29 лучше графа на рис. 11.26, превратим каждый из них в программу на языке ассемблера для абстрактной машины с одним сумматором. Коды операций должны быть понятны (JZERO означает „переход 414
11.3. ПРОГРАММЫ С ЦИКЛАМИ в случае нулевого сумматора", a JNZ — „переход в случае нену- левого сумматора"). Две эти программы приведены на рис. 11.30. LOAD = 0 LOAD = 0 STORE к STORE К LOAD = 1 LOAD J цикл: STORE I ADD = 1 LOAD J STORE s ADD = 1 ADD = 1000 ADD 1 STORE R ADD к цикл: LOAD s STORE к ADD = 1 LOAD I STORE s SUBTR = 1000 ADD к JZERO выход STORE к LOAD I LOAD s ADD = 1 SUBTR R JUMP цикл JNZ цикл выход: END END a 6 Рис. 11.30. Эквивалентные программы: а — программа дли графа управления на рис. 11.26; б — программа для графа управления на рнс. 11.29. Заметим, что длина программы на рис. 11.30,а такая же, как н на рис. 11.30,6. Однако цикл на рис. 11.30,6 короче, чем на рис. 11.30,а (8 команд вместо 12), а это важно с точки зрения времени. □ 3. Замена сложных операций Внутри областей возможна интересная форма замены сложных операций. Если внутри области есть оператор вида Л-—В*1, в котором значение В не зависит от области, а I — индуктивная переменная, то можно заменить умножение сложением или вычи- танием величины, равной произведению значения, не зависящего от области, и разности арифметической прогрессии, порождаемой индуктивной переменной. При этом надо соответствующим обра- зом инициировать величину, вычисляемую в предыдущем опера- торе умножения. Пример 11.38. Рассмотрим фрагмент исходной программы DO 5 J = l, N DO 5 / = 1, M 5 Д(/, J) = B(/, J) делающий массив А равным массиву В в предположении, что А и В имеют одинаковый размер MxN. Пусть A(I, J) запоми- нается в ячейке Д4-М*(У —1)4-/ для 1 Isg/sOV; 415
ГЛ. 11. ОПТИМИЗАЦИЯ КОДА аналогичное предположение относится и к В (/, J). Для удобства А (Д). Тогда из этой исходной Рис. 11.31. Граф управления. программы можно получить частично оптимизированную программу N'^N— 1 ----1 внеш: J «— J + 1 /ч-0 цикл: I«— I 1 L^-K + I A(L)t~B(L) if I < M goto цикл if J <N' goto внеш halt 4U
11.3. ПРОГРАММЫ С ЦИКЛАМИ Граф управления новой программы изображен на рис. 11.31. В этом графе {.53 2, .533, .534{—область, в которой переменная М инвариантна, a J — индуктивная переменная, возрастающая на 1. Поэтому оператор Д<—Л4*7 можно заменить на К,*—Д + Л1, предварительно присвоив Л значение —М вне области. Новый граф управления показан на рис. 11.32. Программа, представ- ляемая этим новым графом, длиннее прежней, но области, соот- ветствующие участкам .535, и 534, могут исполняться быстрее, поскольку умножение заменено сложением. Рис. 11.33. Окончательный граф управления. Интересно отметить, что можно получить еще более эконом- ную программу, заменив всю область {.53{, .533, одним участ- ком, в котором А (Д) принимает значение В (L) для 1 $5 К ^5Л1 * N. Окончательный граф управления изображен на рис. 11.33. □ 4. Развертывание циклов - Последнее преобразование по улучшению кода, которое мы изучим, чрезвычайно просто, ио часто остается незамеченным. Это развёртывание циклов. Рассмотрим граф управления на рис. 11.34. Участки 532 и .533 исполняются по 100 раз. Таким образом, выполняется 100 команд проверки. От всех этих 100 ко- манд можно избавиться, „развернув" цикл. Иными словами, цикл можно превратить в линейный участок, состоящий из 100 опе- раторов присваивания Л(1) — В(1) А (2)«— В (2) А (100)-^- В (100) 417
ГЛ. II. ОПТИМИЗАЦИЯ КОДА Не допуская таких вольностей, можно было бы развернуть цикл только „на один шаг“ и получить граф управления, изображен- ный на рис. 11.35. Программа, представленная рис. 11.35, длин- нее, но в ней исполняется меньше команд. На рис. 11.35 доста- точно 50 команд проверки (вместо 100 команд на рис. 11.34). Рис. Н.34. Граф управления. Рнс. 11.35. Граф управления после раз- вертывания цикла. УПРАЖНЕНИЯ 11.3.1. Постройте промежуточные программы, эквивалентные следующим исходным программам: (a) S = (А 4- В -j-С)» .5 D = S*(S — A)*(S—B)*(S—C) AREA = SQRT(D) (б) for / : = 1 step 1 until N do begin A[/]:= B[Z] + C[/»2]; if (Af/] = O) then halt else A[/] : == I end (в) DO 5 I = 1, N 5 A(l, 1)=C*A(1, I) 418
УПРАЖНЕНИЯ 11.3.2. Какие функции вычисляются следующими двумя про- граммами на промежуточном языке? (a) read N S —О 1^1 цикл: S<—S + Z if I iV goto выход / = /+1 goto цикл выход: write S halt (6) read N T+-N+} T^-T^.5 write T hait Эквивалентны ли эти две программы, если iV и / представляют целые, a S и I — вещественные числа? 11.3.3. Рассмотрим программу Р: read А, В С1— А « А D-<—B*B if С < D goto X Е.— А*А R^R+I E-<—E + R write E halt X: E<—B*B R<-R±2 E — E + R write E if £ > 100 goto Y halt Y: R^R-l goto X Постройте для нее граф управления. 419
ГЛ. И. ОПТИМИЗАЦИЯ КОДА 11.3.4. Найдите доминаторы и прямые доминаторы каждой вершины S в графе управления на рис. 11.36. Рис. 11.36. Граф управления. 11.3.5. Пусть ON (Si, 582)— множество участков, которые мо- гут появиться в графе управления на пути из 9, в 532 (через 53, нельзя проходить повторно, а через 532 можно). Покажите, что если 53, доминирует над S2, то ON (Й„ 9г) = {9 | существует путь из 9 в Эг, когда участок удален из графа управления}. Сколько времени займет вычисление ON (9П 92)? 11.3.6. Докажите утверждения (1) и (2) из леммы 11.13. 11.3.7. Можно следующим образом определить отношение постдоминирования. Пусть F—граф управления и 53— вершина в F. Вершину 9' назовем постдоминатором для 9, если любой путь из 3 в оператор halt проходит через 53'. Прямой постдо- 420
УПРАЖНЕНИЯ минатор для 33 постдоминируется любым другим постдоминато- ром для Покажите, что если вершина графа управления имеет постдоминатор, то она имеет и прямой постдоминатор. 11.3.8. Разработайте алгоритм построения прямых постдоми- наторов всех вершин графа управления. 11.3.9. Найдите все сильно связные области на рис. 11.36. Какие области максимальны? 11.3.10. Пусть Р — программа из упр. 11.3.3. (а) Исключите из Р все общие подвыражения. (б) Исключите из Р все ненужные вычисления коистант. (в) Удалите из цикла в Р все инвариантные вычисления. 11.3.11. Найдите индуктивные переменные в следующей про- грамме: Z-^-l read J, К X: А* С^-А+В write С !^1 + \ if / < 100 goto X halt Исключите их столько, сколько сможете, и замените насколько возможно умножения сложениями. 11.3.12. Приведите алгоритм для нахождения в графе упра- вления всех (а) областей, (б) областей с одним входом и (в) максимальных областей. *11.3.13 . Приведите алгоритм, выявляющий некоторые индук- тивные переменные в области с одним входом. *11.3.14 . Обобщите алгоритм из упр. 11.3.13, чтобы можно было обрабатывать не только области с одним входом. 11.3.15. Приведите алгоритм для перемещения вычислений, не зависящих от области, за пределы области (не обязательно с одним входом). Указание'. В участках вне области, из которых можно достичь области не через вход в область, допускается менять переменные, участвующие в вычислениях, инвариантных относительно области. Возможно, между участками вне области и участками внутри области потребуется поместить новые участки. **11.3.16. Покажите, что проблема эквивалентности двух про- грамм неразрешима. Указание: Выберите подходящие типы данных и интерпретации для операций. 421
ГЛ. 11. ОПТИМИЗАЦИЯ кодл **11.3.17. Покажите, что проблема, индуктивна ли данная пе- ременная, неразрешима. 11.3.18. Обобщите понятие области действия переменных и операторов на программы с циклами. Приведите алгоритм, вы- числяющий область действия переменной в программе с циклами. *11.3.19. Расширьте преобразования 7\— 7\ из разд. 11.1 с тем, чтобы их можно было применить к программам без циклов назад (программам с операторами присваивания и условными опера- торами вида if yRy goto L, где L ссылается на оператор, рас- положенный после условного оператора). *11.3.20. Покажите, что проблема, окончится ли когда-нибудь программа, неразрешима. Проблемы для исследования 11.3.21. Охарактеризуйте модели машин, для которых опи- санные преобразования будут приводить к более быстро выпол- нимым программам. 11.3.22. Разработайте алгоритмы, которые будут определять широкий класс явлений, исследованных в настоящем разделе (например, инвариантные в цикле вычисления или индуктивные переменные). Отметим, что для большинства этих явлений нет алгоритма, определяющего все их вхождения. Открытая проблема 11.3.23. Можно ли вычислить прямые доминаторы графа упра- вления с п вершинами менее чем за 0 (п2) шагов? Разумно пред- положить, что 0 (п2)— лучшее, чего можно достичь для получения всего отношения доминирования, поскольку это как раз столько, сколько требуется для печати результата в матричной форме. Замечания по литературе В ряде работ предполагаются различные оптимизирующие преобразования программ. Нивергельт [1£65], Марилл [К62], Мак-Киман [1S65] и Кларк [ 1C67J перечисляют некоторые машинно-независимые преобразования. Гнр [1965] предлагает оптимизатор, способный к исключению некоторых общих подвы- ражений, размножению констант и к некоторым оптимизациям циклов, таким, как замена сложных операций н удаление инвариантных вычислений. Вузам и Энглунд [ 1969] описывают аналогичные преобразования в рамках Фортрана. Аллен и Кок [1972] дают хороший обзор этих методов. Аллен [1969] приво- дит схему глобальной оптимизации, основанной на нахождении сильно связ- ных областей программы. Подход к оптимизации с точки зрения доминаторов впервые предложили Лоури и Медлок [1963], хотя идея отношения доминирования пришла от Проссера [1959]. 422
11.4. АНАЛИЗ ПОТОКА ДАННЫХ Много теоретических работ посвящено схемам программ, аналогичным графам управления, но с неспецифицированными множествами значений пере- менных и неспецифицированными функциями для знаков операций. Две фун- даментальные работы, в которых рассматривается эквивалентность между такими схемами независимо от реальных множеств и функций, принадлежат Янову [1958] и Лакхэму и др. [1970]. Обзор этих исследований содержится в работах Каплана [1970] и Манны [1973]х). 11.4. АНАЛИЗ ПОТОКА ДАННЫХ В предыдущем разделе мы использовали информацию о вы- числениях в участках программ, не описывая, как ее можно эффективно получить. В частности, мы использовали: (1) „Доступные" при входе в участок выражения. Выражение А + В называют доступным при входе в участок, если А + В всегда вычисляется до достижения участка, но не ранее, чем опреде- ляются А и В. (2) Множество участков, в которых переменная могла опреде- ляться в последний раз перед тем, ках поток управления достиг текущего участка. Эта информация полезна для размножения констант и выявления бесполезных вычислений. Она используется также для выявления возможных ошибок программиста, заклю- чающихся в том, что на переменную делается ссылка до того, как она определена. Информация третьего типа, для вычисления которой можно применить методы настоящего раздела, связана с выявлением активных переменных, т. е. переменных, значения которых должны сохраняться при выходе из участка. Эта информация полезна, когда участки преобразуются в машинный код, поскольку она указывает переменные, которые при выходе из участка должны либо запоминаться, либо сохраняться в быстром регистре. В тер- минах разд. 11.1 эта информация нужна для выявления выход- ных переменных. Отметим, что переменная может вычисляться не в рассматриваемом участке, а в каком-нибудь предыдущем, но быть тем не менее входной и выходной переменной участка. Из трех этих проблем мы исследуем только вторую — уста- новление участка, где могла определяться переменная перед тем, как был достигнут данный участок. Предлагаемый метод, назван- г) В работах советских авторов задача оптимизации циклов рассматрива- лась на ранних этапах автоматизации программирования. Задача разверты- вания циклов была впервые поставлена в работе Ершова и Курочкина ] 1961]. Развертывание циклов, основанное па анализе и преобразовании графа управ- ления, реализовано в АЛЬФА-трансляторе [Бежанова, Поттосин, 1965]. Анализ зависимости индексного выражения от параметра цикла, основанный по су- ществу на понятии индуктивной переменной, проводился в работах Велика- новой и др. [1961 ], Китова н Кривицкого [1959], Камынина, Любимского и Шура-Буры [1958].—Прим, перев. «3
ГЛ. II. ОПТИМИЗАЦИЯ КОДА ный „анализом интервалов", заключается в разбиении графа уп- равления на все большие и большие множества вершин; тем самым с графом связывается иерархическая структура. С помощью этой структуры можно будет дать эффективный алгоритм для класса графов управления, называемых „сводимыми"; такие графы очень часто встречаются в качестве графов управления, возникающих из реальных программ. Затем мы укажем расширения, необхо- димые для обработки несводимых графов. В упражнениях рас- смотрим изменения, которые надо сделать, чтобы при анализе интервалов учитывалась информация двух других типов. 11.4.1. Интервалы Начнем с определения типа подграфа, полезного прн анализе потока данных. Определение. Если h— вершина графа управления F, опре- делим интервал 1(h) с заголовком h как такое множество вер- шин графа F, что (1) h принадлежит 1(h), (2) если вершина п, еще не включенная в 1(h), не является начальной и все дуги, входящие в п, выходят из вершин, при- надлежащих 1(h), добавляем п к 1(h), (3) повторяем шаг (2) до тех пор, пока не останется вершин, которые можно добавить к 1(h). Пример 11.39. Рассмотрим граф управления, изображенный на рис. 11.37. Рассмотрим интервал с начальной вершиной (Ц в качестве заголовка. Согласно шагу (1), 1(п3) включает щ. Поскольку единственная дуга, входящая в п2, выходит из нх, добавляем п2 к /(Hj). Вершину п3 нельзя добавить к /(nJ, так как в нее можно попасть не только из п2, но и из п5. Никаких других вершин добавить к /(и,) нельзя. Таким образом, Z(nx) = {«ц п2}. Рассмотрим теперь 1(п3). Согласно шагу (1), п3 принадлежит 1(п3). Однако пг нельзя добавить к f(n3), так как в п4 можно попасть через пв (как и через ns), а пе не принадлежит J(ns). Никаких других вершин добавить к 1(п3) нельзя, так что /(п3) = {п3\. Продолжая в том же духе, разбиваем наш граф управления на интервалы /(«,) ~ {^з} 1(п3) = {п3, п3] 424
11.4. АНАЛИЗ ПОТОКА ДАННЫХ Приведем алгоритм выделения заголовков интервалов и по- строения соответствующих интервалов; алгоритм разбивает граф управления на непересекающиеся интервалы. Сначала сделаем три замечания относительно интер- валов. Теорема 11.12. (1) Заголовок h до- минирует над всеми остальными вер- шинами в 1(h) (хотя не обязательно все вершины, над которыми домини- рует А, принадлежат 1(h)). (2) Для каждой вершины h графа управления F интервал 1(h) опреде- ляется однозначно и не зависит от порядка, в котором на шаге (2) опре- деления интервала выбираются кан- дидаты для п. (3) Каждый цикл в интервале 1(h) включает заголовок интервала h. Доказательство. Утвержде- ния (1) и (2) оставляем в качестве упражнений; докажем (3). Предполо- жим, что 1(h) имеет цикл nlf ..., nk, не включающий h. Это означает, что существуют дуга из и, в п1+1, 1 si / < А, и дуга из п* в пг. Пусть вершина п; первая среди п1г ..., пк добавляется к 1(h). Тогда вершина и,.! (нли пк, если 1=1) должна к этому времени уже быть в 1(h) воп- реки предположению. □ Одни из интересных аспектов анализа интервалов заключается в том, что графы управления мож- но единственным образом разбить на интервалы, а интервалы одного Рнс. 11.37. Граф управления, графа управления можно рассматривать как вершины другого графа управления, в кото- ром из интервала Д ведет дуга в другой интервал 1г, если какая-нибудь дуга ведет из вершины интервала Ц в заголовок интервала /2. (Ясно, что никакая дуга не может вести из [t в вершину интервала /2, отличную от заголовка.) Новый граф можно точно таким же образом снова разбить на интервалы, и этот процесс можно продолжить. Поэтому в дальнейшем мы будем считать, что граф управления состоит не из участков, а из вер- 14 А. Аяо, Дж. Ульман, т. 2 42S
ГЛ. 11. ОПТИМИЗАЦИЯ КОДА шии, тип которых не специфицирован. Итак, вершины могут представлять структуры произвольной сложности. Дадим теперь алгоритм разбиения графа управления на не- пересекающиеся интервалы. Алгоритм 11.6. Разбиение графа управления на н е пе р е с ек а ющи ес я интервалы. Вход. Граф управления F. Выход. Множество непересекаюдцихся интервалов, объединение которых содержит все вершины графа F. Метод. (1) С каждой вершиной в F свяжем два параметра: счетчик и достижимость. Счетчик для п щначале равен числу дуг, вхо- дящих в п. В ходе выполнения алгоритма счетчик для п равен числу еще пе пройденных дуг, входящих в п. Достижимость для п либо не определена, либо является некоторой вершиной из F. Вначале достижимость не «определена для всех вершин, кроме начальной, достижимость которой есть она сама. В конеч- ном итоге достижимостью для п станет первый найденный заго- ловок интервала h, такой, что из некоторой вершины интервала 1(h) ведет дуга в п. (2) Образуем список вершин, называемый списком заголовков. Вначале список заголовков содержит только начальную вер- шину графа F. (3) Если список заголовков пу<ст, остановиться. В противном случае пусть п—следующая верпдина списка заголовков. Уда- ляем п из списка заголовков. (4) Затем применяем шаги (5| — (7) Для построения интер- вала 1(п). На этих шагах к списку заголовков добавляются прямые потомки вершин из 1(п). (5) 1(п) строится как список в<ершин. Вначале /(п) содержит только вершину п и она „не помечена". (6) Выбираем в 1(п) непомеченную вершину п', помечаем ле и для каждой вершины п", в которую ведет дуга из п', выпол- няем такие операции: (а) Уменьшаем на 1 счетчиЬ Для п". (б) (1) Если достижимость для п" не определена, полагаем ее равной п и делаем следующее. Если счетчик для п" равен теперь 0 (перед эт.им был равен 1), то добавляем вершину п” к' 1(п) и переходим к шагу (7); иначе до- бавляем вершину п’ к шписку заголовков, если ее там не было, и переходим к шагу (7). (ii ) Если достижимость .для п" равна п, а счетчик вер- шины п" равен 0, добавляем вершину п" к 1(п) и уда- 426
11.4. АНАЛИЗ ПОТОКА ДАННЫХ ляем ее из списка заголовков, если она там есть. Переходим к шагу (7). Если ни (1), ни (11) не применимы, в (б) не делается ничего. (7) Если в /(п) остается непомеченная вершина, возвращаемся к шагу (6). Иначе список 1(п) заполнен; возвращаемся к ша- гу (3). □ Определение. Из интервалов графа управления F можно по- строить другой граф управления 1(F), который будем называть производным графом от F. Производный граф определяется так: (1) 1(F) имеет по одной вершине для каждого интервала, построенного алгоритмом 11.6. (2) Начальной вершиной для 1(F) служит интервал, содер- жащий начальную вершину для F. (3) Из интервала / в интервал J ведет дуга тогда и только тогда, когда I J и из вершины в I ведет дуга в заголовок интервала J. Производный граф 1(F) графа управления F показывает поток управления между интервалами в F. Поскольку граф 1(F) сам является графом управления, можно также построить граф I(I(F)), производный от 1(F). Таким образом, если дан граф управ- ления F„, можно построить последовательность графов управле- ния Fo, Flt ..., F„, называемую производной последователь- ностью от F, в которой Fi+i— производный граф от Ft, < п, a Fn—граф, производный от самого себя (т. е. I(Fn) = F„). Граф Г,- называют l-м производным графом от F„. Граф называется пределом графа F„. Нетрудно показать, что Fn всегда существует и единствен. Если F„ состоит из одной вершины, го граф F называют сво- димым . Интересно отметить, что если граф F„ строится по реальной программе, то с большой вероятностью он будет сводимым. В разд. 11.4.3 мы изложим метод расщепления вершин, с помощью которого любой несводимый граф управления можно превратить в сводимый. Пример 11.40. Воспользуемся алгоритмом 11.6 для построения интервалов графа управления, изображенного на рис. 11.38. Начальной вершиной служитпг. Вначале список заголовков со- держит только п,. Для построения /(пг) включаем nt в /(nJ как непомеченную вершину. Помечаем вершину п, ее прямым потомком п2. Для этого уменьшаем счетчик п2 с 2 до 1, полагаем достижимость для нее равной пт и добавляем ее к списку заголов- ков. К этому моменту в 1(пг) не остается непомеченных вершин, так что список 1(П1)= {nJ заполнен. 14* 427
ГЛ. 11. ОПТИМИЗАЦИЯ КОДА Список заголовков содержит потомка вершины из /(nJ. Для вычисления /(п2) включаем п2 в /(п2) и рассматриваем вершину п3, счетчик для которой равен 2. Уменьшаем счетчик на 1, полагаем достижимость для нее равной п2 и добавляем ее к списку заголовков. Находим, таким образом, что J(n2)={n2}. Список заголовков содержит теперь потомка п3 вершины из /(п2). Вычисление /(п3) начинаем с занесения па в 1(п3). Рас- сматриваем затем вершины п4 и п5, уменьшая счетчики для них с 1 до 0, полагая достижимости для них равными п3 и добав- ляя их к 1(п3) как непомеченные вершины. Помечаем п„ умень- шая счетчик для и, с 2 до 1, полагая достижимость для пе, рав- ной п3 и добавляя пв к списку заголовков. Помечая п, в /(п3), уменьшаем счетчик для n, с 1 до 0, удаляем ее из списка заго- ловков и добавляем к Цп3). Чтобы пометить пв в 1(п3), делаем счетчик для п, равным О, полагаем достижимость для нее равной п3 и добавляем ее к 1(п3). 428
II.4. АНАЛИЗ ПОТОКА ДАННЫХ Следующей рассматривается вершина п3, поскольку есть дуга из п„ в п3. Так как достижимость для п3 равна п2, вершина п3 в данный момент не изменяет. 1(п3) и списка заголовков. Чтобы пометить п7, делаем счетчик для равным 0, полагаем дости- жимость для нее равной п3 и добавляем ее к /(п3). Вершина п3 также является потомком вершины п7, но так как достижимость для п3 равна nt, то п3 не добавляется ни к 1(п3), ни к списку заголовков. Наконец, чтобы пометить па, не надо производить никаких операций, поскольку п3 не имеет потомков. К этому моменту в 1(п3) не остается непомеченных вершин, так что /(«.)={«». nlt п3, п3, п„ п8}. Fl Fi G Рис. 11.39. Последовательность графов управления. Список заголовков теперь пуст, так что алгоритм заканчи- вается. В результате граф управления оказался разбитым на следующие три непересекающихся интервала: 1(п2) = {п3} Цп3) = {п3, nt, п3, п„ я,} Из этих интервалов можно построить первый производный граф F{. Затем к F3 можно применить алгоритм 11.6 и получить его интервалы. Повторяя весь этот процесс, строим последова- тельность производных графов, изображенную на рис. 11.39. □ Пример 11.41. Рассмотрим граф управления F на рис. 11.40. Интервалы для него таковы; /(па) = {п2} /(«,) = {«>} Находим, что 1(F)— F, так что граф F несводим. □ 429
ГЛ. 11. ОПТИМИЗАЦИЯ КОДА Рис. 11.40. Граф управления F. Теорема 11.13. Алгоритм 11.6 строит множество непересе- кающихся интервалов, объединение которых совпадает со всем графом. Доказательство. Ясно, что интервалы не пересекаются Если вершина добавлена к интервалу на шаге (661) алгорит- ма 11.6, то она не будет включена в список заголовков. Если вершина добавлена к интервалу на шаге (ббп), то она удаляет- ся из списка заголовков. Аналогично, легко показать, что объеди- нение всех построенных списков /(п) — это множество вершин графа F. Предполагая, что F— граф управления, можно счи- тать, что каждая вершина достижима из начальной вершины в F и потому попадает либо в список заголовков, либо в неко- торый интервал. Если вершина не добавляется к интервалу, оиа становится заголовком своего собственного интервала. Наконец, надо показать, что каждый построенный список 1(п) есть интервал. На шаге (6) вершина п" добавляется к 1(п) тогда и только тогда, когда достижимость для нее равна п, а счетчик уменьшен до 0. Таким образом, каждая дуга, входящая в п", идет из вершины, уже содержащейся в 1(п}, и в соответ- ствии с определением интервала вершину п" можно добавить к 1(п). □ Заметим, что на машине с произвольным доступом алгоритм 11.6 может выполняться за время, пропорциональное числу дуг графа управления. Поскольку в графе управления, вершины которого являются участками программы, ни из какой вершины не выходит более двух дуг, это равносильно тому, что алгоритм 11.6 линейно зависит от числа участков программы. В качестве упражнения предлагаем показать, что каждый производный граф, построенный повторным применением алгоритма 11.6 из программы, состоящей из п участков, имеет не более 2п дуг. 430
11.4. АНАЛИЗ ПОТОКА ДАННЫХ 11.4.2. Анализ потока данных с помощью интервалов Покажем, как анализ интервалов может использоваться для определения потока данных внутри сводимого графа. Про- блема, которую мы будем исследовать, заключается в том, что для каждого участка 33 и для каждой переменной А сводимого графа управления выясняется, в каких операторах программы могла определяться переменная А в последний раз перед тем, как управление достигло участка 33. Затем основной алгоритм анализа интервалов мы распространим на несводимые графы управления. Важно отметить, что отчасти преимущество подхода к анализу потока данных с помощью интервалов связано с трактовкой мно- жеств как упакованных векторов битов. Для вычисления пере- сечения,- объединения и дополнения множеств используются логические операции AND, OR и NOT на векторах битов, обычно весьма эффективно выполняющиеся на большинстве машин. Построим таблицы, дающие для каждого участка 33 программы все позиции I, где определяется данная переменная А и откуда существует путь в S3, вдоль которого А не переопределяется. Эта информация может пригодиться для выявления возможных значений А при входе в участок 33. Начнем с определения четырех функций, отображающих участки в множества. Определение. Путем вычислений из оператора st в оператор s2 назовем последовательность операторов, начинающуюся с s, и закапчивающуюся в s2, которая в данном порядке может выпол- няться в процессе исполнения программы. Пусть 33 — участок программы Р. Определим четыре множе- ства, связанные с операторами определения: (1) IN(S) = {d € Р | существует такой путь вычислений из оператора определения d в первый оператор в 33, что никакой из операторов на этом пути, кроме, быть может, первого опе- ратора в 55, не переопределяет переменную, определяемую опе- ратором d}. (2) OUT(®) = {d € Р | существует такой путь вычислений из d в последний оператор в 33, что никакой из операторов на нем не переопределяет переменную, определяемую d}. (3) TRANS(3) = {dgP| переменная, определяемая d, не опре- деляется никаким оператором в 33}. (4) GEN(59) = {d | переменная, определяемая d, не опре- деляется впоследствии нигде в 53}. Гороря неформально, IN(3) содержит определения, которые могут быть активными при входе в 33, OUT(®) содержит опре- «1
ГЛ, 11. ОПТИМИЗАЦИЯ КОДА деления, которые могут быть активными при выходе из S3, TRANS(®) содержит определения, передаваемые через S3 без определения в 3, GEN(SJ) содержит определения, создаваемые в 3, которые остаются активными при выходе из S3. Легко показать, что OUT(3) = (IN(3) Л TRANS(S)) U GEN(3) Пример 11.42. Рассмотрим программу S1: /^-1 S2: J *—О S3: J^-J + l S4: read I S5: if /< 100 goto 38 S6: write/ S7: halt S8: /«-/•/ S9: goto S3 Для удобства все операторы помечены. Граф управления этой программы изображен на рис. 11.41. Каждый участок помечен явно. Определим для множества IN, OUT, TRANS и GEN. Рис. 11.41. Граф управления. Оператор S1 определяет I, a Si, S2, S3 —путь вычислений, на котором I не определяется (кроме как в S1). Поскольку этот путь ведет из SI в первый оператор участка ясно, 432
11.4. АНАЛИЗ ПОТОКА ДАННЫХ что SI g IN(®2). Аналогично можно показать, что IN(®2) = {SI, S2, S3, S8} Отметим, что S4 не принадлежит IN(S2), поскольку нет пути вычислений из S4 в S3, не переопределяющего I после S4. OUT(®2) не содержит S1, поскольку все пути вычислений из S1 в S5 переопределяют /. Предоставляем читателю прове- рить, что OUT(®2) = {S3, S4} TRANS(592) = 0 GEN(S2) = {S3, S4) □ Остаток этого раздела посвящен разработке алгоритма вы- числения IN(S) для всех участков программы. Предположим, что 33г, ..., —все прямые предки участка 33 в Р (одним из них может быть сам участок 3). Ясно, что IN(3)= и ООТ(3() = U [(IN(3,)nTRANS(3())UGEN(3,)l i=i Для вычисления IN(3) можно было бы выписать это уравнение для каждого участка программы вместе с уравнением IN(30) = 0, где 3, — начальный участок, а затем попытаться разрешить систему уравнений1). Однако мы дадим другой метод решения, учитывающий преимущества представления графов управления в виде интервалов. Определим сначала, что мы понимаем под входом и выходом из интервала. Определение. Пусть Р — программа, a F„— ее граф управле- ния. Пусть F„, fj, ..., F„— производная последовательность от F„. Каждая вершина в F,-, i>l, является интервалом в Fi_i и называется интервалом порядка i. Входом интервала порядка 1 служит заголовок интервала (отметим, что этот заголовок—участок программы). Вход интер- вала порядка i > 1—это вход в заголовок этого интервала. Та- ким образом, вход любого интервала — это линейный участок исходной программы Р. Выходом интервала / (п) порядка 1 служит такой последний оператор участка 33 в / (п), что ® имеет прямого потомка, ко- торый является либо заголовком интервала п, либо участком вне I (п). Выход интервала ! (п) порядка i > 1 —это последний ]) Как и в случае уравнений над регулярными выражениями разд. 2.2, решение может быть не единственным. Здесь нам хотелось бы иметь наимень- шее решение. 433
ГЛ. II. ОПТИМИЗАЦИЯ КОДЛ оператор участка ®, содержащегося в I (п)и такого, что в Fa есть дуга, ведущая из S3 либо в заголовок интервала п, либо в участок вне / (п). Отметим, что каждый интервал имеет один вход и пуль или более выходов. Пример 11.43. Пусть Fo — граф управления на рис. 11.41. С помощью алгоритма 11.6 построим его разбиение на интервалы: /2 = /(®а) = {®„ 34} Из этих интервалов можно построить первый производный граф Fj, показанный на рис. 11.42. Из F. можно построить его ин- тервалы (в данном случае только один):-" Л = /(/1) = {Л, U = ®2, ®3, 33.} и получить предельный граф управления, также показанный на рис. 11.42. 6 Рис. 11.42. Производная последовательность от Fo. Интервалами порядка 1 являются /( и 1г. Вход для 1г—это S3, Вход для /3—это Единственный выход для ^ — опера- тор S2. Единственный выход для /2—оператор S9. Интервалом порядка 2 является 1„ с входом 33.. Интервал /3 не имеет вы- ходов. □ Продолжим теперь функции IN, OUT, TRANS и GEN на интервалы. Пусть F,, ..., F„—производная последователь- ность от Fo, F —граф управления для Р. Пусть® — участок в Р, а / — интервал некоторого графа Fh ijsl. Введем следую- х) Строго говоря, интервал 7 порядка i > 1 состоит из интервалов по- рядка I—I. Будем неформально говорить, что участок S& содержится в /, если ои принадлежит одному из интервалов, входящих в 7. Таким образом, множество участков, представляющих интервал произвольного порядка, опре- делено так, как этого и следовало ожидать. 434
11.4. АНАЛИЗ ПОТОКА ДАННЫХ щие рекурсивные определения: (1) IN(/) = IN(59), если I имеет порядок 1, a S—заголовок для /, IN (/'), если I имеет порядок i > 1, а Г—заголовок для I. В (2)—(4) ниже s — выход для I. (2) OUT(/, s) = OUT(S), где участок tS£I таков, что s — его последний оператор. (3) (a) TRANS(S, s) = TRANS(5J), если s — последний опера- тор в S. (б) TRANS(/, s)—множество таких операторов d£P, что существуют путь без циклов It, 12) Iк, состоящий исключительно из вершин в 1, и такая последовательность выходов Sj......sb для It......lk соответственно, что (i) А—заголовок для I, (ii) в F„ участок Sy является прямым предком входа для IJ+l при 1 j < fe, (iii) d£TRANS(/y, st) для isgjsgfe, (iv) ss = s. Эти условия проиллюстрированы на рис. 11.43. (4) (a) GEN(.S, s)=GEN(®), если s —последний оператор в S. (б) GEN(/, s)—множество таких операторов d£P, что существуют путь без циклов Л, .... состоящий 435
ГЛ. И. ОПТИМИЗАЦИЯ КОДА исключительно из вершин в I, и такая последователь- ность выходов Sj, .. ., sk для /,..Ik соответственно, что (i) dCGEN(/1; sj, (ii) в Fo участок Sj является прямым предком входа для IJ+i, 1 j < fe, (iii) dgTRANS(/y, s/) при 2^j<J fe, (iv) sk = s. Отметим, что здесь интервал /, не обязан быть заголов- ком для I. Таким образом, TRANS(/, s) — это множество определений, которые можно передать со входа в I на выход s без переопре- деления в I, GEN(/, s)—это множество определений в /, кото- рые без переопределений могут достичь s. Пример 11.44. Рассмотрим F„ на рис. 11.41 и F, и на рис. 11.42. В Fj интервал /2 — это {Я32, ®3, 33л], и он имеет выход S9. Таким образом, IN(/2) = IN(.®2) = {SI, S2, S3, S8} и OUT(/S, S9) = OUT(®3) = {S3, S8}. TRANS(/2, S9) = 0, поскольку TRANS(32)=0. GEN(/2, S9) содержит S8, поскольку существует последова- тельность участков, состоящая только из S3, в которой S8£ gGEN(S3, S9). Кроме того, S3gGEN(/a, S9), поскольку суще- ствует последовательность участков 332, ®3 с выходами S5 и S9. Это означает, что S3gGEN(®2, S5), 332— прямой предок участ- ка 593, S3 g TRANS(®3, S9). □ Дадим теперь алгоритм вычисления IN(®) для всех участков программы Р. Он обрабатывает только программы со сводимым графом управления. Модификации, необходимые для обработки программ с несводимыми графами, приведены в следующем раз- деле. Алгоритм 11.7. Вычисление функции IN. Вход. Сводимый граф управления F„ для программы Р. Выход. IN(S) для каждого участка 33 С Р. Метод. (1) Пусть Fo, Flt ..., Fk—производная последовательность от Fo. Вычисляем TRANS(®) и GEN(S) для всех участков 33 из /=„. (2) Для i = l, ..., k последовательно вычисляем TRANS(/, s) и GEN(/, s) для всех интервалов порядка ( и выходов s для I. Рекурсивное определение этих функций гарантирует, что это можно сделать. 436
11.4. АНАЛИЗ ПОТОКА ДАННЫХ (3) Полагаем IN(/) = 0, где/—одиночный интервал порядка k. Устанавливаем i = k. (4) Для всех интервалов порядка i выполняем следующее. Пусть / = {/,..../„} — интервал порядка i . .., /й — ин- тервалы порядка i—1 или участки, если i = 1). Можно считать, что эти подынтервалы перечислены в том порядке, в котором из них составлялся интервал / в алгоритме 11.6. Иными словами, /,—это заголовок и для каждого /> 1 множество {/,, ..., содержит все вершины из А,-.,, являющиеся прямыми предками интервала /у. (а) Пусть Sj, s2, sr—выходы интервала /, каждый из которых принадлежит участку в Fa, являющемуся пря- мым предком входа для I. Полагаем IN(/j)“ IN(/) U (J GEN(/, s,) (б) Для всех выходов s ё /, L) полагаем OUT(/„ s) = (IN(/1) n TRANS (/j, s)) U GEN (/„ s) (в) Для / = 2, ..., n пусть s„, sr2.srkr—выходы ин- тервала Ir, каждый из которых принадлежит участку в Fo, являющемуся прямым предком входа для /,. Полагаем IN(/y) = UOUT(/r, sj Г, I OUT(/y, s) = (IN(/y) П TRANS(/y, s)) U GEN(/,, s) для всех выходов s интервала /f. (5) Если i = 1, остановиться. В противном случае уменьшить i на 1 и вернуться к шагу (4). □ Пример 11.45. Применим алгоритм 11.7 к графу управления на рис. 11.41. Для четырех участков в GEN и TRANS вы- числяются просто. Результаты вычислений приведены в табл. 11.9. Таблица 11.9 Участок GEN TRANS И « СО Ч {51, 52} {S3, 54} {58} 0 0 0 {S2, S3} {Si, S2, S3, S4, S8} 1) Если интервал имеет два выхода, ведущих к одному н тому же сле- дующему интервалу, то их для эффективности выполнения можно „слить". „Слияние" состоит в объединении функций GEN и TRANS. 437
ГЛ. 11. ОПТИМИЗАЦИЯ КОДА Например, поскольку 333 определяет только переменную I, 333 „убивает" предыдущие ее определения, но передает опреде- ления переменной J, а именно S2 и S3. Поскольку никакой из участков не определяет переменную дважды, все операторы опре- деления внутри участка принадлежат множеству GEN для дан- ного участка. Заметим, что интервал Ilt состоящий из одного участка Sdlt имеет один выход — оператор S2. Так как пути в /, тривиальны, то GEN(/t, S2) = {S1, 52} и TRANS(/1; S2) = 0. Интервал Ц имеет выход S9. В примере 11.44 мы видели, что GEN(/2, S9) = {S3, S8} и TRANS(/2, S9) = 0. Теперь можно начать вычисление функции IN. Как и тре- буется, IN(/8) = 0. Затем к двум подынтервалам в /3 можно применить шаг (4) алгоритма 11.7. Это можно сделать только в порядке /2. На шаге (4а) вычисляем lN(/,)= lN(/3)^ 0, а на шаге (46) — ОиТ(Л, S2)=(IN(/1)nTRANS(/1, S2))UGEN(/I, S2) = {SI, S2} Далее, на шаге (4в) IN(/2) = OUT(/i, S2) = {S1, S2} Проходя по интервалам порядка 1, мы должны рассмотреть составляющие для /х и /2. Интервал !, состоит только из так что Вычисляем IN(^1) = 0. Интервал /а состоит из участ- ков 53г, 50 и 34, которые в таком порядке и можно рассматри- вать. На шаге (4а) IN(®2) = IN(/2) U GEN(/S, S9) = {S1,S2, S3, S8} На шаге (46) OL'T(50, S5) = (IN(®2)nTRANS(S2, S5))uGEN(®2, S5) = {S3, S4} Поскольку S5 ведет к ®3, находим IN(S8) = OUT(®2, S5) = {S3, S4} а так как S5 также ведет к S3, то IN(S4) = OUT(®2, S5) = {S3, S4} Итак, IN(®,) = 0 IN(592) = {S1, S2, S3, S8} IN(50)-{S3, S4} IN(S4) = {S3, S4} □ Индукцией по порядку интервала I можно доказать, что (1) TRANS(/, s)—множество таких операторов определений d^P, что существует путь из первого оператора заголовка для 438
11.4. АНАЛИЗ ПОТОКА ДАННЫХ I вплоть до 8, вдоль которого пи один из операторов не пере- определяет переменную, определенную в d, (2) GEN(/, s) — множество таких определений d, что сущест- вует путь из d в s, вдоль которого ни один из операторов не переопределяет переменную, определенную в d. Индукцией по числу применений шага (4) алгоритма 11.7 можно доказать, что (11,4.1) если для вычисления IN(Zy) применяется шаг (4), то lN(/7) — множество таких определений d, что суще- ствует путь из d ВО ВХОД ДЛЯ /у, вдоль которого ни один из операторов не переопределяет переменную, определенную в d, a OUT)/,-, s) — множество таких d, что существует путь из d в s, вдоль которого ни один из операторов не переопределяет переменную, определенную в d. Частным случаем утверждения (11.4.1), когда I/— участок, является следующая теорема. Теорема 11.14. Для всех линейных участков ЗЗС.Р множество IN(®) в алгоритме 11.7—это множество таких определений d, что в Fo существует путь из d в первый оператор участка 3d, вдоль которого ни один из операторов не переопределяет пере- менную, определенную в d. □ 11.4.3. Несводимые графы управления Поскольку не каждый граф управления сводим, введем еще одно понятие, называемое расщеплением вершин, позволяющее обобщить алгоритм 11.7 на все графы управления. Вершина, в которую входит более одной дуги, „расщепляется" на несколь- ко одинаковых копий, по одной на каждую входящую дугу. Таким образом, каждая копия имеет единственную входящую дугу и становится частью интервала для вершины, из которой идет эта дуга. Поэтому расщепление вершины с последующим построением интервала уменьшает число вершин графа ио крайней мере на 1. Повторяя, если необходимо, этот процесс, можно превратить любой несводимый граф управления в сво- димый. Пример. 11.46. Рассмотрим несводимый граф управления на рис. 11.40. Вершину па можно расщепить на две копии п'3 и п3 . получив граф F', изображенный на рис. 11.44. Интервалами для F' будут /, = /(п,) = {па, n"j 439
ГЛ. 11. ОПТИМИЗАЦИЯ КОДА Первый производный от F' граф F't имеет две вершины (рис. 11.45). Второй производный граф состоит из единственной вершины. Таким образом, с помощью расщепления вершин мы превра- тили F в сводимый граф управления F’. □ Рис. 11.45. Первый производный граф. Дадим теперь модифицированный вариант алгоритма 11.7, учи- тывающий этот новый метод. Начнем с простого полезного заме- чания. Лемма 11.15. Если G—граф управления и l(G) = G, то лю- бая вершина п, отличная от начальной, имеет по крайней мере две входящие дуги; ни одна из них не выходит из п. Доказательство. Все дуги, выходящие из некоторой вер- шины и входящие в нее же, исчезают при построении интерва- лов. Поэтому предположим, что вершина п имеет только одну входящую дугу, выходящую из другой вершины т. Тогда п принадлежит 1(т). Если /(G) = 0, то вершина т в конце кон- цов появляется в списке заголовков алгоритма 11.6. Но тогда п заносится в 1(т), так что 1(G) не может совпасть с G. □ Алгоритм 11.8. Общее вычисление функции IN. Вход. Произвольный граф управления F программы Р. Выход. IN(53) для каждого участка 33 из Р. Метод. (1) Для каждого участка 33 £F вычисляем GEN(.®) и TRANS(55). Затем к F рекурсивно применяем шаг (2). Входом для шага (2) служит граф управления G вместе с GEN(/,S) и TRANS(/,s), из- вестными для каждой вершины I £G и каждого выхода s интер- вала /. Выходом шага (2) служит IN(/) для каждой вершины /£G. 440
11.4. АНАЛИЗ ПОТОКА ДАННЫХ (2) (а) Пусть G— вход для этого шага и G, G1; ..., Gk — его производная последовательность. Если Gk — одиночная вер- шина, продолжаем в точности так же, как в алгоритме 11.7. Если Gk — не одиночная вершина, то для всех вершин в G], ..., Gk можно вычислить GEN и TRANS, как в алго- ритме 11.7. Тогда по лемме 11.15 Gk содержит некоторую вершину, отличную от начальной, в которую входит более одной дуги. Выберем одну из таких вершин I. Если в I входит / дуг, заменяем I новыми вершинами /п ..., В каждую из 74, I] входит по одной дуге, все они выходят из различных вершин, из которых ранее шли дуги в I. (б) Для каждого выхода s интервала / порождаем выход sf- для 1 -С I / и считаем, что в F есть дуга, ведущая из- каждого а,- во вход каждой вершины, с которой s связан в Ga. Определяем GEN(7Z, s,-) = GEN(7, s) и TRANS(/Z, s,) = = TRANS (I, s) для Результирующий граф обо- значим G'. (в) Применим шаг (2) к G'. Функция IN будет рекурсивно- вычисляться для G'. Затем, полагая IN(7)= (J IN(/,)K i= 1 вычисляем IN для вершин из СА. Никакие другие изме- нения для IN не требуются. (г) Как и в алгоритме 11.7, вычисляем IN для G по IN для Gt. (3) После завершения шага (2) функция IN будет вычислена- для каждого участка из F. Эта информация и образует выход алгоритма. □ Пример 11.47. Рассмотрим граф управления 7% на рис. 11.46,а.. Можно вычислить граф Fj= 7(F0), изображенный на рис. 11.46,6.. Однако 7(F1)=F1, так что надо применять процедуру расще- пления вершин шага (2). Пусть {п2, пв} — вершина /, которая расщепляется на 7t и 12. Результат показан на рис. 11.47. Свяжем, и.! с а {п8, п4} с /2. На рисунке изображены дуги из 7, и /2 в ("а. п4}- В действительности каждый выход для I дублируется — один для /, и один для /2. С входом для {п3, п3} связаны именно продублированные выходы, и этот факт на рис. 11.47 представлен двумя дугами. Отметим, что граф на рис. 11.47—сводимый. □ Теорема 11.15. Алгоритм 11.8 всегда заканчивается. Доказательство. По лемме 11.15 каждое обращение к шагу (2) осуществляется либо на сводимом графе, и в этом слу- чае можно быть уверенным, что вычисление закончится; ли- бо на вершине 7, которую можно расщепить. Заметим, что каждый из интервалов 7О ..., 7у, порождаемых на шаге (2), имеет един- 441
ГЛ. 11. ОПТИМИЗАЦИЯ КОДА ственную входящую дугу. Таким образом, при построении ин- тервалов каждый из них окажется в интервале с другой вершиной в качестве заголовка. Из этого можно заключить, что следую- щее обращение к шагу (2) будет на графе, имеющем по край- ней мере на одну вершину меньше, так что алгоритм 11.8 дол- жен закончиться. □ Теорема 11.16. Алгоритм 11.8 правильно вычисляет функцию IN. Доказательство. Достаточно заметить, htoGEN и TRANS для /„ ..., Ij на шаге (2) те же, что и для I. Кроме того, ясно, 442
11.4. АНАЛИЗ ПОТОКА ДАННЫХ что IN(7)~ U IN(7J и OUT (7)= j OUT. Поскольку каждый i=i i=i интервал /, связывает те же вершины, что и /, функция 1N для вершин в Gt, отличных от /, та же, что и в G'. Таким обра- зом, простая индукция по числу обращений к шагу (2) показы- вает, что IN вычисляется правильно. □ 11.4.4. Обзор содержания главы При построении оптимизирующего компилятора сначала надо решить, какие лучше всего применить оптимизации. Решение должно базироваться на характеристиках того класса про- грамм, которые, как предполагается, должны компилироваться. К сожалению, часто эти характеристики трудно определить, а работ по этому вопросу опубликовано мало. В этой главе мы рассматривали оптимизацию кода с до- вольно общей точки зрения, и разумно было бы спросить, как связаны друг с другом различные обсуждаемые нами оптимизации кода. Методами разд. 11.2, касающимися арифметических выраже- ний, можно пользоваться при построении окончательной объект- ной программы. Однако некоторые аспекты алгоритмов разд. 11.2 можно внести также и в генерацию промежуточного кода. Иными словами, отдельные части алгоритмов разд. 11.2 можно встроить в выход синтаксического анализатора. Это приведет к тому, что на линейных участках будут эффективно использо- ваться регистры. На фазе компилятора, генерирующей код, у нас есть про- межуточная программа, которую можно рассматривать как нечто аналогичное „программам" из разд. 11.3. Наша первая задача — построить граф управления способом, описанным в этом разделе. Следующий возможный шаг — оптимизировать циклы, как описано в разд. 11.3, сначала внутренние, а затем и внешние. Когда это сделано, можно вычислить глобальную информацию относительно потока данных, например, как в алгоритме 11,8 и/или в упр. 11.4.19 и 11.4.20. Зная эту информацию, можно выполнить „глобальные" оптимизации из разд. 11.3, например размножение констант и исключение общих подвыражений. На этой стадии, однако, надо проявлять осторожность, чтобы не увеличить размера внутренних циклов. Для этого можно по- местить участки во внутренних циклах и избегать в таких уча- стках дополнительных действий, связанных с запоминанием значения выражения, даже если это выражение используется позднее в участке вне цикла. Если машина, для которой генериру- 443
ГЛ. 11. ОПТИМИЗАЦИЯ КОДА ется код, имеет более одного регистра, можно выявить активные переменные (упр. 11.4.20), чтобы определить, какие переменные должны занимать регистры при выходе из участков. Наконец, линейные участки можно преобразовать методами разд. 11.1 или аналогичными методами в зависимости от конкрет- ного промежуточного языка. На этой стадии осуществляется также распределение регистров внутри участка, удовлетворяющее упомянутым выше ограничениям на глобальное распределение регистров. Здесь обычно требуются эвристические методы. УПРАЖНЕНИЯ 11.4.1. Постройте производную последовательность графов управления, изображенных на рнс. 11.32 и 11.36. Сводимы ли эти графы? 11.4.2. Приведите дополнительные примеры несводимых гра- фов управления. 11.4.3. Докажите утверждения (1) и (2) теоремы 11.12. *11.4.4. Покажите, что алгоритм 11.6 можно выполнить так, что он будет тратить время, пропорциональное числу дуг гра- фа управления F. 11.4.5 . Докажите теорему 11.14. 11.4.6 . Закончите доказательство теоремы 11.16. 11.4.7 . Используйте анализ интервалов (алгоритм 11.7) как основу алгоритма, выясняющего по данному оператору, ссылаю- щемуся на переменную А, определена ли она явно так, что будет принимать в качестве значения одну и ту же константу при каждом выполнении оператора. Указание: Необходимо найти, ка- кие из операторов, определяющих А, могут быть предыдущими определениями А до очередного выполнения рассматриваемого оператора. Это легко выяснить, если предыдущий оператор, опре- деляющий А, встречается в том же участке, что и рассматривае- мый оператор. Если нет, нужно вычислить IN(S) для участка, в котором встречается оператор. В последнем случае говорят, что А имеет значением константу тогда и только тогда, когда все операторы определения в IN(S3), определяющие А, присва- ивают А одну и ту же константу. 11.4.8 . Приведите алгоритм, использующий анализ интерва- лов как основу для выяснения, бесполезен ли оператор S, т. е. существует ли оператор, употребляющий значение, определяе- мое S. 11.4.9 . Пусть 33— участок графа управления с дугами в 33t и 532, a d — оператор управления в 33, значение которого в 33 444
УПРАЖНЕНИЯ не употребляется. Если никакой из участков, достижимых из ®2, не употребляет значения, определяемого оператором d, то d мож- но переместить в Используйте анализ интервалов как осно- ву для алгоритма, выявляющего такие ситуации. 11.4.10 . Вычислите IN для каждого участка программы N-<—2 У: I — 2 Г: if I < N goto X write N Z-. X—X-l goto У х-. J"—remainder (Л', 7) if J = 0 goto Z 7 — 7 + 1 goto W 11.4.11 . Вычислите IN для каждого участка программы Z: X: W: У: read / if I = 1 goto X if 7 > 10 goto У J+-1+3 write J 7 — 7 + 1 goto Z 7 — / —1 if / > 15 goto W halt *11.4.12. Пусть Tj и T2 — преобразования, следующим образом определенные на графах управления: Т,'. Если вершина п. имеет дугу в себя, удаляем эту дугу. Тг: Если в вершину п входит единственная дуга, выходя- щая из вершины пг, и п не является начальной верши- ной, сливаем m и п, заменяя дугу из пг в п дугами из пг в каждую вершину п', в которую раньше шла дуга из п. Затем исключаем п. Покажите, что если 7\ и Тг применяются к графу управления F до тех пор, пока они применимы, то результатом будет предел графа F. 445
ГЛ. 11. ОПТИМИЗАЦИЯ КОДА *11.4.13. Примените преобразования 7\ и Т2 для вычисления функции IN другим способом, не использующим анализа интер- валов. **11.4.14. Пусть G— граф управления с начальной верши- ной па. Покажите, что G несводим тогда и только тогда, когда он имеет такие вершины nlt п2 и н3, что существуют пути из па в п2, из в л, и в п3, из п„ в н, и из п, в п.£ (рис. 11.48), сов- Рис. 11.48. Структура любого несводимого графа. падающие только в их конечных точках. Все па, nit п,, и п3 должны быть различны, только может совпадать с на. 11.4.15. Покажите, что любая d-схема (см. разд. 1.3.2) сво- дима. Указание: Воспользуйтесь упр. 11.4.14. 11.4.16. Покажите, что любая программа на Фортране, в ко- торой каждый переход на предыдущий оператор вызывается циклом DO, имеет сводимый граф управления. **11.4.17. Покажите, что можно за время 0(n log п) выяснить, сводим ли данный граф управления. Указание: Воспользуйтесь упр. 11.4.12. * 11.4.18. Какая существует связь между понятиями интервала и области с одним входом? * 11.4.19. Приведите основанный на понятии интервала алго- ритм, выясняющий для каждого выражения (скажем, Л-|-В) и каждого участка 53, при каждом ли выполнении программы дос- тигается оператор, вычисляющий А-)-В (т. е. существует ли оператор вида С<—Л —В) и не переопределяющий впоследствии ни А, ни В. Указание: Если ЗА не является начальным участком, то положим IN (3?) = A OUT (59,), где все 59,-—прямые предки i участка ЗА. Пусть OUT (3) = (IN (ЗА( П X) U У 446
УПРАЖНЕНИЯ где X — множество выражений, „убиваемых" в ЗА (мы „убываем" А В, переопределяя А или В), a Y—множество выражений, вычисляемых участком и неубиваемых. Для каждого интервала I различных производных графов и каждого его выхода s вычисляем GEN'(/, S) как множество выражений, вычисляемых и впослед- ствии не убиваемых ни на каком пути из входа в интервал I в его выход. Вычисляем также TRANS' (7, s) как множество выражений, которые, будучи убитыми, генерируются затем на лю- бом таком пути. Отметим, что GEN'(7, s) s TRANS' (/, s). * 11.4.20. Приведите алгоритм, основанный на анализе интер- валов, который для каждой переменной А и каждого участка ЗА выясняет, есть ли выполнение, которое после прохождения через ЗА будет ссылаться иа переменную А перед ее переопределением. 11.4.21. Пусть F— граф с/г вершинами и е дугами. Покажите, что i-й производный граф от F имеет не более чем е — i дуг. * 11.4.22. Приведите пример графа управления с п вершинами и 2п дугами, производная последовательность которого имеет длину п. * 11.4.23. Покажите, что алгоритм 11.7 и алгоритмы из упр. 11.4.19 и 11.4.20 тратят не более 0(/С) элементарных векторных шагов на графах управления с п вершинами и не более чем 2п дугами. Существует другой подход к анализу потока данных, таблич- ный по своей природе. Например, по аналогии с алгоритмом 11.8 можно построить таблицу значений IN (d, ЗА), равных 1, если в 1N (3)) есть определение d, и 0 в противном случае. Вначале пусть IN (d, ЗА) = 1 тогда и только тогда, когда из некоторой вер- шины S ведет дуга в ЗА и d g GEN (ЗА'). Для каждой единицы, добавленной в таблицу, скажем на элемент (d, ЗА), помещаем 1 в элемент (d, ЗА"), если есть дуга из ЗВ в 33' и ЗА не убивает d. * 11.4.24. Покажите, что приведенный выше алгоритм правильно вычисляет IN (ЗА) и занимает 0 (тп) времени на графе управления с п вершинами, не более чем 2п дугами и т определениями. * 11.4.25. Дайте алгоритмы, аналогичные приведенному выше и решающие те же задачи, что и в упр. 11.4.19 и 11.4.20. Как быстро они работают? * *11.4.26. Приведите алгоритмы, тратящие 0 (п log п) элементар- ных векторных шагов на вычисление функций IN алгоритма 11.7 или упр. 11.4.19 для графов управления с п вершинами. * *11.4.27. Покажите, что граф управления сводим тогда и только тогда, когда множество его дуг можно разбить на два таких множества и Е2, что 1) Е{ образует ориентированный ацик- 447
ГЛ. II. ОПТИМИЗАЦИЯ КОДА лический графи 2) если (/тг, п) принадлежит 52, то т — п или п доминирует над /тг, * *11.4.28. Приведите алгоритм, вычисляющий прямые домина- торы сводимого графа с п вершинами за время 0 (п log/г). Проблемы для исследования 11.4.29. Предложите дополнительную информацию относи- тельно потока данных (не упоминаемую в алгоритме 11.7 и упр. 11.4.19 и 11.4.20), которая пригодилась бы для целей оптими- зации кода. Дайте алгоритмы, вычисляющие эту информацию как для сводимых, так и для несводимых графов управления. 11.4.30. Существуют ли методы вычисления функций IN алго- ритма 11.8 или других функций, связанных с потоком данных, которые были бы предпочтительнее для расщепления вершин несводимых графов? Под „предпочтительностью** мы понимаем, что допустимы операции над элементарными векторами и что алго- ритмы упр. 11.4.24 и 11.4.25 становятся явно оптимальными. Замечания по литературе Подход к оптимизации с точки зрения анализа интервалов был развит Коком [1970] и затем разработай Коком и Шварцем [1970] и Алленом [1970]. Кеннеди [1971] рассматривает глобальный алгоритм, использующий анализ интервалов для распознавания в программе активных переменных (упр. 11.4.20). Решения упр. 11.4.12—11.4.16 можно идйтн у Хекта и Ульмана [1972а]. Упр. 11.4.17 взято из работы Хопкрофта и Ульмана [19726]. Ответ на упр. 11.4.19 можно найти у Кока [1970] или Шефера [1973]. Упр. 11.4.24 и 11.4.26 взяты у Ульмана [197261, упр. 11.4.27 —у Хекта и Ульмана [19726], упр. 11.4.28 —у Ахо и др, [1972]. В ряде статей обсуждается реализация оптимизи- рующих компиляторов. Лоури и Медлок [1969] приводят некоторые оптимиза- ции, применяемые в компиляторе OS/360 FORTRAN Н. Вузам и Энглунд [1969] описывают методы для распознавания общих подвыражений, удаления инвари- антных вычислений нз циклов и распределения регистров для другого компи- лятора с Фортрана. Кнут [1971] собрал много программ на Фортране и проанализировал неко- торые их характеристики1). 2) Анализ потока данных, использующий представление программы в ви- де операторной схемы, применяется в АЛЬФА-трансляторе (Ершов и др. [1965]). О применении графов управления программ для целей оптимизации см. также [Касьянов, Трахтенброт, 1975], [Поттосии, 1973, 1975], [Касьянов, 1975].— Прим, перев.
СПИСОК ЛИТЕРАТУРЫ К I и 2 ТОМАМ1) Айронс [1961] (Irons Е. Т.), A syntax directed compiler for ALGOL 60, Comm. ACM, 4:1, 51—55. Айронс'[1963a] (Irons E, T.), An error correcting parse algorithm, Comm. ACM, 6:11, 669—673. Айронс [19636] (Irons E. T.) The structure and use of the syntax directed com- piler, Ann. Rev. Auton. Program., 3, 207—227. Айронс [1964] (Irons E. T.), Structural connections in formal languages, Comm< ACM, 7:2, 62—67. Аллард, Вольф, Землин [1964] (Allard R. W., Wolf K. A., Zemlin R. A.), Some effects of the 6600 computer on language structures, Comm. ACM, 7:2, 112-127. Аллен [1969] (Allen F. E.), Program optimization, Ann. Rev. Autom. Program., 5. Аллен J1970] (Allen F. E.), Control flow analysis, ACM S/GPLAN Notices, 5: 7, 1 — 19. Аллен, Кок [1972] (Allen F. E., Cocke J.), A catalogue of optimizing transforma- tions, сб. Design and Optimization of Compilers, под ред. Rustin R., Pren- tice-Hall, Englewood Cliffs, N. J., pp. 1—30. Айгер [1968] (Unger S. H.), A global parser for context-free phrase structure grammars, Comm. ACM, 11:4, 240—246; 11:6, 427. Андерсон [1964] (Anderson J. P.), A note on some compiling algorithms, Comm. ACM, 7:3, 149—150. AHC [19661 (Ans X3.9), American National Standards FORTRAN, American National Standards Institute, New York. AHC Подкомитет [1971] (Ansi Subcommittee X3J3), Clarification of FORTRAN Standards—Second Report, Comm. ACM, 14:10, 628—642. Арбнб [1970] (Arbib M. A.), Theories of abstract automata, Prentice-Hall, Inc., Englewood Cliffs, N. J. Axo [1968] (Aho A. V.), Indexed grammars—an extention of context-free gram- mars, J. ACM, 15:4, 647—671. (Русский перевод: Ахо А., Индексные грам- матики—расширение контекстно-свободных грамматик, в^сб. „Языки и автоматы44, изд-во „Мир“, М.» 1975, стр. 130—165.) Ахо [1973] (Aho А. V. (ed.)), Currents in the theory of computing, Prentice-Hall, Englewood Cliffs, N. J. ° Ахо, Ульман [ 1968] (Aho A. V., Ullman J. D.), The theory of languages, Math. Syst. Theory, 2:2, 97—125. (Русский перевод: Ахоу А., Улмаи Дж., Теория языков, Кибернетический сборник, новая серия, вып. 6, изд-во „Мир“, М., 1969, стр. 145—183.) Ахо, Ульман [1969а] (Aho А. V., Ullman J. D.), Syntax directed translations and the pushdown assembler, J. Comput. Syst. Sci., 3:1, 37—56. *) Кружочком ° отмечена литература, добавленная при переводе тома 2. — Прим, перев. 449
СПИСОК ЛИТЕРАТУРЫ Ахо, Ульман [19696] (Aho А. V., Ullman J. D.), Properties of syntax directed translations, J. Comput. Syst. Sci., 3:3, 319—334. Ахо, Ульман [1971a] (Aho Л. V., Ullman J. D.), The care and feeding of LR(fe) grammars, Proc, of 3rd Annual ACM Symposium on Theory of Computing, 159—170. Ахо, Ульман [19716] (Aho A. V., Ullman J. D.), Translations on a context-free grammar, Inform, and Control, 19:5, 439—475. Ахо, Ульман [1972a] (Aho A. V., Ullman J. D.), Linear precedence functions for weak precedence grammars, Intern. J. Comput. Math., в печати. Ахо, Ульман 119726] (Aho А. V., Ullman J. D.), Error detection in precedence parsers, Math. Syst. Theory, в печати. Ахо, Ульман [1972в] (Aho А. V., Ullman J. D.), Optimization of LR(&) par- sers, J. Comput. Syst. Sci., в печати. Ахо, Ульман [1972г] (Aho А. V., Ullman J. D.), A technique for speeding up LR(fe) parsers, Proc. Fourth Annual ACM Symposium on Theory of Compu- ting, pp. 251—263. Ахо, Ульман |1972д] (Aho A. V., Ullman J. D.), Optimization of straight line code, SIAM J. on Computing, 1:1, 1 —19. Ахо, Ульман [1972e] (Aho A. V., Ullman J, D.), Equivalence of programs with structured variables, J. Comput. Syst. Sci., 6:2, 125—137. Ахо, Ульман [1972ж] (Aho A. V., Ullman J. D.), LR(/z) syntax directed trans- lation, неопубликованная рукопись, Bell Laboratories, Murray Hill, N. J. Ахо и др. [1968] (Aho A. V., Hopcroft J. E., Ullman J. D.), Time and tape complexity of pushdown automaton languages, Inform, and Control, 13:3, 186—206. (Русский перевод: Ахо А., Хопкрофт Дж., Ульман Дж., Вре- менная и ленточная сложности языков, допускаемых магазинными авто- матами, в сб. „Языки и автоматы1-, изд-во „Мир“, М., 1975, стр. 181—197.) Ахо и др. [1972а] (Aho А. V., Denning Р. J., Ullman J. D.), Weak and mixed strategy precedence parsing, J. ACM, 19:2, 225—243. Ахо и др. [19726] (Aho A. V., Hopcroft J. E., Ullman J. D.), On finding lowest common ancestors in trees, неопубликованная рукопись, Bell Laboratories, Murray Hill, N. J. Ахо и др. [1972в] (Aho A. V., Sethi R., Ullman J. D.), Code optimization and finite Church-Rosser systems, в сб. Design and Optimization of Compilers, под род. Rustin R., Prentice-Hall, Englewood Cliffs, N, J., pp. 89—106. Ахо н др. [1975] (Aho A. V., Johnson S. C., Ullman J. D.), Deterministic par- sing of ambiguous grammars, Comm. ACM, 18:8, 441—453. Багвелл [1970] (Bagwell J. T.), Local optimizations, ACM SIGPLAN Notices, 5:7, 52—66. Барнет, Футрель [1962] (Barnett M. P., Futrelle R. P.), Syntactic analysis by digital computer, Comm. ACM, 5:10, 515—526. Бар-Хнллел [1964] (Bar-Hillel Y.), Language and information, Addison-Wesley, Reading, Mass. Бар-Хиллел н др. [1961] (Bar-Hillel Y„ Perles M., Shamir E.), On formal properties of simple phrase structure grammars. Z. Phonetik, Sprachwissen- schaft und Kommunikationsforschung, 14, 143—172. См. также ^ар-Хил- лел [1964], pp. 116—150. Бауэр и др. [1968] (Bauer Н., Becker S., Graham S.), ALGOL W Implementa- tion, QS98, Computer Science Dept. Stanford University, Stanford, Calif. рБежаиова M. M., Поттосни H, B. [1965], Программирование циклов и индек- сных выражений в Альфа-трансляторе, в сб. „Альфа-система автоматиза- ции программирования41 под ред. А.П. Ершова; ВЦ СО АН СССР, Ново- сибирск (2-е издание, „Наука", М., 1967). Белл [1969] (Bell J. R.), A new method for determining linear precedence func- tions for precedence grammars, Comm. ACM, 12:10, 316—333. Белл [1970] (Bell J. R.), The quadratic quotient method: a hash code elimina- ting secondary clustering, Comm. ACM, 13:2, 107—109. 450
СПИСОК ЛИТЕРАТУРЫ Берж [1958] (Berge С.), The theory of graphs and its applications, Wiley, New York. (Русский перевод: Берж К., Теория графов и ее применение, ИЛ, М., 1962.) • Бжозовский [1962] (Brzozowski J. A.), A survey of regular expressions and their applications, /RE Trans, on Electr. Comput., 11:3, 324—335 Бжозовский [1964] (Brzozowski J. A.), Derivatives of regular expressions, Л ACM, 11:4, 481—494. Биледи [1966] (Belady L. A.), A study of replacement algorithms for a virtual storage computer, IBM Systems J., 5, 78—82. Билз [1969] (Beals A. J.), The generation of a deterministic parsing algorithm, Report № 304, Department of Computer Science, University of Illinois, Urbana. Билз и др. [1969] (Beals A. J., LaFrance J. E., Northcote R. S.), The auto- matic generation of Floyd production syntactic analyzers, Report № 350, Department of Computer Science, University of Illinois, Urbana. Бити [1972] (Beatty J. C.), An axiomatic approach to code optimization for expressions, J. ACM, 19:4. Бирман, Ульмаи [1970] (Birman A., Ullman J. D.), Parsing algorithms with backtrack, IEEE Conf, Record of 11th Annual Symposium on Switching and Automata Theory, 153—174. (Расширенный вариант этой работы см. в Inform, and Control, 23:1 (1973), 1—34.) Блатнер [1972] (Blattner М.), The unsolvability of the equality problem for sentential forms of context-free languages, неопубликованное сообщение, UCLA, Los Angeles, Calif. Бобров [1963] (Bobrow D. G.), Syntactic analysis of English by computer — a survey, Proc. AFIPS Fall Joint Computer Conference, 24, 365—387. Бородин [1970] (Borodin A.), Computational complexity — a survey, Proc. 4th Annual Princeton Conference on Information Sciences and Systems, 257—262. См. также Ахо [1973]. °Бошман [1976] (Bochmann G. V.), Semantic evaluation from left to right, Comm. ACM, 19:2, 55—62. °Братчиков И. Л. [1975], Синтаксис языков программирования, изд-во „На- ука“, М. Браффорт, Хиршберг [1963} (Braffort Р., Hirschberg D. (eds.)), Computer prog- ramming and formal systems, North-Holland, Amsterdam. Браха [1972] (Bracha N.)> Transformations on loop-free program schemata, Re- port № U1UCDCS-R-72-516, Department of Computer Science, University of Illinois, Urbana. Брукер, Моррис [1963] (Brooker R. A., Morris D.), The compiler-compiler, Ann Rev. Autom. Program., 3, 229—275, Бруно, Беркхард [1970] (Bruno J. L., Burkhard W. A.), A circularity test for interpreted grammars. Technical Report 88. Computer Sciences Labora- tory, Department of Electrical Engineering, Princeton University, Prince- ton, N. J. Брюер [1969] (Breuer M. A.), Generation of optimal code for expressions via factorization, Comm. ACM,. 12:6, 333—340. Буэам, Энглуид [1969] (Busam V. A., Englund D. E.), Optimization of expres- sions in Fortran, Comm. ACM, 12:12, 666—674. Бук [1970] (Book R. V.), Problems in formal language theory, Proc. 4th An- nual Princeton Conference on Information Sciences and Systems, 253—256. См. также Ахо [1973]. Бут [1967] (Booth T. L.), Sequential machines and automata theory, Wiley, New York. Бэкус и др. [1957] (Backus J. W. et al.), The FORTRAN automatic coding system, Proc. Western Joint Computer Conference, 11, 188—198. Бэр, Бове [1968] (Baer J. L., Bovet D. P.), Compilation of arithmetic expres- sions for parallel computations, Proc. IFIP Congress 68, B4 — B10. 451
СПИСОК ЛИТЕРАТУРЫ Вайз [1971J (Wise D. S.), Domolki’s algorithm applied to generalized overlap resolvable grammars, Proc. 3d Annual Symposium on Theory of Computing, 171—184. Ban Вейнгаардеи [1969} (Van Wijngaarden A. (ed.)), Report on the algorithmic language ALGOL 68, Numer. Math., 14, 79—218. (Русский перевод: Ал- горитмический язык АЛГОЛ 68, Кибернетика, 6 (1969); 1 (1970).) °Ван Вейнгаардеи и др. [1975] (Van Wijngaarden et al. (eds.)), Revised report on the algorithmic language ALGOL 68, Acta Information, 5, 1—236. (Рус- ский перевод готовится к печати в нзд-ве „Мир“, М.) Вегбрейт [1970] (Wegbreit В.), Studies in extensible programming languages, Ph. D. Thesis, Harvard Univ., Cambridge, Mass. “Великанова T. M., Ершов А. П., Ким К. В., Курочкин В. М., Олейник- Овод Ю. Н., Поддерюгин В. Д. [1961], Программируемая программа для машины (ППС), Тр. Всесоюзн. совещ. по вычисл. математике и приме- нению средств вычисл. техники, Изд-во АН АзССР, Баку. Виноград [1965] (Winograd S.), On the time required to perform addition, J. ACM, 12:2, 277—285. (Русский перевод: Виноград С., О времени, требующемся для выполнения сложения, Кибернетический сборник, новая серия, вып. 6, изд-во „Мир", М., 1969, стр. 41—54.) Виноград [1967] (Winograd S.), On the time required to perform multiplication, J. ACM, 14:4, 793—802. (Русский перевод: Виноград С., О времени, требующемся для выполнения умножения, Кибернетический сборник, новая серия, вып. 6, изд-во „Мир“, М., 1969, стр. 55—71.) Вирт [1965] (Wirth N.), Algorithm 265: Find precedence functions, Comm. ACM, 8:10, 604—605. Внрт [1968] (Wirth N.), PL 360—a programming language for the 360 com- puters, J. ACM, 15:1, 37—54. Вирт, Вебер [1966] (Wirth N., Weber H.), EULER — a generalization of ALGOL and its formal definition,. Parts 1 and 2, Comm. ACM, 9:1, 13—23; 9:2, 89—99. Возеикрафт, Эваис [1969] (Wozencraft J. M., Evans A., Jr.), Notes on prog- ramming languages, Dept, of Electrical Engineering, Massachusetts Institute of Technology, Cambridge, Mass. Вуд [1969a] (Wood D.), The theory of left factored languages, Comput. J., 12:4, 349—356; 13:1, 55—62. Вуд [19696) (Wood D.), A note on top on top-down deterministic languages, BIT, 9:4, 387—399. Вуд [1970] (Wood D.), Bibliography 23: Formal language theory and automata theory, Comput. Rev., 11:7, 417—430, Галлер, Перлис [1967] (Gallcr В. A., Perlis A. J.), A proposal for definitions in ALGOL, Comm. ACM, 10:4, 204—219. Гарвик [1964] (Garwick J. V.), GARGOYLE, a language for compiler writing. Comm. ACM, 7:1, 16—20. Гарвик [1968] (Garwick J. V.), GPL, a truly general purpose language, Comm. ACM, 11:9, 634—638. Гилл [1962] (Gill A.), Introduction to the theory of finite state machines, McGraw-Hill, New York. (Русский перевод: Гилл А., Введение в теорию конечных автоматов, изд-во „Наука“, М., 1966.) Гинзбург [1968] (Ginzburg A.), Algebraic theory of automata, Academic Press. New York, Гинзбург [1962] (Ginsburg S.), An Introduction to mathematical machine theory, Addison-Wesley, Reading, Mass. Гинзбург [1966] (Ginsburg S.), The mathematical theory of context-free lan- guages, McGraw-Hill, New York. (Русский перевод: Гинзбург С., Матема- тическая теория контекстно-свободных языков, изд-во „Мир“, М., 1970.) Гинзбург, Грейбах [1966] (Ginsburg S., Greibach S. A.), Deterministic context- free languages, Inform, and Control, 9:6, 620—648. 452
СПИСОК ЛИТЕРАТУРЫ Гинзбург, Грейбах [1969] (Ginsburg S.,’Greibach S. A.), Abstract families of languages, Memoir Amer. Math. Soc., 87, I—32. (Русский перевод: Гинзбург С., Грейбах Ш.» Абстрактные семейства языков, в сб. „Языки и автоматы", изд-во „Мир", М., 1975, стр. 233—281.) Гинзбург, Райс [1962] (Ginsburg S., Rice Н. G.), Two families of languages related to ALGOL, J, ACM, 9:3, 350—371. (Русский перевод: Гинзбург С., Райс X., Два класса языков типа АЛГОЛ, Кибернетический сборник, новая серия, вып. 6, нзд-во „Мир", М., 1969, стр. 184—216.) Гир [1965] (Gear С. W.), High speed compilation of efficient object code, Comm. ACM, 8:8, 483—487. Глении [1960] (Glennie A.), On the syntax machine and the construction of a universal compiler, Technical Report № 2, Computation Center, Carnegie- Mellon University, Pittsburg, Pa. Грау и др. [1967] (Grau A« A., Hill U., Langmaack H.), Translation of ALGOL 60, Springer, New York. Грейбах [1965] (Greibach S. A.), A new normal form theorem for context-free phrase structure grammars, J. ACM, 12:1, 42—52. Грейбах, Хопкрофт [1969] (Greibach S. A., Hopcroft J.), Scattered context grammars, J. Comput. Sysi, Sci., 3:3, 233—247. (Русский перевод: Грей- бах Ш., Хопкрофт Дж., Грамматики с рассеянным контекстом, в сб. „Языки н автоматы", изд-во „Мир", М,, 1975, стр. 166—184.) Грнс [1971] (Gries D.), Compiler construction for -digital computers, Wiley, New YorK. (Русский перевод: Грис Д., Конструирование компиляторов- для цифровых вычислительных машин, изд-во „Мир", М., 1975.) Грисволд и др. [1971] (Griswold R. Е., Poage J. F., Polonsky I. Р.), The- SNOBOL 4 programming language (2nd ed.), Prentice-Hall, Englewood Cliffs, N. J. Гриффитс [1968] (Griffiths T. V.), The unsolvability of the equivalence prob- lem for A-frec nondeterministic generalized machines, J. ACM, 15:3, 409—413. (Русский перевод: Гриффитс T. В., Неразрешимость проблемы эквивалентности для А-свободиых обобщенных машин, Кибернетический сборник, новая серия, вып. 8, изд-во „Мир", М., 1971.) Гриффитс, Петрик [1965] (Griffiths Т. V., Petrick S. R.), On the relative effi- ciencies of context-free grammar recognizers, Comtn. ACM, 8:5, 289—300. Гросс, Лантен [1970] (Gross M., Lentin A.), Introduction to formal grammars, Springer, New York. (Русский перевод: Гросс M., Лантеи А., Теория формальных грамматик, нзд-во „Мир", М., 1971.) Грэй [1969] (Gray J. N.), Precedence parsers for programming languages, Ph. D. Thesis, Univ, of California, Berkeley. Грэй, Харрисон [1969] (Gray J. N., Harrison M. A.), Single pass precedence analysis, IEEE Conf. Record of 10th Annual Symposium on Switching and Automata Theory, 1C6—117. Грэй и др. [1967] (Gray J. N., Harrison M. A., Ibarra O.), Two way pushdown automata, Inform, and Control, 11:1, 30—70. Грэхем [1972] (Graham R. L.), Bounds on multiprocessing anomalies and rela- ted packing algorithms, Proc. AFIPS Spring Joint Computer Conference, 40, AFIPS Press, Montvale, N. J., 205—217. Грэхем [1964] (Graham R. M.), Bounded context translation, Proc. AFIPS Spring Joint Computer Conference, 25, 17—29. Грэхем [1970] (Graham S. L.), Extended precedence languages, bounded right context languages and deterministic languages, IEEE Conf. Record of 11th Annual Symposium on Switching and Automata Theory, 175—180. Де Бэккер [1971] (De Bakker J. W.), Axiom systems for simple assignment statements, см. Эигелер [1971, стр. 1—22]. Де Ремер [1968] (DeRemer F. L.), On the generation of parsers for BNF gram- mars: an algorithm, Report № 276, Dept, of Computer Science, University of Illinois, Urbana. 453>
СПИСОК ЛИТЕРАТУРЫ Де Ремер [1969] (DeRemer F. L.), Practical translators for LR(/e) languages, Ph. D. Thesis, Massachusetts Institute of Technology, Cambridge, Mass. Де Ремер [1971] (DeRemer F. L.), Simple LR(£) grammars, Comm. ACM, 14:7, 453—460. Джентльмен [1971] (Gentleman W. M.), A portable coroutine system, Informa- tion processing—71 (1F1P Congress), TA —3, 94—98. Джонсон и др. [1968] (Johnson W. L., Porter J. H., Ackley S. 1., Ross D. T.}, Automatic generation of efficient lexical processors using finite state techni- ques, Comm. ACM, 11:12, 805—813. Дьюар и др. [1969] (Dewar R. В. К... Hochsnrung R. R., Worley W, S.), The IITRAN programming language, Comm. ACM, 12:10, 569—575. Дэвис [1958] (Davis M.), Computability and unsolvability, McGraw-Hill, New York. Дэвис [1965] (Davis M. (ed.)), The undecidable, Basic papers in undecidable propositions, unsolvable problems and computable functions, Raven Press, New York. °Ершов А. П. [1958a], Программируемая программа для быстродействующей электронной счетной машины, Йзд-во АН СССР, М. сЕршов А. П, [19586], О программировании арифметических операторов, ДАН СССР, 118: 3. сЕршов А. П. [1962], Сведение задачи распределения памяти при составлении программ к задаче раскраски вершин графов, ДАН СССР, 142: 4. Ершов А. П. [1966], ALPHA — an automatic programming system of high efficiency, J. ACM, 13:1, 17—24. °Ершов А. П., Змиевская Л. Л., Мишкович P. Д., Трохан Л. К. [1965], Экономия и распределение памяти в Альфа-трансляторе, в сб. „Альфа- система автоматизации программирования44, ВЦСОАН СССР, Новосибирск. рЕршов А. П., Курочкин В. М. [1961], О некоторых проблемах автоматиче- ского программирования, Тр. Всесоюзн. совещ. по вычисл. матем. и при- менению средств вычисл. техники, Изд-во АН АзССР, Баку. ®Ершова Н. М., Мостинская С. В., Руднева Т. Л. [1961], Арифметический блок, в сб. „Система автоматизации программирования14 под ред. Н. П. Трифонова и М. Р. Шура-Буры, изд-во „Наука44, М. Замельзои, Бауэр [1960] (Samelson К., Bauer F. L.), Sequential formula translation, Comm. ACM, 3:2, 76—83. ИБМ [1969] (IBM), System 360 Operating System PL/I(F) Compiler Program Logic Manual, PubL № Y286800, IBM, Hurslcy, Winchester, England.' Игараси [1968] (Igarashi S.), On the equivalence of programs represented by Algol-like statements, Report of the Computer Centre, University of Tokyo, 1, 103—118. Ингермаи [1966] (ingerman P. Z.), A syntax oriented translator, Academic Press, New York. (Русский перевод: Ингермаи П,, Синтаксически ориен- тированный транслятор, изд-во „Мир“, М., 1969.) Ихбиа, Морзе [19/0] (Ichbiah J. D., Morse S. Р.), A technique for generating almost optimal Floyd-Evans productions for precedence grammars, Comm. ACM, 13:8, 501—508. Кавинесс [1970] (Caviness B. F,), On canonical forms and simplification, J. ACM, 17:2, 385—396. Камеда, Вайиер [1968] (Kameda T., Weiner P.), On the reduction of nonde- terministic automata, Proc. 2nd Annual Princeton Conference on Information Sciences and Systems, 348—352. Кантор [1962] (Cantor D. G.), On the ambiguity problem of Backus systems, J. ACM, 9:4, 477—479. 9Камыиин С. С., Любимский Э. 3., Шура-Бура M. P. [1958], Об автома/и- зацин программирования, Проблемы кибернетики, вып. 1. Каплан [1970] (Kaplan D. М.), Proving things about programs, Proc. 4th Annual Princeton Conference on Information Sciences and Systems, 244—251. 454
СПИСОК ЛИТЕРАТУРЫ Касамн [1965] (Kasami Т.), An efficient recognition and syntax analysis algo- rithm for context-free languages, Sci. Rep. AFCRL-65-758, Air Force Camb- ridge Research Laboratory, Bedford, Mass. Касамн, Торин [1969] (Kasami T., Torii K), A syntax analysis procedure for unambiguous context-free grammars, J. ACM, 16:3, 423—431. ₽Касьянов В. H. [1975], Выделение гамаков в ориентированном графе, ДАН СССР, 221:5, 1020—1022. “Касьянов В. Н-, Трахтенброт М. Б. [1975], Анализ структур программ в глобальной оптимизации, Труды Всесоюзп. сими, по методам реализации новых алгоритм, языков, Новосибирск. Кеннеди [1971] (Kennedy К.), A global flow analysis algorithm, Intern. J. Comput. Math., 3:1, 5—16. Кеннеди [1972] (Kennedy K.), Index register allocation in straight line code and simple loops, в сб. „Design and Optimization of Compilers" под ред. Rustin R., Prcntice-Hall, Englewood Cliffs, N. J., 51—64. “Китов А. И., Крииицкий H. A. [1959], Электронные цифровые машины и программирование, Физматгиз, М. Кларк [1967] (Clark Е. R.), On the automatic simplification of source language programs, Comm. ACM, 10:3, 160—164. Клнии [1952] (Klccnc S. C.), Introduction to metamathematics, Van Nostrand Reinhold, New York. (Русский перевод: Клини С. К., Введение в метама- тематику, ИЛ, М., 1957.) Клипы [1956] (Kleene S. С.), Representation of events in nerve nets, в сб. „Automata Studies" под ред. Shannon С. E., McCarthy J., Princeton Uni- versity Press, Princeton, N. J. (Русский перевод: Клиии С. К., Пред- ставление событий в нервных сетях, в сб. „Автоматы", ИЛ, М., 1956». стр. 15—67.) 'Кнут [1965] (Knuth D. Е.), On the translation of languages from left to right. Inform. Control, 8:6, 607—639. (Русский перевод: Кнут Д. Е., О пере- воде (трансляции) языков слева направо, в сб. „Языки н автоматы", изд-во „Мир", М., 1975, стр. 9—42.) Кнут [1967] (Knuth D. Е.), Top-down syntax analysis, Lecture Notes, Inter- national Summer School on Computer Programming, Copenhagen. См. также Acta Informatica, 1:2 (1971), 79—110. Кнут [1968a] (Knuth D. E.), The art of computer programming, Vol. 1: Fun- damental algorithms, Addison-Wesley, Reading, Mass. (Русский перевод: Кнут Д., Искусство программирования для ЭВМ, т. I, изд-во „Мир", М., 1975.) Кнут [19686] (Knuth D. Е.), Semantics of context-free languages, Math. Syst. Theory, 2:2, 127—146. См. также Math. Syst. Theory, 5:1, 95—96. Кнут [1971] (Knuth D. E.), An empirical study of FORTRAN programs, Software—Practice and Experience, 1:2, 105—134. Киут [1973] (Knuth D. E.), The art of computer programming, Vol.3: Sorting and searching, Addison-Wesley, Reading, Mass. (Русский перевод гото- вится к печати в изд-ве „Мир", М.) Кок [1970] (Cocke J.), Global common subexpression elimination, ACM SIGPLAN Notices, 5:7, 20—24. Кок, Шварц [1970] (Cocke J., Schwartz J. T.), Programming languages and their compilers, Courant Institute of Mathematical Sciences, New York University, Nem York. Колмерауэр [1970] (Colmerauer A.), Total precedence relations, J. ACM, 17:1, 14—30. Конвэй [1963] (Conway M. E.), Design of a separable transitlon-daigram com- piler, Comm. ACM, 6:7, 396—408. (Русский перевод: Конвей M. Е., Проект делимого компилятора, осиоваиного на диаграммах перехода, в сб. „Сов- ременное программирование", изд-во „Сов, радио", М., 1967, стр. 206— 246.) 455
СПИСОК ЛИТЕРАТУРЫ Конвэй, Максвелл [1963] (Conway R. W., Maxwell W. L.), CORC: The Cor- nell computing language, Comm. ACM, 6:6, 317—321. Конвэй, Максвелл [1968] (Conway R. W., Maxwell W. L.), CUPL — an appro- ach to introductory computing instruction, TR № 68—4, Dept, of Com- puter Science, Cornell Univ., Ithaca, N. Y. Конвэй и др. [1970] (Conway R. W. et al.), PL/C. A high performance subset of PL/I, TR 70—55, Dept, of Computer Science, Cornell Univ., Ithaca, N. Y. Корсньяк [1969] (Korenjak A. J.), A practical method for constructing LR (k) processors. Comm. ACM, 12:11, 613—623. Кореиьяк, Хопкрофт [1966] (Korenjak A. J., Honcroft J. E.), Simple determi- nistic languages, IEEE Conf. Record of 7th Annual Symposium on Swit- ching and Automata Theory, 36—46. (Русский перевод: Кореиьяк A., Хопкрофт Дж., Простые детерминированные языки, в сб. „Языки и авто- маты“, изд-во „Мир“, М., 1975, сгр. 71—96.) Косараю [1970] (Kosaraju S. R ), Finite state automata with markers, Proc. 4th Annual Princeton Conference on Information Sciences and Systems, 380. Коэн, Готлиб [1970] (Cohen D. J., Gotlieb С. C.), A list structure form of grammars for syntactic analysis, Comput. Surveys, 2:1, 65—82. Коэн, Чулнк [1971] (Cohen R. S., Culik К., II), LR-reguIar grammars —an extension of LR(fe) grammars, IEEE Conf. Record of 12th Annual Sympo- sium on Switching and Automata Theory, 153—165. Кристенсен, Шоу [1969] (Christensen C., Shaw J. C. (eds)), Proc, of the exten- sible languages symposium, ACM SIGPLAN Notices, 4:8. Кук [1971] (Cook S. A.), Linear time simulation of deterministic two-way pushdown automata, Information Processing —71 (IFIP Congress), TA — 2, 174—179. Кук, Аандераа [1969] (Cook S. A., Aanderaa S. D.), On the minimum compu- tation time of functions, Trans. Amer. Math. Soc. 142, 291—314. (Русский перевод: Кук С. А. Аандераа С. Д., О минимальном времени вычисления функций, Кибернетический сборник, новая серия, вып. 8, изд-во „Мир“, М., 1971, стр. 168—200.) Куио, Эттингер [1962] (Kuno S., Oettinger A. G-), Multiple-path syntactic analyzer, Information Processing —62 (IFIP Congress), 306—311. Курки-Суоино [1969] (Kurki-Suonio R.), Notes on top-down languages, BIT, 9 , 225—238. ₽Курочкин В. M. [1975a], Обобщенная схема синтаксически управляемой трансляции, Труды Всесоюзного симпозиума по методам реализации но- вых алгоритмических языков, ч. I. Новосибирск. ’’Курочкин В. М. [19756], Об одном алгоритме преобразования грамматик, Труды Всесоюзного симпозиума по методам реализации новых алгорит- мических языков, ч, 1, Новосибирск. ’’Курочкин В. М., Столяров Л. Н., Сушков Б. Г., Флеров Ю. А. [1973], Теория и реализация языков программирования, МФТИ, М. ’’Лавров С. С. [1961], Об экономии памяти в замкнутых операторных схемах, Журнал вычисл. машем. и машем. физики, 1:4. ^Лавров С. С., Гончарова Л. И. J1971], Автоматическая обработка данных, Хранение информации в памяти ЭВМ, изд-во „Наука“, М. Лакхэм и др. [1970] (Luckham D. С., Park D. М. R., Paterson М. S.), On formalized computer programs, J. Comput. Syst. Set., 4:3, 220—249. Лалонд и др. [1971] (LaLonde W. R., Lee E. S., Horning J. J.), An LALR (k) parser generator, Information Processing —71. (IFIP Congress), TA—3, 153-157. Лафранс [1970] (LaFrance J.), Optimization of error recovery in syntax direc- ted parsing algorithms, ACM SIGPLAN Notices, 5:12, 2—17. Ледли, Уилсон [1960] (Ledley R. S., Wilson J. B.), Automatic programming language translation through syntactical analysis, Comm. ACM, 3, 213—> 214. 456
СПИСОК ЛИТЕРАТУРЫ Лейниус [1970] (Leinius R. Р.), Error detection and recovery for syntax dire- cted compiler systems. Ph. D. Thesis, Univ, of Wisconsin, Madison. Ли [1967] (Lee J. A. N.), Anatomy of a compiler, Van Nostrand Reinhold, New York. Ливенворт [1966] (Leavenworth В. M.), Syntax macros and extended transla- tion, Comm. ACM, 9:11, 790—793. Локс [1970} (Loeckx J.), An algorithm for the construction of bounded-context parsers, Comm. ACM, Л3:5, 297—307. Лоури, Медлок [1969] (Lowry E.S., Medlock C. W.), Object code optimization, Comm. ACM, 12:1, 13—22. Лукаш, Вальк [1969] (Lucas P., Walk K.), On the formal description of PL/I, Ann. Rev. Autom. Program., 6:3, 105—182. Льюис, Розеикраиц [1971] (Lewis P. M., Il, Rosenkrantz D. J.), An ALGOL compiler designed using automata theory. Proc. Polytechnic Institute of Brooklyn Symposium on Computers and Automata, 75—88. Льюис, Стнрнз [1968] (Lewis P. M., II, Stearns R. E.), Syntax directed trans- duction, J. ACM, 15:3, 464—488. еЛьюис и др. [1974] (Lewis P M., -II, Rosenkrantz D. J., Stearns R. E.), Attributed translations, J. Comput. Syst. Sci., 9:3, 279—307. Мак-Илрой [1960] (McIlroy M. D.), Macro instruction extentions of compiler languages, Comm. ACM, 3:4, 414—220. Мак-Илрой [1968] (McIlroy M. D.), Coroutines, неопубликованная рукопись, Bell Laboratories, Murray Hill, N. J. Мак-Илрой [1972] (McIlroy M. D.), A manual for the TMG compiler writing language, неопубликованное сообщение, Bell Laboratories, Murray Hill, N. J. Мак-Каллок, Пите [1943] (McCulloch W. S., Pitts E.), A logical calculus of the ideas immanent in nervous activity, Bull. Math. Biophys., 5, 115—133. (Русский перевод: Маккалок У. С,, Питтс Э., Логическое исчисление идей, относящихся к нервной активности, в сб. „Автоматы", ИЛ, М., 1956, стр. 362—384.) Мак-Карти [1963] (McCarthy J.), A basis for the mathematical theory of com- putation, в сб. Computer Programming and Formal Systems, под ред. Braffort P., Hirschberg D., 33—71. Мак-Карти, Пейнтер [1967] (McCarthy J., Painter J. A.), Correctness of a com- piler for arithmetic expressions, в сб. под ред. Шварца [1967], 33—41. Мак-Кимаи [1965] (McKeeman W. М.), Peephole optimization, Сотт. АСМ, 8:7, 443—444. Мак-Кнман [1976] (McKeeman W. М.), An approach to computer language design, CS48, Computer Science Department, Stanford Univ., Stanford, Calif. Мак-Киман и др. [1970] (McKeeman W. M,, Horning J. J., Wortman D. B.), A compiler generator, Prentice-Hall, Inc., Englewood Cliffs, N. J. Мак-Клюр [1965] (McClure R. M.), TMG —a syntax directed compiler, Proc. ACM National Conference, 20, 262—274. Мак-Нотон [1967] (McNaughton R.), Parenthesis grammars, J. ACM, 14:3, 490—500. Мак-Нотон, Ямада [1960] (McNaughton R., Yamada H.), Regular expressions and state graphs for automata, IRE Trans, on Electr, Comput., 9:1, 39— 47. Манна [1973] (Manna Z.), Program schemas, в сб. Ахо [1973], Марилл [1962] (Marill М.), Computational chains and the size of computer programs, IRE Trans, on Electr. Comput., EC-11:2, 173—180. Марков A. A. [1951], Теория алгорифмов, Труды Математического института им. В. А. Стеклова, 38. Мартин [1972] (Martin D. F.), A Boolean matrix method for the computation of linear precedence functions, Comm. ACM, 15:6, 448—454. 15 А. Ахо, Дж. Ульман, т. 2 457
СПИСОК ЛИТЕРАТУРЫ Маурер [1968] (Maurer W. D.), An Improved hash code for scatter storage, Comm. ACM, 11:1, 35—38. Мейерс [1965] (Meyers W, J.), Optimization of computer code, неопубликоваи- иое сообщение, G. E. Research Center, Schenectady, N. Y. Мендельсон [1968] (Mendelson E.), Introduction to mathematical logic, Van Nostrand Reinhold, New York. (Русский перевод: Мендельсон Э_, Введение в математическую логику, изд-во „Наука11, М., 1971.) Миллер, Шоу [1968] (Miller W. F., Shaw А. С.), Linguistic methods In picture processing — a survey, Proc. AFIPS Fall Joint Computer Conference, 33, 279—290. Минский [1967] (Minsky M.), Computation: finite and infinite machines, Prentice-Hall, Inc., Englewood Cliffs, N. J. (Русский перевод:-Миискяй M., Вычисления и автоматы, изд-во „Мир“, М., 1971.) Монтаиари [1970] (Montanari U. G.), Separable graphs, planar graphs, and web grammars, Inform, and Control, 16:3, 243—267. Моргай [1970] (Morgan H, L.), Spelling correction in systems programs, Comm. ACM, 13:2, 90—93. Моррис [1968] (Morris R.), Scatter storage techniques, Comm. ACM, 11:1, 35—44. Моултон, Мюллер [1967] (Moulton P. G., Muller M. E.), A compiler empha- sizing diagnostics, Comm. ACM, 10:1, 45—52. Мунро [1971] (Munro 1.), Efficient determination of the transitive closure of a directed graph, Inform. Processing Letters, 1:2, 56—58. Myp [1956] (Moore E. F.), Gedanken experiments on sequential machines, в сб. под ред. Шеннона и Мак-Карти [1956], 129—153. (Русский пере- вод: Мур Э. Ф., Умозрительные эксперименты с последовательностными машинами, в сб. „Автоматы11, ИЛ, М., 1956, стр. 179—210.) Мур [1964] (Moore Е. F.), Sequential machines: Selected Papers, Addison-Wesley, Reading, Mass. Наката [1967] (Nakata 1.), On compiling algorithms for arithmetic expressions, Comm. ACM, 12:2, 81—84. Hayp [1963] (Naur P. (ed.)), Revised report on the algorithmic language ALGOL 60, Comm. ACM, 6:1, 1 —17. (Русский перевод: Алгоритмический язык АЛГОЛ 60, изд-во „Мир“, М., 1965.) Нивергельт [1965] (Nievergelt J.), On the automatic simplification of com- puter programs, Comm. ACM, 8:6, 366—370. Огден [19681 (Ogden W.), A helpful result for proving inherent ambiguity, Math. Syst. Theory, 2:3, 191—194. (Русский перевод: Огдеи У., Резуль- тат, полезный для доказательства существенной неоднозначности, в сб. „Языки и автоматы11, изд-во „Мир“, М., 1975, стр. 109—113.) Оре [1962] (Ore О.), Theory of graphs. Amer. Math. Soc. Colloq. Publ., 38. (Русский перевод: Ope О., Теория графов, изд-во „Наука11, М., 1968.) Павлндис [1972] (Pavlldis Т.), Linear and context-free graph grammars, J. ACM, |g.| 11_______23 Парик [1966] (Parikh R.J.), On context-free languages, J. ACM, 13:4, 570—581. Патерсон [1968] (Paterson M. S.), Program schemata, в сб. Machine Intelli- gence, v. 3, под ред. Michie, Edinburg University Press, Edinburg, 19—31. Паул, Ангер [1968a] (Paul M. C., Unger S. H.), Structural equivalence of context-free grammars, J. Comp. Syst. Sci., 2:1, 427—463. Паул, Ангер [19686] (Pauli M. C., Unger S. H.), Structural equivalence and LL(fe) grammars. Пейджер [1970] (Pager D.), A solution to an open problem by Knuth, Inform, and Control, 17:5, 462—473. Пейнтер [1970] (Painter J. A.), Effectiveness of an optimizing compiler for arithmetic expressions, ACM SIGPLAN Noties, 5:7, 101—126. Петерсон [1957] (Peterson W. W.), Adressing for random access storage, IBM J. Research and Development, 1:2, 130—146. 458
СПИСОК ЛИТЕРАТУРЫ Петрове [1968] (Petrone L.), Syntax directed mapping of context-free langua- ges, IEEE Conference Record of 9th Annual Symposium on Switching and Automata Theory, 160—175. Пол [1962] (Paul M-), A general processor for certain formal languages, Proc. ICC Symposium of Symb. Lang. Data Processing, 65—74. Пост [1943] (Post E. L.), Formal reductions of the general combinatorial deci- sion problem, Amer. J. Math., 65, 197—215. Пост [1947] (Post E. L.), Recursive unsolvability of a problem of Thue, J. Symb. Logic, 12, 1—11. См. также Дэвис [1965], 292—303. Пост [1965] (Post E. L.), Absolutely unsolvable problems and relatively undecidable propositions — account of an anticipation, в сб. под ред, Дэвиса [1965], 338—433. °Поттосии И. В. [1973], Оптимизирующие преобразования н их последова- тельность, в сб. „Системное программирование*1, ч. 2 (материалы Всесоюз- ного симпозиума, март 1973), Новосибирск, стр. 128——137. °Поттосин И. В. [1975], Глобальная оптимизация: практический подход, Труды Всесоюзного симпоз. по методам реализации новых алгоритм, языков, Новосибирск. Прайс [1971] (Price С. Е.), Table lookup techniques, ACM Comput. Surveys. 3:2, 49—66. Пратер [1969] (Prather R. E.), Minimal solutions of Pauli-Unger problems, Math. Syst. Theory, 3:1, 76—85. Проссер [1959] (Prosser R. T.), Applications of Boolean matrices to the ana- lysis of flow diagrams, Proc. Eastern J. Computer Conf., 133— 138. Пфальц, Розенфельд [1969] (Pfaltz J. L., Rosenfeld A.), Web grammars, Proc. International Joint Conf, on Artificial Intelligence, Washington, 609—619. Пэр [1964] (Pair C.), Trees, pushdown stores and compilation, RFTI— Chiffres, 7:3, 199—216. Рабии [1967] (Rabin M. O.), Mathematical theory of automata, в сб, под ред. Шварца [1967], 173—175. Рабии, Скотт [1959] (Rabin М. О., Scott D.), Finite automata and their decision problems, IBM J. Res. Devel., 3, 114—125. См. также Мур [1964], 63—91. (Русский перевод: Рабин М. О., Скотт Д.» Конечные автоматы и задачи их разрешения, Кибернетический сборник, вып. 4, ИЛ, М., 1962, стр. 56—91.) Радке [1970] (Radke С. Е.), The use of quadratic residue search, Comm. ACM, 13:2, 103—109. Редзиевский [1969] (Redziejowski R. R.), On arithmetic expressions and trees, Comm. ACM, 12:2, 81—84. Рейнольдс [1965] (Reynolds J. C.), An introduction to the COGENT program- ming system, Proc. ACM National Conference, 20, 422. Рейнольдс, Хаскел [1970] (Reynolds J. C., Haskell R.), Grammatical cove- rings, неопубликованное сообщение, Syracuse Univ. Реиделл, Рассел [1964] (Randell В., Russell L. J.), ALGOL 60 implementa- tion, Academic Press, New York. (Русский перевод: Реиделл Б., РасселЛ., Реализация АЛГОЛа 60, изд-во „Мир“, М., 1967.) Ричардсон [1968] (Richardson D.), Some unsolvable problems involving ele- mentary functions of a real variable, J. Symb. Logic, 33, 514—520. Роджерс [1967] (Rogers H., Jr.), Theory of recursive functions and effective computability, McGraw-Hill, New York. (Русский перевод: Роджерс X., Теория рекурсивных функций и эффективная вычислимость, изд-во „Мир“, М„ 1972.) Розен [1967а] (Rosen S, (ed.)), Programming systems and languages, McGraw- Hill, New York. Розен [19676] (Rosen S.), A compiler-building system developed by Brooker and Morris, в сб. под ред. Розена [1967а], 306—331. 15* 459
СПИСОК ЛИТЕРАТУРЫ Розенкранц [1967] (Rosenkrantz D. J.), Matrix equations and normal forms for context-free grammars, J. ACM, 14:3, 501—507. Розенкранц [1968] (Rosenkrantz D. J.). Programmed grammars and classes of formal languages, J, ACM, 16:1, 107—131. (Русский перевод: Розен- кранц Д., Программные грамматики и классы формальных языков, в сб. „Сборник переводов по вопросам информационной теории н практики41, ВИНИТИ, № 16, М., 1970, стр. 117—146.) Розенкранц, Льюис [1970] (Rosenkrantz D. J., Lewis Р. М., 11), Determini- stic left corner parsing, IEEE Conf. Record of Ilth Annual Symposium on Switching and Automata Theory, 139—152. Розенкранц, Стирнз [1970] (Rosenkrantz D. J., Stearns R. E.), Properties of deterministic top-down grammars, Inform, and Control, 17:3, 226—256. Саломаа [1966] (Salomaa A.), Two complete axiom systems for the algebra of regular events, J. ACM, 13:1, 158—169. Саломаа [1969a] (Salomaa A.), Theory of automata, Pergamon, Elmsford, N. Y. Саломаа [19696] (Salomaa A.), On the index of a context-free grammar and language, Inform, and Control, 14:5, 474—477. Саммет [1969] (Sammet J. E.), Programming languages: history and fundamen- tals, Prentice-Hall, Englewood Cliffs, N. J. Сети [1972] (Sethi R.), Validating register allocations for straight line prig- rams, Ph. D. Thesis, Department of Electrical Engineering, Princeton Universi ty. Сети, Ульман [1970] (Sethi R., Ullman J. D.), The generation of optimal code for arithmetic expressions, J. ACM, 17:4, 715—728, Скотт, Стрэчи [1971] (Scott D., Strachey C.), Towards a mathematical seman- tics for computer languages, Proc. Symposium on Computers and Automata, Microwave Research Institute Symposia Series, Vol. 21, Polytechnic Insti- tute of Brooklyn, New York, 19—46. Стил [1966] (Steel T. B. (ed.)), Formal language description languages for computer programming, North-Holland, Amsterdam. Стирнз [1967] (Stearns R. E.), A regularity test for pushdown machines, Inform, and Control, 11:3, 323—340. (Русский перевод: Стирнз P., Проверка регу- лярности для магазинных автоматов, Кибернетический сборник, новая серия, вып. 8, изд-во „Мир“, М., 1971, 117—139.) Стиряз [1971] (Stearns R. Е.), Deterministic top-down parsing, Proc. 5th Annual Princeton Conference on information Sciences and Systems, 182—188. Стирнз, Льюис [1969] (Stearns R. E., Lewis P. M., Il), Property grammars and table machines, Inform, and Control, 14:6, 524—549. Стирнз, Розенкранц [1969] (Stearns R. E., Rosenkrantz D. J.), Table machine simulation, IEEE Conf. Record of 10th Annual Symposium on Switching and Automata Theory, 118—128. Стоун [1967] (Stone H. S.), One-pass compilation of arithmetic expressions for a parallel processor, Comm. ACM, 10:4, 220—223. Суплес [I960] (Suppcs P.), Axiomatic set theory, Van Nostrand Reinhold, New York. Тарьян [1972] (Tarjan R.), Depth first search and linear graph algorithms, SIAM J. Comput., 1:2, 146—160. Томпсон [1968] (Thompson K.), Regular expression search algorithm, Comm. ACM, 11:6, 419—422. Тьюрииг [1936] (Turing A. M.), On computable numbers with an application to the Entscheidungsproblem, Proc. London Math. Soc., ser. 2, 42, 230—265; Corrections, там же, 43 (1937), 544—546. Уилкокс [1971) (Wilcox T. R.), Generating machine code for high-level pro- gramming languages, TR 71—103, Dept, of computer Science, Cornell Uni- versity, Ithaca, N. Y. Ульман [1972a] (Ullman J. D.), A note on hashing functions, J. ACM, 19:3, 569—575. 460
СПИСОК ЛИТЕРАТУРЫ Ульман (19726] (Ullman J. D.), Fast algorithms for the elimination of common subexpressions, TR-106, Dept. of.Electrical Engineering Princeton Univer- sity, Princeton, N. J. e “s’ Уолтерс [1970] (Walters D. A.), Deterministic context-sensitive languages, Inform, and Control, 17:1, 14—61. Уоршолл J1962] (Warshall S-), A theorem on Boolean matrices, J. ACM, 9:1, Уоршолл, Шапиро [1964] (Warshall S., Shapiro R. M_), A general purpose or ко скеп compiler, Proc. AFIPS Spring Joint Computer Conference, *o, ОУ—bo. Фельдман [1966] (Feldman J. A.), A formal semantics for computer languages and its application in a compiler-compiler, Comm. ACM, 9:1, 3—9. Фельдман, Грис [1968] (Feldman j. A., Gries D.), Translator writing systems, Comm. ACM, 11:2, 77—113. (Русский перевод; Фельдман Дж., Грис Д., Системы построения трансляторов, в сб. „Алгоритмы и алгоритмические языки», вып. 5, ВЦ АН СССР, М., 1971.) Фишер [1968] (Fisher М. J.), Grammars with macro-like productions, IEEE 131 142C°rd Symposium on Switching ana Automata Theory, Фишер [1969] (Fischer M. J.), Some properties of precedence languages, Proc, of 1st Annual ACM Symposium on Theory of Computing. 131—190. ФИШкгР J’>’ Efficiency of equivalence algorithms, Memo № 256, Artificial Intelligence Laboratory, Massachusetts Institute of Techno- logy, Cambridge, Mass. Флойд [1961a] (Floyd R< W.), An algorithm for coding efficient arithmetic operations, Comm. ACM, 4:1, 42—51. * Флойд [19616] (Floyd R, W.), A descriptive language for symbol manipulation, J. ACM, 8:4, 579—584. J Флойд 11962a} (Floyd R. W.), Algorithm 97: shortest oath, Comm. ACM, 5:6, 345. K ФЛ°Сотт96ТсмР15УИ) 526^534°” arn^igulty *n Phrase structure languages, Флойд 3°^316^ Syntactic analysis and operator precedence, Флойд [1964a] (Floyd R. W.), Bounded context syntactic analysis» Comm. ACM, , tli — О/. Флойд [19646] (Floyd R. W.), The syntax of programming languages—a survey, IEEE Trans. Electr. Comput., EC-13:4, 346—ЗБЗ. Флойд [1967a] (Floyd R. W.), Assigning meanings to nrogrr™s, в сб. под ред. Шварца [1967], 19—32. н * Флойд [19676] (Floyd R. W.), Nondeterministic algorithms, АСМ, 14:4, 636—644. Фрейли [1970] (Frailey D. J.), Expression optimization using unary comple- ment operators, ACM SIGPLAN Notices, 5:7, 67—85. Фримэн [1964] (Freeman D. N.), Error correction in CORC, the Cornell com- puting language, Proc. AFIPS Fall Joint Computer Conference, 26, 15—34. Хакстэбл [1964] (Huxtable D. H. R.), On writing an optimizing translator for ALGOL 60, в сб. „Introduction to System Programming**, Academic Press, New York. B Халмош [1960] (Halmos P. R.), Naive set theory Van bfo^lrand Reinhold, New York. Халмош [1963] (Halmos P. R.), Lectures on Boolean alsel?ras, Van Nostrand Reinhold, New York. & Харари [1969] (Harary F.), Graph theory, Addison-Wesley» Reading, Mass. (Русский перевод: Харари ф., Теория графов, изд-во „Мнр“, М., 1973.) Харрисон [1965] (Harrison М. A.), Introduction to switching and automata theory, McGraw-Hill, New York. 461
4С0К ЛИТЕРАТУРЫ ртманнс, Хопкрофт [1970] (Hartmanis J., Hopcroft J. E.), An overview of the theory of computational complexity, J. ACM, 18:3, 444—475. (Рус- ский перевод: Хартманне Ю., Хопкрофт Дж., Обзор теории сложности вычислений, Кибернетический сборник, новая серия, вып. 11, нзд-во „Мир“, М., 1974, стр. 131—176.) ртманис и др. [1965] (Hartmanis J., Lewis Р. М., 11, Stearns R. Е.), Clas- sifications of computations by time and memory requirements, Proc. IFIP Congress, 65, 31—35. фмен [1954] (Huffman D. A.), The synthesis of .sequential switching circuits, "J. Franklin Inst., 257, 3—4, 161, 190, 275—303. йнс [1970] (Haines L. H.), Representation theorems for context-sensitive languages, Dept, of Electrical Engineering and Computer Sciences, Univ, of California, Berkeley. йнс, Шютте [1970] (Haynes H. R., Schutte L. J.), Compilation of optimized syntactic recognizers from Floyd-Evans productions, ACM SIGPLAN Noti- ces, 5:7, 38—51. йс [1967] (Hays D. G.), Introduction to computational linguistics, American Elsevier, New York. кст, Робертс [1970] (Hext J. B., Roberts P. S), Syntax analysis by Domolki’s algorithm, Computer J., 13:3, 263—271. кт, Ульман [1972a] (Hecht M. S., Ullman J. D.), Flow graph reduci- bility, SIAM J. on Computing, 1:2, 188—202. кт, Ульман [19726] (Hecht M. S., Ullman J. D.), неопубликованное сооб- щение, Dept, of Electrical Engeneering, Princeton University. ллерман [1966] (Hellerman H.), Parallel processing of algebraic expressions, /ЕЕЕ Trans. Elect. Comput., EC-15:1, 82—91. мский [1956] (Chomsky N.), Three models for the description of language, IEEE Trans. Inform. Theory, 2:3, 113—124. (Русский перевод: Хомский H., Три модели описания языка, Кибернетический сборник, вып. 2, ИЛ, М., 1961, стр. 237—266.) мский [1957] (Chomsky N.), Syntactic structures, Mouton and Co., The Hague. (Русский перевод: Хомский H., Синтаксические структуры, в сб. „Новое в лингвистике", вып. 11, ИЛ, М., 1962, стп. 412—527.) мский [1959а] (Chomsky N.), On certain formal properties of grammars, Inform, and Control, 2:2, 137—167. (Русский перевод: Хомский H., О некоторых формальных свойствах грамматик, Кибернетический сборник, вып. 5, ИЛ, М., 1962, стр. 279—311.) мский [19596] (Chomsky N.), A note on phrase structure grammars, Inform, and Control, 2:4, 393—395. (Русский перевод: Хомский H., Заметка о грамматиках непосредственно составляющих, Кибернетический сборник, вып. 5, ИЛ, М., 1962.) мский [1962] (Chomsky N.), Context-free grammars and pushdown storage, Quarterly Progress Report, № 65, Research Laboratory of Electronics, Massachusetts Institute of Technology, Cambridge, Mass. мский [1963] (Chomsky N.), Formal properties of grammars, в сб. „Handbook of Mathematical Psychology", 2, под ред. Luce R. D., Bush R. R., Ga- lanter E., Wiley, New York, 323—418. (Русский перевод: Хомскнй H., Формальные свойства грамматик, Кибернетический сборник, новая серия, вып. 2, изд-во „Мнр", М., 1966, стр. 121—230.) мский [1965] (Chomsky N.), Aspects of the theory of syntax, M.I.T. Press, Cambridge, Mass. (Русский перевод: Хомскнй H., Аспекты теории син- таксиса, Изд-во МГУ, М., 1972.) мский, Миллер [1958] (Chomsky N., Miller G. A.), Finite state languages, Inform, and Control, 1:2, 91 — 112. (Русский перевод: Хомский H., Мил- лер Дж., Языки с конечным числом состояний, Кибернетический сборник, вып. 4, ИЛ, М., 1962, стр. 233—255.) мский, Шютцеиберже [1963] (Chomsky N., Schutzenberger М. Р.), The algeb-
СПИСОК ЛИТЕРАТУРЫ raic theory of context-free languages age:as, в сб. под ред. Бпаффорта и Хирш- берга [1963], 118—16]. (Русский ггерц^евереггвод: Хомскнй Н., шютцеиберже М. Н., Алгебраическая теория контекстнвгшттно- -свободных языков, Кибернетический сборник, новая серия, вып. 3, изд-цдезд-тао „Мир", М., 1966, стр. 195—242.) Хопгуд [1969] (Hopgood F.R.A.), СогкрСот ttpiling techniques, American Elsevier, New York. (Русский перевод: Хсэ^ОСюппгуд Ф., Методы компиляции, изд-во „Мир", 1972.) Хопкинс [1971] (Hopkins М. Е.), Ап яп_п ooptimlzing compiler design. Proc. IFiP Congress 71, TA-3, North-Holland, «Н, AAmsterdam, 69—73. Хопкрофт [1971] (Hopcroft J. E.), Ao n л n log n algorithm for minimizing states in a finite automaton, CS71 —190„ О • . Coomputer Science Dept., Stanford Univ., Stanford, Calif. (Русский перевод: ХХопкрофт Дж., Алгоритм для мини- мизации конечного автомата, Ки ддХиб®»ернетический сборник, новая серия, вып. 11, изд-во „Мир", М., 1974, о «, стгтр. 177—184.) Хопкрофт, Ульмаи [1967] (Hopcroft « J... Е.; Ullman J. D.), An approach to a unified theory of automata, BeJl T&ll Saystem Tech. J., 46:8, 1763—1829. Хопкрофт, Ульман [1969] (Hopcroft JL J. . E., Ullman J. D.), Formal languages and their relation to automata, A_doB?-ddi;i son-Wesley, Reading, Mass. Хопкрофт, Ульман [1972a] (Hopcroft JTL J. E., Ullman J. D.), Set merginig algo- rithms, неопубликованное сообщены .а.ениае, Dept, of Computer Science, Cornell University, Ithaca, N.Y. Хопкрофт, Ульман [19726] (Hopcroft it J. E., Ullman J. D.) An n log n algo- rithm to detect reducible graphs, t г-S, HProc. 6th Annual Princeton Conference on Information Sciences and SysterrirmetnsM., 119—122. Хорвиц и др. [1966] (Horwitz L. P., ЮЖ Кавгр R. M., Miller R. E., Winograd S.), Index register allocation, J. ACM, *13:1, 43—61. Чен [1972] (Chen S.), On the Sethi— ii—-Ullman algorithm, неопубликованное сообщение, Bell Laboratories, Holmi>l»lrn(fdel, N. J. Чёрч [1941] (Church A.) The calculi ol 1 I tf lazimbda-conversion, Ann. Math. Stud., 6. Чёрч [1956] (Church A.), Introduction гжооп to mathematical logic, Princeton Uni- versity Press, Princeton, N. J. (H)g (Р^усский перевод: Чёрч А., Введение в математическую логику, ИЛ, М, „М, Й1961.) Читэм [1965] (Cheatham Т. Е.), The ТОТТ TGSrS-II translator-generator system, Proc. IFIP Congress, 65, 592—593. Читэм [1966] (Cheatham T. E.), The in^mnntrroduction of definitional facilities into higher level programming languag«o§sagess, Proc. AFIPS Fall Joint Computer Conference, 30, 623—637. Чнтэм [1967] (Cheatham T. E.), The therrillieocry and construction of compilers (2nd ed.), Computer Associates, Inc., akxefield, Mass. Читэм, Стэидиш [1970] (Cheatham T. E 23 E.)t> Standish T.) Optimization aspects of compiler-compilers, ACM SIGPLAlWV^IN . Notices, 5:10, 10—17. Читэм, Сэттлн [1964] (Cheatham T. Е.э S ,, Saattley K.), Syntax directed compiling, proc. AFIPS Spring Joint Cofnptuteteisrfer*- Conference, 25, 31—57. Чулик [1968] (Culik К., II), Contributio:ooLion i to deterministic top-down analysis of context-free languages, Kybernetika, „otz, <4:5, 422—431. Чулик [1970] (Culik K., 11), n-ary gran^rartnmars and the description of mapping of languages, Kybernetlka, 6, 99—11 I 1-117 \ Шварц [1967] (Schwartz J. T. (ed.)), Mib-V. Mat thematical aspects of computer science, Proc. Symp. Appl. Math., 19. Шеннон, Мак-Карти [1956] (Shannon С. Ж E..., McCarthy J. (eds)), Automata studies, Princeton University Press, Princet*t_9=etoi n, N. J. (Русский перевод: Автоматы (сб. статей), ИЛ, М., 1956.) Шепердсон [1959] (Shepherdson J. С.), г-т(-)? TThe reduction of two-way automata to one-way automata, IBM J. Res., e.s., i 3, 198—200. См. также Мур [1964], 92—97. (Русский перевод: Шепер дс_э. д-дсо »н Дж., Сведение двухсторонних авто- 463
СПИСОК ЛИТЕРАТУРЫ матов к односторонним автоматам, Кибернетический сборник, вып. 4, ИЛ, М., 1962, стр. 92—98.) Шефер [1973] (Schaefer М.), A mathematical theory of global flow analysis, Prentice-Hall, Englewood Cliffs, N. J., в печати. Шорре [1964] (Schorre D. V.), META П, a syntax oriented compiler writing language, Proc. ACM National Conference, 19, DI. 3-1—DI. 3-11. Шоу [1970] (Shaw A. C.), Parsing of graph-representable pictures, J, ACM, 17:3, 453—481. Штрассен [1969] (Strassen V.), Gaussian elimination is not optimal, Numer. Math., 13, 354—356. (Русский перевод: Штрассен Ф., Алгоритм Гаусса не оптимален, Кибернетический сборник, новая серия, вып. 7, нзд-во „Мир", М., 1970, стр. 67—70.) Шютценберже [1963] (Schutzcnberger М. Р.), On context-free languages and pushdown automata, Inform, and Control, 6:3, 246—264. Эванс [1964] (Evans A., Jr.), An ALGOL 60 compiler, Ann. Rev. Autom. Prog- ram. 4. 87—124. Эви [1963]*Evey R. J.), Applications of pushdown-store machines, Proc. AFIPS Fall Joint Computer Conference, 24, 215—227. Эйкель и др. [1963] (Eickel J., Paul M., Bauer F.L., Samelson K-), A syntax- controlled generator of formal language processors, Comm. ACM, 6:8, 451—455. Элсон, Рейк [1970] (Elson M., Rake S. T.), Code-generation technique for large- language compilers, IBM Systems J., 9:3, 166—188. Элспас и др. [1971] (Elspas В., Green M. W., Levitt К. N.), Software reliability, Computer, 1, 21—27. Энгелер [1971] (Engeler E.(ed.)), Symposium on semantics of algorithmic languages, Lecture Notes in Mathematics, Springer, Berlin. Эрланд, Фишер [1970] (Irland M. I., Fisher P. C.), A bibliography on compu- tational complexity, CSRR 2028, Der. of Applied Analysis and Computer Science, Univ, of Waterloo, Ontario. Эрли [1966] (Earley J.), Generating a recognizer for a BNF grammar, Computa- tion Center Report, Carnegie-Mellon University, Pitsburgh. Эрли [1968] (Earley J.), An efficient context-free parsing algorithm, Ph. D. The- sis, Carnegie-Mellon Univ., Pittsburgh, Pa. См. также Comm. ACM. 13:2, (1970), 94—102. (Русский перевод: Эрли Дж., Эффективный алгоритм ана- лиза контекстно-свободных языков, в сб. „Языки и автоматы41, изд-во „Мир", М., 1975, стр. 47 — 70.) Эттингер [1961] (Oettinger A.), Automatic syntactic analysis and the pushdown store, в сб. Structure of Language and its Mathematical Concepts, Proc. 12th Symposium on Applied Mathematics, American Mathematical Society, Providence, 104—129. ’Языки и автоматы, Сборник переводов, изд-во „Мир“, М., 1975. Янгер [1967] (Younger D. Н.), Recognition and parsing of context-free languages in time n3, Inform, and Control, 10:2, 189—208. (Русский перевод: Янгер Д. X., Распознавание и анализ контекстно-свободных языков за время п3, в сб. „Проблемы математической логики", изд-во „Мир", М., 1970, стр. 344—362.) Янов Ю. И. [1958], О логических схемах алгоритмов, сб. „Проблемы ки- бернетики", вып. 1, Фнзматгиз, М., 1958.
УКАЗАТЕЛЬ ЛЕММ, ТЕОРЕМ И АЛГОРИТМОВ К ТОМУ 2 Номер леммы Стр. Номер леммы Стр. Номер леммы Стр. Номер леммы Стр. 7.1 83 8.7 160 10.2 283 11.6 346 7.2 83 8.8 169 10.3 315 11.7 346 7.3 109 8.9 170 10.4 319 11.8 372 7.4 127 8.10 179 10.5 320 11.9 372 8.1 142 8.11 180 10.6 320 11.10 374 8.2 150 8.12 180 11.1 339 11.11 374 8.3 154 8.13 188 11.2 339 11.12 385 8.4 156 8.14 189 11.3 343 11.13 401 8.5 156 8.15 190 11.4 343 11.14 402 8.6 157 10.1 283 11.5 346 11.15 440 Номер Стр. Номер Стр. Номер Стр. Номер Стр. теоремы теоремы теоремы теоремы 7.1 13 8.4 153 8.20 187 11.2 339 7.2 21 8.5 156 8.21 189 11.3 343 7.3 39 8.6 157 8.22 192 . 11.4 344 7.4 40 8.7 161 9.1 208 11.5 346 7.5 58 8.8 161 9.2 210 11.6 372 7.6 61 8.9 165 9.3 214 11.7 375 7.7 71 8.10 168 9.4 220 11.8 379 7.8 84 8.11 171 9.5 224 11.9 387 7.9 95 8.12 172 9.6 230 11.10 403 7.10 НО 8.13 173 9.7 243 11.11 410 7.11 111 8.14 174 10.1 284 11.12 425 7.12 125 8.15 176 10.2 286 11.13 430 7.13 129 8.16 176 10.3 321 11.14 439 8.1 142 8.17 180 10.4 322 11.15 441 8.2 146 8.18 182 11.1 337 11.16 442 8.3 149 8.19 185 46$
УКАЗАТЕЛЬ ЛЕММ, ТЕОРЕМ И АЛГОРИТМОВ К ТОМУ 2 Номер алгоритма Стр. Номер алгоритма Стр. Номер алгоритма Стр. Номер алгоритма Стр. 7.1 11 7.11 102 8.7 190 10.4 314 7.2 33 7.12 104 9.1 218 10.5 317 7.3 38 7.13 106 9.2 220 11.1 366 7.4 40 8.1 147 9.3 228 11.2 367 7.5 51 8.2 151 9.4 240 11.3 377 7.6 56 8.3 155 9.5 242 11.4 383 7.7 60 8.4 172 10.1 272 11.5 402 7.8 69 8.5 177 10.2 275 11.6 426 7.9 82 8.6 188 10.3 309 11.7 436 7.10 94
ИМЕННОЙ УКАЗАТЕЛЬ К 1 И 2 ТОМАМ1) Аандераа (Aanderaa S. D.) 48 Абрахам (Abraham S.) 123 Абэ (Abe N.) 102 Агафонов В. Н. 408 Айронс (Irons Е. Т.) 96, 268, 351, 510 Аллард (Allard R. W.) 392 Аллен (Allen F. Е.) 422, 448 Ангер (Unger S. Н.) 351; 163 Андерсон (Anderson J. Р.) 392 Анисимов А. В. 408 Арбиб (Arbib М. А.) 163 Ахо (Aho А. V.) 123, 220, 283, 408, 409, 452, 480; 29, 91, 117, 138, 185, 236, 266, 362, 448 Барздинь Я. М. 163 Барнет (Barnet М. Р.) 268 Бар-Хиллел (Bar-Hillel Y.) 102, 123, 241 Бауэр Ф. (Bauer F. L.) 510 Бауэр X. (Bauer Н.) 480 Бежанова М. М. 423 Беккер (Becker S.) 480 Белл (Bell J. R.) 29, 292 Берж (Berge С.) 68 Беркхард (Berkhard W. А.) 266 Бжозовский (Brzozowsky J, А.) 147, 163 Биледи (Belady L. А.) 392 Билз (Beals A, J.) 45 Бирман (Birman А.) 542 Блатиер (Blattner М.) 241 Бобров (Bobrow D. G.) 102 Бове (Bovet D. Р.) 392 Бородин (Borodin А.) 52 Браха (Bracha N.) 362 Брукер (Brooker R. А.) 96, 351 Бруно (Bruno J. L.) 266 Брюер (Breuer М. А.) 362 Вузам (Busam V. А.) 422, 448 Бук (Book R. V,) 123, 241 Бут (Booth Т. L.) 163 Бэкус (Backus J. W.) 95; 206 Бэр (Baer J. L.) 392 Вайз (Wise D. S.) 510 Вайнер (Weiner Р.) 163 Валнант (Valiant L. G.) 372 Вальк • (Walk К.) 74 Вебер (Weber Н.) 480; 29 ван Вейнгаардеи (van Wijngaarden А.) 75, 559 Вегбрейт (Wegbreit В.) 75 Великанова Т, М. 423 Вельбнцкий И. В. 408, 411 Виноград С. (Winograd S.) 48 Виноград Т. (Winograd Т.) 102 Вирт (Wirth N.) 480, 565; 29 Возенкрафт (Wozencraft J, М.) 569 Вуд (Wood D.) 408 Вудс (Woods W. А.) 102 Галлер (Galler В. А.) 74 Гилл (Gill А.) 163 Гинзбург A. (Ginzburg А.) 163 Гинзбург С. (Ginsburg S.) 123, 163, 192, 241, 268, 305 Гир (Gear С, W.) 422 Гладкий А. В. 123, 241 Гончарова Л. И. 452 Глушков В. М. 163 Готлиб (Gotlieb С. С.) 352 Грау (Grau А. А.) 206 Грии (Green М, W.) 96 Грейбах (Greibach S.) 123, 192, 241, 305 Грис (Gries D.) 95, 96 Грисволд (Griswold R, Е.) 562 1) Курсивом выделены номера страниц тома 2.—Прим, перед. 461
ИМЕННОЙ УКАЗАТЕЛЬ К 1 И 2 ТОМАМ Гриффитс (Griffiths Т. V.) 268, 351 Гросс (Gross М.) 241 Грэй (Gray J. N.) 220, 315, 480, 510, 558; 185 Грэхем Р. (Graham R. М.) 510; 393 Грэхем С. (Graham S. L.) 372, 480; 185 Деннинг (Denning Р. J.) 480 Де Ремер (De Remer F. L.) 452, 569; 45, 117, 138 Джентльмен (Gentleman W. M.) 77 Джонсон В. (Johnson W, L.) 295 Джоисон C. (Johnson S. C.) 408, 409 Дейкстра (Dijkstra E. W.) 98 Домёлкн (Domolki B.) 352 Дьюар (Dewar R. В. K.) 96 Дэвис (Davis M.) 51, 52 Ершов А. П. 393, 423, 448 Ершова H. M. 393 Замельсон (Samelson K.) 510 Змиевская Л. Л. 362 Зонис В. С. 452 Зыков А. А. 68 Ибарра (Ibarra- О.) 220 Игараси (Jgarashi S.) 362 Ингермаи (Ingerman Р. Z.) 96 Ихбиа (Ichbia J. D.) 480; 45 Кавинесс (Caviness В. F.) 362 Камеда (Kameda Т.) 163 Камыннн С. С. 393, 423 Кантор (Cantor D. G.) 241 Каплан (Kaplan D. М.) 422 Касами (Kasami Т.) 372 Касьянов В. Н. 448 Кауфман В. Ш. 408, 409 Кеннеди (Kennedy К.) 392, 448 Ким К- В. 423 Китов А. И. 393, 423 Кларк (Clark Е. R.) 422 Клини (Kleene S. С.) 38, 52, 147 Кнут (Knuth D. Е.) 52, 68, 74, 408, 452, 542; 163, 185, 206, 266, 292, 448 Кок (Cocke J.) 95, 96, 372; 422, 448 Колмерауэр (Colmerauer А.) 558 Комор (Komor Т.) 408, 409 Конвэй М, (Conway М. Е.) 408, 414 Конвэй Р. (Conway R, W.) 96 Кореньяк (Korenjak A. J.) 408, 452; 117, 163 Косараю (Kosaraju S. R.) 163 Коэн Д. (Cohen D. J.) 352 Коэн Р. (Cohen R. S3 558 Кравчик (Krawczyk Т.) 408 Криницкин Н, А. 393, 423 Кристенсен (Christensen С.) 75 Кук (Cook S. А.) 48, 220 Куио (Kuno S.) 351 Курки-Суонио (Kurki-Suonio R.) 408; 163 Курочкин В. М. 423 Лавров С. С. 558 Лакхэм (Luckham D. С.) 422 Лалонд (Lalonde W. R.) 504 Лантен (Lentin А.) 241 Лафранс (LaFrance J.) 45 Левнт (Levitt К. N.) 96 Лейниус (Leinius R. Р.) 452, 480; 117 Ли Дж. (Lee J. A. N.) 96 Ли Э. (Lee Е. S.) 504 Ливенворт (Leavenvorth В. М.) 74, 559 Локс (Loecks J.) 510 Ломет (Lomet D.) 417 Лоури (Lowry Е. S.) 422, 448 Лукасевич (Lukasiewicz J.) 244 Лукаш (Lucas Р.) 74 Льюис (Lewis Р. М,, II) 220, 268, 408; 91, 236, 326 Любимский Э. 3. 393, 423 Мак-Илрой ((McIlroy М. D.) 74, 77; 236, 326 Мак-Каллок (McCulloch W. S.) 123 Мак-Карти (McCarthy J.) 96 Мак-Кимаи (McKeeman W. М.) 96, 480, 510; 422 Мак-Клюр (McClure R, М.) 96, 542; 236 Мак-Нотон (McNaughton R.) 147; 163 Максвелл (Maxwell W. L.) 96 Мальцев А. И. 43, 46, 52 Манна (Manna Z.) 422 Марилл (Marili М.) 422 Марков А. А. 42 Мартин (Martin D. FJ 29 Маурер (Maurer W. D.) 292 Медлок (Medlock С. W.) 422, 448 Мейерс (Meyers W. J.) 392 Миллер В. (Miller W. F.) 102 Миллер Г. (Miller G. А.) 147 Минский (Minsky М.) 43, 52, 122, 163 Мицумото (Mizumoto М.) 102 Мншкович Р. Д. 362 468
ИМЕННОЙ УКАЗАТЕЛЬ К I И 2 ТОМАМ Монтанари (Montanary U. G.) 102 Морган (Morgan Н. L.) 96, 296 Морзе (Morse S. Р.) .480; 45 Моррис (Morris R.) 96, 351; 292, 326 Мостинская С. В. 393 Моултон (Moulton Р. G.) 96 Мунро (Munro 1.) 68 Мюллер (Muller М. Е.) 96 Роджерс (Rogers Н.) 46 Розен (Rosen S.) 95, 351 Розенкранц (Rosenkrantz D. J.) 123, 192, 408; 91, 163, 236, 326 Розенфельд (Rosenfeld А.) 98, 102 Росс (Ross D, Т.) 295 Роудз (Rhodes Е. М.) 408 Руднева Т. Л. 393 Руццо (Ruzzo W. L.) 372 Наката (Nakata 1.) 392 Наур (Naur Р.) 74, 559 Непомнящая А. Ш. 408 Нивергельт (Nievergelt J.) 422 Никнтченко Н. С. 408 Нийхольт (Nij'holt А.) 408 Огден (Ogden W.) 241 Олейник-Овод Ю. И. 423 Ордян А. А. 558 Ope (Ore О.) 68 Саломаа (Salomaa А.) 147, 163, 241 Саммет (Sammet J. Е.) 42, 74 Сети (Sethi R.) 392 Скотт (Scott D.) 123, 147, 162 Стил (Steel Т. В.) 74 Стирнз (Stearns R. Е.) 220, 241, 268, 408; 91, 163, 326 Стокхаузсн (Stokhausen) 392 Стоун (Stone Н. S.) 392 Стэнднш (Standish Т.) 96 • Суппес (Suppes Р.) 13 Сэттли (Sattley К.) 351 Павлидис (Pavlidis Т.) 102 Парик (Parikh R. J.) 241 Паул (Paul М. С.) 192; 163 Пейджер (Pager D.) 91 Пейнтер (Painter J. А.) 96 Перлз (Perles М.) 241 Перлис (Perlis A. J.) 74 Петерсон (Peterson W. W.) 292 Петрик (Petrick S. R.) 351 Петроне (Petrone L.) 268 Питтс (Pitts Е.) 123 Поддерюгин В. Д. 423 Пол (Paul М.) 510 Полонский (Polonsky I. Р.) 562 Портер (Porter J. Н.) 295 Пост (Post Е. L.) 42, 52 Поттосии И. В. 393, 423, 448 Поудж (Poage J. F.) 562 Пратер (Prather R. Е.) 163 Проссер (Prosser R. Т.) 422 Пфальц (Pfaltz J. L.) 98, 102 Пэр (Pair С.) 480 Рабин (Rabin М, О.) 123, 147, 162 Радке (Radke С. Е.) 292 Ране (Rice Н. G.) 192 Рассел (Russel L, J.) 96; 206 Редзиевский (Redziejowski R. R.) 392 Редько В. Н. 147, 408 Рейк (Rake S. Т.) 206 Рейнольдс (Reynolds J. С.) 96, 315, 351 Ренделл (Randell В.) 96; 206 Робертс (Roberts Р, S.) 352 Танака (Tanaka К.) 102 Тоёда (Tojoda J.) 102 Томпсон (Thompson К.) 136, 296 Торин (Torrii К.) 372 Трахтенброт Б. А. 163 Трахтеиброт М. Б. 448 Трахтенгерц Э. А. 510 Трохан Л. К. 362 Тьюринг (Turing А. М.) 42, 43, 51, 123 Уилкокс (Wilcox Т. R.) 206 Уллиан (Lillian' J. S.) 241 Ульман (Ullman J. D.) 52, 123, 200, 241, 283, 408, 409, 452, 480, 542; 29, 91, 117, 236, 266, 292, 326 , 362, 392, 448 Уолтерс (Walters D. А.) 452 Уорли (Worley W. S.) 96 Уортмэн (Wortman D. В.) 96, 510 Уоршолл (Warshall S.) 68, 96 Фельдман (Feldman J. А.) 95, 96, 499, 510 Фишер М. (Fischer М. J.) 123, 480; 195, 326 Фишер П. (Fischer Р. S.) 52 Флойд (Floyd R. W.) 68, 96, 192, 241, 351, 480, 510; 29, 362, 392 Фостер (Foster J. М.) 408 Фрейли (Frailey D. J.) 392 469
ИМЕННОЙ УКАЗАТЕЛЬ К 1 И2 ТОМАМ Фримэн (Freeman D. N.) 96, 296 Фу (Fu К. S.) 102 Фуксман А. Л. 408, 409 Футрель (Futrelle R, Р.) 268 Хавел (Havel I. М.) 510 Халмош (Halmos Р. R.) 13, 38 Хант (Hunt Н. В.) 452 Харари (Нагагу F.) 68 Харрисон (Harrison М. А.) 163, 220, 315, 372 , 510, 558; 185 Хартманне (Hartmanis J.) 52, 147, 220 Хаскел (Haskell R.) 315 Хафмен (Huffman D. А.) 162 Хейнс Л. (Haines L. Н.) 123 Хейнс X. (Haynes Н, R.) 45 Хейс (Hays D. G.) 372 Хекст (Hexst J. В.) 352 Хект (Hecht М. S.) 448 Хеллермая (Hellerman Н.) 392 Хомский (Chomsky N.) 42, 74, 102, 123, 147, 192, 220, 241 Хопгуд (Hopgood F. R. А.) 96, 510 Хопкрофт (Hopcroft J. Е.) 52, 123, 163, 220, 241, 408, 452; 163, 326 , 448 Хорвиц (Horwitz L. Р.) 392 Хорнинг (Horning J. J.) 96, 504, 510 Хохшпрунг (Hochsprung R. R.) 96 Шамир (Shamir Е.) 241 Шапиро (Shapiro R. М.) 96 Шварц (Schwartz J. Т.) 95, 96; 448 Шевченко В. В. 408 Шепердсои (Sheperdson J. С.) 147 Шефер (Schaefer М.) 448 Шиманский (Szymansky Т. G.) 452 Шкильняк С. С. 408 Шор^е (Schorre D. U.) 96, 351, 542; Шоу (Shaw A. S.) 98, 102 Штрассен (Strassen V.) 48, 68 Шумей А. С. 452, 510 Шура-Бура М. Р. 393, 423 Шютте (Schutter L. J.) 45 Шютценберже (Schutzenberger М. Р.) 192, 220, 241 Эванс (Evans A., Jr.) 510, 569 Эви (Evey R. J.) 192, 220 Эйкель (Eickel J.) 510 Эклн (Ackley S. 1.) 295 Эпсон (Elson М.) 206 Элспас (Elspas В.) 96 Энгелер (Engeler Е.) 74 Энглунд (Englund D. Е.) 442, 448 Эрлаид (Irland М. 1.) 52 Эрлн (Earley J.) 372; 45, 117 Эттингер (Oettinger А.) 220, 351 Цейгин Г. С. 102 Ющенко Е. Л. 408, 411 Чен (Chen S.) 392 Чёрч (Church А.) 38, 42, 43 Читэм (Cheatham Т. Е.) 74, 96, 315, 351* 45 Чулик I (Culik К., I) 268 Чулик И (Culik К., И) 408, 558 Яжабек (Jarzabek S.) 408 Ямада (Jamada Н.) 147 Янгер (Younger D. Н.) 372 Янов Ю. И. 422
ПРЕДМЕТНЫЙ УКАЗАТЕЛЬ К I И 2 ТОМАМ ) Аванцепочка (lookahead string) 378 , 427 см. также Заглядывание вперед Автомат (automaton) см. также Распознаватель, Преобразователь — анализирующий (parsing) 117—138 ---канонический (canonical) 119, 120, 129 ---полуприведенный (semireduced) 125, 134 ---расщепленный (split) 123—125, 130, 131 — конечный (finite) 138, 147—151, 286—293, 449 — — двусторонний (two-way) 146 ---детерминированный (deterministic) 138, 287 ---недетерминированный (nondeterministic) 135, 287—293 — — полностью определенный (completely specified) 135 — — приведенный (reduced) 148—151 — линейно ограниченный (linear bounded) 120 — с магазинной памятью (pushdown) 114, 193—220, 318 ---двусторонний (two-way) 219, 220 I — — детерминированный (deterministic) 221—220, 228 , 229, 237—240, 283, 384, 450, 501, 503, 522—525; 157—159, 169, 176, 182—184, 164—185 — в нормальной форме (normal form DPDA) 164—169 — дочитывающий (continuing) 215, 216 — незацикливающийся (halting) 318 — — расширенный (extended) 199—201, 212 ---с одним поворотом (one-turn) 237 Алгебра булева (Boolean algebra) 36, 153 Алгол (ALGOL) 74, 75, 226, 227. 264, 287, 347 , 408 , 559 Алгоритм (algorithm) 38—51 — всюду определенный 40 — Домёлкн (Domolki’s) 351, 352, 507, 510 — Евклида 397 — Кока — Янгера — Касами (Соске — Younger — Kasami) 352—358 — Маркова 42 — недетерминированный (nondeterministic) 320, 346, 347, 351 — разбора, предсказывающий (predictive parsing) 205, 378—381, 391—395, 408 — — корректный (valid) 380 — Уоршолла (Warshall’s) 63, 68 — частичный (procedure) 38—51 — Эрли (Earley’s) 358—372, 450 Алфавит (alphabet) 27 — входной (input) см. Символ входной *) См. примечание на стр. 467.— Прим, перев. 471
ПРЕДМЕТНЫЙ УКАЗАТЕЛЬ К 1 И 2 ТОМАМ Алфавит выходной (output) см. Символ выходной — состояний (of states) см. Состояние Альтернатива (нетерминала) (alternate) 321 Анализ (analysis) — интервалов (interval) 424—448 — лексический (lexical) 76—79, 283—296; 198, 259, 268 , 269, 304 ---непрямой (indirect) 78, 286—290 ---прямой (direct) 78, 290—293 — семантический (semantic) 199 — синтаксический (syntactic) см. Разбор Анализатор (parser) см. также Анализ — двухмагазинный (two-stack) 544—547, 556—558 — канонический LR(£) (canonical LR(£)) 444—447 — левый (left), 299—301 — по левому участку (left-corner) 348—350 — правый (right) 302—304, 338 — предсказывающий (predictive) см. Алгоритм разбора, предсказывающий A-правило (A-production) 175 Блок (block) — открытый (open) 339—342 — приведенный (reduced) 342—345 Блок-схема (flow chart, d-chart) 98—101 Веер (в дереве) см. Куст (в дереве) Вершина (графа) (node, vertex) 52 — концевая см. Лист — младшая (minor) 373, 388 — начальная (begin) 400, 424 — старшая (major) 373, 388 Вершины независимые (independent nodes) 17—19 Вес ЬР(£)-таблицы (height of LR(£)) 66 Включение (множеств) (inclusion) 13, 238 Вход (input) 38 см. также Лента входная Вывод (derivation) 107, 118 — левый (leftmost) 167, 168, 232, 233, 297, 356, 357 — правый (rightmost) 167, 168, 297 Выражение (expression) — арифметическое (arithmetic) 72, 73, 108, 245, 253; 246—252, 256—258, 362—393 — доступное (available) 423 — инфиксное (infix) 244 — постфиксное (postfix) 244, 245, 247, 248, 259, 264, 267, 529; 201, 211, 212 — префиксное (prefix) 244, 245, 259, 264, 267; 201, 207 — расширенное регулярное (extended regular) 284—290 — регулярное (regular) 124—131, 145, 147 Высота (вершины дерева) (height) 58, 84 Выход (output) 38, 243, 255, 258 Вычисления (computations) — избыточные (redundant) 334, 335, 338—342, 345—347, 404—407 — периода компиляции (compile time) 407 Генерация кода (code generation) 75, 82—88, 90, 92, 93; 200, 204, 245, 259—261, 347—351 Глубина (вершины дерева) (depth) 58 472
ПРЕДМЕТНЫЙ УКАЗАТЕЛЬ К I И 2 ТОМАМ Головка входная (распознавателя) (input head) 113—115 Гомоморфизм (homomorphism) 29, 225, 236, 238, 239, 243, 244; 163 Грамматика (grammar) 105 — автоматная см. Грамматика регулярная — без е-правил (e-free) 172, 173, 314, 340, 343, 346, 376, 402, 450, 478, 492 — без ограничений (unrestricted) см. Грамматика общего вида — без циклов (cycle-free) 175, 312, 340, 343, 346, 367 — бесконтекстная см. Грамматика контекстно-свободная — входная (СУ-схемы) (input, underlying) 250; 237, 296 — выходная (output) 250 — индексная (indexed) 120, 121 — каноническая (canonical) 166—172, 174, 175 — Колмерауэра (Colmerauer) 549, 554—558 — контекстно-зависимая (context-sensitive) 111, 112, 117, 119, 121, 237, 452 — контекстно-свободная (context-free) 111, 112, 117, 119, 121, 237 — левоанализируемая (left parsable) 304—306, 381; 145, 146 — леволинейная (left linear) 145 — леворекурсивная (left recursive) 178—181, 324, 325, 331, 332, 385, 400; 154 — линейная (linear) 191, 237, 268 — LC(k) 402—408 — LL 376 — LL(lfe) 301, 373—408, 449, 450; 46, 114, 115, 137, 139—164, 185, 187, 192—194, 207—210, 221—224 — LL(0) 162 — LL(1) 373, 382—387, 408, 411,593; 113,134—136, 148, 149, 161, 162, 192—194, 209, 214 . — LR(£) 304, 373, 421, 423—452, 478, 482, 484, 503; 45—138, 139—146, 207, 209— 215, 218—221 ---простая (simple) 75, 92—102, 103, 111—116, 135 ---с заглядыванием (LALR(fe)) 100, 101, 114—117, 135 — LR(6) 57, 113, 117—129, 145, 164, 174, 176, 183 — LR(1) 424, 463, 503, 504; 164, 176 — неоднозначная (ambiguous) 168, 189, 231—236, 239, 317, 546; 151,188 см. также Грамматика однозначная — пеукорачивающая см. Грамматика контекстно-зависимая и Грамматика без е-правил — общего вида (unrestricted) 105—112, 118—120, 122 — обратимая (unique invertible) 422,450, 457, 503—506,547, 557; 188—192, 195 — ограниченного контекста (bounded context) 505, 507 — ограниченного правого контекста (bounded right context) 481—488, 503—507 — однозначная (unambiguous) 119, 168, 231—233, 240, 364—366, 384, 447, 449, 460, 476, 485, 549; 136 — операторная (operator) 190, 492 — операторного предшествования (operator precedence) 493—497, 503, 504, 507; 14—16, 188—195 — (1,1)-ОПК ((M)-bounded-right-context) 484, 503; 164—176 — ОПК (BRG, bounded right context) 139, 174—176, 184, 193 — (1,0)-ОПК 164, 174—176, 184 — остовная (skeletal) 496, 507; 80 — (2,1)-предшествования (2,2)-precedence 480, 503; 139, 164, 176—182 — правоанализируемая (right parsable) 304—306; 450; 146 — праволинейиая (right linear) 111, 119, 131—133, 143—145, 230, 237 — праворекурсивная (right recursive) 178 — порождающая графы (graph, web) 98—102 — пополненная (augmented) 424, 481; 104 — предшествования (precedence) 456, 457, 463, 480; 7—29, 46 — приведенная (proper) 175; 169 473
ПРЕДМЕТНЫЙ УКАЗАТЕЛЬ К l И 2 ТОМАМ I I I I I I I I I I I I I I I Грамматика простая LL(1) (simple LL(1)) 376, 408, 409 — простая смешанной стратегии предшествования (simple-mixed-strategv pre- cedence) 491, 503, 507 — простого предшествования (simple precedence) 455—463, 474—479, 549, 565; 8, 9, 19—25, 85, 139, 185—189, 192—194 — псевдоразделенная 409, 410, 414, 420 — разделенная см. Грамматика простая LL(1) — расширенного предшествования (extended precedence) 463—469, 478—480, 484, 505; 194 — регулярная (regular) 145, 557 — рекурсивная (recursive) 178 — свойств (property) 199, 267, 292—326 ---недетерминированная (nondeterministic) 324 — сильно LL(£) (strong LL(fe)) 384, 388 — скобочная (parenthesis) 163 — слабого предшествования (weak precedence) 469—477, 479, 491, 492, 503—506; 16, 24, 28, 29—45, 140, 189—192 — слаборазделенная 410, 411, 414 — смешанной стратегии предшествования (mixed-strategy precedence) 488—492, 503, 507; 16 — простая (simple, SMSP) 113, 139, 164, 169—174 — с индикаторами (tagged) 87, 89, 90, 135 — с самовставлением (self-embedding) 240 — • Г-каноннческого предшествования (T-canontcal precedence) 507—510 — Т-остовная (T-skeletal) 509 — Хомского (Chomsky) см. Грамматика Граф (graph) 52—68 — ациклический (ориентированный) (directed acyclic, dag) 54, 138; 240—244, 333—345, 349 линеаризации (linearization) 11—14 нагруженный см. Граф помеченный неориентированный (indirected) 66 переходов (автомата) (transition) см. Диаграмма конечного автомата помеченный (labelled) 53, 57 производный (derived) 427 сверток (reduce) 40 связный (неориентированный) (connected) 66 сдвигов (shift) 36—40 сильно связный (strongly connected) 54 упорядоченный (ordered) 56 — ациклический (dag) 57 управления (flow) 393, 399, 400 — несводимый (irreducible) 439—443 — предельный (limit) 427 -----сводимый (reducible) 424, 427 , 431—439, 446 - GOTO 67 Дерево (tree) 55, 61, 62, 71—73, 81—87, 100, 101, 319, 487—490 — ассоциативное (associative) 381—388 — вывода (derivation) см. Дерево разбора — двоичного поиска (binary search) 272 — неориентированное (undirected) 66, 67 — остовное (spanning) 36—40 - разбора (parse) 164—168, 205—207, 250—252, 307, 431,432, 519—521; 198—204, 365 — — помеченное (labelled) 366, 367 , 381—388 — синтаксическое (syntax) см. Дерево разбора — упорядоченное (ordered) 57, 58 474
ПРЕДМЕТНЫЙ УКАЗАТЕЛЬ К I И 2 ТОМАМ Диаграмма — конечного автомата (transition graph) 138, 255, 256 — синтаксическая (syntactical diagram) 414, 415 Диаграммер (diagrammer) 415—418 Дифференцирование (differentiation) 238—240 Длина (length) — вывода (of a derivation) 107 — цепочки (of a string) 28 ДМП-автомат см. Автомат с магазинной памятью детерминированный Доминатор (dominator) 40!—406 , 410, 420, 425, 448 Дополнение (множества) (complementation) 14, 216, 226, 237, 541 Допускать (цепочку, язык) (accept) 115, 136, 195, 201 Дуга (в графе) (arc, edge) 53 е-правнло (грамматики) (e-production) 111, 177, 178, 340, 402; 147—153, 159—162 163 е-такт (распознавателя) (e-move) 194, 218 Заглядывание вперед (lookahead) 337, 344, 370, 371, 373—375, 378, 402, 421, 424, 450 Заголовок интервала (header of ап interval) 424—427 Загрузчик (loader) 197 Задача слиянии множеств (set merging problem) 316—323 , 326 Закон (law) — ассоциативности (associative) 352—356, 360, 376, 379—388 — днстрибутивиостн (distributive) 352 — коммутативности (commutative) 352—356, 360, 376—388 Законы де Моргана (De Morgan’s laws) 23 Замена сложных операций (reduction in strength) 408, 415—417 Замкнутость (относительно операций) (closure) 152, 224—226, 257, 266 Замыкание (отношения) (closure) — множества допустимых ситуаций (of a set of valid items) 104 — рефлексивное и транзитивное (reflexive and transitive) 19 — транзитивное (transitive) 18, 62—65, 68 Запись польская (Polish notation) см. Выражение префиксное Значение блока (value of a block) 330, 341 Идентификатор (identifier) 76—80, 116, 286, 287, 289—293 Иерархия Хомского (Chomsky hierarchy) 112 Индекс — грамматики, языка 239, 240 — отношения эквивалентности (index) 17 Интерпретатор (interpreter) 197, 201 Исправление ошибок (error correction) 75, 90—93, 96, 337, 338, 407, 446, 451, 452, 480; 9, 10, 53' Исчисление высказываний (propositional calculus) 35, 50 Итерация (языка) (closure) 29, 225 — маркированная (marked) 240 — позитивная (positive) 29 Кисть (cluster) — графа линеаризации (of a linearization graph) 18 — синтаксического дерева (of a syntax tree) 379, 380 КЗ-грамматика см. Грамматика контекстно-завнеимая 475
ПРЕДМЕТНЫЙ УКАЗАТЕЛЬ к 1 и 2 ТОМАМ Код (code) — машинный перемещаемый (relocatable machine) 197 — многоадресный (multiple address) 201—204 — объектный (object) 75, 82, 242; 196 — промежуточный (intermediate) 75, 82—87; 199—204, 327, 328 , 394 Компилятор (compiler) 75—96, 351, 408 — компиляторов (compiler-compiler) 96, 351 Компиляция синтаксически управляемая (syntax directed compiling) 206 Композиция (отношений) (composition) 2b, 281 Конкатенация (concatenation) 27, 29, 225, 238; 163 — маркированная (marked) 240 Конфигурация (configuration) 49, 115, 135, 194, 254, 258, 326, 340, 378, 379, 404, 411, 412, 415, 418, 422, 423, 453, 534, 545; 50 — допускающая (accepting) см. Конфигурация заключительная — достижимая (accessible) 51 — заключительная (final) 115, 135, 195, 201, 255, 258, 259, 379; 51, 120 — зацикливающая (looping) 213—216 — начальная (initial) 115, 135, 194, 326, 340; 379; 50, 120 Конфликт в таблице расстановки (collision in a hash table) 275—279 — отношений предшествования (precedence conflict) 472, 473 — правил 389, 393 — „перенос — свертка" (shift — reduce) 114 Крона (дерева разбора) (frontier) 165—168 КС-грамматика см. Грамматика контекстно-свободная Куст (в дереве) 206 Лексема (token) 76—79, 283—296 Лемма Огдена (Ogden’s lemma) 220—223 ' — о разрастании (pumping lemma) — (для КС-языков) 223, 224 — (для регулярных множеств) 152 Лента входная (распознавателя) (input tape) 113—115 Лист (в графе) (leaf) 54 ЛО-автомат см. Автомат линейно ограниченный Магазин (pushdown list) 114, 192—194, 378 Макрос синтаксический (syntax macro) 265, 266, 559—562 Маркер концевой (endmarker) 113, 304, 326, 378, 381, 409, 412, 415, 418, 457, 522, 525, 541; 173, 174, 175, 182, 189—192 Матрица (matrix) — предшествования (precedence) 457—459 < — —' приведенная (reduced) 11 — сверток (reduce) 40 — смежностей (adjacency) 62, 63 Машина (machine) — анализирующая (parsing) 533—538, 540; 224—232 — Тьюринга (Turing) 42, 49—51, 120, 123 ---универсальная (universal) 50 — с произвольным доступом к памяти (random access) 154, 189, 354, 355, 372, 528, 530, 531 см. также Операция элементарная (алгоритма) Метод цепочек (chaining) 289 — прямой (direct) 289 Множество (set) 11—30 — бесконечное (infinite) 22, 26 — вполне упорядоченное (well ordered) 24, 30 — знаменательных символов (token) 508 476
ПРЕДМЕТНЫЙ УКАЗАТЕЛЬ К 1 И 2 ТОМАМ Множество конечное (finite) 12, 222 — линейное (linear) 239 — непротиворечивое Ш?(£)-ситуаций (consistent set of LR(£) items) 442, 443 — отсрочки (postponement) 67—76, 96 — полулинейное (semi-linear) 239 — пустое (empty) 12 — регулярное (regular) 124—163, 218, 219, 225, 236—238, 257, 266, 269, 270, 400, 478; 163 — рекурсивное (recursive) 42, 48, 112, 119, 120 — рекурсивно перечислимое (recursively enumerable) 42, 48, 111, 112, 118, 268, 558 — счетное (countable) 22, 26 — универсальное (universal) 14 — упорядоченное (ordered) 20 — ЬК(£)-таблнц каноническое (canonical set of LR(£)) 45, 95 ---------корректное (valid) 51 ---------ф-недостижимое (ф-inaccesibie) 55—65, 69—72, 82, 85, 86 /Модуль загрузки (load module) 197 Мощность цепочки (thickness of a string) 156, 157, 163 МП-автомат см. Автомат с магазинной памятью Неоднозначность (ambiguity) 231—236 см. также Грамматика неоднозначная и Язык неоднозначный — конечной степени (finite) 371 — семантическая (semantic) 307, 308 — существенная (inherent) см. Язык неоднозначный Нетерминал (nonterminal) 105, 120, 248, 512—514 Область (region) 409—411 — с одним входом (with a single entry) 411 Область действия (scope) 332 Обратимость (unique invertibility) см. Грамматика обратимая Обращение — гомоморфизма (inverse homomorphism) 30 — цепочки или языка (reversal) 27, 144, 153 Обращение к памяти (memory reference) 389 Объединение (union) 14, 225, 229—231, 238, 541 — маркированное (marked) 240 Однозначность семантическая (semantic unambiguity) 237 OK-грамматика см. Грамматика ограниченного контекста Оператор — бесполезный (useless statement) 327, 332—334, 338—342, 404, 423 — определения (definition statement) 395 — перехода вычисляемый (computed goto) 30 Операция элементарная (алгоритма) (elementary operation) 355, 357, 364—366, 447 — идемпотентная (self-inverse) 352 — коммутативная (commutative) 352, 353—357, 360, 376—389 ОПК-грамматика см. Грамматика ограниченного правого контекста Определение регулярное (regular definition) 285, 286 Оптимизация кода (code optimization) 75, 88—90; 200, 249, 250, 327—448 Организация информации (bookkeeping) 198—200, 259—261, 267—326 * — для языка с блочной структурой (for block-structured language) 271, 293, 294, 297—304 Основа (правовыводимой цепочки) (handle of a right sentential form) 205, 206, 429, 431—434, 455—457, 543 477
ПРЕДМЕТНЫЙ УКАЗАТЕЛЬ К 1 И 2 ТОМАМ Остов (графа) (spanning tree) 67 Отображение (mapping) см. Функция Отношение (relation) 16—26 — антисимметричное (antisymmetric) 21 — асимметричное (asymmetric) 20 — иррефлексивиое (irreflexive) 20 — конгруэнтности (congruence) 158 — обратное (inverse) 16, 22 — операторного предшествования (operator precedence) 493 . — предшествования Вирта — Вебера (Wirth-Weber precedence) 466, 457 ---Колмерауэра (Colmerauer precedence) 547—549 — рефлексивное (reflexive) 17 — симметричное (symmetric) 17 — транзитивное (transitive) 17 — эквивалентности (equivalence) 17, 18, 24, 149—151, 157, 158 ---правоинвариантное (right invariant) 157, 158 -Оценка блоков приемлемая (cost criterion on blocks) 345, 346 Память (распознавателя) (memory) 113—115 Пара цепочек выводимая (translation form) 246—249 Перевод (translation) 71, 242—245, 258, 379, 380, 545; 196—266 — регулярный (regular) см. Преобразование конечное . — синтаксически управляемый (syntax directed) 74, 83—88, 246—253, 260—282, 499, 569—574; 206—266, 363 ---простой (simple) 253, 260—263, 271—274, 282, 298, 569—574; 207, 214 — наследственный (inherited) 255—259, 263 — синтезированный (synthesized) 255—259, 263 Переменная (variable) — активная (active) 332, 423 — входная (input) 329 — выходная (output) 329 — индуктивная (inductive) 412—415 Перемещение кода (code motion) 411, 412 Пересечение (множеств) (intersection) 14, 225, 226, 230 , 237 , 541; 163 Переименование переменных (renaming of variables) 335, 336, 338—342, 345—347 Перестановка операторов (flipping of statements) 336—342, 345—347 Пиг лэтин (pig Latin) 222—224, 234 ПЛ/l (PL/I) 74, 76, 78, 559 ПЛ 360 (PL 360) 565—569 Подстановка (языков) (substitution) 224, 225 Позиция (в цепочке) (position) 220 Покрытие (грамматики) (cover) 309—311, 314, 315 — левое (left) 310, 314, 315, 345; 163 — правое (right) 310, 314, 315, 345; 184, 195 Порядок (как отношение) (order) 20, 21 — лексикографический (lexicografic) 25, 331, 343 — линейный (linear) 21, 25, 59, 60; 350 — обратный (вершин дерева) (postorder) 59 — полный (well) 24, 30 — прямой (вершин дерева) (preorder) 58; 144 — частичный (partial) 20, 21, 25, 26, 59, 60; 350 Порядок (схемы СУ-перевода) (order) 274—281 Последовательность пишущая (write sequence) 168 Постдоминатор (postdominator) 420, 421 Поток данных (data flow) 423—448 , Потомок (в графе) (descendant) 55 Правило (грамматики) (production) 106, 120 478
ПРЕДМЕТНЫЙ УКАЗАТЕЛЬ К 1 И 2 ТОМАМ Правило цепное (single) 173, 174, 507; 76—84, 86, 188, 189 Правило вывода (в формальной системе) (rule of inference) 31 Предикат (predicate) 12 Предложение (sentence) см. Цепочка Предок (в графе) (ancestor) 55 Представление (дерева) (representation) — левое скобочное (left-bracketed) 61, 245 — правое скобочное (right-bracketed) 61, 245 Преобразование (transduction) см. Преобразователь — конечное обратное (inverse finite) 257, 266 Преобразователь (transducer) - конечный (finite) 254—258, 266, 268—270, 273, 281, 282, 284, 291; 198 ---детерминированный (deterministic) 256, 257, 268 — с магазинной памятью (pushdown) 258—263, 267, 268, 298—301, 317—321, 379, 381, 402 -----------детерминированный (deterministic) 259, 260, 283, 304—309,379, 381, 402, 446, 498, 501; 206—214, 234 —-------— расширенный (extended) 302—304, 421—423 Префикс (цепочки) (prefix) 28 — активный (правовыводимой цепочки) (viable) 432, 444; 86 Приоритет (операций) (precedence) 82, 168, 169, 264; 76, 87 Проблема (алгоритмическая) (problem) 43—52 — неразрешимая (undecidable) 44 — остановки (halting) 50 — принадлежности (membership) 154—156, 161, 162, 257 — пустоты (emptiness) 154—156, 161, 162, 169, 170, 539 — разрешимая (decidable) 44 — соответствий Поста (Post’s correspondence problem) 47, 228, 229 — эквивалентности (equivalence) 154—156, 161, 162 , 228—230, 268, 401; 156— 159, 184, 421 Программа (program) — абсолютная (absolute machine code) 196 — исходная (source) 75, 93, 242; 196 — объектная (object) см. Код объектный Продукция (production) см. Правило (грамматики) Произведение декартово (Cartesian product) 16 Производная (регулярного выражения) (derivative) 160, 161 Профиль частотный (frequency profile) 398 Проход компилятора (pass of a compiler) 200, 260 Процессор с магазинной памятью (pushdown processor) 214—224, 240—242 Путь (в графе) (path) 54, 66 — вычислений (computation) 401, 431 Разбиение совместимое (compatible partition) 59—64, 69, 97 Разбор (как синтаксический анализ) (parsing) 72, 75, 80—82, 90—93, 296—309 - восходящий (bottom-up) 205—209, 301—309, 338—344, 542—558; 134—136. 218—221, 246, 297 см. также Грамматика предшествования, LR(&), ОПК — нисходящий (top-down) 205, 297—301, 304—309, 321—338, 499, 511—542; 134—136 , 221—224 , 246, 297 см. также Грамматика LL(fc) — — по текущему символу 408—419 — по левому участку (left corner) 313, 314, 348—350, 403—406 — сверху вниз см. Разбор нисходящий — снизу вверх см. Разбор восходящий — с возвратами (backtrack) 317—352, 511—558; 224—232 — типа „перенос — свертка" (shift—reduce) 303, 338,350. 351, 420—423, 426, 427; 8, 304, 305 Разбор (как результат синтаксического анализа) (parse) 297, 379, 544; 198, 260 479
ПРЕДМЕТНЫЙ УКАЗАТЕЛЬ К I И 2 ТОМАМ Разбор левый (left) см. Вывод левый — по левому участку (left corner) 313, 314, 404 — правый (right) 297, 367 см. также Вывод правый — частичный левый (partial left) 329, 330 ---правый (partial right) 343 Развертывание циклов (loop unrolling) 4/7, 418 Разметка (графа) (labeling) 53, 57 Разность (множеств) (difference) 14 Распознавание образов (pattern recognition) 98—102 Распознаватель (recognizer) 113—116, 123 см. также Автомат — адекватный 410, 413, 417, 419, 420, 501, 513 — односторонний (one-way) 113 — простой МП 409 — синхронный 418—420 — CMR 412—416 Распределение памяти (storage allocation) 200 Расстановка (hashing) — линейная (linear) 285, 286 — по позициям (on locations) 285—287 Расщепление (splitting) — грамматики (grammar splitting) 102—117 — множества ЬК(/г)-снтуаций (of a set of LR(A) items) 100 — состояний анализирующего автомата (of states of parsing automaton) 122—125, 129—131 Редактор связей (link editor) 197 Рубеж (в выводимой цепочке) (border) 374, 421 Свертка (цепочки) (reduction) 205, 302, 338, 339, 344 см. также Разбор типа „пе- ренос — свертка11 Свойство (property) — допустимое (acceptable) 296 — нейтральное (neutral) 295—297, 304, 309—313, 323—325 — префиксное (prefix) 29, 31, 239, 289; 164, 183, 184 — суффиксное (suffix) 29, 31 Связка логическая (logical connective) 33—35 Семантика (semantics) 71—74, 243—246 Сечение (дерева разбора) (cut) 165 Символ (symbol) — бесполезный (в грамматике) (useless) 169, 171, 172, 275, 282, 315 — вспомогательный см. Нетерминал — входной (input) 135, 193, 194, 248, 254, 412, 415 — выходной (output) 248, 258 — исчезающий (nullable) 147—153 — магазинный (pushdown) 193 — начальный (initial, start) 106, 120, 194, 249, 514 — недостижимый (в КС-грамматике) (inaccessible) 170, 171 — нетерминальный (nonterminal) см. Нетерминал — терминальный (terminal) см. Терминал Синтаксис (syntax) 71—74 Система (system) — каноническая ЬР(й)-таблнц (canonical set of LR(&) tables) 444, 445 — каноническая множеств допустимых ситуаций (canonical collection of sets of valid items) 85, 91 — Поста каноническая (Post’s canonical) 42,' 123 — расстановки (hashing system) ---^-равномерная (^-uniform) 291 — случайная (random) 280, 283—287, 289—291 480
ПРЕДМЕТНЫЙ УКАЗАТЕЛЬ К 1 И 2 ТОМАМ Система стандартная уравнений с регулярными коэффициентами (set of regular expression equations in standard form) 127—131 — формальная (formal) 31 Ситуация (item) — в алгоритме Эрли 359, 371, 450 ----ЬК(А)-алгоритме 433 ----допустимая (valid) 433, 435—441, 446 ----квазидопустимая (quasivalid) 108 Слияние столбцов (в ЬИ(й)-анализаторе) (column merger) 80 Слово (word) см. Цепочка Сложность вычисления (временная и емкостная) (computational complexity; time complexity, space complexity), 41, 158, 159, 162, 189, 333—337, 343, 355—357, 364—366, 368—372, 395, 447, 460, 530—532, 557; 214, 322, 323, 347, 358,.430, 446, 447 Снобол (SNOBOL) 70, 562—565 Сортировка топологическая (topological sort) 59, 60 Составляющая (phrase) 543 Состояние (распознавателя, преобразователя) (state) 135, 193, 194, 254, 326, 411, 412, 415 — выталкивания (pop) 122, 123, 130 — достижимое (accessible) 140, 148 — заключительное (final) 135, 194, 254, 326, 412 — записи (write) 164, 167, 183 — заталкивания (push) 130 — начальное (initial) 135, 194, 254, 412 — опроса (interrogation) 122, 130 — переноса (shift) 118 — свертки (reduce) 118 — стирания (erase) 164, 167, 183 — чтения (read, scan) 130, 164, 167, 183 Состояния неразличимые (конечного автомата) (indistinguishable states) 148; 60 ----анализирующего автомата (indistinguishable states of parsing automa- ton) 126 — различимые анализирующего автомата (distinguishable states of parsing auto- maton) 126 Список (list) — магазинный (pushdown) см. Магазин — пересечений (intersection list) 306—316, 322, 323 — разбора (parse) 359 — свойств (property) 306—314, 322, 323 ССП-грамматика см. Грамматика смешанной стратегии предшествования Степень (вершины графа) (degree) — по входу (in-) 54 выходу (out-) 54 СУ-перевод см. Перевод синтаксически управляемый Суффикс (цепочки) (suffix) 28 Схема перевода (translation scheme) см. Перевод зацикленная (circular) 256 ----обобщенная (generalized) 236—244, 261—266 ----простая постфиксная (simple postfix) 210, 235, 236 Сцепление (concatenation) см. Конкатенация Таблица (table) — идентификаторов (symbol) см. Таблица имен — имен (symbol) 75, 79, 80, 92, 93, 287 — разбора (parse) 352 — расстановки (hash table) 274—287 481
ПРЕДМЕТНЫЙ УКАЗАТЕЛЬ К 1 И 2 ТОМАМ Таблица с прямым доступом (direct access table) 270—274 — управляющая разбором (parsing) 379, 385—387, 391—395, 404, 505; 48 см. также ЬК(й)-таблнца — LL(A) 389—391, 394, 395 — LR(fc) 426, 427, 444—446, 451; 45—138, 215—218 ТАГ-снстема (Tag system) 42, 122 Такт (распознавателя) (move) 155, 135, 194 Тезнс Черча — Тьюринга (Church-Turing thesis) 43 Теорема (theorem) 32 — Парика (Parikh’s) 239, 241 Терминал (в грамматике) (terminal) 106, 120, 514 Точка наименьшая неподвижная (minimal fixed point) 127, 129—131, 144—146, 185, 186 Траверс (МП-автомата) (traverse (of a PDA)) 165, 167 Транслятор (translator) 77, 246, 247 см. также Преобразователь Трансляция (translation) см. Перевод Узел (графа) (node) см. Вершина (графа) Упорядочение (ordering) см. Порядок (как отношение) Уравнения (equations) — опредсляющие^для КС-языков) (defining) 185, 186 — с регулярными коэффициентами (regular expression) 126—133, 144, 146 Уровень (вершины дерева) (level) см. Высота (вершины дерева) Устройство управляющее с конечной памятью (finite control) 114, 498 см. также Состояние (распознавателя) Участок линейный (straight-line code) 328—362 Фаза компиляции (phase of compilation) 198—200, 259—261 Факторизация левая (left factoring) 385 Форма (form) — Бэкуса — Наура (Backus-Naur) 74 — нормальная Грейбах (Greibach normal) 182—188, 190, 274, 315, 402, 406; 141, 154, 163, 184 --- слабая 409 — нормальная Хомского (Chomsky normal) 176, 177, 190, 273, 274, 310, 311, 314, 352, 401; 163, 184, 305 Фортран (FORTRAN) 70, 74, 77, 79, 236, 284, 286, 346, 347, 559; 206, 266, 288, 398, 408, 422, 446, 448 Функция (function) 21, 22, 25 — биективная (bijective) 22 — взаимно однозначная см. Функция инъективная — всюду определенная (total) 21, 25 — действия (parsing action) 426—428, 444—446 — доступа к памяти (распознавателя) (store) 114 — инъективная (injective) 22 — общерекуренвная (total recursive) 41 — переходов (goto) 426—428, 444—446 — переходов (состояний автомата) (state transition) 135 — предшествования (precedence) 7—29 — преобразования памяти (распознавателя) (fetch) 114 — расстановки (hashing) 274, 275, 277—279 — рекурсивная (recursive) 41 — слабого предшествования (weak precedence) 16—19, 26, 23 — характеристнческан (characteristic) 48 — частичная (partial) 22 — частично рекурсивная (partial recursive) 41 482
ПРЕДМЕТНЫЙ УКАЗАТЕЛЬ К 1 И 2 ТОМАМ Функция EFF 433, 444, 450 — FIRST 337, 375, 376, 396—399 — FOLLOW 383, 479; 85, 111 — GEN 431—443 — GOTO 438—441, 444; 66, 87, 86 — IN 433—443 — KGOTO 107, 108 — NAME 247 — NEWLABEL 252 — NEXT 64—76, 78, 82, 86 — OUT 431—446 — TRANS 431—443 Цепочка (string) 27, 106 — выводимая (sentential form) 106; 297 — левовыводимая (left sentential form) 167 — правовыводимая (right sentential form) 167, 459, 460, 469—471 — пустая (empty) 27 — характеристическая (characteristic) 136 Цикл (в графе) (cycle, circuit) 54 — в грамматике см. Грамматика без циклов ---программе (loop in program) 393—448 Часть (portion) — (левовыводнмой цепочки) законченная (closed) 374 — незаконченная (open) 374 — (правовыводимой цепочки) замкнутая (closed) 421 — открытая (open) 421 Число псевдослучайное (pseudorandom number) 278. 288 Эквивалентность (equivalence) 71, 147—150, 154—156, 162 — автоматов анализирующих (of parsing automata) 125 — анализаторов (of analyzers) 24, 27, 28, 48 ---строгая (exact) 19—25, 26, 52—55 — выражений относительно алгебраических законов (of expressions under algeb- raic laws) 352 — деревьев относительно алгебраических законов (of trees under algebraic laws) — линейных участков (of straight-line blocks) 332 — структурная (structure) 164 Элемент несущественный (don’t care) 48, 114 — перевода (translation element) 246—248; 237 Ядро множества LR(/s)-cHTyauHfi (core of a set of LR(A) items) 95 Язык (language) 28, 103, 104, 116, 136, 195 см. также Множество — ассемблера (assembly) 82—88; 197, 347—351, 363, 364 — бесконтекстный (context-free) см. Язык контекстно-свободный — детерминированный (deterministic) 211, 216, 229—231, 238, 241, 283, 384,450 501, 503, 522—525 — Дика (Dyck) 239 — естественный (natural) 72, 97, 98, 102, 317, 351 — контекстно-зависимый (context-sensitive) 111, 112, 117, 119—121, 237, 452 — контекстно-свободный (context-free) 111, 112, 117, 119, 121, 237 — левых разборов (left parse) 307, 311 483
ПРЕДМЕТНЫЙ УКАЗАТ ЕЛЬ К 1 И 2 ТОМАМ Язык линейный (linear) 191, 237, 268 — LL 376 — LC(A) 402—408 — LL(/s) 373—408, 449, 450 — LR(A) см. Язык детерминированный и ЬК(й)-грамматика — неоднозначный (ambiguous) 234—236, 238, 239, 241 — нисходящего разбора с ограниченными возвратами (ЯНРОВ) (top-down par- sing language, TDPL) 512—525, 528—530, 539—542 -----обобщенный (ОЯНРОВ) (generalized, GTDPL) 525—542; 224—232 — ограниченного контекста (bounded context) 505, 507 -----правого контекста (bounded right context) 481—488, 503—507 — однозначный (unambiguous) 234, 240 см. также Грамматика однозначная — операторного предшествования (operator precedence) 493—497, 503, 504, 507 — (1,1)-ОПК ((l.l)-bounded-right-context) 484, 503 — правых разборов (right parse) 307, 311 — программирования (programming) 42, 69—74, 373 см. также Алгол, ПЛ/1, ПЛ 360, Фортран, Снобол — простого предшествования (simple precedence) 455—463, 474—479, 549, 565; 5, 9, 19—25, 85, 139, .185—189, 192—194 — расширяемый (extensible) 74, 75, 559—562 — регулярный (regular) см. Множество регулярное —!г существенно неоднозначный (inherent ambiguous) 29—45 см. также Язык не- однозначный — Флойда — Эванса (Floyd-Evans) 411, 497—502, 507, 510 — характеризующий (characterizing) 269—273, 282 ЯНРОВ см. Язык нисходящего разбора с ограниченными возвратами
ОГЛАВЛЕНИЕ ПРЕДИСЛОВИЕ 5 7 МЕТОДЫ ОПТИМИЗАЦИИ СИНТАКСИЧЕСКИХ АНАЛИЗАТОРОВ 7 7.1. Функции предшествования 7 7.1.1. Теорема о представлении матрицы 8 7.1.2. Применения к разбору, основанному на операторном пред- шествовании 14 7.1.3. Функции слабого предшествования 16 7.1.4. Преобразование матриц предшествования 19 Упражнения 25 .Замечания по литературе 29 7.2. Оптимизация анализаторов Флойда—Эванса 29 7.2.1. Механическое построение анализаторов Флойда —Эванса для' грамматик слабого предшествования 30 7.2.2. Усовершенствование анализаторов Флойда — Эванса 35 Упражнения 42 Замечания по литературе 45 7.3. Преобразования, определенные на множествах ЬИ(й)-таблиц 45 7.3.1. Общее понятие ЬР(6)-таблицы 47 7.3.2. Эквивалентность множеств таблиц 52 7.3.3. ф-недостнжимые множества таблиц 55 7.3.4. Слияние таблиц с помощью совместимых разбиений 39 7.3.5. Отсрочка в обнаружении ошибок 64 7.3.6. Исключение сверток по цепным правилам 76 Упражнения 84 Замечания по литературе 91 7.4. Методы построения ЕК(&)-анализаторов 91 7.4.1. Простые LR-грамматнкн 92 7.4.2. Распространение SLR-подхода на грамматики, не являю- щиеся SLR-грамматнкамн 97 7.4.3. Расщепление грамматики 102 Упражнения 113 Замечания по литературе 117 7.5. Анализирующие автоматы 117 7.5.1. Канонический анализирующий автомат 117 7.5.2. 'Расщепление функций состояний 122 7.5.3. Обобщение на ЬР(А)-анализаторы 129 7.5.4. Обзор содержания главы 134 Упражнения 136 Замечания по литературе 138 485
ОГЛА БДЕНИЕ У ТЕОРИЯ ДЕТЕРМИНИРОВАННОГО РАЗБОРА 139 8.1. Теория LL-языков 141 , 8.1.1. LL- и LR-грамматики 141 8.1.2. LL-грамматнкн в нормальной форме Грейбах 147 8.1.3. Проблема эквивалентности для LL-грамматнк 156 8.1.4. Иерархия LL-языков 159 Упражнения 162 , Замечания по литературе 163 I 8.2. Классы грамматик, порождающие детерминированные языки 164 i 8.2.1. ДМП-автоматы в нормальной форме и канонические грам- i матнкн 164 - 8.2.2. Простые ССП-грамматики н детерминированные языки 169 8.2.3. ОПК-грамматики, LR-грамматнки и детерминированные языки 174 8.2.4. Грамматики расширенного предшествования и детермнннро- - ванные языки 176 - Упражнения 182 Замечания по литературе 185 8.3. Теория языков простого предшествования 185 8.3.1. Класс языков простого предшествования 185 ; 8.3.2. Языки операторного предшествования 188 I 8.3.3. Обзор содержания главы 192 * Упражнения 194 ' Замечании по литературе 195 ПЕРЕВОД И ГЕНЕРАЦИЯ КОДА 196 9.1. Роль перевода в процессе компиляции 196 9.1.1. Фазы компиляции 198 9.1.2. Представления промежуточной программы 200 9.1.3. Модели процесса генерации кода 204 Упражнения 205 Замечания по литературе 206 9.2. Синтаксически управляемые переводы 206 9.2.1. Простые синтаксически управляемые переводы 206 9.2.2. Обобщенный преобразователь 214 9.2.3. Детерминированный однопроходной восходящий перевод 218 9.2.4. Детерминированный однопроходной нисходящий перевод 219 9.2.5. Перевод при наличии возвратов 224 Упражнения 232 ( Замечания по литературе 236 i 9.3. Обобщенные схемы переводов 236 9.3.1. Мультисхемы переводов 236 9.3.2. Разновидности переводов 245 9.3.3. Наследственный и синтезированный переводы 255 9.3.4. Замечание о разбиении на фазы 259 Упражнения 261 Замечания по литературе 2С6 486
ОГЛАВЛЕНИЕ IM ОРГАНИЗАЦИЯ ИНФОРМАЦИИ 267 10.1. Таблицы имен 267 10.1.1. Хранение информации о лексемах 268 10.1.2. Механизмы запоминания 270 10.1.3. Таблицы расстановки 274 10.1.4. Функции расстановки 277 10.1.5. Эффективность таблиц расстановки 279 Упражнения 287 Замечания по литературе 292 10.2. Грамматики свойств 292 10.2.1. Мотивировка 293 10.2.2. Определение грамматики свойств 395 10.2.3. Реализация грамматик свойств ЗС4 10.2.4. Анализ алгоритма обработки таблиц 314 Упражнения 323 Замечания по литературе 326 11 ОПТИМИЗАЦИЯ КОДА 327 11.1. Оптимизации линейного участка 328 11.1.1. Модель линейного участка 328 11.1.2. Преобразования блоков 332 11.1.3. Графическое представление блоков 338 11.1.4. Критерий .эквивалентности блоков 342 11.1.5. Оптимизация блоков 345 11.1.6. Алгебраические преобразования 351 Упражнения 357 Замечания по литературе 362 11.2. Арифметические выражения 362 11.2.1. Модель машины 363 11.2.2. Разметка деревьев 366 11.2.3. Программы с командами STORE 373 11.2.4. Влияние некоторых алгебраических законов 376 Упражнения 388 Замечания по литературе 392 11.3. Программы с циклами 393 11.3.1. Модель программы 394 11.3.2. Анализ потока управления 398 11.3.3. Примеры преобразований программ 404 11.3.4. Оптимизация циклов 408 Упражнения 418 Замечания по литературе 422 11.4. Анализ потока данных 423 11.4.1. Интервалы 424 11.4.2. Анализ потока данных с помощью интервалов 431 11.4.3. Несводимые графы управления 439 11.4.4. Обзор содержания главы 443 Упражнения 444 Замечания по литературе 448 Список литературы 449 Указатель лемм, теорем и алгоритмов к тому 2 465 Именной указатель к 1 и 2 томам 467 Предметный указатель к 1 и 2 томам 471