Этот раздел описывает примеры
программ для команд 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