Трансляция переменных
Переменные отражают все многообразие механизмов доступа в языке. Переменная имеет синтезированный атрибут ADDRESS - это запись, описывающая адрес в команде МС68020. Этот атрибут сопоставляется всем нетерминалам, представляющим
значения. В системе команд МС68020 много способов адресации, и они отражены в структуре значения атрибута ADDRESS, имеющего следующий тип:
enum Register {D0,D1,D2,D3,D4,D5,D6,D7,A0,A1,A2,A3,A4,A5,A6,SP,NO}; |
Значение регистра NO означает, что соответствующий регистр в адресации не используется.
Доступ к переменным осуществляется в зависимости от их уровня: глобальные переменные адресуются с помощью абсолютной адресации; переменные в процедуре текущего уровня адресуются через регистр базы А6.
Если стек организован
с помощью статической цепочки, то переменные предыдущего статического уровня адресуются через регистр статической цепочки А5; переменные остальных уровней адресуются «пробеганием» по статической цепочке с использованием вспомогательного регистра. Адрес переменной формируется при обработке структуры переменной слева направо и передается сначала сверху вниз как наследуемый атрибут нетерминала VarTail, а затем передается снизу-вверх как глобальный атрибут нетерминала Variable. Таким
образом, правило для обращения к переменной имеет вид (первое вхождение Number в правую часть - это уровень переменной, второе - ее Лидер-номер):
RULE Variable ::= VarMode Number Number VarTail SEMANTICS int Temp; struct AddrType AddrTmp1, AddrTmp2; 3: if (Val==0) // Глобальная переменная {Address.AddrMode=Abs; Address.AddrDisp=0; } else // Локальная переменная {Address.AddrMode=Index; if (Val==Level) // Переменная текущего уровня Address.AddrReg=A6; else if (Val==Level-1) // Переменная предыдущего уровня Address.AddrReg=A5; else {Address.Addreg=GetFree(RegSet); AddrTmp1.AddrMode=Indirect; AddrTmp1.AddrReg=A5; Emit2(MOVEA,AddrTmp1,Address.AddrReg); AddrTmp1.AddrReg=Address.AddrReg; AddrTmp2.AddrMode=A; AddrTmp2.AddrReg=Address.AddrReg; for (Temp=Level-Val;Temp>=2;Temp-) Emit2(MOVEA,AddrTmp1,AddrTmp2); } if (Val==Level) Address.AddrDisp=Table[Val]; else Address.AddrDisp=Table[Val]+Table[LevelTab[Val]]; }. |
Функция GetFree выбирает очередной свободный регистр (либо регистр данных, либо адресный
регистр) и отмечает его как использованный в атрибуте RegSet нетерминала Block. Процедура Emit2 генерирует двухадресную команду. Первый параметр этой процедуры - код команды, второй и третий параметры имеют тип AddrType и служат операндами команды. Смещение переменной текущего уровня отсчитывается от базы (А6), а других уровней - от указателя статической цепочки, поэтому оно определяется как алгебраическая сумма размера локальных параметров и величины смещения переменной. Таблица
LevelTab - это таблица уровней процедур, содержащая указатели на последовательно вложенные процедуры.
Если стек организован с помощью дисплея, то трансляция для доступа к переменным может быть осуществлена следующим образом:
RULE Variable ::= VarMode Number Number VarTail SEMANTICS int Temp; 3: if (Val==0) // Глобальная переменная {Address.AddrMode=Abs; Address.AddrDisp=0; } else // Локальная переменная {Address.AddrMode=Index; if (Val=Level) // Переменная текущего уровня {Address.AddrReg=A6; Address.AddrDisp=Table[Val]; } else {Address.AddrMode=IndPost; Address.AddrReg=NO; Address.IndexReg=NO; Address.AddrDisp=Display[Val]; Address.IndexDisp=Table[Val]; } }. |
Рассмотрим трансляцию доступа к полям записи. Она описывается следующим правилом (Number - это Лидер-номер описания поля):
RULE VarTail ::= 'FIL' Number VarTail SEMANTICS if (Address.AddrMode==Abs) {Address.AddrMode=Abs; Address.AddrDisp=Address.AddrDisp+Table[Val]; } else {Address=Address; if (Address.AddrMode==Index) Address.AddrDisp=Address.AddrDisp+Table[Val]; else Address.IndexDisp=Address.IndexDisp+Table[Val]; }. |