【问题标题】:Bison: using the Union semantic type with a C++ parserBison:使用带有 C++ 解析器的 Union 语义类型
【发布时间】:2017-04-04 22:42:15
【问题描述】:

我一直在尝试在 Bison 中设置一个小解析器,但是当我尝试构建它时,我得到:

stone.tab.cc:在成员函数“virtual int yy::StoneParser::parse()”中: stone.tab.cc:507:81:错误:从“yy::StoneParser::semantic_type*”类型的右值初始化“StoneDriver&”类型的非常量引用无效 yyla.type = yytranslate_(yylex(&yyla.value, &yyla.location, driver));

我怀疑原因是使用联合定义的语义类型和野牛生成的 C++ 编译器存在问题,但我似乎无法解决它...

如何生成具有“联合”语义定义的有效 C++ 野牛解析器?

石头.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

解决方案: 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:: 是我的 Bison 文件中的命名空间(在我的例子中是 stone.yy)
  • StoneParser 是来自 stone.yy 的定义的 parser_class_name
  • location_type 是必需的,因为 stone.yy 有 %locations 已定义。
  • StoneDriver&amp; 是来自stone.yy 的解析上下文, 定义为%param { StoneDriver&amp; driver }

感谢您的帮助!

【问题讨论】:

    标签: c++ bison


    【解决方案1】:

    错误消息提供了一些明确的指示,虽然它奇怪地集中在yylex 的第一个参数中的类型不匹配,而不是您为yylex 提供的原型只有一个参数,而调用具有三个参数。 Clang 更清晰:

    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;
    ^
    

    bison 信息文件,第 10.1.5.1 节,描述了 yylex 从具有 union 语义类型的 C++ 扫描程序的调用约定:

    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(或任何您调用的第一个参数)视为指针而不是联合,这主要意味着将 . 更改为 -&gt;

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多