- •1. Принципы работы yacc
- •2. Входные и выходные файлы, структура грамматического ана-
- •3. Процедура построения грамматического анализатора
- •4. Задание входной информации yacc
- •4.1. Структура спецификационного файла
- •4.2. Секция правил
- •4.3. Секция деклараций
- •5. Декларация имен лексем
- •6. Декларация приоритетов и ассоциативности лексем
- •7. Декларация имени начального символа
- •7.1. Секция программ
- •Val. Если функция yylex находится в отдельном файле, то эта
- •7.2. Действия с использованием псевдопеременных
- •8. Конфликты грамматического разбора
- •If '(' условие ')' оператор else
- •9. Структура информационного входного файла y.Output
- •10. Обработка ошибок при грамматическом разборе
- •11. Диагностика ошибок
- •0, Считаются восьмеричными, все остальные - десятичными.
- •Int base, regs[26]; /* в действиях */
- •1. Принципы работы yacc .............................. 3
7. Декларация имени начального символа
%start <имя_начального_символа>
Директива отменяет действующий по умолчанию выбор в
качестве начального символа нетериминала, определяемого пер-
вым грамматическим правилом.
7.1. Секция программ
В секцию программ помещается описание пользовательских
процедур, которые должны быть включены в генерируемую прог-
рамму грамматического анализа. Любая из определяемых пользо-
вателем программных компонент может находиться в секции
программ спецификационного файла, либо присоединяться на
этапе вызова Си-компилятора для трансляции файла y.tab.c и
компоновки выходной программы. Перечислим процедуры, которые
одним из этих способов должны быть заданы:
- лексический анализатор - функция с именем yylex();
- все процедуры, вызовы которых содержатся в действиях,
связанных с грамматическими правилами;
- главная процедура main() при необходимости заменить ее
стандартный библиотечный вариант, который имеет вид
main() {return (yyparse();}
- процедура обработки ошибок yyerror() - также для замены
библиотечного варианта (его текст приводится ниже).
#include <stdio.h>
yyerror(s) char *s; {
fprintf(stderr, "%s\n", s);}
Для обеспечения корректной работы грамматического ана-
лизатора функция лексического анализа yylex должна быть сог-
ласована с конкретной спецификацией грамматики и удовлетво-
рять определенным требованиям. Основная задача функции yylex
состоит во вводе из входного потока ряда очередных символов
до выявления конструкции, соответствующей одной из лексем, и
возвращении номера типа этой лексемы. Для нелитеральных лек-
сем номером типа может служить объявленное в секции деклара-
ций имя лексемы (с помощью механизма #define yacc обеспечи-
вает замену его нужным номером), в случае литералов номером
типа является числовое значение символа (если оно не было
- 15 -
переопределено). Алгоритм поиска должен заключаться в
попытке нахождения сначала более сложных (нелитеральных)
лексем и лишь при несовпадении ни с одной из них текущих
элементов ввода возвращать номер типа литеральной лексемы
(любой однозначный символ, не начинающий ни одну из возмож-
ных лексем, сам образует лексему).
Приведем текст процедуры лексического анализа, распоз-
нающей идентификаторы и целые числа:
#include <stdio.h>
yylex() {char c;
while ((c=getc(stdin))==' '||c=='\n');
if(c>='0'&&c<='9'){
while((c=getc(stdin))>='0'&&c<='9');
ungetc(c,stdin));
return (CONST);}
if (c>='a'&&c<='z'){
while ((c=getc(stdin))>'a'&&c<='z'
||c>='0'&&c<='9');
ungetc(c,stdin); return (NAME);}
return (c); }
Сложность лексического анализатора зависит от того,
какие структурные единицы взяты за основу при описании грам-
матических правил. Детализовав грамматику до отдельных сим-
волов, можно обойтись простейшим лексическим анализатором,
осуществляющим только их ввод:
yylex() {return (getchar());}
Однако, в этом случае число правил растет, а граммати-
ческий разбор оказывается менее эффективным. Поэтому пользо-
ватель обычно должен найти некоторый компромисс при выборе
набора лексем.
В процедуре лексического анализа кроме выделения лексем
можно предусмотреть некоторую обработку лексем определенных
типов, в частности, запоминание конкретных значений лексем.
Кроме того, эти значения обычно требуется передать граммати-
ческому анализатору. С этой целью нужное значение должно
быть присвоено внешней переменной целого типа с именем yyl-