А.В. Ахо, М.С. Лам, Р. Сети, Дж. Д. Ульман - Компиляторы - принципы, технологии и инструментарий (1114947), страница 237
Текст из файла (страница 237)
1о. *; 1щрогг 1ехег. *з 3) Тщрогг зущЬо1з.*; 1щрогг апгег.*; 4) рцЬ11с с1азв Рагзег ( 5) 6) 7) 8) 9) 10) 11) 12) 13) 14) 15) 16) 17) 18) 19) 20) рггчасе Ьехег 1ех; // Лексический анализатор ргачасе Тохеп 1оок; // Предпросмотр Епч Гор = пц11; // Текущая или верхняя // таблица символов Епг свес( - 0; // Память для объявлений рцЬ11с Рагвег(ьехег 1) ГЬгоиз 1ОЕхсерсаоп ( 1ех = 1," моче()( ) чоге моче() ГЬгоиз 1ОЕхсерс1оп 1оох - 1ех.зсап(); ) чо1с( еггог(всггпд з) ( СЬгои пеи Еггог("пеаг 11пе 1ех.11пе+": гез); ) чоао щассЬ(апс С) ГЬгоиз 10Ехсерсаоп ( 1г( 1оок.сад == Г ) моче(); е1зе еггог("вупгах еггог"); ! Подобно простому транслятору выражений из раздела 2.5 класс Рагзег содержит по одной процедуре для каждого нетерминала.
Процедуры основаны на грамматике, образованной путем устранения левой рекурсии из грамматики исходного языка, приведенной в разделе А.1. Синтаксический анализ начинается с вызова процедуры рго(Злами, которая вызывает Ь1ос)с( ) (строка 23) для разбора входного потока и построения синтаксического дерева. Строки 24 — 27 генерируют промежуточный код. рпЬ11с чоЫ ргодгащ() СЬгоиз 1ОЕхсерсаоп ( // ргодгат -> Ь1оск Ягщс в = Ь1оск(); Тпс Ьедуп = з.пеи1аЬе1(); апе агсег = з.пеи1аЬе1(); в.ещ1Г1аЬе1(Ьедъп); з.деп(Ьедъп, агсег); в.ещъс1аЬе1(абсег); ) 21) 22) 23) 24) 25) 26) 27) 28) ьПривяекзтеяьиой аяьтериктизой является добавление методов рпвЬ и рор з казас Епч с обращением к текущей таблице посредством статической переменной Епч. Сор.
Обработка таблицы символов показана в процедуре Ь1ос)с явно.з Переменная ~ор (объявленная в строке 7) хранит верхнюю таблицу символов; переменная зачес(Епч (строка 31) представляет собой связь с предыдущей таблицей символов. 1155 А.8. Синтаксический анализатор згес Ь1осх(] Гпгочз 10Ехсерсьоп ( // Ь1осх -> [ сес1з зевсе ) езссп('(']; Епч зачеЕЕпч Гор; сор печ Епч(сор]; сес1з(]; зевс з зсшсз(]; езссп(']']; Гор зачеонпч; гегпгп з; 29) 30) 31) 32) зз) 34) 35) 36) Объявления дают нам записи для идентификаторов в таблице символов (строка 43). Хотя здесь это и не показано, объявление также приводит к юмаидам, резервирующим память для идентификаторов во время выполнения. 37) 38) 39) 40) 41) 42) 43) 44) 45) 46) 47) 48) 49) 50) 51) 52) 53) 54) 55) 56) 57) 58) 59) 60) ] чоьс сес1з(] Гпгочз 10ЕхсерГ1оп ( яЬ11е( 1оох.сад Тад.ВА81С ) ( // Р -> гуре гп ; Туре р - Гуре(]; Токеп сох 1оох; масси(тзд.то]с езссп('ю']1 та 1с печ тс((ного]сох, р, пзео]; Гор.рпг( сох, 14 ]; изео = пзео + р.я1оГЬ; ) ] Туре Гуре(] Гпгоез 10Ехсерсаоп ( Туре р = (Туре]1оох; // охидаееся 1ооа.аад Тао.ВАЗ1С шасси(тзд.ВАБГС]; ТТ( 1ооа.яад ( '[' ) геспгп р; // Т -> Ьаз1с е1зе геспгп оамз(р]," // Тип массива ] Туре огиз(туре р) Гпгоез токхсере1оп ( пасси('[']; Тохеп сох = 1оох; пасси(Тая.ипн]Р езссп(')']! 1г( 1ооа.аад = '[' ) сШпз (р) ' гесигп пех Аггзу(((ипе]сох].чз1пе, р); Процедура зСп]Ь содержит инструкцию выбора с вариантами, соответствующими продукциям нетерминала Язва Каждый вариант строит узел для конструкции с использованием юнструкторов, рассмотренных в разделе А.7.
Узлы для конструкций ]чЫ[е и ([о строятся, югда синтаксический анализатор встречает соответствующее открывающее юнструкцию ключевое слово. Эти узлы строятся до анализа инструкции, чтобы позволить любому оператору Ьгеа[( в пределах цикла указывать на охватывающий цикл. Вложенные циклы обрабатываются при помощи переменной ЯЬ(пс. Епс10зхпд в классе ЯЬ]ас и зачес[ЯЬа]Ь [объявленной в строке б7) для работы с текущим охватывающим циклом. 115е Приложение А. Завершенный пример начальной стадии компилятора 61) 62) 63) 64) 65) 66) 67) 68) 69) 70) 7!) 72) 73) 74) 75) 76) 77) 78) 79) 80) 8!) 82) 83) 84) 85) 86) 87) 88) 89) 90) 91) 92) 93) 94) 95) 96) 97) 98) 99) 100) 101) !02) 103) 104) 105) 106) 107) 108) 109) 110) Зппп впнпв() ГЬгонз 10ЕхсерЫоп ( 11 ( 1оо)Р.Гад ' 1' ) гепигп Зпнс.ии11Р е1ве гесигп пен Зед(вснп(), вснпз())Р 1 Зппп вснп() ГЬгонв 10Ехсерп1оп ( Ехрг хР Зппп з, з1, в2Р згнг зачебзгнгР // сохранение охватнваюией // конструкции для Ьгеак знйпсЬ( 1оо)с.сад ) сазе 'Р': ноче()Р гесигп Зснс.ии11Р сазе Тад.1УР напсЬ(Тад.1Г)Р шасси('(')Р х = Ьоо1( ) Р нассп( ' ) ' ) Р в1 = вснп()Р 11( 1оо)Р.Гад ! Тад.ЕЬЗЕ ) гепигп пен 11(х, в1)Р насел(тад.ЕЬЗЕ)Р в2 зпнс()Р гесигп пен Е1ве(х, з1, в2) Р саве Тад.ИН1ЬЕР ИЬ11е юЬ11епобе пен ИЫ1е() Р зачебЗГнп Вснп.Епс1оз1пдР Вснп.Епс1озЬпд нЫ1епобеР напсп(тад.ИН1ЬЕ)Р напсЬ('(')Р х Ьоо1() Р напсЬ(' ) ' ) Р в1 вснп()Р нЫ1епобе.1п1Г(х, в1)Р Зснс.ипс1оз1пд вачебЗГнГР // Сброс Зпнс.Епс1овьпд гесигп нп11епос1еР сазе Тад.ВОР по бопобе пен по()Р зачебЗГнс = Зснс.ипс1овТпдР Зснс.Епс1озьпд бопобеР насел(Тад.00)Р з1 втнс()Р пасси(Тад.ИНХЬЕ)Р пасси('(')Р х Ьоо1() Р пасси(' ) ' ) Р щассп(' Р' )Р бопобе.1п1Г(в1, х)Р Зснс.Епс1овЬпд вачебЗГнГР // Сброс Зппп.Епс1ов1пд гепигп бопобеР саве Тад.ВПЕЛКР напел(Тад.ВИЕЛК)Р напсЬ('Р')Р гесигп пен ВгеаМ )Р саве '(': гепигп Ь1ос(с()Р 1157 А.8.
Синтаксический анализатор 111) 112) 1!3) 114) оетап1Г: гегпгп авз1дп(); ) Для удобства код для присваивания выделен во вспомогательную процедуру аяяйдп. ) иаесп('!')! гегигп вгвг; ! Синтаксический анализ арифметических и булевых выражений аналогичен. В каждом случае создается соответствующий узел синтаксического дерева.
Генерация кода для этих выражений различна и рассмотрена в разделах А.5 и А.б. Ехрг Ьоо1() 1пгочв 10Ехсерстоп ( Ехрг х = эо1п() ! чЬ11е( 1оок.еад == Тад.ок ) ( Тохеп гох = 1оохч точе(): х = печ ог(Сох, х, 3о1п()): гесогп х: гегпгп х; 115) 116) ! 17) 118) 119) 120) 121) 122) 123) 124) 125) 126) 127) 128) 129) 130) 13!) 132) 133) 134) 135) 136) !37) 138) 139) 140) 141) !42) 143) 144) 145) 146) 147) 148) 149) !50) 151) Яеее авв1дп() Спгочв токхсерг1оп ( Ясис всег; тохеп С = 1оохч пасси(тад.то): 10 10 = Гор.дее(с)! 11( 1с( = пп11 ) еггог(с.еоЯегапд() 4 " ппсес1агее("); 11( 1оок.кад == '=' ) ( // Я -> 1с = Е тече(); всее = пеи Яе1(1с(, Ьоо1() ) 7 е1зе ( // я -> ь - е ; АССЕВЗ Х ОТТВЕЬ(1о)! ваесЬ('='); зеве = пеи ЯеГЕ1еи(х, Ьоо1()); Ехрг 3о1п() ГЬгоив 10Ехсерстоп ( Ехрг х = едпа11су(); иЬ11е( 1оох.сад == Тад.АН0 ) ( Тохеп Гох = 1оох; точе(); х = пеи Апс((тох, х, едпа11су()): ) Ехрг есуза15ау() Гпгочз 10Ехсеретоп ( Ехрг х = ге1(); ин11е( 1оох.гад == Тад.Е0 11 1оох.еад == Тад.НЕ ) ( Тохеп сох = 1оох! тече()! 1158 х = пею Не1(со]с, х, ге1(] ]: ] гесигп х; Остальной код синтаксического анализатора работает с "множителями" в выражениях.
Вспомогательная процедура оййве~ генерирует код для вычисления адресов массивов (см. раздел 6.4.3). 152) 153) ! 54) ! 55) 156) 157) 158) 159) 160) 161) 162) !63) 164) 165) 166) !67) 168) 169) 170) 171) 172) 173) 174) 175) 176) 177) 178) 179) 180) 181) 182) 183) 184) 185) 186) !87) 188) !89) 190) 191) 192) 193) 194) 195) 196) 197) Приложение А. Завершенный пример начальной стадии компилятора ! Ехрг ге1(! ГЬгоев 10Ехсерс1оп ( Ехрг х - ехрг(); вчьссп( 1оо]с.сад ] ( саве '<'с саве Тад.ЬЕ: саве Тад.0Ес саве '>': То]сеп Со]с - 1оо]с; воче(); гесигп пее Не1(со]с, х, ехрг()): с]егаи1г: гесигп х; ! ] Ехрг ехрг(] Гогоча 10Ехсерсаоп ( Ехрг х = Гегв(]с юи11е( 1оои.сад == '+' ! ! 1оо]с.сад == '-' ) ( То]сеп сох = 1оо]сс вочеО; х = печ Агтсв(со]с, х, Гегв(]]; ) гегигп х; ) Ехрг Гегв(] Гогоча 10ЕхсерГ1оп ( Ехрг х = ипагу(]; юв11е(1оои.аад — '*' !! 1оо!с.сад == ' I' ] ( Токеп Го]с = 1оо!с; воче(]; х = пее Агтсп(сох, х, ипагу()); гесигп х; Ехрг ипагу() Гпгоев 10Ехсербаоп ( ТГ( 1оо]с.сад == '-' ] ( воче(]; гегигп пею ппагу(иогс(.вгпив, ипагу(]]; ] е1ве 1Т( 1оо]с.свд == '!' ) ( То]сеп го]с = 1оо]сс хоче(]; гесигп песс Нос(со]с, ипагу()); ! е1ве геСигп гасгог(]с 11бй 248) 1 249) 1 А.9 Построение начальной стадии Код пакетов располагается в пяти каталогах: шаз.п, 1ехек, вуп(Ьо18, ракзек и 1пСек.
Команды для построения компилятора варьируются от одной операционной системы к другой. Вот команды для ОХ1Х: 1ачас 1ехес/*.)ача 3ачас вуапо1з/".3ача 3ачас 1псес/*.)ача зачас расзес/*.3ача бачас иа1п/*.3ача Команда Зачас создает .с1авв-файлы для каждого класса. После этого запуск транслятора может быть осуществлен при помощи команды 3 ача шайи. Махи, за которой следует исходная транслируемая программа. Например, если взять файл Севс 1) ( // Файл(ел( 2) Ьпе 1; Ьпе 3; х1оаС ч; Е1оаС х; х1оаС[100] а; 3) чЬ11е( Стае 1 ( 4) «(о 1 1+1; чи11е( а[1] < ч); 5) «(о 3 3-1; чи11е( а[3] > ч)> 6) Ьх( 1 > 1 1 Ьсеаа; 7) х а[1]ю а[1] а[3]ю а[1) хю 8) 1 9) и транслировать его, на выходе мы получим 1) У1:ЬЗ: 2) Ь5: 3) 4) 5) 14: 6) Ь7: 7) 8) 9) 1,6: 1О) Ь9." 11) Ь8: 12) 13) 110: 14) 15) 16) 17) 111: Приложение А.
Завершенный пример начальной стадии компилятора 1 1+1 С1 1*8 С2 а[С1] 18 Сг < ч 9оео ЬЗ 3 3 — 1 сэ = 3 * 8 С4 - а [ СЗ ] 1Е С4 > ч чоео Ь4 1тса1ве 1 > 3 досо Ь8 доео Ь2 С5 1*8 х = а [ с5 ] Сб 1 е 8 С73е8 С8 а [ С7 ] а [ Сб ] С8 С9 3*8 ПРИЛОЖЕНИЕ Б Поиск линейно независимых решений Алгоритм Б.1. Поиск максимального множества линейно независимых решений Ах > 0 и выражение их как строк матрицы В Вход: матрица А размером т х и.