А.В. Ахо, М.С. Лам, Р. Сети, Дж. Д. Ульман - Компиляторы - принципы, технологии и инструментарий (1114947), страница 93
Текст из файла (страница 93)
Здесь гор означает текущую таблицу символов. Метод (ор.ри! создает запись таблицы символов для Ы.!ехете с типом Т.(уре и относительным адресом офес в области данных. Инициализация офе! на рис. 6.17 будет более очевидной, если переписать первую продукцию в одну строку как Р— ~ (офе! = О;) Р (6.1) Чтобы все действия находились на правых концах продукций, можно использовать нетерминалы, генерирующие е и называющиеся нетерминалами-маркерами (см. 466 Глава 6.
Генерация промежуточного кода раздел 5.5.4). Используя маркер М, можно записать (6.1) как Р— МР М вЂ” е 1офег = О; ) 6.3.6 Поля в записях и классах Трансляция объявлений на рис. 6.17 переносится на поля в записях и классах. Типы записей могут быть добавлены к грамматике на рис. 6.15 путем добавления продукции Т вЂ” гесогп '1' .Р ')' Поля в этом типе записи определяются последовательностью объявлений, генерируемых Р.
Подход, показанный на рис. 6.17, может использоваться и для определения типов и относительных адресов полей при соблюдении следующих условий: ° имена полей в записи должны быть различны, т.е. в обьявлениях, генерируемых Р, каждое имя может появляться не более одного раза; ° смещение, или относительный адрес, имени поля отсчитывается относительно начала области данных, выделенной для записи. Пример 6.10.
Использование имени х для поля внутри записи не конфликтует с другими применениями этого имени вне записи. Таким образом, три использования х в следующих объявлениях различны и не конфликтуют друг с другом: й1оаг х; гесогс) ( й1оас х; г1оаГ у; ) р; гесогс1 ( хпГ сад; 11оас х; й1оас у; 1 с1; Последующее присваивание х = р. х + с1. ха устанавливает значение переменной х равным сумме полей х в записях р и с1. Заметим, что относительный адрес х в р отличается от относительного адреса х в с1.
и Для удобства типы записей будут кодироваться с применением как типов, так и относительных адресов их полей, используя для типа записи таблицу символов. Тип записи имеет вид гесогЫ (г), где гесоп1 — конструктор типа, а 1 — объект, представляющий собой таблицу символов, хранящую информацию о полях данного типа записи.
Схема трансляции на рис. 6.18 состоит из единственной продукции, которая добавляется к продукции на рис. 6.15. Эта продукция содержит два семантических действия. Действие перед Р сохраняет существующую таблицу символов, 467 6.3. Типы и объявления описываемую переменной гор, и устанавливает значение гор равным новой таблице символов. Кроме того, сохраняется текущее значение орзег и переменной обжег присваивается нулевое значение. Объявления, сгенерированные Р, сохраняют типы и относительные адреса в новой таблице символов. Действие после Р создает тип записи с использованием гор, после чего восстанавливает сохраненные таблицу символов и смещение. Т вЂ” гесого '1' ( Епт.риз'п(~ар)' гор = петя Епт()' Я!ас)г.ритл(офяег); а1)зег = О; ) р /)! ( Т.$уре = гесопз(1ор); Т.юийп = оЯзец гор = Епнрор()' обжег = Б~асМ.рор()' ) Рис.
6.18. Обработка имен полей в записях Для конкретности действия на рис. 6.18 содержат псевдокод одного из вариантов реализации. Здесь класс Епт реализует таблицы символов. Вызов Епт.риза (гор) вносит на вершину стека текущую таблицу символов, обозначаемую переменной гор. Точно так же переменная оЯяег вносится на вершину стека с именем 51ас/с. Затем переменная орзег получает значение, равное О. После трансляции объявлений Р таблица символов лэр содержит типы и относительные адреса полей в этой записи.
Значение о()яе~ указывает количество памяти, необходимое для хранения всех полей записи. Второе действие устанавливает значение Тауре равным гесоге) (гор), а значение Т.нй)гл — равным о()яеп Затем восстанавливаются значения переменных гор и огреб которые были ранее сохранены в стеках, и этим завершается трансляция данного типа записи. Данный метод распространяется и на классы, поскольку резервирования памяти для методов не требуется (см. упражнение 6.3.2). 6.3.7 Упражнения к разделу 6.3 Упражнение 6.3.1.
Определите типы и относительные адреса идентификаторов в приведенной ниже последовательности объявлений: й1оаг х; гесогс) ( й1оас х; й1оас у; ) р; гесогд 1 1пГ Гадя г1оаг х; г1оаг у; ) с1; ! Упражнение 6.3.2. Распространите обработку имен полей на рис. 6.18 на классы и иерархии классов с единичным наследованием. а) Приведите реализацию класса Епт, которая поддерживает связанные таблицы символов, так что подкласс может либо переопределять имя поля, либо обращаться непосредственно к имени поля надкласса.
468 Глава 6. Генерация промежуточного кода б) Приведите схему трансляции, которая выделяет непрерывную область данных для полей класса, включая унаследованные поля. Унаследованные поля должны поддерживать относительные адреса, которые они получают в схеме налкласса. 6.4 Трансляция выражений Оставшаяся часть данной главы посвящена вопросам, возникающим при трансляции выражений и инструкций. Мы начнем этот раздел с трансляции выражений в трехадресный код. Выражения с более чем одним оператором, наподобие а+6*с, будут транслироваться в команды с не более чем одним оператором в команде.
Обращения к массивам наподобие А [1] [т] будут разворачиваться в последовательность трехадресных команд, вычисляющих адрес, к которому будет выполняться обращение. Проверка типов будет рассмотрена в разделе 6.5, а использование логических выражений для управления потоком — в разделе 6.6. 6.4.1 Операции в выражениях Синтаксически управляемое определение на рис. 6.19 создает трехадресный код для инструкции присваивания В с использованием атрибута соде для Я и атрибутов агЫг и сог1е для выражения Е. Атрибуты Я.согде и Е гойе означают трехадресный код Я и Е соответственно.
Атрибут Е.агЫг означает адрес, в котором сохраняется значение Е. Вспомним из раздела 6.2.1, что адрес может быть именем, константой или временной переменной, сгенерированной компилятором. Рассмотрим последнюю продукцию синтаксически управляемого определения на рис. 6.19, Š— !и. Когда выражение представляет собой единственный идентификатор, скажем, ж, то х сам по себе хранит значение выражения. Семантические правила для этой продукции определяют атрибут Е.а~Ыг как указывающий на запись в таблице символов для данного экземпляра Ы. Пусть гор означает текущую таблицу символов.
Функция 1ор.дег, будучи примененной к строковому представлению ыЪ.1ехете данного экземпляра И, выбирает из таблицы символов соответствующую запись. Е.соде устанавливается равным пустой строке. В случае продукции Š— (Ег) трансляция Е та же, что и для подвыражения Еь Следовательно, Е.агЫг равно ЕыагЫг, а Е.сог1е равно Ег.сгЫе. Операторы + и унарный — на рис. 6.19 являются представительными операторами типичных языков программирования. Семантические правила для Š— Е1 + Ез генерируют код для вычисления значения Е из значений Е1 и Ез. Вычисленные значения сохраняются во вновь создаваемых временных именах.
Если значение Е1 сохраняется в Е,.а Ыг, а Ез — в Ез.агЫг, то Ег + Ез транслируется в 1 = Е|.а~Ыг+ Ез.агЫг, где 1 — новое временное имя. Е.агЫг устанавливает- 469 6.4. Трансляция выражений Рис. 6.19. Трехвдресный код для выражений ся равным 1. Последовательность различных временных имен йы 1з,... создается последовательными вызовами пезт Тетр(). Для удобства мы используем запись яеп (х ' = ' у '+ ' з) для представления трехадресной команды х = у+ в.
Выражения, находящиеся на местах переменных х, у и г, при передаче в пел вычисляются, а строки в кавычках наподобие ' = ' передаются буквальноз. Другие трехадресные команды создаются аналогично путем применения пел к комбинации выражений и строк. При трансляции продукции Е ~ Ез + Ез семантические правила на рис. 6.19 строят Е.сог1е путем конкатенации Еысог1е, Ез.сог1е и команды сложения значений Ег и Ез.
Команда помешает результат сложения в новое временное имя для Е, обозначаемое при помоши Е.агЫг. Трансляция Š— — Е1 аналогична. Правила создают новое временное имя для Е и генерируют команду для выполнения операции унарного минуса. Наконец, продукция Я вЂ” И = Е; генерирует команды, которые присваивают значение выражения Е идентификатору Ы. Семантическое правило для этой В синтаксически управляемых определениях яел создает и возвращает команду. В схеме трансляции яел создает команду и инкрементнс помещает ее в поток генерируемых команд.