我正在重写解析器以使其可重入。本着这种精神,我有兴趣将一些功能传递给野牛,然后让野牛将它们传递给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))
问题在于我认为野牛在生成代码时可能会有错误。当我尝试bo build时,我收到以下错误:
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()的宏。我认为,因为我的两个参数是函数(使用它们的arglist,因为如果我理解正确就必须声明它们)bison使用每个函数原型的最后一个参数调用YYUSE()...据我所知应该是USE(my_input)和USE(my_callback)......
我很难相信这真的是一个错误,我的意思是,真的,直到现在还没有人尝试过这个吗?我觉得很难相信......
YYUSE()调用遍及生成的文件,即使我真的不知道它们的用途......所以手动更改并不是一个真正的选择...... 有没有人过去这么成功?有什么我做错了吗?
答案 0 :(得分:0)
Bison的参数解析器有点原始。它希望看到像%param {type name}
这样的东西,如果它发现更复杂的东西,它可能会做错事。 (type
可能相当复杂;它可能包含const
,*
和其他此类修饰符。但name
必须是规范中的最后一项。)< / p>
Bison manual中记录了这一点:(强调添加)
指令:
%parse-param {argument-declaration} …
声明一个或多个参数声明是附加的yyparse参数。声明函数或原型时使用参数声明。 argument-declaration中的最后一个标识符必须是参数名称。
类似的限制适用于%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
宏的意图是将参数标记为“已使用”,即使它们不是;这避免了在不使用参数的函数中的编译器警告。可以说,程序员有责任确保使用或标记为未使用的参数,但这并不是Bison采用的方法。无论如何,即使没有YY_USE
,不合格的参数声明(例如您提供的参数声明)也会以其他有趣的方式失败。