В.А. Серебряков - Теория и реализация языков программирования (1134641), страница 32
Текст из файла (страница 32)
9.2. Занесение BP, отведение локальных, сохранение регистров делает вызываемаяподпрограмма.При вызове локальной подпрограммы необходимо установить указательстатического уровня на текущую подпрограмму, а при выходе — восстановить9.2. Динамическая организация памяти167Рис. 9.2его на старое значение (подпрограммы, охватывающей текущую). Для этогоисполняются следующие команды:Занесение фактических параметров в магазинMOVE BP, LPSUB Delta, LPJSR AЗдесь Delta — размер локальных переменных вызывающей подпрограммы плюс двойная длина слова. Магазин после этого принимает состояние,изображенное на рис.
9.3. Предполагается, что регистр LP уже сохраненсреди сохраняемых регистров, причем самым первым (сразу после локальныхпеременных).После выхода из подпрограммы в вызывающей подпрограмме выполняетсякомандаMOVE (LP), LPкоторая восстанавливает старое значение статической цепочки. Если выходосуществлялся из подпрограммы 1-го уровня, эту команду выполнять не надо,поскольку для 1-го уровня нет статической цепочки.При вызове подпрограммы меньшего, чем вызывающая, уровня выполняются следующие команды:168Глава 9. Генерация кодаРис.
9.3Занесение фактических параметров в магазинMOVE (LP), LP /* количество раз равно разностиуровней вызывающей и вызываемой ПП */JSR AТем самым устанавливается статический уровень вызываемой подпрограммы. После выхода из подпрограммы выполняется командаMOVE-Delta(BP), LPвосстанавливающая статический уровень вызывающей подпрограммы.Тело подпрограммы начинается со следующих команд:LINK BP , -размер_локальныхMOVEM -(SP)Команда LINK BP, размер_локальных эквивалентна трем командам:MOVE BP, -(SP)MOVE SP, BPADD -размер_локальных, SPКоманда MOVEM сохраняет в магазине регистры.В результате выполнения этих команд магазин приобретает вид, изображенный на рис.
9.1.Выход из подпрограммы осуществляется следующей последовательностьюкоманд:MOVEM (SP)+UNLK BPRTD размер_фактическихКоманда MOVEM восстанавливает регистры из магазина. Команда UNLK BPэквивалентна такой последовательности команд:MOVE BP,SPMOVE (SP),BP9.2. Динамическая организация памятиADD #4, SP169/* 4 - размер слова */Команда RTD размер_фактических, в свою очередь, эквивалентна последовательностиADD размер_фактических+4, SPJMP -размер_фактических-4(SP)После ее выполнения магазин восстанавливается до состояния, которое былодо вызова.В зависимости от наличия локальных переменных, фактических параметров и необходимости сохранения регистров каждая из этих команд можетотсутствовать.9.2.2.
Организация магазина с дисплеем. Рассмотрим теперь организацию магазина с дисплеем. Дисплей — это массив (DISPLAY), i-й элемент которого представляет собой указатель на область активации последнейвызванной подпрограммы i-го статического уровня. Доступ к переменнымсамой внутренней подпрограммы осуществляется через регистр BP.
Дисплейможет быть реализован либо через регистры (если их достаточно), либо черезмассив в памяти.Для вызова процедуры следующего (по отношению к вызывающей программе) уровня в дисплее отводится очередной элемент. Если вызывающаяпроцедура имеет статический уровень i, то при вызове процедуры уровняj 6 i элементы дисплея j , . . .
, i должны быть скопированы (обычно в магазинвызывающей процедуры), текущим уровнем становится j и в DISPLAY[j]заносится указатель на область активации вызываемой процедуры. По окончании работы вызываемой процедуры содержимое дисплея восстанавливаетсяиз магазина.Иногда используется комбинированная схема — дисплей в магазине. Дисплей хранится в области активации каждой процедуры. Формирование дисплея для процедуры осуществляется в соответствии с правилами, описаннымивыше.Отдельного рассмотрения требует вопрос о технике передачи фактических параметров. Конечно, в случае простых параметров (например, чисел)проблем не возникает.
Однако передача массивов по значению — операциядовольно дорогая, поэтому с точки зрения экономии памяти целесообразнеесначала в подпрограмму передать адрес массива, а затем уже из подпрограммы по адресу передать в магазин сам массив. В связи с передачей параметровследует упомянуть еще одно обстоятельство.Рассмотренная схема организации магазина допустима только для языковсо статически известными размерами фактических параметров. Однако, например, в языке Модула-2 может быть передан по значению гибкий массив,и в этом случае нельзя статически распределить память для параметров.170Глава 9. Генерация кодаОбычно в таких случаях заводят так называемый паспорт массива, в которомхранится вся необходимая информация, а сам массив размещается в магазине — в рабочей области регистров, сохраненных выше.9.3. Назначение адресовНазначение адресов переменным, параметрам и полям записей происходитпри обработке соответствующих объявлений.
В однопроходном транслятореэто может производиться вместе с построением основной таблицы символов, а соответствующие адреса (или смещения) могут храниться в этой жетаблице. В промежуточном Лидер-представлении объявления сохранены, чтоделает это промежуточное представление машинно-независимым. Напомним,что в Лидер-представлении каждому описанию соответствует некоторый номер. В процессе работы генератора кодов поддерживается таблица Table,в которой по этому номеру (входу) содержится следующая информация:– для типа: его размер;– для переменной: смещение в области процедуры (или глобальной области);– для поля записи: смещение внутри записи;– для процедуры: размер локальных параметров;– для массива: размер массива, размер элемента, значение левой и правойграниц.Функция IncTab вырабатывает указатель (вход) на новый элемент таблицы, проверяя при этом наличие свободной памяти.Для вычисления адресов определим для каждого объявления два синтезируемых атрибута: DISP будет обозначать смещение внутри области процедуры(или единицы компиляции), а SIZE — размер.
Тогда семантика правила длясписка объявлений принимает видRULEDeclPart ::= ( Decl )SEMANTICSDisp<1>=0;1A: Disp<1>=Disp<1>+Size<1>;Size<0>=Disp<1>.Все объявления, кроме объявлений переменных, имеют нулевой размер.Размер объявления переменной определяется следующим правилом:RULEDecl ::= ’VAR’ TypeDesSEMANTICS9.4. Трансляция переменных171Tablentry Entry;0: Entry=IncTab;Size<0>=((Table[VAL<2>]+1) / 2)*2;// Выравнивание на границу словаTable[Entry]=Disp<0>+Size<0>.В качестве примера трансляции определения типа рассмотрим обработкуописания записи:RULETypeDes ::= ’REC’ ( TypeDes ) ’END’SEMANTICSint 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.9.4.
Трансляция переменныхПеременные отражают всё многообразие механизмов доступа в языке.Переменная имеет синтезированный атрибут 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 означает, что соответствующий регистр в адресациине используется.172Глава 9.
Генерация кодаДоступ к переменным осуществляется в зависимости от их уровня: глобальные переменные адресуются с помощью абсолютной адресации; переменные в процедуре текущего уровня адресуются через регистр базы А6.Если магазин организован с помощью статической цепочки, то переменные предыдущего статического уровня адресуются через регистр статической цепочки А5; переменные остальных уровней адресуются «пробеганием»по статической цепочке с использованием вспомогательного регистра. Адреспеременной формируется при обработке структуры переменной слева направои передается сначала сверху вниз как наследуемый атрибут нетерминалаVarTail, а затем передается снизу-вверх как глобальный атрибут нетерминала Variable.
Таким образом, правило для обращения к переменной имеетвид (первое вхождение Number в правую часть — это уровень переменной,второе — ее Лидер-номер):RULEVariable ::= VarMode Number Number VarTailSEMANTICSint 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);}9.4.
Трансляция переменных173if (Val<2>==Level<Block>)Address<4>.AddrDisp=Table[Val<3>];elseAddress<4>.AddrDisp=Table[Val<3>]+Table[LevelTab[Val<2>]];}.Функция GetFree выбирает очередной свободный регистр (либо регистрданных, либо адресный регистр) и отмечает его как использованный в атрибуте RegSet нетерминала Block. Процедура Emit2 генерирует двухадреснуюкоманду. Первый параметр этой процедуры — код команды, второй и третийпараметры имеют тип AddrType и служат операндами команды. Смещениепеременной текущего уровня отсчитывается от базы (А6), а других уровней —от указателя статической цепочки, поэтому оно определяется как алгебраическая сумма размера локальных параметров и величины смещения переменной.Таблица LevelTab — это таблица уровней процедур, содержащая указателина последовательно вложенные процедуры.Если магазин организован с помощью дисплея, то трансляция для доступак переменным может быть осуществлена следующим образом:RULEVariable ::= VarMode Number Number VarTailSEMANTICSint 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>];}}.Рассмотрим трансляцию доступа к полям записи.