C++ 解析为std::vector<;字符串>;有了灵气,得到了错误或断言失败

C++ 解析为std::vector<;字符串>;有了灵气,得到了错误或断言失败,c++,parsing,boost,boost-spirit,boost-spirit-qi,C++,Parsing,Boost,Boost Spirit,Boost Spirit Qi,我使用Spirit Qi作为解析器,将数学表达式解析为表达式树。我跟踪在解析时遇到的符号类型,以及必须在解析的文本中声明的符号类型。也就是说,我正在解析,一个简单的ish示例是,一个复杂的示例是,为了完整起见,如下所示: %input: our first input file variable_group x,y; function f,g; f = x^2 - 1; g = y^2 - 4; END; 我一直在研究的语法将是理想的 查找声明语句,然后解析以下以逗号分隔

我使用Spirit Qi作为解析器,将数学表达式解析为表达式树。我跟踪在解析时遇到的符号类型,以及必须在解析的文本中声明的符号类型。也就是说,我正在解析,一个简单的ish示例是,一个复杂的示例是,为了完整起见,如下所示:

%input: our first input file
  variable_group x,y;
  function f,g;

  f = x^2 - 1;
  g = y^2 - 4;
 END;
我一直在研究的语法将是理想的

  • 查找声明语句,然后解析以下以逗号分隔的被声明类型的符号列表,并将得到的符号向量存储在被解析的类对象中;e、 g.
    变量组x,y
  • 查找之前声明的符号,该符号后跟等号,是该符号作为可计算数学对象的定义;e、 g.
    f=x^2-1这部分我大部分都在控制之中
  • 查找之前未声明的符号,后跟
    =
    ,并将其作为子函数进行分析。我想我也能应付
我一直在努力解决的问题似乎很琐碎,但经过几个小时的搜索,我仍然没有找到答案。我已经阅读了几十篇Boost Spirit邮件列表帖子,所以帖子、手册和Spirit的标题本身,但仍然没有对Spirit的一些关键问题进行深入的探讨

下面是有问题的基本语法定义,它将放在
system\u parser.hpp
中:

#define BOOST_SPIRIT_USE_PHOENIX_V3 1


#include <boost/spirit/include/qi_core.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <iostream>
#include <string>




namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;


template<typename Iterator>
struct SystemParser : qi::grammar<Iterator, std::vector<std::string>(), boost::spirit::ascii::space_type>
{


    SystemParser() : SystemParser::base_type(variable_group_)
    {
        namespace phx = boost::phoenix;
        using qi::_1;
        using qi::_val;
        using qi::eps;
        using qi::lit;

        qi::symbols<char,int> encountered_variables;

        qi::symbols<char,int> declarative_symbols;
        declarative_symbols.add("variable_group",0);



        // wraps the vector between its appropriate declaration and line termination.
        BOOST_SPIRIT_DEBUG_NODE(variable_group_);
        debug(variable_group_);
        variable_group_.name("variable_group_");
        variable_group_ %= lit("variable_group") >> genericvargp_ >> lit(';');


        // creates a vector of strings
        BOOST_SPIRIT_DEBUG_NODE(genericvargp_);
        debug(genericvargp_);
        genericvargp_.name("genericvargp_");
        genericvargp_ %= new_variable_ % ',';




        // will in the future make a shared pointer to an object using the string
        BOOST_SPIRIT_DEBUG_NODE(new_variable_);
        debug(new_variable_);
        new_variable_.name("new_variable_");
        new_variable_ %= unencountered_symbol_;


        // this rule gets a string.
        BOOST_SPIRIT_DEBUG_NODE(unencountered_symbol_);
        debug(unencountered_symbol_);
        unencountered_symbol_.name("unencountered_symbol");
        unencountered_symbol_ %= valid_variable_name_ - ( encountered_variables | declarative_symbols);


        // get a string which fits the naming rules.
        BOOST_SPIRIT_DEBUG_NODE(valid_variable_name_);
        valid_variable_name_.name("valid_variable_name_");
        valid_variable_name_ %= +qi::alpha >> *(qi::alnum | qi::char_('_') | qi::char_('[') | qi::char_(']') );



    }


    // rule declarations.  these are member variables for the parser.
    qi::rule<Iterator, std::vector<std::string>(), ascii::space_type > variable_group_;
    qi::rule<Iterator, std::vector<std::string>(), ascii::space_type > genericvargp_;
    qi::rule<Iterator, std::string(), ascii::space_type>  new_variable_;
    qi::rule<Iterator, std::string(), ascii::space_type > unencountered_symbol_;// , ascii::space_type


