问题描述
Flex/Bison 新手在这里。
我正在尝试创建一个 hello world 词法分析器/解析器。当我运行解析器时,我希望它从命令行读取。如果我输入:
Hello,World
然后我希望解析器打印出这个 XML:
<Document>Hello,World</Document>
这是我的词法分析器 (helloworld.l)
%{
#include "helloworld.tab.h"
%}
%%
.+ { yylval = yytext; return(DATA); }
\n { return(EOL); }
%%
int yywrap(){ return 1;}
这是我的解析器 (helloworld.y)
%{
#include <stdio.h>
%}
%token DATA
%token EOL
%%
start: /* nothing */
| data EOL { printf("<Document>%s</Document>\n> ",$1); }
;
data: DATA { $$ = $1; }
;
%%
int main()
{
printf("> ");
yyparse();
return 0;
}
yyerror(char *s)
{
fprintf(stderr,"error: %s\n",s);
}
这是我的 Makefile
main: helloworld.l helloworld.y
..\..\win_bison -d helloworld.y
..\..\win_flex helloworld.l
gcc -o $@ helloworld.tab.c lex.yy.c
当我运行 make 时,我收到以下警告消息。他们的意思是什么?我该如何修复它们?
helloworld.tab.c: In function 'yyparse':
helloworld.tab.c:576:16: warning: implicit declaration of function 'yylex' [-Wimplicit-function-declaration]
576 | # define YYLEX yylex ()
| ^~~~~
helloworld.tab.c:1236:16: note: in expansion of macro 'YYLEX'
1236 | yychar = YYLEX;
| ^~~~~
helloworld.tab.c:1378:7: warning: implicit declaration of function 'yyerror'; did you mean 'yyerrok'? [-Wimplicit-function-declaration]
1378 | yyerror (YY_("Syntax error"));
| ^~~~~~~
| yyerrok
helloworld.y: At top level:
helloworld.y:24:1: warning: return type defaults to 'int' [-Wimplicit-int]
24 | yyerror(char *s)
| ^~~~~~~
helloworld.l: In function 'yylex':
helloworld.l:6:10: warning: assignment to 'YYSTYPE' {aka 'int'} from 'char *' makes integer from pointer without a cast [-Wint-conversion]
6 | .+ { yylval = yytext; return(DATA); }
| ^
解决方法
自从 C 允许没有声明返回类型的函数(例如您的 yyerror
)以来,已经有 20 多年了,这表明您正在使用一个非常的旧示例作为模板。我强烈建议您查看 examples in the Bison manual。尽管它们没有表现出与 flex 的集成,但它们在编译时不会抱怨现代 C 编译器。
在编写该示例时,完全不声明返回 int
的函数可能是可以接受的,但是在本世纪,您需要在使用之前为每个函数提供声明。
bison 生成的解析器需要您定义两个函数,yylex
和 yyerror
。 (通常,您使用 flex
生成 yylex
但这与 bison 无关,因为扫描器是单独编译的。)您必须在生成的解析器的序言中声明这些函数(您也将#include
指令,用于您的操作所需的任何库函数。
对于一个简单的解析器,声明可能是:
%{
#include <stdio.h>
int yylex(void);
void yyerror(const char* msg);
%}
请注意,我通过添加 yyerror
更改了 const
的参数声明,这与现代风格一致(因为参数可能是字符文字,yyerror
不得尝试修改)。这将与以下实现一致:
void yyerror(const char* msg) {
fprintf(stderr,"%s\n",msg);
}
除此之外,您必须修复您的扫描仪操作,因为您不应在扫描仪返回后依赖 yytext
的值。 (更准确地说,该值将在下一次调用 yylex
时发生变化,但允许解析器提前读取,而且经常如此。)因此,如果要将 yytext
传递给解析器:
.+ { yylval = malloc(yyleng + 1);
strcpy(yylval,yytext);
return(DATA); }
(我写出来是因为您似乎使用的是 Windows;通常,我只会使用 strdup
,如果您的实现包含它,我建议您也这样做。)