段故障试图在类中使用boost::spirit::qi解析器

Segfault trying to use boost::spirit::qi parser in a class

本文关键字:boost spirit qi 故障 段故障      更新时间:2023-10-16

我一直在使用boost::spirit编写一些解析器代码,并开始获得段错误。

我已经尽可能地简化了我的代码,以便于发布,见下文。

段错误发生在解析器回调addModule时回推int的过程中。

Valgrind声明vector v_modules没有初始化。在代码的早期,我可以看到它是初始化的,所以我假设一些内存垃圾正在发生。我曾多次尝试用这个较小的测试用例重写它,但都无济于事。任何帮助,感谢!

verilog.cpp:

#include "verilog.h"
#include <string>
#include <boost/spirit/include/qi.hpp>
Verilog::Verilog() {
  m_parser.verilog = this;
}
Verilog::~Verilog(){}
void Verilog::parse(string contents) {
  string::const_iterator iter = contents.begin();
  string::const_iterator end = contents.end();
  bool r = phrase_parse(iter,end,m_parser,boost::spirit::ascii::space);
}
void Verilog::addModule() {
  int new_mod = 1;
  v_modules.push_back(new_mod);
}
int main()
{
  Verilog* verilog = new Verilog();
  string contents = "hello";
  verilog->parse(contents);
}

verilog.h

#ifndef VERILOG_H
#define VERILOG_H
#include <iostream>
#include <string>
#include <boost/spirit/include/qi.hpp>
#include <boost/bind.hpp>
using namespace std;
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
class Verilog
{
 public:
  Verilog();
  ~Verilog();
  void parse(string contents);
  void addModule() ;
  template <typename Iterator>
    struct verilog_parser : qi::grammar<Iterator, ascii::space_type>  
    {
    verilog_parser() : verilog_parser::base_type(module)
        {
          module = qi::eps[boost::bind(&Verilog::addModule, verilog)];
        }
      qi::rule<Iterator, ascii::space_type> module;
      Verilog* verilog;
    };
 private:
  std::vector<int>    v_modules;
  verilog_parser<string::const_iterator> m_parser;
};
#endif

您使用的boost::bind导致一个临时函数对象,该对象引用verilog成员在语法构建期间指向的任何内容。

没用的。

您需要一个phoenix lazy actor,如果您希望它在您从Verilog构造函数中设置它后拾取更改的值,那么您最好让它通过_reference引用this->verilog

老实说,代码看起来有点笨拙。为什么不使用Spirit的属性兼容性规则来自动构建向量(或列表、集合、映射……)等等)给你?

这里有一个修复:

#include <boost/spirit/include/phoenix.hpp>
namespace phx = boost::phoenix;
// ... later
            module = qi::eps[phx::bind(&Verilog::addModule, phx::ref(verilog))];

注意,这仍然在main中留下泄漏的Verilog实例。为什么在现代c++中使用new ?

集成:

Live On Coliru

#include <iostream>
#include <string>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/bind.hpp>
using namespace std;
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
namespace phx = boost::phoenix;
class Verilog {
  public:
    Verilog();
    ~Verilog();
    void parse(string contents);
    void addModule();
    template <typename Iterator> struct verilog_parser : qi::grammar<Iterator, ascii::space_type> {
        verilog_parser() : verilog_parser::base_type(module) {
            module = qi::eps[phx::bind(&Verilog::addModule, phx::ref(verilog))];
        }
        qi::rule<Iterator, ascii::space_type> module;
        Verilog *verilog;
    };
  private:
    std::vector<int> v_modules;
    verilog_parser<string::const_iterator> m_parser;
};
#include <string>
#include <boost/spirit/include/qi.hpp>
Verilog::Verilog() { m_parser.verilog = this; }
Verilog::~Verilog() {}
void Verilog::parse(string contents) {
    string::const_iterator iter = contents.begin();
    string::const_iterator end = contents.end();
    bool r = phrase_parse(iter, end, m_parser, boost::spirit::ascii::space);
}
void Verilog::addModule() {
    int new_mod = 1;
    v_modules.push_back(new_mod);
}
int main() {
    Verilog verilog;
    string contents = "hello";
    verilog.parse(contents);
}