将函数作为参数传递给 yyparse 时存在 Bison 错误?
Bison bug when passing functions as arguments to yyparse?
我正在重写解析器以使其可重入。本着这种精神,我有兴趣将几个函数传递给 bison,然后让 bison 也将它们传递给 lex。
其中一个函数是我在操作中使用的回调,另一个是 flex 调用以获取输入数据的函数。
为此,我已将其放入我的 .y 文件中:
%lex-param {void (*my_input)(void *, char*, int *, int)}
%parse-param {void (*my_input)(void *, char*, int *, int)}
%parse-param {void *(*my_callback)(void *, char *, int, struct YYLTYPE *, int, ...)}
然后,在我的 .l 文件中声明:
#define YY_DECL int yylex (YYSTYPE *yylval_param, YYLTYPE *yylloc_param, yyscan_t yyscanner, void (*my_input)(void *, char*, int *, int))
问题是我认为 bison 在生成它的代码时可能有一个错误。当我尝试构建 bo 时,出现以下错误:
tmp.tab.c: In function ‘yy_symbol_value_print’:
tmp.tab.c:4043: error: expected expression before ‘)’ token
如果我们访问那一行,我们会得到这个函数:
static void
yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, yyscan_t scanner, void (*my_input)(void *, char*, int *, int), void *(*my_callback)(void *, char *, int, struct YYLTYPE *, int, ...))
{
FILE *yyo = yyoutput;
YYUSE (yyo);
YYUSE (yylocationp);
YYUSE (scanner);
YYUSE (int);
YYUSE (int);
if (!yyvaluep)
return;
YYUSE (yytype);
}
带有 YYUSE(int) 的第一行是抛出错误的行。如您所见,此函数以某种方式接收与 yyparse 相同的参数,然后它使用接收到的参数调用名为 YYUSE() 的宏。我认为,由于我的两个参数是函数(带有它们的参数列表,因为如果我理解正确的话,它们必须被声明)野牛调用 YYUSE() 并使用每个函数原型的最后一个参数......据我所知应该是 USE(my_input) 和 USE(my_callback)...
我很难相信这真的是一个错误,我的意思是,真的,直到现在还没有人尝试过吗?我很难相信...
YYUSE() 调用遍及生成的文件,尽管我真的不知道它们的用途...所以手动更改不是真正的选择...
过去有人成功地做到过吗?我做错了什么吗?
Bison 的参数解析器有点原始。它希望看到类似 %param {type name}
的内容,如果发现更复杂的内容,它可能会做错事。 (type
可以相当复杂;它可以包括 const
、*
和其他此类修饰符。但是 name
需要是规范中的最后一件事。)
这记录在 Bison manual 中:(强调)
Directive: %parse-param {argument-declaration} …
Declare that one or more argument-declaration are additional yyparse arguments. The argument-declaration is used when declaring functions or prototypes. The last identifier in argument-declaration must be the argument name.
类似的限制适用于 %union
指令中的标记名。
您可以使用 typedef 使您的程序对野牛和人类读者都更具可读性:
将其放入通用头文件中:
typedef void (*InputFunction)(void *, char*, int *, int);
typedef void *(*CallbackFunction)(void *, char *, int, struct YYLTYPE *, int, ...);
野牛文件:
%lex-param {InputFunction my_input}
%parse-param {InputFunction my_input} {CallbackFunction my_callback}
弹性文件:
#define YY_DECL int yylex (YYSTYPE *yylval_param, YYLTYPE *yylloc_param, yyscan_t yyscanner, InputFunction my_input)
顺便说一下,YY_USE
宏的目的是将参数标记为 "used",即使它们不是;这避免了碰巧不使用参数的函数中的编译器警告。有人可能会争辩说,确保参数被使用或标记为未使用是程序员的责任,但这并不是 bison 碰巧采取的方法。无论如何,即使没有 YY_USE
.
,non-conforming 参数声明(例如您提供的那个)也会以其他有趣的方式失败
我正在重写解析器以使其可重入。本着这种精神,我有兴趣将几个函数传递给 bison,然后让 bison 也将它们传递给 lex。 其中一个函数是我在操作中使用的回调,另一个是 flex 调用以获取输入数据的函数。
为此,我已将其放入我的 .y 文件中:
%lex-param {void (*my_input)(void *, char*, int *, int)}
%parse-param {void (*my_input)(void *, char*, int *, int)}
%parse-param {void *(*my_callback)(void *, char *, int, struct YYLTYPE *, int, ...)}
然后,在我的 .l 文件中声明:
#define YY_DECL int yylex (YYSTYPE *yylval_param, YYLTYPE *yylloc_param, yyscan_t yyscanner, void (*my_input)(void *, char*, int *, int))
问题是我认为 bison 在生成它的代码时可能有一个错误。当我尝试构建 bo 时,出现以下错误:
tmp.tab.c: In function ‘yy_symbol_value_print’:
tmp.tab.c:4043: error: expected expression before ‘)’ token
如果我们访问那一行,我们会得到这个函数:
static void
yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, yyscan_t scanner, void (*my_input)(void *, char*, int *, int), void *(*my_callback)(void *, char *, int, struct YYLTYPE *, int, ...))
{
FILE *yyo = yyoutput;
YYUSE (yyo);
YYUSE (yylocationp);
YYUSE (scanner);
YYUSE (int);
YYUSE (int);
if (!yyvaluep)
return;
YYUSE (yytype);
}
带有 YYUSE(int) 的第一行是抛出错误的行。如您所见,此函数以某种方式接收与 yyparse 相同的参数,然后它使用接收到的参数调用名为 YYUSE() 的宏。我认为,由于我的两个参数是函数(带有它们的参数列表,因为如果我理解正确的话,它们必须被声明)野牛调用 YYUSE() 并使用每个函数原型的最后一个参数......据我所知应该是 USE(my_input) 和 USE(my_callback)...
我很难相信这真的是一个错误,我的意思是,真的,直到现在还没有人尝试过吗?我很难相信...
YYUSE() 调用遍及生成的文件,尽管我真的不知道它们的用途...所以手动更改不是真正的选择... 过去有人成功地做到过吗?我做错了什么吗?
Bison 的参数解析器有点原始。它希望看到类似 %param {type name}
的内容,如果发现更复杂的内容,它可能会做错事。 (type
可以相当复杂;它可以包括 const
、*
和其他此类修饰符。但是 name
需要是规范中的最后一件事。)
这记录在 Bison manual 中:(强调)
Directive:
%parse-param {argument-declaration} …
Declare that one or more argument-declaration are additional yyparse arguments. The argument-declaration is used when declaring functions or prototypes. The last identifier in argument-declaration must be the argument name.
类似的限制适用于 %union
指令中的标记名。
您可以使用 typedef 使您的程序对野牛和人类读者都更具可读性:
将其放入通用头文件中:
typedef void (*InputFunction)(void *, char*, int *, int);
typedef void *(*CallbackFunction)(void *, char *, int, struct YYLTYPE *, int, ...);
野牛文件:
%lex-param {InputFunction my_input}
%parse-param {InputFunction my_input} {CallbackFunction my_callback}
弹性文件:
#define YY_DECL int yylex (YYSTYPE *yylval_param, YYLTYPE *yylloc_param, yyscan_t yyscanner, InputFunction my_input)
顺便说一下,YY_USE
宏的目的是将参数标记为 "used",即使它们不是;这避免了碰巧不使用参数的函数中的编译器警告。有人可能会争辩说,确保参数被使用或标记为未使用是程序员的责任,但这并不是 bison 碰巧采取的方法。无论如何,即使没有 YY_USE
.