    // the rule which determines valid variable names
    qi::rule<Iterator, std::string()> valid_variable_name_;
};
#定义助力(精神)使用(凤凰)V3 1
#包括
#包括
#包括
#包括
#包括
#包括
名称空间qi=boost::spirit::qi;
名称空间ascii=boost::spirit::ascii;
模板
结构系统分析器:qi::grammar
{
SystemParser():SystemParser::基本类型(变量组)
{
名称空间phx=boost::phoenix;
使用气::_1;
使用qi:(u val);
使用qi::eps;
使用qi::lit;
qi::遇到的符号\u变量;
qi::符号声明性_符号;
声明性_符号。添加(“变量_组”,0);
//将向量包装在其相应的声明和行终止之间。
BOOST\u SPIRIT\u DEBUG\u节点(变量组);
调试(变量组);
变量组名称(“变量组”);
变量组=lit(“变量组”)>>genericvargp\u>>lit(“;”);
//创建字符串向量
BOOST_SPIRIT_DEBUG_节点(genericvargp_);
调试(genericvargp_u2;);
genericvargp_u2;.name(“genericvargp_2;”);
genericvargp_Ugp%=新的_变量_Ugp%',';
//将来将使用字符串创建指向对象的共享指针
BOOST_SPIRIT_DEBUG_节点(新的_变量_);
调试(新变量);
新变量名称(“新变量”);
新的\u变量\uu%=未计数的\u符号\uu;
//此规则获取一个字符串。
BOOST_SPIRIT_DEBUG_节点(未抵消的_符号);
调试(非计数器符号);
未抵消符号名称(“未抵消符号”);
uncountered_symbol_u%=有效的_变量u名称-(遇到的_变量|声明性_符号);
//获取符合命名规则的字符串。
BOOST\u SPIRIT\u DEBUG\u节点(有效的变量名);
有效变量名称(“有效变量名称”);
有效的_变量名称_u%=+qi::alpha>>*(qi::alnum | qi::char_124;(“124;”)| qi::char_124;(“[”)| qi::char_124;(“]);
}
//规则声明。这些是解析器的成员变量。
qi::规则变量组;
qi::规则genericvargp_u2;;
qi::规则新变量;
qi::规则未计数的\u符号\u;//,ascii::空格\u类型
//确定有效变量名的规则
qi::规则有效\u变量\u名称\u;
};
以及一些使用它的代码:

#include "system_parsing.hpp"



int main(int argc, char** argv)
{


    std::vector<std::string> V;
    std::string str = "variable_group x, y, z;";


    std::string::const_iterator iter = str.begin();
    std::string::const_iterator end = str.end();


    SystemParser<std::string::const_iterator> S;


    bool s = phrase_parse(iter, end, S, boost::spirit::ascii::space, V);

    std::cout << "the unparsed string:\n" << std::string(iter,end);


    return 0;
}
#包括“system_parsing.hpp”
int main(int argc,字符**argv)
{
std::向量V;
std::string str=“变量组x,y,z;”;
std::string::const_迭代器iter=str.begin();
std::string::const_迭代器end=str.end();
系统分析器;
bool s=短语解析(iter,end,s,boost::spirit::ascii::space,V);
std::cout
而不是
变量组规则的定义中,我得到了我们亲爱的老朋友
分段错误:11

在我的学习过程中,我遇到了诸如、、之类的优秀帖子,它们导致了一个segfault,它有一个使用定制点的链接(但链接中没有示例),它将关键字与动作结合起来,也许与我正在尝试做的事情最相关,这当然是我需要的,因为符号集在增长,我不允许以后将它们用作另一种类型,因为已经遇到的符号集开始变空,并且在增长——它的解析规则是动态的

这就是我的问题所在。我当前的问题是这个特定示例生成的assert/segfault。然而,我对一些事情不清楚,需要一些指导性建议,我只是没有从我咨询过的任何来源收集到这些建议,而我的请求希望使这个问题与之前提出的其他问题脱节:

  • 什么时候使用词素合适?我只是不知道什么时候使用词素,也不知道
  • 关于何时使用
    >
    而不是
    >
    有哪些指导原则
  • 我见过许多Fusion adapt示例,其中有一个要解析的结构和一组规则。我的输入文件可能会多次出现函数、变量等的声明,这些声明都需要放在同一个位置,因此我需要能够以任何方式添加到要解析的terminal class对象的字段中顺序,多次。我想我想对类对象使用getter/setter,这样解析就不是构建对象的唯一途径。这是个问题吗
欢迎向初学者提供任何建议。

<
#define BOOST_SPIRIT_USE_PHOENIX_V3 1
#define BOOST_SPIRIT_DEBUG 1

#include <boost/spirit/include/qi_core.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <iostream>
#include <string>

namespace qi    = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;

template <typename Iterator, typename Skipper = ascii::space_type>
struct SystemParser : qi::grammar<Iterator, std::vector<std::string>(), Skipper> {

    SystemParser() : SystemParser::base_type(variable_group_) 
    {
        declarative_symbols += "variable_group";

        variable_group_        = "variable_group" >> genericvargp_ >> ';';
        genericvargp_          = new_variable_ % ',';
        valid_variable_name_   = qi::alpha >> *(qi::alnum | qi::char_("_[]"));
        unencountered_symbol_  = valid_variable_name_ - (encountered_variables|declarative_symbols);
        new_variable_          = unencountered_symbol_;

        BOOST_SPIRIT_DEBUG_NODES((variable_group_) (valid_variable_name_) (unencountered_symbol_) (new_variable_) (genericvargp_))
    }
  private:

    qi::symbols<char, qi::unused_type> encountered_variables, declarative_symbols;

    // rule declarations.  these are member variables for the parser.
    qi::rule<Iterator, std::vector<std::string>(), Skipper> variable_group_;
    qi::rule<Iterator, std::vector<std::string>(), Skipper> genericvargp_;
    qi::rule<Iterator, std::string()> new_variable_;
    qi::rule<Iterator, std::string()> unencountered_symbol_; // , Skipper

    // the rule which determines valid variable names
    qi::rule<Iterator, std::string()> valid_variable_name_;
};

//#include "system_parsing.hpp"

int main() {

    using It = std::string::const_iterator;
    std::string const str = "variable_group x, y, z;";

    SystemParser<It> S;

    It iter = str.begin(), end = str.end();
    std::vector<std::string> V;
    bool s = phrase_parse(iter, end, S, boost::spirit::ascii::space, V);

    if (s)
    {
        std::cout << "Parse succeeded: " << V.size() << "\n";
        for (auto& s : V)
            std::cout << " - '" << s << "'\n";
    }
    else
        std::cout << "Parse failed\n";

    if (iter!=end)
        std::cout << "Remaining unparsed: '" << std::string(iter, end) << "'\n";
}
Parse succeeded: 3
 - 'x'
 - 'y'
 - 'z'