скачать рефераты
  RSS    

Меню

Быстрый поиск

скачать рефераты

скачать рефератыРеферат: Проектирование трансляторов

     Поскольку этот алгоритм распределения памяти касается  опре-

деленных частей последовательности, можно написать

     ST   V1

     U    V1

     ST   V2

     U    V2

     ST   V3

     U    V3

     Так как последнее использование каждой переменной встречает-

ся до определения следующей переменной, то легко видеть, что дос-

таточно одной ячейки памяти.

     Предположим, что имеется стек неиспользованных ячеек  памяти

[T1, T2, T3, ...]. Предположим далее, что каждый раз, когда  нуж-

на ячейка, она берется из вершины стека и что сразу после послед-

него использования какой-либо переменной отведенная для нее ячей-

ка возвращается в стек. Тогда алгоритм распределения  памяти  для

временных переменных проще всего описать следующим образом.

     Последовательность команд просматривается НАЧИНАЯ С КОНЦА, В

ОБРАТНОМ ПОРЯДКЕ. Если встречается команда вида U Vi и  при  этом

для переменной Vi еще не отведена ячейка памяти,  то  из  вершины

стека берется свободная ячейка, ставится в соответствие  перемен-

ной Vi и производится замена символа Vi в данной команде  на  ад-

рес соответствующей ячейки памяти. Такая же замена производится и

в том случае, когда ячейка памяти для переменной Vi уже  отведена

ранее. Если встречается команда ST Vi и для переменной Vi еще  не

отведена ячейка памяти, то это означает либо ошибку,  либо  избы-

точность данной команды, так как подразумевается, что  переменная

вычисляется без дальнейшего использования. Если для переменной Vi

ранее отведена ячейка памяти, то производится замена символа Vi в

данной команде на адрес соответствующей  ячейки  памяти  и,  пос-

кольку это первое  обращение  к  переменной  Vi,  соответствующая

ячейка в данный момент может быть возвращена в стек свободной па-

мяти, так как для Vi она больше не понадобится.

     Данциг и Рейнольдс показали, что  этот  алгоритм  оптимален,

хотя он и не единственный возможный оптимальный алгоритм.

     Например, рассмотрим последовательность

     (1)  ST   V1

     (2)  ST   V2

     (3)  U    V2

     (4)  U    V1

     (5)  ST   V3

     (6)  U    V1

     (7)  U    V3

     (8)  ST   V4

     (9)  U    V3

     (10) U    V4

     и предположим, что стек свободной памяти есть [T1, T2,  T3].

Начинаем просмотр последовательности с конца; команда (10)  поме-

щает переменную V4 в ячейку T1, команда (9) отводит для  перемен-

ной V3 ячейку T2, после этого стек остается в виде [T3].  Команда

(8) освобождает ячейку T1, после этого стек  принимает  вид  [T1,

T3]. Команда (6) помещает V1 в ячейку T1. Подобным же образом ко-

манда (5) освобождает ячейку T2; затем эта ячейка  отводится  ко-

мандой (3) переменной  V2.  В  результате  получается  последова-

тельность

     (1)  ST   T1

     (2)  ST   T2

     (3)  U    T2

     (4)  U    T1

     (5)  ST   T2

     (6)  U    T1

     (7)  U    T2

     (8)  ST   T1

     (9)  U    T2

     (10) U    T1

     Этот алгоритм находит интервал для  каждой  переменной,  ис-

пользуя первое появление этой переменной  при  обратном  посмотре

для определения конца интервала, а соответствующую команду ST для

определения начала интервала. Больше от алгоритма ничего не  тре-

буется.

     Предложенный алгоритм может быть изменен так, чтобы  выраба-

тывать ту же информацию путем прямого просмотра последовательнос-

ти команд. При прямом  просмотре  каждая  команда  ST  определяет

по-прежнему начало интервала. Если для каждой переменной  подсчи-

тано число ее использований, то можно найти и последнее использо-

вание любой переменной, так что конец соответствующего  интервала

становится известным.

     Другой вариант состоит в том, чтобы находить конец  интерва-

ла способом, описанным для  обратного  просмотра,  но  фактически

осуществлять прямой просмотр. Это достигается образованием цепоч-

ки всех обращений к данной переменной в порядке их появления  при

