【问题标题】:Flex, Bison, C++ - compile errorFlex、Bison、C++ - 编译错误
【发布时间】:2013-09-21 13:45:06
【问题描述】:

我想做一个程序,为函数创建解析树。 例如:“f(g(x,h(y),v,k(l(c))))”可能是一个有效的函数调用。

h1.l

%{
#include <iostream>
#include <list>
using namespace std;
#include "h1.tab.hpp"

%}

%option noyywrap
%option c++

%%

[a-z][a-zA-z0-9]*       { yylval.s = yytext; return (TERM_ID); }
"("                     { return (OP); }
")"                     { return (CP); }
";"                     { return (COMMA); }

%%

h1.ypp

%{

#include <list>
#include <string>
#include <iostream>

using namespace std;


extern "C" int yylex(); 
extern "C" int yyerror(char *p) { cerr << "Error!" << endl; }

struct ts {
    string                  *name;
    list<struct ts*>        *plist; /* NULL if the sturcture represents a variable, parameter list if the structure represents a function */
};

%}

%union {
    struct ts *t;
    list<struct ts *> *tl;
    char *s;
}

%token <s> TERM_ID
%token OP CP COMMA

%type <tl> termlist
%type <t> term


%%

term : TERM_ID OP termlist CP   { $$ = new struct ts(); $$->name = new string($1); $$->plist = $3; }
    | TERM_ID   { $$ = new struct ts(); $$->name = new string($1); $$->plist = NULL; }
;

termlist : termlist COMMA term  { $$ = $1; $$->push_back($3); }
    | term  { $$ = new list<struct ts*>(); $$->push_back($1); }
;


%%

int main()
{
    yyparse();
    return 0;
}

编译:

$ bison -d h1.ypp
$ flex h1.l 
$ g++ h1.tab.cpp lex.yy.cc
h1.tab.cpp: In function ‘int yyparse()’:
h1.tab.cpp:1382: warning: deprecated conversion from string constant to ‘char*’
h1.tab.cpp:1528: warning: deprecated conversion from string constant to ‘char*’
Undefined symbols for architecture x86_64:
  "_yylex", referenced from:
      yyparse()    in ccmRHVKn.o
ld: symbol(s) not found for architecture x86_64
collect2: ld returned 1 exit status

我对这些工具了解不多,也没有用过cpp。

我应该改变什么才能使这些东西起作用?

【问题讨论】:

  • 问题出在链接器上。找不到yylex函数的定义?您是否正在编译其定义所在的源文件?
  • flex 工具生成 yylex() 函数。您不得编译它生成的源代码。

标签: c++ bison flex-lexer


【解决方案1】:

问题是您正在生成一个 C++ 词法分析器类(在 .l 文件中使用 %option c++),而 bison 需要一个 C yylex 函数。删除%option c++ 并将extern "C" int yyex(); 添加到.l 文件的顶部(或从.y 文件中删除extern "C"),一切都会好起来的。

【讨论】:

    【解决方案2】:

    您正在生成 C++ yylex,然后在解析器中将其声明为 extern "C"。 C++ 函数和 C 函数没有相同的名称(即使它们看起来相同),因此链接器无法找到 yylex(或 _yylex,因为它实际上被称为。)

    从两个声明中删除外部“C”,它可能会链接。

    您应该将%union 中的char* s 更改为std::string* s;否则,您将遇到初学者最常见的 bison/flex 问题之一:指向的 C 字符串 yytext 仅在下次调用 yylex 之前有效,因此当 bison 开始使用指针,它指向不同的字符串。

    所以你需要在词法分析器中复制yytext,而不是在解析器中。因此,在您的词法分析器中,您会这样做:

    yylval.s = new std::string(yytext);
    

    在你的语法中,你会做(例如):

    term : TERM_ID OP termlist CP   { 
             $$ = new struct ts();
             $$->name = $1;        // <-- Here is the change
             $$->plist = $3;
           }
    

    【讨论】:

    • 我收到以下错误消息:h1.ypp:23: error: member 'std::string YYSTYPE::s' with constructor not allowed in union h1.ypp:23: error:联合 h1.ypp:23 中不允许使用析构函数的成员“std::string YYSTYPE::s”:错误:联合中不允许使用复制赋值运算符的成员“std::string YYSTYPE::s”
    • @DavidAngyal:哎呀。没错,你不能在联合中加入字符串;它必须是一个结构。您必须将其设为字符串* 并将分配更改为 yylval.s = new std::string(yytext);然后在你的野牛行动中你有一个TERM_ID,而不是$$->name = new string($1),你可以做$$-&gt;name = $1。 (更改答案以反映评论)
    • 现在,再次显示此消息:体系结构 x86_64 的未定义符号:“yylex()”,引用自:ccXWYT6Z.o 中的 yyparse() ld:未找到体系结构 x86_64 的符号 collect2:ld返回 1 个退出状态
    • 从 ".ypp" 重命名为 ".y",并从 flex 文件中删除了 "%option c++",现在它可以工作了!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-09-21
    • 1970-01-01
    • 1970-01-01
    • 2020-09-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多