А.В. Ахо, М.С. Лам, Р. Сети, Дж. Д. Ульман - Компиляторы - принципы, технологии и инструментарий (1114947), страница 236
Текст из файла (страница 236)
Промежуточный код для инструкций а ложным выходом является новая метка й. Следующая команда присваивает переменной севр значение Ькце (строка 20), после чего следует переход к новой метке а (строка 2!). Код в строке 22 генерирует метку й и команду, которая присваивает переменной Севр значение йа1яе. Фрагмент кода завершается меткой а, генерируемой в строке 23. Наконец, метод деп возвращает Ьевр (строка 24).
А.7 Промежуточный код для инструкций Каждая конструкция реализуется подклассом класса ЯКп(С. Поля для компонентов конструкции находятся в соответствующих подклассах; например, класс (ЯЬ11е содержит поля для проверяемого выражения и подынструкции. В строках 3 и 4 приведенного далее кода класса Якп(Ь выполняется работа по построению синтаксического дерева. Конструктор Ятзпс ( ) не делает ничего, поскольку вся работа выполняется подклассами.
Статический объект Яказк . (чц11 (строка 4) представляет пустую последовательность инструкций. 1) расхаде япСек; // Файл Ят~/ача 2) рчЬ11с с1азз Язве ехеепсз Носе ( 3) рчЬ11с ЯзвЕ() ( 4) рпЫъс ззас1с Язве Нп11 = пеи Ясве(); 5) // вызызается с метками начала и после конструкции: 6) рчЫьс чогс( чеп(1пс Ь, ьпс а) 7) 1пс акзек = О; // Сохраняет метку после конструкции 8) // Используется для инструкций Ькеах: 9) рчЫьс зеаеяс Яьвь Епс1озьпд Язвщип11; 1О) 1 Строки б — 9 предназначены для генерации трехадресного кода. Метод реп вызывается с передачей ему двух методов, Ь и а, где Ь маркирует начало кода инструкции, а а — первую команду после кода для данной инструкции.
Метод реп (строка 6) представляет собой заполнитель для методов реп в подклассах. Подклассы И)(11е и Ро сохраняют метку а в поле а1кег (строка 7), так что она может использоваться любыми включаемыми инструкциями для перехода за пределы охватывающей конструкции. Объект ЯквЬ.Епс1озйпд используется в процессе синтаксического анализа для отслеживания охватывающей конструкции.
(В исходном языке с инструкциями соппйпце можно использовать тот же подход для отслеживания конструкции, охватывающей инструкцию сопк1пце.) Конструктор класса 1й строит узел для инструкции )!' ( .Е) о. Поля ехрг и яквк хранят соответственно узлы для Е и 5. Заметим, что ехрк представляет собой имя поля типа Ехрк, записанного строчными буквами, как якп(Ь вЂ” имя поля типа Якп(Ь, представляющего собой название типа, записанного строчными буквами. 1150 Приложение А.
Завершенный пример начальной стадии компилятора // Файл //!азза 1) расхаде 1пиегз 2) з.врогс вувЬо1в.*з 3) риЬ11с с1азя тг ехпепе(в Ясвп ( 4) Ехрг ехргз Ясвг виве! 5) риЬ11с тг(Ехрг х, Яевг в) ( 6) ехрг = хз зевс = зз 7) ЕГ( ехрг.суре 1= Туре.Воо1 ) 8) ехрг.еггог("Ьоо1еап гециъгеп Тп 1г"!з 9) ) 1О) риЬрвс иоле( реп(1пп Ь, 1пс а) ( 11) Тпи 1аЬе1 = пен1аЬе1()з // метка кода инструкции 12) ехрг.зивртпд(0, а)з // Проходим при значении 13) // Ггие, переход к метке а при значении га1ве 14) евТГ1аЬе1(1аЬе1)з зеве.реп(1аЬе1, а)з 15) ) 16) ! Код объекта 1 й состоит из кода с переходами для выражения ехрг, за которым следует код для Ястс. Как говорилось в разделе А б, вызов ехрг .
3 цтр1пз3 ( О, а ) в строке 12 указывает, что управление должно пройти через код для ехрг, если вычисления дают для этой переменной значение Егце, в противном случае управление переходит к метке а. Реализация класса Е1яе, который обрабатывает часть е)зе конструкции 1з-е!ве, аналогична реализации класса 1Й. // Файл Е!зе!аеа !) раскаое Тпеегз 2) 1врогп зувЬо1з.*; 3) риЬ11с с1азз Е1зе ехсепе(в Япви ( 4) Ехрг ехргз Яевп зевГ1, зевс2з 5) риЬ11с Е1зе(Ехрг х, Яеви в1, ЯГве в2) ( 6) ехрг = хз вгвс1 = в1з всвг2 = в2з 7) зг( ехрг.суре 1= Туре.Воо1 ! 8) ехрг.еггог("Ьоо1еап гепи1гезз Тп зт")з 9) ) 1О) риЬ11с чо10 деп(апе Ь, Тпс а) ( 11) Тпс 1аЬе11 = пен1аЬе1()з // Метка дпя всвГ1 12) Епе 1аЬе12 = пеи1аЬе1()з // Метка дпя зсвс2 13) ехрг.зиврзпч(0,1аЬе12)з // При Ггие — х зивГ1 14) евТГ1аЬе1(1аЬе11)з впвг1.ззеп(1аЬе11, а)з 15) евьс("доео !." + а)з 16) ев1г1аЬе1(1аЬе12)з вгвг2.ззеп(1аЬе12, а)з 17) 18) ! Построение объекта В))з11е разделено между конструктором ((()з11е(), который создает узел с нулевым дочерним узлом (строка 5), и функцией инициализации 1п10 (х, я ), которая устанавливает поле ехрг равным х, а поле ВЬшЬ равным я (строки б-10).
Функция заец(Ь, а) для генерации трехадресного кода (строки 11-17) написана в духе соответствующей функции зЗеп ( ) класса 1й. 1151 А.7. Промежуточный код для инструкций 1) расхаде Ьппег! // Файл Нтн!е/ача 2) Ьврогс зувЬо1з, *; 3) риЫяс с1авв ИЬ11е ехсепсз Ясвг ( 4) Ехрг ехрг; Ясвс зевс; 5) риЬ11с ИЬ11е() ( ехрг = пи11! всвг = пи11; 6) риЫтс чотй Тптп(Ехрг х, Ясвс з) ( 7) ЕХРГ = Х2 ВГВС = В! 8) 18( ехрг.гуре 1= Туре.Воо1 ) 9) ехрг.еггог("Ьоо1еап геди1геб гп нЫ1е"); 10) 11) 12) 13) 14) 15) 16) 17) 18) ) ) риЬатс чояй деп(япе Ь, тпг а) ( атгег = а! // Сохранение метки а ехрг.зивр1пд(0, а)! Тпе 1аЬе1 = пен1аЬе1(); // Метка для всвг евьс1аЬе1(1аЬе1); зевщдеп(1аЬе1, Ь)! ев1Г("депо 1," + Ь); Класс ()о очень похож на класс (й)311е.
1) расхаде тпсег; // Файл Ра/ача 2) 1врогс вувЬо1в.*! 3) риЬ11с с1авв по ехсепйв Ясвс ( 4) Ехрг ехрг; Ясвг зевс! 5) риЬ11с по() ( ехрг = пи11; вснп = пи11; ) 6) риЫ1с чо16 1птс(ЯГвп в, Ехрг х) ( 7] ехрг = х; зевс з! 8) 18( ехрг.суре != Туре.Воо1 ) 9) ехрг.еггог("Ьоо1еап гедЫгеб Тп йо"); 1О) 11) 12) 13) 14) 15) 16) 17) !8) ) ) раЫтс чети деп(тпп Ь, тпс а) ( атгег = а! Тпп 1аЬе1 = пен1аЬе1()! // Метка для ехрг всвп.деп(Ь,1аЬе1)! евтс1аЬе1(1аЬе1); ехрг.зивртпд(Ь,О); ) Класс Бес реализует присваивание с идентификатором в левой части и выражением в правой.
В основном, код класса Бег предназначен для построения узла и проверки типов (строки 5-17). Функция деп генерирует трехадресную команду (строки 18-21). Отличие между ними заключается в том, что метка а сохраняется в поле айгег (строка 12) и что за кодом для Яеп(с следует переход к метке ь (строка 16) для выполнения следующей итерации цикла (ч)311е.
1152 Приложение А. Завершенный пример начальной стадии компилятора !) Расхаде Тпсег; // Файл Бе(./ача 2) Тврогс 1ехег.*; трогс зувпо1з.*; 3) риЫТс с1азз Яес ехсепоз Ясвс ( 4) риЫ1с тс( 1о; риЫ1с Ехрг ехрг; 5) риЬ11с Яес(то 1, Ехрг х) ( 6) 1о = 1; ехрг = х; 7) 18 ( спеск(1о.гуре, ехрг.суре) == пи11 ) 8) еггог(тауре еггог")," 9) (О) )!) 12) (3) )4) )5) 16) )7) ) (8) риЫ1с чо1П деп(тпс Ь, 1пс а) ( (9) ев1Г( 1о.солсг1пд(! 20) ехрг.деп(!.Гоасг1пд(! ); 2!) ! 22) ] ! риЬ11с ТУРе спесл(ТУРе Р1, ТУРе Р2! ( 18 ( туре.пивегас(р1) аа Туре.пивег1с(р2! ) гееигп р2; е1зе 18 ( р1 =- Туре.Воо1 ьь р2 == Туре.Воо1 ) гесигп р2; е1зе гегигп пи11; Класс ЯепЕ1ет реализует прнсванвание элементу массива.
! риЫ1с чо1о деп(апс Ь, 1пс а! ( Бсг1пд з1 = 1пбех.гелосе().соЯГгтпд() Ясг1пд з2 = ехрг.гее(исе().соЯГг1пд(); евас(аггау.соЯГгтпд() а " [ з1 + " ] = " а 32); !) Раскаде 1пгег; // Файт Бе(Е1ет/ача 2) 1мрогс 1ехег.*; Тврогс зувпо1з.*; 3) риЬ11с с1азз ЯеГЕ1ев ехсепоз Ясак ( 4) риЫТс 1б аггау; риЫТс Ехрг 1пбех; риЫ1с Ехрг ехрг; 5) риЬ11с ЯеГЕ1ев(Ассезз х, Ехрг у) ( 6) аггау х.аггау; Тпбех = х.1пбех; ехрг у; 7) 18 ( спесх(х.суре, ехрг.суре! = пи11 ) 8) еггог("Гуре еггог")с 9) ! 10) риЫ1с Туре спесх(туре р1, Туре р2) )!) ТТ ( р1 1пзсапсеот Аггау (! Р2 1пзеапсеот Аггау ) (2) гесигп пи11; 13) е1зе 18 ( р1 == р2 ! (4) гееигп р2; ]5) е1зе 18 ( туре.пивегас(р1) аа туре.питегас(р2) ) )6) гегигп р2; (7) е1зе ]8) гегигп пи11; )9) 20) 2!) 22) 23) 24) 25) 26) ! ПЯЗ А.8. Синтаксический анализатор Класс Яесг реализует последовательность инструкций.
Проверки на нулевые инструкции в строках 6 и 7 выполняются, чтобы избежать лишних меток. Обратите внимание, что для нулевой инструкции ЯЕ!пЕ. в]ц11 никакой код не генерируется, так как метод деп класса ЯЕ(ас не выполняет никаких действий. 1) расхаде ьпсег; // Файл Бел/ага 2) риЬ11с с1авя Яед ехсепе(я Ягтк ( 3) Ягве ветс1; Яств зеее2! 4) рпЬ11с Яед(ягес з1, Ясес з2) ( зстг1 = я1; всшс2 = з2; ) 5) рпЬ11с ао1с( деп(ьпс Ь, 1пг а) ( 6) 1я ( вгве1 — Ягте.ии11 ) яете2.деп(Ь, а); 7) е1ве 16 ( вгтс2 == Яств.ип11 ) встс1.деп(Ь, а]; 8) е1ве 9) 1пг 1аЬе1 = пен1аЬе1()! 1О) ясае1.деп(Ь,1аЬе1)! 11) еетг1аЬе1(1аЬе1)! 12) всес2.деп(1аЬе1,а)7 13) ) 14) ) !5) ) Инструкция ]згеа]с передает управление за пределы цикла илн инструкции выбора.
Класс Вгеа]с использует поле Бсл(С для сохранения охватывающей конструкции (синтаксический анализатор гарантирует, что Ясп(Е. Епс1оя1пд описывает узел синтаксического дерева для охватывающей конструкции). Код объекта Вгеа]с представляет собой переход к метке БЬ!вЬ. айзек, которая маркирует команду, следующую непосредственно после кода ЯЕ(аЕ. 1) расхаде тпгег! // Файл Вгеав/ага 2) рпЬ11с с1авв Вгеах ехсепе(в Ясег ( 3) ягвг всея; 4) рсЬ11с Вгеах() ( 5) 16( ясес.кпс1оз1пд == по11 ) 6) еггог("ппепс1овес( Ьгеах")! 7) ясег = Ясвс.япс1оззпд! 8) ) 9) рпЬ11с чо1о деп(1пс Ь, 1пг а) ( 10) ееьс( "доео 1." а встс.ассег)! 11) ) 12) ] А.8 Синтаксический анализатор Синтаксический анализатор считывает поток токенов и строит синтаксическое дерево путем вызовов соответствующих конструкторов из разделов А.5-А.7.
Текущая таблица символов поддерживается так, как в схеме трансляции на рис. 2.38 в разделе 2.7. 1154 Приложение А. Завершенный пример начальной стадии компилятора Пакет рагзег состоит из единственного класса Рагвег. 1) расхаде рагвег; // Файл Ращет/ака 2) 1щрогг )ача.