Реферат: Программное обеспечение удалённого доступа к технической документации
Лексический анализатор распознает тип каждой лексемы и соответствующим образом помечает ее. Лексический анализатор должен не только выделить лексему, но и выполнить некоторые преобразования. Например, если лексема - число, то его необходимо перевести во внутреннюю форму записи.
Хотя лексический анализ по своей идее прост, тем не менее эта фаза работы транслятора часто занимает больше времени, чем любая другая. Частично это происходит из-за необходимости просматривать и анализировать исходный текст символ за символом. Иногда даже бывает необходимо вернуть прочитанный символ во входной поток с тем, чтобы повторить просмотр и анализ. Происходит это потому, что часто бывает трудно определить, где проходят границы лексемы. Например, могут существовать две лексемы: “make” и “makefile”. При анализе входного потока символов может быть выделена лексема “make”, хотя правильно было бы выделить лексему “makefile”. Единственный способ преодолеть это затруднение - просмотр полученной цепочки символов назад и вперед. В нашем примере при выделении лексемы “make” мы должны просмотреть следующий поступающий символ и, если он будет символом "f", то вполне возможно, что поступает лексема “makefile”.
Вообще говоря, в общем случае программы лексического анализа, построенные с помощью генератора программ Lex, всегда просматривают входной поток вперед. При этом из входного потока выбирается лексема, соответствующая правилам, с наибольшей длиной. Это несколько замедляет работу, но помогает избежать ошибок.
Также в общем случае предполагается, что лексема может находиться в любом месте входного потока. Но при этом предусмотрены способы учитывать контекст. Во первых, для этого применяются так называемые «состояния» лексического анализатора. Переход в состояние осуществляется при срабатывании какого либо правила по специальной команде. Исходным состоянием анализатора является состояние «0». Возможна ситуация, когда одно и тоже правило может выполняться в нескольких состояниях. Во вторых, существует оператор определения контекста: «/». Например, выражение «ab/cd» удовлетворяет строке ab только в том случае, если за ней следует cd.
Кроме того, в Lex существуют инструменты, использующие просмотр вперед и назад: в правиле при определении лексемы могут использоваться спецсимволы «^» и «$», говорящие, что лексема должна находится в начале строки или в конце. Последний, на самом деле, является частным случаем оператора «/», так как для определения конца строки используется выражение
\”\n”
При использовании лексического анализатора совместно с синтаксическим, от лексического анализатора требуется полное поглощение входного потока и передача в синтаксический анализатор найденных лексем и данных, им соответствующих. Для того, чтобы весь входной поток был полностью поглощен и в конечный файл не попали необработанные фрагменты входного формата, лексемы, содержащиеся в спецификации лексического анализатора должны полностью описывать все возможные наборы символов.
Для передачи данных из лексического анализатора в синтаксический существует несколько путей. Наиболее простым является метод передачи данных при помощи глобальных переменных – текстовой yytext и числовой yylval.
Для упрощения написания спецификаций можно применять так называемые «подстановки». Какой-либо часто используемый шаблон описывается и сопоставляется с некоторым именем. В дальнейшем это имя можно использовать в правилах вместо данного шаблона. При этом, если возникнет необходимость изменения шаблона, не надо будет искать вхождения шаблона на протяжении всей спецификации – достаточно будет изменить шаблон в определении подстановки.
2.3 Грамматики.
Принципы построения грамматических анализаторов.
Спецификация Yacc (грамматика) описывается как набор правил в виде, близком к форме Бэкуса Наура (БНФ). Каждое правило описывает грамматическую конструкцию, называемую нетерминальным символом, и сопоставляет ей имя. С точки зрения грамматического разбора правила рассматриваются как правила вывода (подстановки). Грамматические правила описываются в терминах некоторых исходных конструкций, которые называются лексическими единицами, или лексемами. Как правило, имена сопоставляются лексемам, соответствующим классам объектов, конкретное значение которых не существенно для целей грамматического анализа.
Прежде, чем говорить о конкретных принципах построения синтаксических анализаторов с использованием генератора программ Yacc, необходимо разобраться в том, какие грамматики существуют и чем они отличаются.
Прежде всего стоит отметить, что различают два основных типа грамматик: контекстно-зависимые и контекстно-независимые.
Если порождающее правило имеет следующий вид:
A ::= ,
где A – нетерминальный символ, а - терминальный или нетерминальный, то порождающее правило называется контекстно-зависимым, то есть замена нетерминального символа A на последовательность может иметь место только в контекстах и . Соответственно, и грамматика, содержащая подобное правило, называется контекстно-зависимой.
Если порождающее правило имеет вид:
A ::= ,
то есть, если левая часть порождающего правила состоит из одного нетерминального символа, который в итоге (через ряд промежуточных шагов) может заменяться на последовательность , стоящую в правой части, независимо от контекста, в котором этот нетерминальный символ встречается, то такое правило и, соответственно, грамматика называются контекстно-независимыми (или контекстно-свободными).
Контекстно независимые грамматики более универсальны. Для разработки универсальных принципов проектирования трансляторов следует использовать их, так как они позволяют обработать практически любой входной язык.
Контекстно-свободные грамматики.
Существует несколько основополагающих терминов в теории грамматик. Нетерминальный символ (нетерминал) – описываемые элементы. Например, при определении языков программирования нетерминалами служат <оператор>,