【问题标题】:Old bison/flex code does not compile旧的 bison/flex 代码无法编译
【发布时间】:2014-01-28 19:43:28
【问题描述】:

我继承了一些非常古老的野牛代码,我已经有一段时间没有处理这个问题了,编译失败并出现许多警告和错误,我可以解决这些警告,但我不知道如何纠正错误。这是一个例子:

鉴于这组定义:

    %%
    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); }"

【问题讨论】:

  • 显示 gram.y 中声明新节点的部分。它在哪里,在规则之前还是之后?
  • “newnode 的先前隐式声明在这里”。看到隐式了吗?这意味着 newnode 从未明确地 声明过,即在 y.lex.c 或它包含的任何标头中没有它的原型。用这么少的上下文不可能回答,例如NAME的语义类型是什么?

标签: c compiler-errors bison


【解决方案1】:

我将回答这个问题,因为它涉及的主题可能会导致学习使用 bison/yacc 的学生以及像 OP 这样正在编译旧代码并且对错误来自何处感到困惑的人感到困惑。

正如cmets中所暗示的,错误与bison根本无关,而是来自bison文件中包含的C代码,但不是bison的人工制品,也不是由bison或yacc over的变化引起的这些年。它们是由多年来 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 的内容,以及如何解决它:

脚注: 可以关闭一些 gcc 错误,或者通过使用#pragma 或控制错误诊断的级别将它们减少为警告,但在这种情况下这是不可能的。 gcc option -Wno-error-implicit-function-declaration is not supported。行:

#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)); }
               ^

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

%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 的用户或采用其他人代码库的用户。

【讨论】:

  • 对答案的元评论:我确实将原始问题标记为无法回答,因为我们无法重现该问题。 This flag eventually timed-out (along with several hundred others)。这意味着社区认为它应该得到一个答案,所以我做了一个。
  • 这意味着不是社区认为它应该得到答案,而是社区没有足够快地审查标志(或者版主没有足够快地处理队列)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多