旧野牛/弹力代码无法编译

时间:2014-01-28 19:43:29

标签: c compiler-errors 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); }"

1 个答案:

答案 0 :(得分:2)

我会回答这个问题,因为它涉及的主题可能会导致学习使用bison / yacc的学生和那些正在编译旧代码并且错误来自哪里的混淆

正如评论中暗示的那样,错误与野牛完全无关,而是来自野牛文件中包含的C代码,但不是野牛的人工制品,也不是由野牛或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将输出你看到的相同错误信息。

关于这个问题有很多关于它的问题,以及如何解决这个问题:

脚注:可以关闭一些gcc错误,或者使用#pragma将其减少为警告,或者控制错误诊断的级别,但在这种情况下无法实现。 gcc option -Wno-error-implicit-function-declaration is not supported。{{3}}。这一行:

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

(或类似)也不能消除错误。只要提到它,万一有人想知道

在Bison中键入冲突

许多人在使用bison / yacc中的类似代码时,他们的代码中的类型不匹配会被bison检测到。可能值得添加一些注释,以使答案更完整。通常情况下,在解析类似于语法的内容时,会使用函数dlinkLinknewnodeattribute创建解析树。该树将由一些struct构成,并通过指向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如何使用类型来使其生成类型正确的代码。这是通过在野牛代码中增加几行来完成的。首先,我们必须告诉它语法规则操作可以返回的类型:

%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代码中发现了类型冲突的某些方面,这些方面可能会影响新手野牛或采用别人代码库的用户。