我正在尝试使用lex和yacc编写一个非常简单的计算器程序,但是在打印输出时遇到困难。文件是:
calc.l:
%{
#include "y.tab.h"
extern int yylval;
%}
%%
[0-9]+ {yylval = atoi(yytext); return NUMBER;}
[ \t] ;
\n return 0;
. return yytext[0];
%%
calc.y:
%{
#include <stdio.h>
void yyerror(char const *s) {
fprintf(stderr, "%s\n", s);
}
%}
%token NAME NUMBER
%%
statement: NAME '=' expression
| expression {printf(" =%d\n", $1);}
;
expression: expression '+' NUMBER {$$ = $1 + $3;}
| expression '-' NUMBER {$$ = $1 - $3;}
| NUMBER {$$ = $1;}
;
我使用过的命令:
flex calc.l
bison calc.y -d
gcc lex.yy.c calc.tab.c -lfl
./a.out
运行最后一个命令后虽然程序从键盘输入但没有打印任何内容,只需终止。编译时我没有收到任何警告或错误,但它没有给出任何输出。请帮忙。
答案 0 :(得分:1)
您没有main
的定义,因此将使用-lfl
中的主要功能。该库用于flex程序,其main
函数将调用yylex
- 词法扫描程序 - 直到它返回0.
您需要调用解析器。此外,您需要重复调用它,因为每次读取换行符时,词法扫描程序返回0,表示输入结束。
所以你可以使用这样的东西:
int main(void) {
do {
yyparse();
} while (!feof(stdin));
return 0;
}
然而,这将揭示一些其他问题。最烦人的是,你的语法不会接受空输入,所以空行会触发语法错误。这肯定会在输入结束时发生,因为EOF会导致yylex
立即返回0,这与空行无法区分。
此外,在解析过程中遇到的任何错误都会导致解析立即终止,导致输入行的其余部分未读。
总的来说,扫描程序通常最好为换行符返回换行符号(或\n
)。
除了您不需要的main
函数之外,-lfl
中的唯一内容是yywrap
的默认定义。你可以自己定义这个函数(它只需返回1),或者你可以通过添加
%option noyywrap
到你的flex文件。事实上,我通常建议
%option noyyrap noinput nounput
这将避免编译器警告(你没有看到,因为你在编译程序时没有提供-Wall
,你应该这样做。)
通过在yylex
的定义之前向您的野牛输入文件添加yyerror
声明,可以避免另一个编译器警告:
int yylex(void);
最后,在yylval
中声明了y.tab.h
,因此您的flex文件中不需要extern int yylval;
。在这种情况下,它不会造成伤害,但如果您更改了最终可能想要执行的语义值的类型,则此行也需要更改。最好是消除它。