c-旧的bison/flex代码无法编译



我继承了一些非常旧的bison代码,处理这些代码已经有一段时间了,编译失败了,出现了一些警告和错误,这些警告我可以解决,但我不知道如何纠正这些错误。这里有一个例子:

给定这组定义:

%%
pgm:    exp                     { pgm = $1; }
exp:    list                    { $$ = dlink(newnode(NULL,NULL),$1); }
|       exp ';' list            { $$ = Link($1, dlink(newnode(NULL,NULL),$3)); }
list:   rec
|       list ',' rec            { $$ = Link($1, $3); }
rec:    /* null */              { $$ = newnode(NULL, NULL); }
|       path
|       path '@' NAME           { $$ = attribute($1, $3); }
|       path '(' list ')'       { $$ = dlink($1, $3); }
path:   NAME                    { $$ = newnode($1, NULL); }
|       path '.' NAME           { $$ = dlink($1, newnode($3, NULL)); }
|       path '[' INT ']'        { $$ = dlink($1, newnode($3, $3)); }
|       path '[' INT '-' INT ']'{ $$ = dlink($1, newnode($3, $5)); }
%%

它们被编译为:

bison -d -y gram.y
gcc -std=c89 -c y.tab.c

我得到以下错误(这只是众多错误中的一个):

gram.y: At top level:
gram.y:218:1: error: conflicting types for newnode
newnode(name, range)
^
gram.y:49:26: note: previous implicit declaration of newnode was here
"exp: list   { $$ = dlink(newnode(NULL,NULL),$1); }"

我将回答这个问题,因为它涉及的主题可能会给学习使用bison/yacc的学生和像OP这样编译旧代码并混淆错误来源的人带来困惑。

正如评论中所暗示的,这些错误与bison无关,而是来自于bison文件中包含的C代码,但不是bison的人工制品,也不是由bison或yacc多年来的变化引起的。它们是由C编译器多年来的变化引起的。现代的C编译器比以前的编译器宽容度低(更好),尤其是在函数调用和参数检查方面。即使在现代编译器上选择选项来实现向后兼容性,当以前的编译器可能什么都没说或只发出警告时,它有时仍然会产生错误。

为了证明故障完全在C中,可以执行以下操作:

Prompt> gcc -c -xc -std=c89 -
main () {
#line 49 "gram.y"
int a  = newnode(a,1);
int * b  = newnode(1,1);
}
void *
#line 218 "gram.y"
newnode(name, range)
int name,
range;
{
}
^Z
gram.y: In function 'main':
gram.y:50:12: warning: initialization makes pointer from integer without a cast
[enabled by default]
^
gram.y: At top level:
gram.y:218:1: error: conflicting types for 'newnode'
gram.y:49:10: note: previous implicit declaration of 'newnode' was here
^

您可以看到,在C的几行中,gcc将输出与您所看到的相同的错误消息。

关于这个问题,以及如何解决这个问题,SO上有很多内容:

  • C中的冲突类型错误
  • 使用gcc编译c程序时发生冲突类型错误
  • 得到"函数的冲突类型";在C中,为什么
  • C中的隐式函数声明
  • 警告:函数的隐式声明
  • 错误:函数的隐式声明';create_proc_read_entry';[-Weror=隐式函数声明]

脚注:可以关闭一些gcc错误,或通过使用#pragma或控制错误诊断级别将其减少为警告,但在这种情况下是不可能的。不支持gcc选项-Wno-error-implicit-function-declaration。线路:

#pragma GCC diagnostic warning "-Werror-implicit-function-declaration"

(或类似的)也不能消除错误。只是为了以防万一有人想知道

Bison中的类型冲突

在bison/yacc中使用类似代码时,许多人都会遇到bison检测到的代码类型不匹配的问题。也许值得在这方面添加一些注释,以使答案更加完整。通常情况下,在解析与语法类似的内容时,使用函数dlinkLinknewnodeattribute生成解析树。该树将由一些struct组成,并通过指向结构struct *的指针链接,如下所示:

struct treeNode {
int  item1,item2;
struct treeNode *left;
struct treeNode *right;
};
typedef  struct treeNode TREE_NODE;
typedef  TREE_NODE        *BINARY_TREE;

为了避免前面显示的隐式函数类型的问题,我们可以声明如下函数的原型:

BINARY_TREE dlink(BINARY_TREE left, BINARY_TREE right);
BINARY_TREE newnode(int item1, int item2);
BINARY_TREE attribute(BINARY_TREE left, int item);
BINARY_TREE Link(BINARY_TREE left, BINARY_TREE right);

我们可以将其与您的语法相结合,以制作此文件:

%{
#define NULL 0
struct treeNode {
int  item1,item2;
struct treeNode *left;
struct treeNode *right;
};
typedef  struct treeNode TREE_NODE;
typedef  TREE_NODE        *BINARY_TREE;
BINARY_TREE pgm;
BINARY_TREE dlink(BINARY_TREE left, BINARY_TREE right);
BINARY_TREE newnode(int item1, int item2);
BINARY_TREE attribute(BINARY_TREE left, int item);
BINARY_TREE Link(BINARY_TREE left, BINARY_TREE right);
%}
%token INT NAME
%%
pgm:    exp                     { pgm = $1; }
exp:    list                       {    $$ = dlink(newnode(NULL,NULL),$1); }
|       exp ';' list            { $$ = Link($1, dlink(newnode(NULL,NULL),$3)); }
list:   rec
|       list ',' rec            { $$ = Link($1, $3); }
rec:    /* null */              { $$ = newnode(NULL, NULL); }
|       path
|       path '@' NAME           { $$ = attribute($1, $3); }
|       path '(' list ')'       { $$ = dlink($1, $3); }
path:   NAME                    { $$ = newnode($1, NULL); }
|       path '.' NAME           { $$ = dlink($1, newnode($3, NULL)); }
|       path '[' INT ']'        { $$ = dlink($1, newnode($3, $3)); }
|       path '[' INT '-' INT ']'{ $$ = dlink($1, newnode($3, $5)); }
%%

也许你所拥有的就是这样的东西?如果我们把它通过bison和gcc,我们会得到很多警告,但它确实会生成代码。我注意到你说过你有很多警告。也许他们是这样的:

gram.y: In function 'yyparse':
gram.y:23:11: warning: assignment makes pointer from integer without a cast [enabled by default]
pgm: exp                     { pgm = $1; }
^
gram.y:25:5: warning: passing argument 2 of 'dlink' makes pointer from integer without a cast [enabled by default]
exp:    list                       {    $$ = dlink(newnode(NULL,NULL),$1); }
^
gram.y:14:13: note: expected 'BINARY_TREE' but argument is of type 'YYSTYPE'
BINARY_TREE dlink(BINARY_TREE left, BINARY_TREE right);
^
gram.y:25:18: warning: assignment makes integer from pointer without a cast [enabled by default]
exp:    list                       {    $$ = dlink(newnode(NULL,NULL),$1); }
^
gram.y:26:5: warning: passing argument 2 of 'dlink' makes pointer from integer without a cast [enabled by default]
|       exp ';' list            { $$ = Link($1, dlink(newnode(NULL,NULL),$3)); }
^
gram.y:14:13: note: expected 'BINARY_TREE' but argument is of type 'YYSTYPE'
BINARY_TREE dlink(BINARY_TREE left, BINARY_TREE right);
gram.y:25:18: warning: assignment makes integer from pointer without a cast [enabled by default]
exp:    list                       {    $$ = dlink(newnode(NULL,NULL),$1); }
^
gram.y:26:5: warning: passing argument 2 of 'dlink' makes pointer from integer without a cast [enabled by default]
|       exp ';' list            { $$ = Link($1, dlink(newnode(NULL,NULL),$3
)); }
^
gram.y:14:13: note: expected 'BINARY_TREE' but argument is of type 'YYSTYPE'
BINARY_TREE dlink(BINARY_TREE left, BINARY_TREE right);
^
gram.y:26:5: warning: passing argument 1 of 'Link' makes pointer from integer without a cast [enabled by default]
|       exp ';' list            { $$ = Link($1, dlink(newnode(NULL,NULL),$3
)); }
^
gram.y:17:13: note: expected 'BINARY_TREE' but argument is of type 'YYSTYPE'
BINARY_TREE Link(BINARY_TREE left, BINARY_TREE right);
^
gram.y:26:15: warning: assignment makes integer from pointer without a cast [enabled by default]
|       exp ';' list            { $$ = Link($1, dlink(newnode(NULL,NULL),$3
)); }
^
gram.y:29:5: warning: passing argument 1 of 'Link' makes pointer from integer without a cast [enabled by default]
|       list ',' rec            { $$ = Link($1, $3); }
^
gram.y:17:13: note: expected 'BINARY_TREE' but argument is of type 'YYSTYPE'
BINARY_TREE Link(BINARY_TREE left, BINARY_TREE right);
^
gram.y:29:5: warning: passing argument 2 of 'Link' makes pointer from integer without a cast [enabled by default]
|       list ',' rec            { $$ = Link($1, $3); }
^
gram.y:17:13: note: expected 'BINARY_TREE' but argument is of type 'YYSTYPE'
BINARY_TREE Link(BINARY_TREE left, BINARY_TREE right);
^
gram.y:29:15: warning: assignment makes integer from pointer without a cast [enabled by default]
|       list ',' rec            { $$ = Link($1, $3); }
^
gram.y:31:15: warning: assignment makes integer from pointer without a cast [enabled by default]
rec:    /* null */              { $$ = newnode(NULL, NULL); }
^
gram.y:33:5: warning: passing argument 1 of 'attribute' makes pointer from integer without a cast [enabled by default]
|       path '@' NAME           { $$ = attribute($1, $3); }
^
gram.y:16:13: note: expected 'BINARY_TREE' but argument is of type 'YYSTYPE'
BINARY_TREE attribute(BINARY_TREE left, int item);
^
gram.y:33:15: warning: assignment makes integer from pointer without a cast [enabled by default]
|       path '@' NAME           { $$ = attribute($1, $3); }
^
gram.y:34:5: warning: passing argument 1 of 'dlink' makes pointer from integer without a cast [enabled by default]
|       path '(' list ')'       { $$ = dlink($1, $3); }
^
gram.y:14:13: note: expected 'BINARY_TREE' but argument is of type 'YYSTYPE'
BINARY_TREE dlink(BINARY_TREE left, BINARY_TREE right);
^
gram.y:34:5: warning: passing argument 2 of 'dlink' makes pointer from integer without a cast [enabled by default]
|       path '(' list ')'       { $$ = dlink($1, $3); }
^
gram.y:14:13: note: expected 'BINARY_TREE' but argument is of type 'YYSTYPE'
BINARY_TREE dlink(BINARY_TREE left, BINARY_TREE right);
^
gram.y:34:15: warning: assignment makes integer from pointer without a cast [enabled by default]
|       path '(' list ')'       { $$ = dlink($1, $3); }
^
gram.y:36:15: warning: assignment makes integer from pointer without a cast [enabled by default]
path:   NAME                    { $$ = newnode($1, NULL); }
^
gram.y:37:5: warning: passing argument 1 of 'dlink' makes pointer from integer without a cast [enabled by default]
|       path '.' NAME           { $$ = dlink($1, newnode($3, NULL)); }
^
gram.y:14:13: note: expected 'BINARY_TREE' but argument is of type 'YYSTYPE'
BINARY_TREE dlink(BINARY_TREE left, BINARY_TREE right);
^
gram.y:37:15: warning: assignment makes integer from pointer without a cast [enabled by default]
|       path '.' NAME           { $$ = dlink($1, newnode($3, NULL)); }
^
gram.y:38:5: warning: passing argument 1 of 'dlink' makes pointer from integer without a cast [enabled by default]
|       path '[' INT ']'        { $$ = dlink($1, newnode($3, $3)); }
^
gram.y:14:13: note: expected 'BINARY_TREE' but argument is of type 'YYSTYPE'
BINARY_TREE dlink(BINARY_TREE left, BINARY_TREE right);
^
gram.y:38:15: warning: assignment makes integer from pointer without a cast [enabled by default]
|       path '[' INT ']'        { $$ = dlink($1, newnode($3, $3)); }
^
gram.y:39:5: warning: passing argument 1 of 'dlink' makes pointer from integer without a cast [enabled by default]
|       path '[' INT '-' INT ']'{ $$ = dlink($1, newnode($3, $5)); }
^
gram.y:14:13: note: expected 'BINARY_TREE' but argument is of type 'YYSTYPE'
BINARY_TREE dlink(BINARY_TREE left, BINARY_TREE right);
^
gram.y:39:15: warning: assignment makes integer from pointer without a cast [enabled by default]
|       path '[' INT '-' INT ']'{ $$ = dlink($1, newnode($3, $5)); }
^

