Опубликован: 06.08.2007 | Уровень: профессионал | Доступ: платный
Лекция 10:

Генерация кода

Назначение адресов

Назначение адресов переменным, параметрам и полям записей происходит при обработке соответствующих объявлений. В однопроходном трансляторе это может производиться вместе с построением основной таблицы символов и соответствующие адреса (или смещения) могут храниться в этой же таблице. В промежуточном представлении Лидер объявления сохранены, что делает это промежуточное представление машинно-независимым. Напомним, что в Лидер-представлении каждому описанию соответствует некоторый номер. В процессе работы генератора кодов поддерживается таблица Table, в которой по этому номеру (входу) содержится следующая информация:

  • для типа: его размер;
  • для переменной: смещение в области процедуры (или глобальной области);
  • для поля записи: смещение внутри записи;
  • для процедуры: размер локальных параметров;
  • для массива: размер массива, размер элемента, значение левой и правой границы.

Для вычисления адресов определим для каждого объявления два синтезируемых атрибута: DISP будет обозначать смещение внутри области процедуры (или единицы компиляции), а SIZE - размер. Тогда семантика правила для списка объявлений принимает вид

RULE
DeclPart ::= ( Decl )
SEMANTICS
	Disp<1>=0;
1A: Disp<1>=Disp<1>+Size<1>;
	Size<0>=Disp<1>.

Все объявления, кроме объявлений переменных, имеют нулевой размер. Размер объявления переменной определяется следующим правилом:

RULE
Decl ::= 'VAR' TypeDes
SEMANTICS
Tablentry Entry;
0: Entry=IncTab;
  Size<0>=((Table[VAL<2>]+1) / 2)*2;
  // Выравнивание на границу слова
  Table[Entry]=Disp<0>+Size<0>.

В качестве примера трансляции определения типа рассмотрим обработку описания записи:

RULE
TypeDes ::= 'REC' ( TypeDes ) 'END'
SEMANTICS
int Disp;
Tablentry Temp;
0: Entry<0>=IncTab;
  Disp=0;
2A: {Temp=IncTab;
  Table[Temp]=Disp;
  Disp=Disp+Table[Entry<2>]+1) / 2)*2;
  // Выравнивание на границу слова
  }
Table[Entry<0>]=Disp.

Трансляция переменных

Переменные отражают все многообразие механизмов доступа в языке. Переменная имеет синтезированный атрибут ADDRESS - это запись, описывающая адрес в команде МС68020. Этот атрибут сопоставляется всем нетерминалам, представляющим значения. В системе команд МС68020 много способов адресации, и они отражены в структуре значения атрибута ADDRESS, имеющего следующий тип:

enum Register
{D0,D1,D2,D3,D4,D5,D6,D7,
	A0,A1,A2,A3,A4,A5,A6,SP,NO};
	
enum AddrMode
{D,A,Post,Pre,Indirect,IndPre,IndPost,IndirPC,
IndPrePC,IndPostPC,InDisp,Index,IndexPC,Abs,Imm};

struct AddrType{
  Register AddrReg,IndexReg;
  int IndexDisp,AddrDisp;
  short Scale;
};

Значение регистра NO означает, что соответствующий регистр в адресации не используется.

Доступ к переменным осуществляется в зависимости от их уровня: глобальные переменные адресуются с помощью абсолютной адресации; переменные в процедуре текущего уровня адресуются через регистр базы А6.

Если стек организован с помощью статической цепочки, то переменные предыдущего статического уровня адресуются через регистр статической цепочки А5 ; переменные остальных уровней адресуются "пробеганием" по статической цепочке с использованием вспомогательного регистра. Адрес переменной формируется при обработке структуры переменной слева направо и передается сначала сверху вниз как наследуемый атрибут нетерминала VarTail, а затем передается снизу-вверх как глобальный атрибут нетерминала Variable. Таким образом, правило для обращения к переменной имеет вид (первое вхождение Number в правую часть - это уровень переменной, второе - ее Лидер-номер):

