lex和yacc中的简单计算器程序不提供输出

时间:2017-11-07 09:46:43

标签: yacc lex

我正在尝试使用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

运行最后一个命令后虽然程序从键盘输入但没有打印任何内容,只需终止。编译时我没有收到任何警告或错误,但它没有给出任何输出。请帮忙。

1 个答案:

答案 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;。在这种情况下,它不会造成伤害,但如果您更改了最终可能想要执行的语义值的类型,则此行也需要更改。最好是消除它。