Hello world Flex/Bison 解析器生成一堆警告消息......如何摆脱它们?

问题描述

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 生成的解析器需要您定义两个函数,yylexyyerror。 (通常,您使用 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,如果您的实现包含它,我建议您也这样做。)