Flex, Bison, C++ - 编译错误

Flex, Bison, C++ - compile error

本文关键字:编译 错误 C++ Bison Flex      更新时间:2023-10-16

我想做一个程序,为函数创建解析树。例如:"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。

我应该更改什么才能使这些东西正常工作?

问题是你正在生成一个C++词法分析器类(使用 .l 文件中的%option c++),而 bison 期待一个 C yylex 函数。 删除%option c++,改为将extern "C" int yyex();添加到.l文件的顶部(或从.y文件中删除extern "C"),一切都应该没问题。

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

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

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

因此,您需要在词法分析器中复制yytext,而不是在解析器中。因此,在词法分析器中,您将执行以下操作:

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

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

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