просмотре. С каждой переменной Vi связываются три ячейки,  содер-

жащие Fi, Li и Ri. Значение Fi является номером  команды  ST  для

переменной Vi в последовательности команд. Значение  Li  является

номером команды последнего обращения к переменной Vi. Поэтому ин-

тервал для Vi имеет вид (Fi,Li).  Значение  Ri  является  адресом

ячейки, отведенной для переменной Vi, и обычно первоначально  ус-

танавливается равным нулю.

     Если при просмотре последовательности команд встречается ко-

манда ST Vi, то это вызывает установку значений Fi и  Li,  равных

номеру этой команды в последовательности. Если встречается коман-

да U Vi, то Vi заменяется в ней на Li, а Li становится равным но-

меру этой команды. Для предыдущего примера  переменные  Fi  и  Li

принимают конечные значения:

     F1=1      L1=6

     F2=2      L2=3

     F3=5      L3=9

     F4=8      L4=10

     а команды принимают вид

     (1)  ST   0

     (2)  ST   0

     (3)  U    2

     (4)  U    1

     (5)  ST   0

     (6)  U    4

     (7)  U    5

     (8)  ST   0

     (9)  U    7

     (10) U    8

     После завершения просмотра  последовательности  значение  Li

указывает конец цепочки всех обращений к  переменной  Vi.  Каждая

команда содержит в адресной части номер предыдущей команды из той

же цепочки. Если для переменной Vi отведена ячейка в  памяти,  то

не представляет труда подняться по соответствующей цепочке, заме-

няя адресные части команд на адрес  ячейки,  отведенной  для  Vi.

Итак, интервал для каждой  переменной  определяется  парой  чисел

(Fi,Li). Теперь можно просмотреть эти  пары,  чтобы  распределить

память для всех переменных. Если Fi=Li, то соответствующая коман-

да ST является избыточной, как отмечалось раньше.

     Интервалы просматриваются в порядке возрастания Fi. В  нашем

примере переменные уже перенумерованы в этом порядке. Обычно  ал-

горитм генерирования команд может быть  согласован  с  алгоритмом

распределения памяти так, чтобы такая нумерация переменных  всег-

да имела место. Для этого только требуется, чтобы порядок, в  ко-

тором имена переменных впервые  появляются  в  последовательности

команд, совпадал с порядком мест, отведенных в векторах для соот-

ветствующих ячеек Fi и Li. В нашем примере переменная  V1  должна

быть определена до переменной V2 и т.д.

     При просмотре интервалов в порядке возрастания  значений  Fi

первая переменная помещается в ячейку T1. Для каждого  очередного

интервала (Fj,Lj) исследуются АКТИВНЫЕ интервалы, для которых па-

мять уже распределена, с тем чтобы выяснить, существует ли  такой

интервал (Fi,Li), что Li<Fj. Если такой интервал  существует,  то

переменная Vj помещается в ту же ячейку памяти, что и  переменная

Vi, а интервал (Fi,Li) отмечается как НЕАКТИВНЫЙ. Таким  образом,

на каждом этапе активные интервалы определяют текущие переменные,

которые размещены в ячейках памяти, а также  определяют  моменты,

когда эти ячейки освобождаются. Если не существует активного  ин-

тервала со значением Li<Fj, то нужно взять из стека новую  ячейку

и отвести ее для Vj.

     В нашем примере для V1 была бы отведена ячейка T1.  Так  как

L1>F2, то для V2 нужна новая ячейка, и поэтому для V2 была бы от-

ведена ячейка T2. С другой стороны, L2<F3, так что  можно  помес-

тить V3 в ту же ячейку памяти, что  и  V2  (т.е.  в  ячейку  T2).

Интервал для V2 теперь отмечается как неактивный. Так как  L1<F4,

то переменная V4 тоже помещается в ячейку T1.

                       3.3 Алгоритм Биледи

     Многие ЭВМ имеют небольшой набор быстрых регистров,  которые

сходны с ячейками основной памяти с той разницей, что выборка ин-

формации, запомненной в быстрых регистрах, требует во  много  раз

меньше времени, чем выборка из основной памяти.  На  самом  деле,

быстрые регистры могут  быть  индекс-регистрами  или  добавочными

