本文介绍了带YYSTYPE的可重入flex/bison标头中的循环依赖性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个问题,我相信在flexbison生成的标头之间存在循环依赖性.类型yyscan_t在lex头中定义,在yacc头中需要.宏YYSTYPE在yacc头中定义,在lex头中需要.无论我导入两个标头的顺序如何,另一个都不满意.

I have a problem where I believe there is a cyclic dependency between the headers generated by flex and bison. The type yyscan_t is defined in the lex header and needed in the yacc header. The macro YYSTYPE is defined in the yacc header and needed in the lex header. No matter which order I import the two headers, the other will not be happy.

reentrant.lex:

%{
#include "reentrant.yacc.h"
%}

%option reentrant bison-bridge

%%

[0-9]+     { yylval->int_value = atoi(yytext); return INT_TERM; }
[a-zA-Z]+  { yylval->str_value = strdup(yytext); return STR_TERM; }
,          { return COMMA;    }

reentrant.yacc:

%{

// UN-COMMENT THE FOLLOWING LINE TO "FIX" THE CYCLE
//typedef void * yyscan_t

#include "reentrant.yacc.h"
#include "reentrant.lex.h"

void yyerror(yyscan_t scanner, char * msg);
%}

%define api.pure full
%lex-param {yyscan_t scanner}
%parse-param {yyscan_t scanner}

%union {
  int int_value;
  char * str_value;
}

%token <int_value> INT_TERM
%token <str_value> STR_TERM
%token COMMA
%type  <int_value> int_non_term
%type  <str_value> str_non_term

%%

complete : int_non_term str_non_term { printf(" === %d === %s === \n", $1, $2); }

int_non_term : INT_TERM COMMA { $$ = $1; }
str_non_term : STR_TERM COMMA { $$ = $1; }

%%

int main(void) {
  yyscan_t scanner;

  yylex_init(&scanner) ;
  yyset_debug(1, scanner);
  yydebug=1;

  int val = yyparse(scanner);

  yylex_destroy (scanner) ;
  return val;
}

int yywrap (yyscan_t scanner) {
  return 1;
}

void yyerror(yyscan_t scanner, char * msg) {
  fprintf(stderr, msg);
}

GCC输出:

In file included from reentrant.yacc:5:0:
reentrant.yacc.h:74:14: error: unknown type name ‘yyscan_t’
 int yyparse (yyscan_t scanner);
              ^~~~~~~~

使用的命令参数:

bison -vt --debug --defines=reentrant.yacc.h -o reentrant.yacc.c reentrant.yacc
flex -8 -d --header-file=reentrant.lex.h -o reentrant.lex.c reentrant.lex
gcc -Wall -Wno-unused-function -g reentrant.lex.c reentrant.yacc.c -o reentrant

软件版本:

$ flex --version
flex 2.6.4

$ bison --version
bison (GNU Bison) 3.0.4
Written by Robert Corbett and Richard Stallman.

Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ gcc --version
gcc (GCC) 6.3.1 20170306
Copyright (C) 2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

YYSTYPE:

在这里您可以看到YYSTYPE在yacc标头中定义,并在lex标头中使用.

Here you can see that YYSTYPE is defined in the yacc header and consumed in the lex header.

$ grep 'YYSTYPE' *.h
reentrant.lex.h:YYSTYPE * yyget_lval ( yyscan_t yyscanner );
reentrant.lex.h:void yyset_lval ( YYSTYPE * yylval_param , yyscan_t yyscanner );
reentrant.lex.h:               (YYSTYPE * yylval_param , yyscan_t yyscanner);
reentrant.lex.h:               (YYSTYPE * yylval_param , yyscan_t yyscanner)
reentrant.yacc.h:#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
reentrant.yacc.h:union YYSTYPE
reentrant.yacc.h:typedef union YYSTYPE YYSTYPE;
reentrant.yacc.h:# define YYSTYPE_IS_TRIVIAL 1
reentrant.yacc.h:# define YYSTYPE_IS_DECLARED 1

yyscan_t:

在这里您可以看到yyscan_t在lex标头中定义,并在yacc标头中使用.

Here you can see that yyscan_t is defined in the lex header and consumed in the yacc header.

$ grep 'yyscan_t' *.h
reentrant.lex.h:typedef void* yyscan_t;
<snip lots of function decls including yyscan_t>
reentrant.yacc.h:int yyparse (yyscan_t scanner);

推荐答案

这确实是一个无答案的问题,但是我发现该问题并未得到应有的重视,因此我将其发布为提醒您野牛设计中的严重缺陷.

This is a non-answer, really, but I see that the question has not received the attention it should have so I am posting this as a depressing reminder of this serious flaw in bison's design.

不可能(至少在当前版本的bison/flex中)干净地包含适当的头文件.原因是bison生成的* .h文件的结构(与出现在%union声明中的文件完全相同):union YYSTYPE {...} YYSTYPE;声明后紧跟int yyparse( yyscanner_t yyscanner);的声明(除非您将前缀yy更改为其他名称).由于没有在两个声明之间插入由flex 产生的lexer定义文件的机制,因此无论在何处包含lexer定义,都不可避免地发生冲突,无论是否还包括解析器定义.将lexer * .h文件放在解析器1之前(或在%union声明之前),gcc会抱怨不知道YYSTYPE是什么.在后面加上它---编译器将不知道yyparseyyparse声明中的含义.

It is not possible (at least in the current version of bison/flex) to cleanly include the appropriate header files. The reason is the structure of the *.h file produced by bison (which is exactly the same as what appears in place of the %union declaration): the union YYSTYPE {...} YYSTYPE; declaration is followed immediately by the declaration for int yyparse( yyscanner_t yyscanner); (unless you changed the prefix yy to something else). As there is no mechanism to insert the lexer definitions file produced by flex between the two declarations, no matter where the lexer definitions are included, the conflict is inevitable, whether or not the parser defines are included as well. Put the lexer *.h file before the parser one (or before the %union declaration) and gcc will complain about not knowing what YYSTYPE is. Include it after---and the compiler will not know what yyscanner_t means in the yyparse declaration.

除非野牛分别输出其%defines文件的不同块,否则不清楚如何解决.解决该问题的一种实用方法是先将解析器定义为yyscanner_t定义为void *(无论是宏还是typedef都没关系,两者的工作原理和效果都很难看),然后再由解析器定义flex生成的定义文件.

Unless bison outputs different chunks of its %defines file separately, it is unclear how this can be resolved. A practical way to circumvent this problem is to include the parser defines first after defining yyscanner_t as void * (whether as a macro or a typedef, does not matter, both work and both are equally ugly), followed by the definitions file produced by flex.

这篇关于带YYSTYPE的可重入flex/bison标头中的循环依赖性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

05-28 01:15