这些对于野牛的新用户来说可能非常常见。为了消除这些警告,有必要通知bison如何使用类型,使其能够生成类型正确的代码。这是通过在bison代码中再添加几行来完成的。首先,我们必须告诉它语法规则操作可以返回的类型:

%union {
BINARY_TREE tVal;
int iVal;
}

然后我们必须告诉它为单个令牌和规则操作返回的类型:

%token <iVal> NAME INT
%type <tVal> exp list rec path

如果我们将这些插入到语法文件中,所有的错误和警告都会被消除,我们得到:

%{
#define NULL 0
struct treeNode {
int  item1,item2;
struct treeNode *left;
struct treeNode *right;
};
typedef  struct treeNode TREE_NODE;
typedef  TREE_NODE        *BINARY_TREE;
BINARY_TREE pgm;
BINARY_TREE dlink(BINARY_TREE left, BINARY_TREE right);
BINARY_TREE newnode(int item1, int item2);
BINARY_TREE attribute(BINARY_TREE left, int item);
BINARY_TREE Link(BINARY_TREE left, BINARY_TREE right);
%}
%union {
BINARY_TREE tVal;
int iVal;
}
%token <iVal> NAME INT
%type <tVal> exp list rec path 
%%
pgm:    exp                     { pgm = $1; }
exp:    list                       {    $$ = dlink(newnode(NULL,NULL),$1); }
|       exp ';' list            { $$ = Link($1, dlink(newnode(NULL,NULL),$3)); }
list:   rec
|       list ',' rec            { $$ = Link($1, $3); }
rec:    /* null */              { $$ = newnode(NULL, NULL); }
|       path
|       path '@' NAME           { $$ = attribute($1, $3); }
|       path '(' list ')'       { $$ = dlink($1, $3); }
path:   NAME                    { $$ = newnode($1, NULL); }
|       path '.' NAME           { $$ = dlink($1, newnode($3, NULL)); }
|       path '[' INT ']'        { $$ = dlink($1, newnode($3, $3)); }
|       path '[' INT '-' INT ']'{ $$ = dlink($1, newnode($3, $5)); }
%%

我希望我在C代码中发现了类型冲突的一些方面,这些方面可能会影响新加入bison的用户或采用其他代码库的用户。

最新更新