RULE
Variable ::= VarMode Number Number VarTail
SEMANTICS
int Temp;
struct AddrType AddrTmp1, AddrTmp2;
3: if (Val<2>==0) // Глобальная переменная
	{Address<4>.AddrMode=Abs;
	Address<4>.AddrDisp=0;
	}
  else // Локальная переменная
	{Address<4>.AddrMode=Index;
	 if (Val<2>==Level<Block>) // Переменная
		// текущего уровня
	  Address<4>.AddrReg=A6;
	 else if (Val<2>==Level<Block>-1)
		// Переменная предыдущего уровня
		Address<4>.AddrReg=A5;
	 else
		{Address<4>.Addreg=
		  GetFree(RegSet<Block>);
		AddrTmp1.AddrMode=Indirect;
		AddrTmp1.AddrReg=A5;
		Emit2(MOVEA,AddrTmp1,
		Address<4>.AddrReg);
		AddrTmp1.AddrReg=Address<4>.AddrReg;
		AddrTmp2.AddrMode=A;
		AddrTmp2.AddrReg=Address<4>.AddrReg;
		for (Temp=Level<Block>-Val<2>;
			Temp>=2;Temp--)
		Emit2(MOVEA,AddrTmp1,AddrTmp2);
	  }	
	if (Val<2>==Level<Block>)
	 Address<4>.AddrDisp=Table[Val<3>];
	else
	 Address<4>.AddrDisp=
		Table[Val<3>]+Table[LevelTab[Val<2>]];
	}.

Функция GetFree выбирает очередной свободный регистр (либо регистр данных, либо адресный регистр) и отмечает его как использованный в атрибуте RegSet нетерминала Block. Процедура Emit2 генерирует двухадресную команду. Первый параметр этой процедуры - код команды, второй и третий параметры имеют тип AddrType и служат операндами команды. Смещение переменной текущего уровня отсчитывается от базы ( А6 ), а других уровней - от указателя статической цепочки, поэтому оно определяется как алгебраическая сумма размера локальных параметров и величины смещения переменной. Таблица LevelTab - это таблица уровней процедур, содержащая указатели на последовательно вложенные процедуры.

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

RULE
Variable ::= VarMode Number Number VarTail
SEMANTICS
int Temp;
3: if (Val<2>==0) // Глобальная переменная
	{Address<4>.AddrMode=Abs;
	Address<4>.AddrDisp=0;
	}
  else // Локальная переменная
	{Address<4>.AddrMode=Index;
	 if (Val<2>=Level<Block>) // Переменная
		// текущего уровня
	 {Address<4>.AddrReg=A6;
	 Address<4>.AddrDisp=Table[Val<3>];
	 }
	else
	 {Address<4>.AddrMode=IndPost;
	 Address<4>.AddrReg=NO;
	 Address<4>.IndexReg=NO;
	 Address<4>.AddrDisp=Display[Val<2>];
	 Address<4>.IndexDisp=Table[Val<3>];
	}
  }.

Рассмотрим трансляцию доступа к полям записи. Она описывается следующим правилом ( Number - это Лидер- номер описания поля):

RULE
VarTail ::= 'FIL' Number VarTail
SEMANTICS
if (Address<0>.AddrMode==Abs)
  {Address<3>.AddrMode=Abs;
  Address<3>.AddrDisp=
  Address<0>.AddrDisp+Table[Val<2>];
  }
 else
  {Address<3>=Address<0>;
  if (Address<0>.AddrMode==Index)
   Address<3>.AddrDisp=
   Address<0>.AddrDisp+Table[Val<2>];
  else
   Address<3>.IndexDisp=
   Address<0>.IndexDisp+Table[Val<2>];
  }.

Никита Барсуков
Никита Барсуков
Россия, СПБПУ
Николай Архипов
Николай Архипов
Россия, Екатеринбург, Уральский федеральный университет