来自词法分析器和语法的简单计算器的意外行为

我开始了整个Flex和Bison的世界。 所以我按照教程为flex编写了这个l文件:

%{ #include  #include  void yyerror(char *); #include "y.tab.h" %} %% /******************** RULES ********************/ /* One letter variables */ [az] { yylval = *yytext - 'a'; // This is to return a number between 0 and 26 representting the letter variable. printf("VAR: %s\n",yytext); return VARIABLE; } /* Integer constants */ [0-9]+ { yylval = atoi(yytext); printf("INT: %d\n",yylval); return INTEGER; } /* Operators */ [-+()=/*\n]+ { printf("OPR: %s\n",yytext); return *yytext; /*\n is considered an operator because it signals the end of a statement*/ } /* This skips white space and tab chararcters */ [ \t] ; /* Anything esle is not allowed */ . yyerror("Invalid character found"); /***************** SUBROUTINES *****************/ %% int yywrap(void){ return 1; } 

这就是语法:

 /***************** DEFINITIONS *****************/ %token INTEGER VARIABLE %left '+' '-' %left '*' '/' %{ void yyerror(char *); int yylex(void); int sym[26]; %} %% /******************** RULES ********************/ program: program statement '\n' | ; statement: expr { printf("EXPR: %d\n", $1); } | VARIABLE '=' expr { sym[$1] = $3; } ; expr: INTEGER | VARIABLE { $$ = sym[$1]; } | expr '+' expr { $$ = $1 + $3; } | expr '-' expr { $$ = $1 - $3; } | expr '*' expr { $$ = $1 * $3; } | expr '/' expr { $$ = $1 / $3; } | '(' expr ')' { $$ = $2; } ; %% /***************** SUBROUTINES *****************/ void yyerror(char *s){ printf("%s\n",s); } int main(void) { yyparse(); return 0; } 

并且出现了几个问题。 第一个来自编译时。 这是我编译的方式:

 bison -d bas.y -o y.tab.c flex bas.l gcc y.tab.h lex.yy.c y.tab.c -o bas_fe 

这给了我两个这样的警告:

 bas.y:24:7: warning: incompatible implicit declaration of built-in function 'printf' expr { printf("EXPR: %d\n", $1); } ^ bas.y: In function 'yyerror': bas.y:39:4: warning: incompatible implicit declaration of built-in function 'printf' printf("%s\n",s); 

现在,它们是警告和打印工作,但我发现它很奇怪,因为我已经清楚地包含了使用printf函数的库。

我真正的问题来自于我与该计划的互动。 这是控制台输出:

 x = (3+5) VAR: x OPR: = OPR: ( INT: 3 OPR: + INT: 5 x OPR: ) VAR: x syntax error 

由此产生了几个问题。 1)输入x =(3 + 5)后,程序打印输出不包括’)’为什么?

2)当输入x(预期输出为8)时,才会出现’)’。 为什么?

3)然后是“语法错误”消息。 我假设消息是在y.tab.c的代码中自动生成的。 可以改成更有意义的东西吗? 我是正确的假设语法错误是因为程序找到了)和换行符和变量,并且这不符合程序语句,如语法所定义的那样?

我已经清楚地包含了用于printf函数的库。

您在flex文件中包含stdio.h ,但在bison文件中没有。 有关printf未声明的警告来自你的野牛文件,而不是你的flex文件。

使用gcc(或任何其他C编译器)编译多个文件时,文件将独立编译,然后链接在一起。 所以你的命令

 gcc y.tab.h lex.yy.c y.tab.c -o bas_fe 

不会连接这三个文件并将它们编译为一个单元。 相反,它独立编译三个文件,包括无用地编译头文件y.tab.h

你应该做的是在你的bas.y文件中添加一个prolog块,包括#include

[-+()=/*\n]+ {... return *yytext; ...}

此弹性模式匹配集[-+()=/*\n]中的任意数量的字符。 所以在输入x=(3+5)\n)\n被匹配为单个标记 。 但是,该操作返回*yytext*yytext的第一个字符,实际上忽略了\n 。 由于你的语法需要\n ,这会产生语法错误。

只需从模式中删除重复运算符即可。

可以将错误消息更改为更有意义的内容吗?

如果您有一个相当现代的野牛,请添加声明

 %error-verbose 

到你的野牛文件的开头。