Yacc Lex 使用中错误信息解决解决方案

ex3.y: In function ‘yyerror’:
ex3.y:32: warning: incompatible implicit declaration of built-in function
‘printf’

这一条是因为.y缺少头文件。在.y文件中需要在%{…%}之中写入#include
<stdio.h>等头文件。如果只有printf那就只用这个头文件就行了。

ex3.l: In function ‘yylex’:
ex3.l:11: error: ‘yylval’ undeclared (first use in this function)
ex3.l:11: error: (Each undeclared identifier is reported only once
ex3.l:11: error: for each function it appears in.)

这一条信息是由于yylval 对于lex不可见造成的。原因yacc调用yylex()读取token,lex读到一个token就将这个token返回,但这个t
oken同时可能有值。此值必须保留在yylval中。但是古老的yacc不让lex见到,那么就需要extern YYSTPYE
yylval.传说这就需要加在y.tab.h中。但是经我测试这是不行的。(我也不知道为啥偏偏就我这么倒霉。)我在加上extern YYSTPYE
yylval之后产生如下错误:

ex3.l:5: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘attribute’ before
‘yylval’
ex3.l: In function ‘yylex’:

…不过还有救,我不使用byacc,而改用bison。之后去掉extern YYSTPYE yylval再编译:

ex3.y: In function ‘yyparse’:
ex3.y:26: warning: format ‘%s’ expects type ‘char *’, but argument 2 has type
‘YYSTYPE’

这是因为YYSTYPE这个变量是int型的。所以要在.y文件的%{…%}中添加两行

typedef char* string; #define YYSTPYE string

然后编译成功,却冒出了:

ex3.l: In function ‘yylex’:
ex3.l:10: warning: assignment makes integer from pointer without a cast

这肯定是yylval=strdup(yytext);处没有进行强制转换。于是改为yylval=(int)strdup(yytext);就ok了。但这里的问题
是yylval应该是一个YYSTYPE的变量。但是却必须转换为int型,确实有些诡异。之后又尝试在gcc中添加-Wstrict-
prototypes来查看此错误。结果发现又报一错⚠️ function declaration isn’t a
prototype.这个错误的确是自己从来不喜欢写void造成的。将main()改为main(void)
即可。

首先要有flex 和 bison两个东东,没有就yum或者apt-get

最终的两个文件和编译命令为:

ex3.l文件:

%{ #include <stdio.h> #include “ex3.tab.h” %} name [a-zA-Z][a-zA-Z0-9]* age
[1-9][0-9]* eq = %% {name} {yylval=(int)strdup(yytext); return NAME;} {age}
{yylval=(int)strdup(yytext); return AGE;} {eq} {return EQ;} %% int yywrap() {
return 1; }

ex3.y文件

%{ typedef char* string; #define YYSTYPE string #include <stdio.h> #include
<string.h> int main(void) { // extern int yyparse(void); yyparse(); return 0;
} int yyerror(char * msg) { printf(“%s is error in line”,msg); } %} %token
NAME EQ AGE %% file : record file | record ; record : NAME EQ NAME {
printf(“%s’s age is equal with %s./n”,$1,$3); } | NAME EQ AGE {
printf(“ssssss/n”); } ; %%

这之后执行:

root@chico-laptop:~/compiler# bison -d ex3.y root@chico-laptop:~/compiler#
flex ex3.l root@chico-laptop:~/compiler# cc -Wstrict-prototypes lex.yy.c
ex3.tab.c -o test root@chico-laptop:~/compiler# ./test

input:

AA = BB

output:

AA’s age is equal with BB.

简单的东西算是完成了

但是还有一个问题没有解决,为啥使用bison就可以解决问题,而使用byacc就不行呢?我看了下bison生成的ex3.tab.h文件,其中有几句话:

#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED typedef int YYSTYPE; #
define yystype YYSTYPE /* obsolescent; will be withdrawn */ # define
YYSTYPE_IS_DECLARED 1 # define YYSTYPE_IS_TRIVIAL 1 #endif extern YYSTYPE
yylval;

直接将上面的话贴入byacc生成的y.tab.h即可编译通过。不过即使你在其中更改 typedef char*
YYSTYPE;lex程序还是会将yylval默认为int型。

不过想要通过c++编译的话,还需要做些改动。

ex4.y

%{ #include #include using namespace std; typedef char*
strings; #define YYSTYPE strings extern “C” { int yyparse(void); int
yylex(void); int yydebug; int yyerror(const char*); } int main(void) { //
extern int yyparse(void); yydebug=1; yyparse(); return 0; } int yyerror(const
char * msg) { printf(“%s is error in line”,msg); } %} %token NAME EQ AGE %%
file : record file | record ; record : NAME EQ NAME { printf(“%s’s age is
equal with %s./n”,$1,$3); } | NAME EQ AGE { printf(“ssssss/n”); } ; %%

ex4.l

%{ #include <stdio.h> #include “ex4.tab.h” %} name [a-zA-Z][a-zA-Z0-9]* age
[1-9][0-9]* eq = %% {name} {yylval=(int)strdup(yytext); return NAME;} {age}
{yylval=(int)strdup(yytext); return AGE;} {eq} {return EQ;} %% int
yywrap(){return 1;}

编译指令:

root@chico-laptop:~/compiler# bison -d ex4.y root@chico-laptop:~/compiler#
flex ex4.l root@chico-laptop:~/compiler# cc -c lex.yy.c -o lex.yy.o root
@chico-laptop:~/compiler# c++ lex.yy.o ex4.tab.c -o ex4test

常见的编译error和warning有:

ex4.tab.c:1519: warning: deprecated conversion from string constant to ‘char*’
这里去查看了一下ex4.tab.c发现是函数yyerror的问题,将int yyerror(char*)改为int yyerror(const
char*)即可。

另外不要typedef char* string;这可能会重,不定义又会报出:

ex4.y: In function ‘int yyparse()’:
ex4.y:36: warning: cannot pass objects of non-POD type ‘struct
std::basic_string<char, std::char_traits, std::allocator >’
through ‘…’; call will abort at runtime

所以改为typedef char* strings;

另外lex.yy.c要先用cc或gcc编译为.o文件,然后在用g或c联合编译。