сумматорами. т.е. их сожержимое может использоваться  специальным

образом в арифметических или логических операциях, но здесь мы не

учитываем эти свойства.

     Эти быстрые регистры могут быть  использованы  для  хранения

копий переменных, размещенных в основной памяти; что же  касается

временной переменной, то она может находиться в быстром  регистре

все время своего существования, не требуя места в основной  памя-

ти. Если число доступных быстрых регистров превышает  число  нуж-

ных переменных, то проблемы не возникает и быстрые  регистры  мо-

гут быть распределены по алгоритму для временных переменных.

     Однако если число доступных быстрых  регистров  не  является

достаточным, то возникает ситуация, когда необходимо решать,  ка-

кие из переменных должны оставаться в быстрых регистрах.  Решение

будет зависеть от частоты использования различных  переменных,  и

алгоритм должен стремиться максимально использовать  быстрые  ре-

гистры.

     Алгоритм Биледи приводит к оптимальному результату при неко-

торых ограничениях и часто дает хорошие результаты в более  общих

случаях. Предполагается, что быстрые регистры должны  применяться

для хранения копий переменных из ОП и что использовать эти  пере-

менные можно только после занесения их в быстрые регистры.

     В дальнейшем будем предполагать, что  рассматриваемые  пере-

менные не будут изменяться;  поэтому,  если  нужно  заменить  ка-

кую-то переменную в быстром регистре, то нет необходимости  запо-

минать текущее содержимое быстрого регистра, так как копия  этого

содержимого уже есть в основной памяти.

     Возникающая задача похожа на задачу замещения страниц в сис-

теме с двумя уровнями памяти.

     Биледи (1966) сформулировал оптимальный алгоритм для случая,

когда известна полная картина будущих обращений, что  использова-

лось в системе с двумя уровнями памяти для получения  оценки  эф-

фективности многих применяемых эвристических алгоритмов.

     Задача распределения быстрых регистров отличается от  задачи

с двумя уровнями памяти тем, что для нее нет необходимости выпол-

нять распределение до получения полной последовательности команд.

Поэтому алгоритм Биледи может быть применен  непосредственно  для

получения оптимальных результатов. Этот алгоритм прменялся в ком-

пиляторах в течение нескольких лет, и только с недавнего времени,

в связи с его использованием в системе с двумя уровнями памяти, с

ним стало связываться имя Биледи.

     Интервалы, в которых используются  основные  переменные  Vi,

могут быть изображены диаграммой, как показано на рис. 20.8.

     V5                   ├────────────────┤

     V4             ├───────────────────┤

     V3       ├──────────────┼──────────────────┤

     V2    ├─────┼─────┼────────┤

     V1 ├───────────────────────────┤

        1  2  3  4  5  6  7  8  9  10  11  12  13

     Рис. 20.8 Диаграмма использования переменных Vi в последова-

тельности команд

     Каждая горизонтальная переменная изображает интервал для не-

которой переменной, причем точки указывают номера мест в последо-

вательности команд, где используется эта переменная. Будем  пред-

полагать, что в каждой команде используется только одна  перемен-

ная, так что на одной вертикали не может появится  двух  и  более

точек. Число горизонтальных линий,  пересекающихся  с  какой-либо

вертикалью, указывает, сколько ячеек памяти содержат  в  соответ-

ствующий момент нужные значения переменных. Если число  пересече-

ний какой-то вертикали с различными горизонтальными линиями  пре-

вышает число доступных быстрых регистров, то одна или  более  чем

одна из переменных не может быть помещена в быстрых регистрах.

     Мы будем также полагать, что каждая выборка какой-либо пере-

менной из быстрого регистра требует  ничтожной  затраты  времени.

Если нужной переменной нет в быстром регистре, то необходимо  за-

менить содержимое одного из быстрых регистров  на  значение  этой

переменной. Определим функцию S(i,t) следующим образом:

     S(i,t)=0, если переменная Vi не находится в  быстром  регис-

тре в момент t;

     S(i,t)=1, если Vi находится в быстром регистре в момент t.

     Тогда сумма по всем номерам "t" не должна превышать N, где N

- число доступных быстрых регистров.

     Если m(t) - номер переменной, используемой в команде "t", то

