2013-09-21 112 views
0

我想製作一個程序,它爲函數創建一個分析樹。例如:「f(g(x,h(y),v,k(l(c))))」可能是一個有效的函數調用。Flex,Bison,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。

我應該改變什麼才能使這些東西有效?

+0

問題出在鏈接器上。它無法找到'yylex'函數的定義?你正在編譯它的定義存在的源文件嗎? – Mahesh

+0

flex工具生成yylex()函數。您不得編譯它生成的源代碼。 –

回答

0

的問題是,你生成一個C++詞法分析器類(在.l文件中使用%option c++),而野牛期待C yylex函數。刪除%option c++,而是將extern "C" int yyex();添加到.l文件的頂部(或從.y文件中刪除extern "C"),並且都應該沒問題。

0

您正在生成C++ yylex,然後在解析器中將其聲明爲extern "C"。 C++函數和C函數不具有相同的名稱(即使它們看上去),因此鏈接程序找不到yylex(或_yylex,因爲它實際上被稱爲)。

刪除外部「C」從這兩個聲明,它可能會鏈接。

您應該將您的%union中的char* s更改爲std::string* s;否則,你會遇到最常見的野牛/ flex問題之一,初學者:C字符串yytext指出,直到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; 
     } 
+0

我收到以下錯誤消息: h1.ypp:23:錯誤:成員'std ::字符串YYSTYPE :: s'不允許在工會構造函數 h1.ypp:23:錯誤:成員'std ::字符串YYSTYPE :: s'在工會中不允許使用析構函數 h1.ypp:23:錯誤:成員'std ::字符串YYSTYPE:s'在工會中不允許使用複製賦值運算符 –

+0

@DavidAngyal:糟糕。這是真的,你不能把弦放在工會裏;它必須是一個結構。您必須將其設置爲一個字符串*並將賦值更改爲'yylval.s = new std :: string(yytext)';那麼在你擁有'TERM_ID'的野牛行動中,而不是$$ - > name ='new string($ 1)',你可以做'$$ - > name = $ 1'。(已更改回復以反映評論) – rici

+0

現在,此消息再次顯示:體系結構x86_64的未定義符號: 「yylex()」,引用來自: yXparse()in ccXWYT6Z.o ld:找不到架構x86_64的符號 collect2:ld返回1退出狀態 –