- •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
11. Диагностика ошибок
yacc выдает ряд сообщений об ошибках в случае невозмож-
ности построения грамматического анализатора. В тексте сооб-
щения, предваряемом заголовком "ошибка:", содержится указа-
ние причины ошибки и номер просматриваемой в момент ее появ-
ления строки спецификационного файла. Перечислим основные
типы фиксируемых yacc ошибок:
неверно заданные флаги командной строки;
невозможность открытия входного или временных файлов;
отсутствие файла /usr/lib/yaccpar с текстом процедуры
yyparse;
неверная структура спецификационного файла;
ошибки в задании директив;
синтаксические ошибки в описании грамматических правил,
незавершенность комментариев, строк символов и дейст-
вий;
- 32 -
некорректное использование псевдопеременных;
неопределенные нетерминальные символы;
нарушение количественных ограничений (по числу терми-
нальных или нетерминальных символов, грамматических
правил, состояний и проч.).
- 33 -
Приложение 1
Ниже приведен полный входной файл для yacc, реализующий
небольшой настольный калькулятор; калькулятор имеет 26
регистров, помеченных буквами от a до z и разрешает исполь-
зовать арифметические выражения, содержащие операции +, -,
*, /, % (остаток от деления), & (побитовое и), | (побитовое
или) и присваивание. Как и в Си, целые числа, начинающиеся с
0, Считаются восьмеричными, все остальные - десятичными.
В примере демонстрируются способы использования приори-
тетов для разрешения конфликтов, а также простые операции по
восстановлению из состояния ошибки. Калькулятор работает в
интерактивном режиме с построчным формированием выхода.
%token DIGIT LETTER /* имена лексем */
%left '|' /* задание приоритетов */
%left '&' /* операций */
%left '+' '-'
%left '*' '/' '%'
%left UMINUS /* установка приоритета
операции унарный минус */
%{ /* oписания, используемые */
Int base, regs[26]; /* в действиях */
%}
%% /* начало секции правил */
list:
| list stat '\n'
| list stat error '\n' {yyerrok; }
stat:
expr {printf("%d\n",$1);}
| LETTER '=' expr {regs[$1]=$3; }
expr:
'(' expr ')' { $$=$2; }
| expr '+' expr { $$=$1+$3; }
| expr '-' expr { $$=$1-$3; }
| expr '*' expr { $$=$1*$3; }
| expr '/' expr { $$=$1/$3; }
| expr '%' expr { $$=$1%$3; }
| expr '&' expr { $$=$1&$3; }
| expr '|' expr { $$=$1|$3; }
| '-' expr %prec UMINUS { $$= -$2; }
| LETTER { $$=regs[$1]; }
| number;
number:
DIGIT { $$=$1; base=10;
if($1==0) base=8; }
- 34 -
| number DIGIT {$$=base*$1+$2; }
%% /* начало секции программ */
/*
* Программа лексического анализа
* для строчных латинских букв
* возвращает LETTER,
* значение yylval от 0 до 25;
* для цифр - DIGIT,
* значение yylval от 0 до 9;
* остальные символы возвращаются
* непосредственно
*/
yylex()
{
int c;
while( (c=getchar()) == ' ' );
if( c>='a' && c<='z' ) {
yylval = c - 'a';
return(LETTER);
}
if( c>='0' && c<='9' ) {
yylval = c - '0';
return(DIGIT);
}
return(c);
}
- 35 -
Приложение 2
Анализ и преобразование в матричную форму входных дан-
ных для задачи линейного программирования.
Входная информация из обычной алгебраической формы:
c1X1+c2X2+...+cnXn -> min(max)
a11x1+a12X2+...+a1nXn=b1
am1X1+am2X2+...+amnXn=bm
преобразуется в матричную:
C: c1 c2 ... cn
A: a11 a12 ... a1n
...
am1 am2 ... amn
B: b1 b2 ... bm
Одновременно изменяются знаки коэффициентов при неизвестных
в ограничениях с отрицательным свободным членом, а также
знаки коэффициентов линейного функционала в случае его мак-
симизации. С иллюстративной целью допускаются некоторые
варианты синтаксической записи. Предусмотрена возможность
повторного задания ошибочных строк.
%token число Xi оптим
%%
злп:функционал '\n' система_ограничений
{final();}
| система_ограничений функционал '\n'
{ final();}
функционал: линейная_функция {stf();}
/* По умолчанию - минимизация */
| оптим '(' линейная_функция ')'
{if($1) conv(); stf();}
/* В случае максимизации выполнить conv() */
| линейная_функция '-''>' оптим
{if($4) conv();stf();}
линейная_функция: элем1
| линейная_функция элем ;
элем: знак число Xi {stc($1*$2,$3); }
| знак Xi '*' число { stc($1*$4,$2);}
| знак Xi { stc($1,$2);}
/* Формы записи коэффициентов */
элем1: элем
| число Xi { stc($1,$2);}
| Xi '*' число { stc($3,$1);}
- 36 -
| Xi { stc(1,$1); }
знак: '+' {$$=1; }
| '-' {$$= -1;}
система_ограничений: ограничение '\n'
| система_ограничений ограничение '\n'
| система_ограничений error '\n'
{aclear();yyerrok;
printf("повторите последнюю строку\n");}
/* В случае ошибки: стирание инф. о строке,
восстановление и выдача подсказки */
ограничение: линейная_функция '=' число
{ stcb($3);}
| линейная_функция '=' знак число
{ if($3<0) conv(); stcb($4);}
/* Если bi<0, выполнить conv() */
%%
#include "stdio.h"
#define MAXM 100 /* предельное число */
#define MAXN 100 /* ограничений и перем.*/
int c[MAXN],b[MAXM],a[MAXM+1][MAXN],
neqs,nx,x[MAXN];
/* Лексический анализатор возвращает:
* для целых чисел - число,
* yylval равно знач. числа;
* для идент.вида xi, i=1,2,...XI*
* yylval равно его порядк. номеру;
* для max/min - оптим,
* yylval равно соответственно 1 или 0
*/
yylex() {
char c,i;
while((c=getc(stdin))==' ');
switch(c) {
case'0':
case'1':
case'2':
case'3':
case'4':
case'5':
case'6':
case'7':
case'8':
case'9': yylval=c-'0';
while((c=getc(stdin))<='9'&&c>='0')
yylval=yylval*10+c-'0';
ungetc(c,stdin); return(число);
- 37 -
case'm': if((c=getc(stdin))=='i') yylval=0;
else if(c=='a') yylval=1;
else return('m');
while((c=getc(stdin))<='z'&&c>='a');
ungetc(c,stdin); return(оптим);
case'X':
case'x': if((c=getc(stdin))<'0' || c>'9')
return('x');
yylval=0;
while(c<='9'&&c>='0')
{yylval=yylval*10+c-'0';c=getc(stdin);}
ungetc(c,stdin);
for(i=0;i<nx;i++)
if(x[i]==yylval){yylval=i;return(Xi);}
x[nx]=yylval; yylval=nx++;return(Xi);
}
return(c);
}
/* Печать условия задачи в матричной форме */
final() {
char i,j;
printf("c:\n");
for(i=0;i<nx;i++) printf("%8d",c[i]);
printf("\na:\n");
for(i=0;i<neqs;i++) {
for(j=0;j<nx;j++) printf("%8d",a[i][j]);
printf("\n"); }
printf("b:\n");
for(i=0;i<neqs;i++) printf("%8d",b[i]);
}
/* Изменение знаков коэффициентов */
conv() {
char i;
for(i=0;i<nx;i++) a[neqs][i]*=(-1);
}
/* Запоминание коэффициентов функционала */
stf() {
char i;
for(i=0;i<nx;i++)
{ c[i]=a[neqs][i]; a[neqs][i]=0; }
}
/* Запоминание очередного коэффициента */
stc(nmb,adr) {
a[neqs][adr]=nmb; }
/* Запоминание свободного члена */
stcb(nmb) {
b[neqs++]=nmb; }
- 38 -
/* Стирание ошибочной строки*/
aclear(){
char i;
for(i=0;i<nx;i++)
a[neqs][i]=0;
}
- 39 -
Приложение 3
Формальное описание структуры спецификационного файла.
файл_спецификаций:
секция_деклараций '%''%'
'\n' секция_правил '%''%'
'\n' секция_программ
| секция_деклараций '%''%'
'\n' секция_правил ;
секция_деклараций:
| секция_деклараций дир_или_описание
'\n' ;
дир_или_описание:
'%''{''\n'ВНЕШНИЕ_ОПИСАНИЯ
'\n''%''}'
| '%''s''t''a''r''t' ИДЕНТИФИКАТОР
| '%''t''o''k''e''n'список_им_лексем
| ассоциативность список_лексем ;
ассоциативность:
'%''l''e''f''t'
| '%'''r''i''g''h''t'
| '%''n''o''n''a''s''s''o''c' ;
список_им_лексем:
| декл_имени_лексемы
| список_им_лексем
декл_имени_лексемы ;
список_лексем:
декл_лексемы
| список_лексем декл_лексемы ;
декл_имени_лексемы:
ИДЕНТИФИКАТОР
| ИДЕНТИФИКАТОР ЦЕЛОЕ_БЕЗ_ЗНАКА;
декл_лексемы:
декл_лексемы
| декл_литерала;
декл_литерала:
ЛИТЕРАЛ
| ЛИТЕРАЛ ЦЕЛОЕ_БЕЗ_ЗНАКА;
секция_правил:
набор_правил
| '%''{''\n'СИ_ОПЕРАТОРЫ'\n''%''}'
'\n' набор_правил '\n' ;
набор_правил:
правило
| набор_правил ';' правило ;
правило:
левая_часть ':' альтернатива
| правило '|' альтернатива ;
левая_часть: ИДЕНТИФИКАТОР ;
альтернатива:
- 40 -
правая_часть
| правая_часть изм_приор
| правая_часть изм_приор действие
| правая_часть действие ;
правая_часть:
| правая_часть лит_или_идент
| правая_часть действие лит_или_идент;
изм_приор:
секция_программ:
ПРОГРАММНЫЕ_КОМПОНЕНТЫ ;
При описании структуры спецификационного файла не рас-
шифровывались некоторые исходные конструкции, совпадающие с
аналогичными конструкциями Си: идентификатор, литерал, целое
без знака. Не описаны также и более сложные конструкции,
являющиеся фрагментами Си-программ, переносимыми в текст
анализатора (внешние описания, Си-операторы). Под расширен-
ными Си-операторами понимаются операторы с возможным исполь-
зованием псевдопеременных. ПРОГРАММНЫЕ_КОМПОНЕНТЫ включают
операторы препроцессора, описания внешних переменных и функ-
ций (возможный состав их приводится в разделе 4.3).
- 41 -
СОДЕРЖАНИЕ
. Аннотация ......................................... 2