2017-04-04 68 views
0

我一直在試圖建立在野牛一個小解析器,但是當我嘗試建立我得到它:野牛:使用聯盟語義類型與C++解析器

stone.tab.cc: In member function ‘virtual int yy::StoneParser::parse()’: stone.tab.cc:507:81: error: invalid initialization of non-const reference of type ‘StoneDriver&’ from an rvalue of type ‘yy::StoneParser::semantic_type*’ yyla.type = yytranslate_ (yylex (&yyla.value, &yyla.location, driver));

我懷疑的原因是使用由Bison生成的C++編譯器使用聯合定義的語義類型時存在問題,但似乎無法解決它...

如何使用'union'語義定義生成有效的C++ bison分析器?

stone.yy:

%skeleton "lalr1.cc" 
%require "3.0.4" 

%defines 
%define parser_class_name {StoneParser} 

%code requires 
{ 
# include <string> 
class StoneDriver; 
} 

%param { StoneDriver& driver } 

%locations 

%code 
{ 
# include "StoneDriver.hpp" 
} 

%union 
{ 
    int intVal; 
    char* stringVal; 
} 

%token <stringVal> KEY_ENUM 
%token <stringVal> KEY_CLASS 

%token K_TEST 
%token T_ID 

%type <stringVal> class 
%type <stringVal> enum 

%% 

input: toplevel_declarations 

toplevel_declarations: toplevel_declarations toplevel_declaration 
    | %empty 

toplevel_declaration: class 
    | enum 

class: KEY_CLASS { $$ = "test"; } 

enum: KEY_ENUM { $$ = "test"; } 

StoneDriver.hpp

#ifndef STONEDRIVER_INCLUDED_HPP 
#define STONEDRIVER_INCLUDED_HPP 
#include <string> 
#include <map> 
#include "stone.tab.hh" 

class StoneDriver; 

//Tell Flex the lexer's prototype ... 
#define YY_DECL \ 
    yy::StoneParser::symbol_type yylex (StoneDriver& driver) 
// ... and declare it for the parser's sake. 
YY_DECL; 

//Scans and parses Stone 
class StoneDriver 
{ 
    public: 
     //Constructor 
     StoneDriver(); 

     //Destructor 
     virtual ~StoneDriver(); 

    std::map<std::string, int> variables; 

    int result; 
    // Handling the scanner. 
    void scan_begin(); 
    void scan_end(); 
    bool trace_scanning; 
    // Run the parser on file F. 
    // Return 0 on success. 
    int parse (const std::string& f); 
    // The name of the file being parsed. 
    // Used later to pass the file name to the location tracker. 
    std::string file; 
    // Whether parser traces should be generated. 
    bool trace_parsing; 
    // Error handling. 
    void error (const yy::location& l, const std::string& m); 
    void error (const std::string& m); 
};//StoneDriver 

#endif 

StoneDriver.cpp:

#include "StoneDriver.hpp" 
#include "stone.tab.hh" 

StoneDriver::StoneDriver() 
    : trace_scanning (false), trace_parsing (false) 
{ 
    variables["one"] = 1; 
    variables["two"] = 2; 
}//constructor 

StoneDriver::~StoneDriver() 
{ 
}//destructor 

int StoneDriver::parse(const std::string &f) 
{ 
    file = f; 
    scan_begin(); 
    yy::StoneParser parser(*this); 

    #if YYDEBUG 
     parser.set_debug_level(trace_parsing); 
    #endif 

    int res = parser.parse(); 
    scan_end(); 

    return res; 
}//parse 

void StoneDriver::error(const yy::location& l, const std::string& m) 
{ 
    std::cerr << l << ": " << m << std::endl; 
}//error 

void StoneDriver::error(const std::string& m) 
{ 
    std::cerr << m << std::endl; 
}//error 

SOLUTION: RICI表明,YY_DECL方法簽名應該被定義像這樣:

int yylex (semantic_type* YYLVAL, location_type* YYLLOC, TYPE1 ARG1, ...) 

在我的情況下,神奇的路線是:

#define YY_DECL int yylex(yy::StoneParser::semantic_type* const lval, yy::StoneParser::location_type* location, StoneDriver& driver) 
  • yy::是從我的野牛文件(在我的情況stone.yy)
  • StoneParser是從石頭的定義parser_class_name的命名空間。 yy
  • location_type是必需的,因爲stone.yy已定義%位置 。
  • StoneDriver&是stone.yy解析背景下, 定義爲%param { StoneDriver& driver }

感謝您的幫助!

回答

3

錯誤消息提供了一個清楚的指示,說明問題是什麼,雖然它奇怪地集中在yylex的第一個參數中的類型不匹配,而不是你爲yylex提供的原型只有一個參數,而調用有三個參數。鏘更清晰:

stone.tab.cc:474:39: error: no matching function for call to 'yylex' 
      yyla.type = yytranslate_ (yylex (&yyla.value, &yyla.location, driver)); 
             ^~~~~ 
./stone_driver.hpp:14:1: note: candidate function not viable: requires single argument 'driver', but 3 arguments were provided 
YY_DECL; 
^ 

野牛信息文件,第10.1.5.1,描述了yylex從C++掃描器調用約定與union語義類型:

The interface is as follows. 

-- Method on parser: int yylex (semantic_type* YYLVAL, location_type* 
      YYLLOC, TYPE1 ARG1, ...) 
-- Method on parser: int yylex (semantic_type* YYLVAL, TYPE1 ARG1, ...) 
    Return the next token. Its type is the return value, its semantic 
    value and location (if enabled) being YYLVAL and YYLLOC. 
    Invocations of ‘%lex-param {TYPE1 ARG1}’ yield additional 
    arguments. 

這實際上是相同的調用約定與C API中的純解析器一起使用:yylex的前兩個參數(如果位置已啓用,如程序中的情況那樣)是語義值對象的地址和位置對象的地址;第三個和隨後的參數是由%param(如果存在)指定的參數。

所以你應該根據上面的原型修復YY_DECL的定義。

您還必須更改flex動作以將yylval(或任何您稱爲第一個參數的值)視爲指針而不是聯合,這主要表示將.更改爲->