Этот раздел описывает примеры
программ для команд lex и yacc. Эти программы
описывают простой калькулятор, поддерживающий операции сложения, вычитания,
умножения и деления. Калькулятор также позволяет присваивать значения
переменным (обозначаемым одной строчной буквой) и затем использовать их в
вычислениях. Примеры программ lex и yacc
находятся в следующих файлах:
| Файл | Содержание |
|---|---|
| calc.lex (Исходный текст лексического анализатора) | Файл спецификаций lex, в котором определяются правила лексического анализа. |
| calc.yacc (Исходный текст синтаксического анализатора) | Файл грамматики yacc, который содержит правила грамматического разбора. Для ввода информации применяется функция yylex, созданная командой lex. |
Далее везде предполагается, что программы calc.lex и calc.yacc находятся в текущем каталоге.
Для создания программы калькулятора выполните следующие действия в указанном порядке:
yacc -d calc.yacc
| y.tab.c | Исходный файл на языке C, созданный командой yacc для синтаксического анализатора. |
| y.tab.h | Файл заголовка, содержащий определения лексем, используемых анализатором. |
lex calc.lex
| lex.yy.c | Исходный файл на языке C, созданный командой lex для лексического анализатора. |
cc y.tab.c lex.yy.c
| y.tab.o | Объектный файл для исходного файла y.tab.c |
| lex.yy.o | Объектный файл для исходного файла lex.yy.c |
| a.out | Исполняемая программа |
$ a.out
Или переименуйте файл и запустите программу:
$ mv a.out calculate $ calculate
В любом случае, после запуска программы курсор будет помещен на строку, расположенную ниже приглашения командной строки ($). После этого вы можете работать с калькулятором, вводя числа и операторы. После нажатия клавиши Enter программа выведет результаты операции. Присвойте значение переменной:
m=4 <enter> _
Курсор переместится на следующую строку. После этого вы сможете использовать переменную в дальнейших вычислениях:
m+5 <enter> 9 _
Ниже приведен текст файла calc.yacc. В это файле находится код из всех трех разделов файла грамматики yacc: объявления, правила и программы.
%{
#include <stdio.h>
int regs[26]; int base;
%}
%start list
%token DIGIT LETTER
%left '|' %left '&' %left '+' '-' %left '*' '/' '%' %left UMINUS /* определение приоритета унарного минуса */
%% /* начало раздела правил */
list: /*empty */
|
list stat '\n'
|
list 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 = ($1==0) ? 8 : 10;
} |
number DIGIT
{
$$ = base * $1 + $2;
}
;
%%
main()
{
return(yyparse());
}
yyerror(s)
char *s;
{
fprintf(stderr, "%s\n",s);
}
yywrap()
{
return(1);
}
Записи этого раздела выполняют следующие функции:
Раздел правил содержит правила грамматического разбора входного потока.
Раздел программ содержит
описанные ниже функции. В связи с тем, что все необходимые функции
определены в самом файле, при его обработке не требуется подключать библиотеку
yacc.
Ниже приведен текст файла calc.lex. В этом файле подключается библиотека стандартного ввода-вывода и файл y.tab.h. Программа yacc создает этот файл заголовка на основе файла грамматики yacc, если в вызове команды yacc указан флаг -d. Файл y.tab.h содержит определения лексем, используемых синтаксическим анализатором. Файл calc.lex содержит правила формирования этих лексем из входного текста.
%{
#include <stdio.h>
#include "y.tab.h"
int c;
extern int yylval;
%}
%%
" " ;
[a-z] {
c = yytext[0];
yylval = c - 'a';
return(LETTER);
}
[0-9] {
c = yytext[0];
yylval = c - '0';
return(DIGIT);
}
[^a-z0-9\b] {
c = yytext[0];
return(c);
}
Глава 1, Инструменты и утилиты.
Создание языка ввода с помощью команд lex и yacc.
Работа с программами lex и yacc.
Функция printf