Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
УМК по СПО.doc
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
1.79 Mб
Скачать

8.5.2.Сборка yacc-программ

Допустим, мы располагаем Yacc-программой в файле source.y и Lex-программой в файле source.l, которые необходимо собрать в работающую программу. Существует два способа сборки:

сборка Lex- и Yacc-программы с созданием файла y.tab.h;

сборка Lex- и Yacc-программы без создания файла y.tab.h.

Рассмотрим первый способ сборки.

Ниже приведен пример makefile для программы make, которая осуществляет последовательную обработку и сборку этих программ и размещает результат в файле program:

program: y.tab.o lex.yy.o

cc y.tab.o lex.yy.o -ly -ll -o program

y.tab.o: y.tab.c

cc -c -O y.tab.c

lex.yy.o: lex.yy.c y.tab.h

cc -c -O lex.yy.c

y.tab.h:

y.tab.c: source.y

yacc -d source.y

lex.yy.c: source.l

lex -v source.l

clear:

rm -f yy.tab.? lex.yy.? program

В файле source.l размещена Yacc-программа, реализующая небольшой настольный калькулятор. Калькулятор имеет 52 регистра, помеченных буквами от A до z, и разрешает использовать арифметические выражения, содержащие операции +, -, *, /, % (остаток от деления), & (побитовое и), | (побитовое или) и присваивание. Как и в Си, целые числа, начинающиеся с 0, считаются восьмеричными, все остальные - десятичными. Результат всегда выводится десятичными числами.

Калькулятор работает в интерактивном режиме с построчным формированием выхода, может читать задание из файла и выводить результат в файл.

Знак "=" используется для присваивания, а для выведения результата достаточно нажать клавишу <ВК>. Распознаются скобочные структуры, изменяющие порядок приоритетов при вычислениях. Калькулятор работает только с целыми типа integer.

%token DIGIT LETTER

%left '|'

%left '&'

%left '+' '-'

%left '*' '/' '%'

%left UMINUS

%{

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;

}

| number DIGIT

{

$$=base*$1+$2;

}

В файле source.l размещена Lex-программа лексического анализатора для этого калькулятора:

%{

#include "y.tab.h"

extern int yylval;

%}

%%

^\n ;

[ \t]* ;

[A-Za-z] {

yylval = yytext[yyleng-1] - 'a';

return(LETTER);}

[0-9] {

yylval = yytext[yyleng-1] - '0';

return(DIGIT);}

Рассмотрим второй способ сборки. Makefile теперь существенно проще:

program: y.tab.c lex.yy.c

cc -O y.tab.c -ly -ll -o program

y.tab.c: source.y

yacc source.y

lex.yy.c: source.l

lex -v source.l

clear:

rm -f y.tab.? lex.yy.? program

Но в файлах source.y и source.l произойдут следующие изменения. В разделе входной информации для Yacc-программы необходимо указать строку #include lex.yy.c, а из Lex-программы необходимо убрать строку #include "y.tab.h". Теперь файл source.y выглядит следующим образом:

%token DIGIT LETTER

%left '|'

%left '&'

%left '+' '-'

%left '*' '/' '%'

left UMINUS

%{

#include "lex.yy.c"

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;

}

| number DIGIT

{

$$=base*$1+$2;

}

А файл source.l выглядит следующим образом:

%{

extern int yylval;

%}

%%

^\n ;

[ \t]* ;

[A-Za-z] {

yylval = yytext[yyleng-1] - 'a';

return(LETTER);}

[0-9] {

yylval = yytext[yyleng-1] - '0';

return(DIGIT);}