将函数作为参数传递给yyparse时的Bison bug?

时间:2017-02-06 13:49:23

标签: gnu bison flex-lexer text-parsing

我正在重写解析器以使其可重入。本着这种精神,我有兴趣将一些功能传递给野牛,然后让野牛将它们传递给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()调用遍及生成的文件,即使我真的不知道它们的用途......所以手动更改并不是一个真正的选择...... 有没有人过去这么成功?有什么我做错了吗?

1 个答案:

答案 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}

Flex文件:

#define YY_DECL int yylex (YYSTYPE *yylval_param, YYLTYPE *yylloc_param, yyscan_t yyscanner, InputFunction my_input)

顺便说一下,YY_USE宏的意图是将参数标记为“已使用”,即使它们不是;这避免了在不使用参数的函数中的编译器警告。可以说,程序员有责任确保使用或标记为未使用的参数,但这并不是Bison采用的方法。无论如何,即使没有YY_USE,不合格的参数声明(例如您提供的参数声明)也会以其他有趣的方式失败。