функцию U, характеризующую  эффективность  использования  быстрых

регистров, можно определить следующим образом:

     U=сумма S(m(t),t)).

         t

     Максимальное значение функции U (при заданных выше ограниче-

ниях) достигается, когда наибольшее число использований  перемен-

ных будет происходить путем непосредственного  обращения  к  быс-

трым регистрам. Единственное доп. ограничение состоит в том, что

     S(m(t-1),t)=1

     для всех значений t. Это означает, что каждая переменная при

использовании заносится в быстрый регистр.

     Алгоритм Биледи состоит в следующем.

     Последовательность команд исследуется, начиная с первой  ко-

манды, определенной значением t=1. Для каждого  значения  t  рас-

сматривается переменная Vi, где i=m(t), и выполняются действия по

одному из следующих вариантов:

     (1) Для переменной Vi отведен  быстрый  регистр;  тогда  ис-

пользуется этот регистр.

     (2) Для переменной Vi  не  отведено  быстрого  регистра,  но

имеется неиспользованный быстрый регистр; в  таком  случае,  этот

регистр отводится для Vi.

     (3) Для переменной Vi не отведено быстрого регистра, и  рас-

пределены все быстрые регистры. Тогда рассматриваются переменные,

для которых в текущий момент имеются копии в быстрых регистрах, и

если значение какой-то одной из них  больше  не  потребуется,  то

соответствующий быстрый регистр теперь отводится для Vi. Если со-

держимое всех быстрых регистров все еще необходимо, то для Vi от-

водится быстрый регистр, соответствующий той переменной,  следую-

щее использование которой наиболее удалено от данной команды.

     Пусть имеются 3 быстрых регистра R1, R2 и R3. Начиная с  мо-

мента t=1 первые три команды отведут регистры R1, R2 и R3 для пе-

ременных V1, V2 и V3. В момент t=5 содержимое всех  трех  быстрых

регистров еще необходимо, а требуется регистр для V4.  Переменная

V1 не будет использоваться до момента  t=10,  тогда  как  V2  ис-

пользуется при t=6 и V3 - при t=8. Поэтому регистр R1 теперь  ис-

пользуется для V4. При t=7 вновь  возникает  такая  же  проблема.

Значение V4 не требуется  до  момента  t=11,  тогда  как  V3  ис-

пользуется при t=8 и V2 - при t=9. Поэтому регистр  R1  отводится

для V5. При t=10 переменная V1 используется снова. Теперь  приме-

няется сформулированное выше условие (2),  так  как  значение  V2

больше не потребуется. Поэтому регистр R2 отводится для V1.  Ана-

логично при t=11 регистр К2 отводится для V4, так как  больше  не

потребуется значение V1.

     Распределение регистров R1 и R3 для V5 и V3  сохраняется  до

конца последовательности команд. Описанное распределение  быстрых

регистров показано диаграммой на рис. 20.9.

     V5                   ├─────────────────┤

     V4             ├────── ─ ─ ─ ─ ─ ──┤

     V3      ├───────────────┼──────────────────┤

     V2    ├─────┼─────┼────────┤

     V1 ├──────────── ─ ─ ─ ─ ─ ─ ──┤

        1  2  3  4  5  6  7  8  9  10  11  12  13

     Рис. 20.9 Диаграмма использования переменных Vi в последова-

тельности команд, поясняющая работу алгоритма Биледи

                       4. ТАБЛИЦА СИМВОЛОВ

                          4.1 Описатели

     Для каждого вхождения идентификатора в исх.  программе  осу-

ществляется поиск соотв. элемента в таблице символов (ТС), инфор-

мация, полученная при данном вхождении,  сопоставляется  с  ранее

полученной информацией, выполняется необходимый контроль и регис-

трация новой информации. Таким образом, ТС является очень  важной

частью компилятора и, в некотором  смысле,  узловой  точкой  всей

трансляции. Ее структура должна  допускать  эффективный  поиск  и

внесение информации. В то же время, каждый элемент  должен  зани-

мать как можно меньше места, для того,  чтобы  хватало  места  на

большие программы с большим числом идентификаторов. Вообще  гово-

ря, желательно, чтобы возможно меньшее число программ  транслято-

ра непосредственно работало с ТС. Это позволит  достаточно  легко

