GCC - The Complete Reference (537669), страница 74
Текст из файла (страница 74)
Он демонстрирует использование 1ех-сканера для считывания лексем (!оКепз) исходной программы и применение синтаксического разделителя (рагзег) для логического построения полученных лексических элементов. Также будет рассмотрен порядок вызова функций С, которым передается выводимая нарсерои информация. Обычно в ССС на выходе парсера вырабатывается промежуточный код на языке йТ>, но в нашем примере только будут выводиться текстовые строки, которые комментируют генерируемый код. Программа, выполняющая синтаксическое разделение, может быть сгенерирована стандартной утилитой 0>Ч!Х уасс. Ее имя — сокращение от "Уе> Апогйег Совр!1ег Согпрйег", что можно перевести как "Компилятор Дополнительного Компилятора". Соответствующая ей утилита О)413 называется Ь1аоп. Обе программы почти идентичны по назначению и способу применения.
Наш пример основывается на очень простом языке с1апд, который воспринимает команды для прорисовки цветных кругов и прямоугольников в указанном расположении графического поля. Вот пример программы на языке с1апд (сохраним ее в файле К1дигев.с1апд): вет со1ог Ь1ие; вес 1осаегоп (1оо,аоо)) к)гни с1гс1е ЗО) вет со1ог тек() вет 1осат1оп (аво,аоо)) Егаи гестапд1е (10,10)/ Операторы вее используются для установки цвета и координат положения следующей фигуры, а операторы е)геи прорисовывают фигуру указанного типа и размера. Далее следует содержимое файла лексических определений этого языка (файл называется с1апд. 1ех): ( гееигп(акттокем)/ ) ( тееигп(соьоатоккм)/ ) ( гетигп(ЬОСАТ10НТОКЕМ)у ) ( гетигп(ПВАИТОКЕМ)) ) ( гетитп(СХВСЬЕТОККН)г ) ( гееигп(вкстлндьетОККН)) ) ( гееигп(веитсоьом)р ) ( гетигп(СОММА)) ( гегигп(ЬКРТРАВКМ); ( гетигп(В16НТРАЕЕН)г ) ( уузта1 = аео1(ууеехе)> гетигп(НОИВЕВ)) (а-вА-К)(а-ва-ЕО-9)» ( уу1та1 = вггцир(уутехг)) гетигп(МАНЕ); ) /* игнорировать конец строки »/ /* игнорировать лишние пробепн */ хп ( хе)» Ъи Этот листинг нуждается в небольшом комментарии.
Включаемый по директиве ()апс1ибе заголовочный файл с1апд. ЬаЬ.Ь вырабатывается утилитой Ьфвоп из файла определений парсера, что будет описано позже. Каждое лексическое определение возвращает значение, которое указывает его тип (тип определен в заголовочном файле). Следует учитывать, что лексические определения используются для генерирования программы на языке С. Поэтому нужно использовать обратную наклонную черту "Х" перед определяемыми как лексемы знаками пунктуации. /* с1апд.1ех "/ и( аапс1икте "с1апд.таЬ.Ь" ехгегп Ьпг уузта1) ехгетп сват *уусехг) я) е»» вес со1от 1осат1оп йтаи сагс1е гесеапд1е хг х( х) (0-9)+ Глава (д. Реализация алгоритмического языка 333 334 Часть (и.
Внутренняя структура н окружение Каждый входящий элемент сохраняется в строке, на которую указывает значение переменной уусехс. Когда это необходимо, их значения для дальнейшей передачи подпрограммам на языке С преобразовываются и сохраняются в переменой уу1ча1. В этом примере значения лексем типа МАМЕ сохраняются как строки, а значения лексем мпмвек преобразовываются в целые числа с помощью вызова функции асо1(). Описания двух последних элементов не имеют соответствий. Но они необходимы для успешного считывания исходного текста после концов строк и за периодами из пробелов и отступов. Для создания парсера языка, ориентированного на построчное разделение операторов, может понадобиться специальное лексическое определение для символа перевода строки.
Далее следует файл с1апд.у„который содержит синтаксические определения рассматриваемого языка: Ъвсагс сошшапав агснеп ВвттОКВИ ОВЛИтОКЕИ СОЬОВтОКЕМ кесхеп ЬОСЛтХОИтокеи СХВСЬетокеи ВЕСтлИОЬетОкен Ъсовеп ВЕИХСОЬОИ ЬЕРтРЛВЕИ ВтаитРАВЕИ СОИИЛ Ъеокеп ИОИВЕВ ИЛИЕ ссвваапсв: /* поги(пд */ 1 сошшапсв совваапа сошшапа: ВвттОКВИ вее ВЕИХСОЬОИ ( ОВЛИтОКЕИ Оган ВЮПСОЬОИ все: СОЬОВтОКЕИ ИЛИЕ ( веессХог($2); ) ) ьосАтхомтокем ьевтРАВеи иоивев соииА иоивев ВхонтРАВем ( веСХосаеьсп($3,$5)г ) агам: СХВСЬЕтОКЕИ ИОИВЕВ ( дгансьгсХе($2); ) ВестАмоьетокеи ьевтРАВеи моивек соииА иоивеи ВхонтРАВем ( сгангесеапдте($3,$5); ) В первой строке файла указана начальная точка определения синтаксического дерева. Далее следуют определения лексических элементов (ее со)сеп ...) как именованных констант, в генерируемом кодс парсера они используются в качестве уникальных идентификаторов лексем входного потока.
Каждое вхождение определения для синтаксического разбора (рагзе дейпгйоп) называется выработкой (ргог(вс((оп). Выработка имеет нмя, связанное с одним или более определений синтаксического расположения (зуп(ах )ауощ г(ейп(((опз) в ее пра- Глава 1д. Реализация алгоритмического языка 335 вой части. Синтаксические элементы правой части определения выработки разделяются между собой вертикальной чертой "1", за последним из них следует точка с запятой "; ". Парсер после того как встречает известное ему имя выработки, просматривает входной поток лексем на их соответствие элементам правой части определения этой выработки.
Парсеры, генерируемые утилитами Ь1воп и уесс, относятся к типу [ А[ В(1). Для поиска соответствий ожидаемому элементу они просматривают входной поток не далее, чем на одну лексему вперед. Семантические разделители типа ЕА[.В(1), упрощенно называемые ЕЙ(1)-парсерами, достаточно эффективны для поддержки современных языков программирования. Некоторые более древние языки с неоднозначным синтаксисом требуют применения более сложных и своеобразных процедур разделения кода. Все современные языки программирования разрабатываются с расчетом на использование парсеров [.гс(1). Начальная выработка имеет имя сопппепбв. Она может быть пустой (в случае конца файла) или содержать список из одной или более выработок соппепбв.
Тот факт, что начальная выработка ссылается на себя прежде следующей выработки, обусловлен рекурсивными свойствами вырабатываемого парсером кода. В нашем примере в этом нет необходимости, но в общем случае делается именно так. Выработка совввепб может иметь соответствие одному из ключевых слов вес или г[хатч. От этого зависит, какая выработка будет применяться для поиска соответствий следующих лексем. Ключевое слово вес указывает парсеру на выработку с именем зев, соответственно ключевое слово бхем указывает ему в качестве следующей выработку с именем бхета. Имена выработок не должны обязательно соответствовать ключевым словам, просто листинг так лучше читается. Внутри определения каждой конечной выработки имеется заключенный в фигурные скобки код на языке С.
Это может быть любой блок кода, в нашем примере это простые вызовы функций, которые будут определены позже. Имена аргументов функций определяются положением соответствующих им лексем в правой части определения выработки: 31 — для первого параметра выработки, $2 — для второго и тд. Обратите внимание, что в нашем примере функциям передаются значения лексем ддмж и ь[пмвж[[, при этом соответствующие аргументы получают значения переменных ууеехс И ууз. ге1.
После того как утилита Ь1воп скомпилирует сценарий с1епд.у в заголовочный файл с1епд. сеЬ. Ь, остается только написать программу на языке С, которая генерирует объектный код из исходного языка с1епд. В нашем примере вместо объектного кода программа только выводит описания работы прелполагаемого объектного кода. Следующий исходный файл с3[ве1п.
с содержит все функции, необходимые любому парсеру, и те функции, которые вызываются выработками определений нашего языка; /* с1еа1п.с */ Еъпс1иде "с1епд. Ееп. Ь" [[1псзпее <есезо. Ь> сцег со1охпеее[301 = "Ьзесх'Ы 1пе х = О[ ъпе у = Ог 336 часть ш. Внутренняя структура н окружение шаьп() ( уурагве()/ ) впе уунгар() ( геепгп(1)/ ) чо1с ууеггог(сопвг сьаг "всг) ( ерг1пгг(вгктегг,"с1апд: ъахп",вег)з ) ьпс вегсо1ог(сиаг *паше) < вггсру(со1огпаюе,паше) гегпгп(0)к /* Сохранение координат х и у положения следующей изображаемой фигурм.
*/ впг аег1осагьоп(ьпг х1ос,апс у1ос) ( х = х1ос/ у = у1ос> ) /* Прорисовка круга указанного цвета и размера в текущем расположении. */ ьпс сгаис<гс1е(<пг гак(1пв) ( ргьпея("оган ззв сьгс1е аг (Ъ((,ззс) гас1ив=ЪсХп", со1огпаие,х,у,гас<па); ) /* Прорисовка прямоугольника указанного цвета, вмсотм и ширины в текущем расположении. */ 1пе «тгангесеапд1е(1пе не<дне,ьпе ныеь) ( рг1пег'("оган ззв гесеапд1е ае (зн(,таз) ь=ззс н=зитхп", со1огпаше,х,у,ье1дце,н<сеи); ) Заголовочный файл с1апд. еаЬ.Ь вырабатывается утилитой Ь1воп из файла с1апд.у, он также содержит определения некоторых полезных констант, которые могут использоваться в компилирующей программе.
Функция щафп() — головная процедура нашего компилятора. В примере она только выполняет вызов уурагве(), функции синтаксического разбора. В реальном компиляторе оиа отвечает за создание кода на промежуточном языке, управление преобразованием промежуточного языка в объектный код, за выполнение оптимизаций, обработку параметров командной строки, определение имен входных и выходных файлов и за прочие выполняемые компиляторамн действия. Глава тд.
Реализация алгоритмического языка 337 Функция ууихер ( ) вызывается синтаксическим разделителем (парсером) в конце текущего входного файла. Она может использоваться для перехода к считыванию следующего исходного файла. Возвращаемое значение, равное 1, указывает на отсутствие дальнейшего ввода. Функция ууеххох () вызывается парсером при возникновении любой ошибки. Функции передается строка описания ошибки. В нашем примере она только выводит на стандартное устройство вывода сообщение об ошибке. Функция аессо1ох() вызывается парсером каждый раз, когда в исходном файле ключевое слово вес используется для назначения нового цвета. В зависимости от вырабатываемого объектного кода и возможностей управления графической системой эта функция может так или иначе устанавливать текущий цвет.
Или„как в нашем примере, локально сохранять информацию о текущем цвете, чтобы она могла быть использована при прорисовке фигур. Функция вес1осасвоп ( ) действ)ет сходно с рассмотренной функцией аессо1ох ( ), зз исключением того, что она определяет положение для прорисовки следующей фигуры. В примере она локально сохраняет координаты в переменных, используемых при прорисовке фигур. Функции стханс1хс1е ( ) и стхенхесеапд1е ( ) вызываются парсером для выработки кода, выполняющего прорисовку. Генерируемые при этом инструкции могут использовать предварительно установленные значения цвета и координаты положевия.