【问题标题】:Multiple definition of `main' while bison output file compiling编译野牛输出文件时“main”的多重定义
【发布时间】:2019-10-23 00:05:48
【问题描述】:

所以我正在编写一个野牛(没有 lex)解析器,现在我想从文件中读取输入代码并将输出写入另一个文件。

在stackoverflow上搜索了一段时间,发现这种方式应该不错。 bison.y:

%{
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>

    extern FILE *yyin;

    int yylex() { return getc(stdin); }
    void yyerror(char *s) {
      fprintf (stderr, "%s\n", s);
    }
    int counter = 1;
    char filename2[10] = "dest.ll";
    FILE *f2;
%}
%name parse

%%

//grammars

%%

int main(int argc, char *argv[]) {
    yyin = fopen(argv[1], "r");
    if (argc > 2)
      f2 = fopen(argv[2], "w");
    else
      f2 = fopen(filename2, "w");
    yyparse();

    return 0;
} 

然后我这样编译:

bison bison.y
cc -ly bison.tab.c

这里是cc编译的结果:

/tmp/ccNqiuhW.o: In function `main':
bison.tab.c:(.text+0x960): multiple definition of `main'
/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/liby.a(main.o):(.text.startup+0x0): first defined here
/tmp/ccNqiuhW.o: In function `main':
bison.tab.c:(.text+0x98c): undefined reference to `yyin'
collect2: error: ld returned 1 exit status

输出 bison.tab.c 文件只有 1 个主文件。 Ofc int/void main 无关紧要。你能教我如何正确地做吗?

附:顺便说一句,我不想​​给不同的帖子发垃圾邮件,在这里有一个小问题。如何将字符串 (char *) 存储在野牛的 $$ 中?比如我遇到int语法后想生成一个code string。我有这个错误,找不到答案:

bison.y:94:8: warning: assignment makes integer from pointer without a cast [-Wint-conversion]
 INTNUM: NUMBER | DIGIT INTNUM {$$ = "string"};

bison.y: In function ‘yyparse’:
bison.y:28:15: warning: format ‘%s’ expects argument of type ‘char *’, but argument 3 has type ‘int’ [-Wformat=]
 PROGRAM: EXPRS { fprintf(f2, "%s: string here %d.\n", $$, counter++) };

如果我能找到帮助会非常好。

【问题讨论】:

  • 使用-l 选项添加库的顺序是相关的。将-ly 选项移到源文件后的最后,这样您就可以像cc bison.tab.c -ly 一样构建。
  • 所以库liby包含一个默认的main,当用户没有提供main时使用。这意味着 main 必须首先找到,因此不会从库中提取 main。

标签: c parsing bison


【解决方案1】:

您正在链接库liby(链接器选项-ly)。 The Bison manual 有话要说:

Yacc 库包含 yyerrormain 函数。

这就是为什么您有多个main 定义的原因。你提供一个,liby 里就有一个。

此外,文档继续说

这些默认实现通常没有用处,但 POSIX 需要它们。

(已添加重点)

你不需要链接 liby 来构建一个包含野牛生成解析器的程序,通常你不应该这样做。相反,请提供您自己的main() 和您自己的yyerror(),您已经完成了这两项工作。

此外,您需要提供yyin定义,而不仅仅是声明,无论您是否链接 liby。为此,请从语法文件中 yyin 的声明中删除 extern 关键字。

您的语法不完整(根本没有规则)并且 %name 指令没有记录并且我的 Bison 无法识别,但是如果我添加一个虚拟规则并注释掉 %name,同时与讨论的其他更改一起,bison 为我生成一个 C 源文件,可以成功编译为可执行文件(无需 liby)。

【讨论】:

  • 而且,如果您确实链接了库,请将库放在命令行中的对象(或源)文件之后(这通常是您应该对库执行的操作):cc bison.tab.c -ly — 那也可以解决问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-07-13
  • 1970-01-01
  • 2010-12-17
  • 1970-01-01
  • 2017-07-22
  • 1970-01-01
  • 2015-05-27
相关资源
最近更新 更多