вносить необходимые изменения. Особенно важно тщательно  согласо-

вать формат описателя  до  того,  как  начнется  программирование

транслятора.

     ОПИСАТЕЛЕМ называется часть элемента ТС,  в  которой  описы-

вается идентификатор. Существует другой  термин  для  обозначения

этого же понятия, введенный Фельдманом - "семантическое слово" (У

Ахо и Ульмана это назывется "дескриптором").

      Количество информации, которое нужно хранить  в  описателе,

зависит от того, чем является фактически идентификатор -  простой

переменной, массивом, функцией и т.д. Поэтому в некоторых  реали-

зацих описатели имеют переменную длину. Это допустимо не при  лю-

бой организации ТС. Иногда в целях экономии памяти выбирают  эле-

мент ТС малого размера, а для идентификаторов,  требующих  больше

места, отводят по несколько соседних элементов.

     Другая возможность открывается, емли в нужных случаях  отво-

дить часть  описателя  под  указатель,  ссылающийся  на  дополни-

тельную таблицу. Это несколько осложняет  программирование,  пос-

кольку тип описателя может менять свой смысл в зависимости от ти-

па элемента.

     4.2 Возможные параметры описания переменных и процедур

                       в таблице символов

     Для переменных и процедур в  описателе  может  потребоваться

следующая информация:

     ПЕРЕМЕННАЯ:

     Тип (вещ., целый, строка, комплексный,  метка  и т.д.);

     Точность, масштаб, длина;

     Вид (простая переменная, массив, структура и т.д.);

     Адрес во время выполнения программы;

     Если массив, то - число измерений. Если есть граничные  пары

(ограниченные множества в Паскале), то их значения;

     Если структура или компонента  структуры,  то  связь  данной

компоненты с другими компонентами;

     Формальный параметр или нет; если да,  то  тип  соответствия

параметров;

     Описана ли переменная как extern или как идентификатор объе-

динения (union) ?

     Обрабатывалось ли уже ее описание ?

     Существует ли инструкция, присваивающая ей значение ?

     ПРОЦЕДУРА:

     Является ли она внешней по отношению к программе ?

     Является ли она функцией ?

     Каков ее тип ?

     Обрабатывалось ли уже ее описание ?

     Является ли она рекурсивной ?

     Каковы ее формальные параметры ? Их  описатели  должны  быть

связаны с именем функции для того, чтобы можно было проверить  их

соответствие фактическим параметрам.

          4.3 Таблица символов компилятора /360 WATFOR

     /360 WATFOR - однопроходной компилятор с  языка  ФОРТРАН  IV

для машин IBM/360.

     ТС состоит из пяти  разных  списков:

     - списка  меток;

     - списка арифметических констант;

     - списка имен общих блоков, подпрограмм, переменных;

     - списка блоков;

     - списка подпрограмм.

     (Таким образом, некоторые элементы оказываются в двух списках.)

     Элементы всех списков помещаются в одной и той  же  таблице;

первые 2 байта каждого элемента используются для ссылки  на  сле-

дующий элемент в этом же списке. Следовательно, поиск  отдельного

элемента сводится к линейному просмотру по ссылкам.

     Элементы различных типов имеют разлмчную длину в пределах от

8 до 20 байтов.

     Например, элемент для переменной имеют длину 16 байтов и со-

держит следующую информацию (первые 2 байта опущены):

       3-4  5-10      11-12     13-14    15-16

     ┌────┬───────┬───────────┬──────┬───────────┐

     │ B2 │идент-р│размерность│COMMON│EQUIVALENCE│

     └────┴───────┴───────────┴──────┴───────────┘

     В полях "COMMON" и  "EQUIVALENCE"  помещаются  указатели  на

элементы других переменных, связанных с  данной  при  помощи  ин-

струкций COMMON и EQUIVALENCE.

     В поле "размерность" содержится 0, если  переменная  не  яв-

ляется массивом; в противном случае оно  указывает  на  отдельный

элемент,  содержащий  всю  информацию  о  размерности:   величины

d1,...,dn и длину d1*...*dn.

     Два байта, обозначенные B2, содержат всю остальную  информа-

цию (см. рис. 20.10). Первоначально все поля содержат нули,  и  в

них заносится информация по мере обработки программы.

     Единица в каждом однобитовом поле на рис.  20.10  говорит  о

наличии соответствующего факта.

│    0-1    │  2-4   │   5-6    │   7    │   8   │    9    │

├───────────┼────────┼──────────┼────────┼───────┼─────────┤

│10 - прос- │число   │   тип    │ длина  │ тип   │исполь-  │

│     тая   │индексов│00 - лог. │задается│сформи-│зование  │

│     перем.│в случае│01 - цел. │програм-│рован  │сформиро-│

│11 - массив│массива │10 - вещ. │мистом  │       │вано     │

│           │        │11 - ком- │        │       │         │

│           │        │   плекс. │        │       │         │

│   10    │   11   │   12    │   13   │   14   │   15      │

├─────────┼────────┼─────────┼────────┼────────┼───────────┤

│формаль- │текущий │присваи- │имеет   │встреча-│встреча-   │

│ный пара-│параметр│вается   │нач.    │ется в  │ется в     │

│метр     │цикла   │значение │значение│COMMON  │EQUIVALENCE│

│програм- │        │по ASSIGN│        │        │           │

│мы       │        │         │        │        │           │

     Рис. 20.10 Схема подполей поля B2

          4.4 Представление структур в таблице символов

     Мы можем представлять структуру, отводя по  одному  элементу

для каждой компоненты. Кроме обычных полей, каждый элемент  имеет

три дополнительных поля: FATHER, SON и BROTHER.

     Поле FATHER указывает на ОТЦА, SON - на первого СЫНА  компо-

ненты, а поле  BROTHER - на  ее  следующего  БРАТА  в  последова-

тельности братьев группы.

     Если данный элемент не имеет отца, сына или следующего  бра-

та, то соответствующее поле будет содержать 0.

     Ниже на рис. 20.11 приведены  иерархические  схемы  строения

двух  структур  с  указанием  перед  идентификатором  каждой   из

(под)компонент уровня ее вложенности.

     1 A                    1 L

       2 B                    2 M

         3 C                    4 C

         3 D                    4 D

       2 E                    2 B

       2 F                      5 C

                                5 D

     Рис. 20.11 Схема построения двух структур

     Элементы ТС для этих двух структур приведены ниже на  Табли-

це 20.1. Этой информации может хватить с избытком (а  может  ока-

заться и недостаточно) для эффективной работы со структурами.

     Поскольку могут существовать элементы, имена которых  совпа-

дают, вводится еще один указатель SAME, связывающий такие элемен-

ты между собой. Первый из этих элементов содержит в этом поле 0.

     Таблица 20.1 Схема заполнения элементов ТС для  двух  струк-

тур на рис. 20.11

            ┌────┬───┬─────┬──────┬────┬───────┐

            │    │ID │ SAME│FATHER│ SON│BROTHER│

            ├────┼───┼─────┼──────┼────┼───────┤

            │ A1 │ A │  0  │   0  │ B1 │   0   │

            │ B1 │ B │  0  │  A1  │ C1 │  E1   │

            │ C1 │ C │  0  │  B1  │  0 │  D1   │

            │ D1 │ D │  0  │  B1  │  0 │   0   │

            │ E1 │ E │  0  │  A1  │  0 │  F1   │

            │ F1 │ F │  0  │  A1  │  0 │   0   │

            │ L1 │ L │  0  │   0  │ M1 │   0   │

            │ M1 │ M │  0  │  L1  │ C2 │  B2   │

            │ C2 │ C │  C1 │  M1  │  0 │  D2   │

            │ D2 │ D │  D1 │  M1  │  0 │   0   │

            │ B2 │ B │  B1 │  L1  │ C3 │   0   │

            │ C3 │ C │  C2 │  B2  │  0 │  D3   │

            │ D3 │ D │  D2 │  B2  │  0 │   0   │

            └────┴───┴─────┴──────┴────┴───────┘

_


Страницы: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23


Новости

Быстрый поиск

Группа вКонтакте: новости

Пока нет

Новости в Twitter и Facebook

  скачать рефераты              скачать рефераты

Новости

скачать рефераты

Обратная связь

Поиск
Обратная связь
Реклама и размещение статей на сайте
© 2010.