ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

c-使用Spirit Qi解析为std :: vector,获取段错误或断言失败

2019-10-13 21:17:41  阅读:234  来源: 互联网

标签:boost-spirit-qi c parsing boost boost-spirit


我使用Spirit Qi作为解析器,将数学表达式解析为表达式树.我跟踪诸如在解析时遇到的符号类型之类的事情,这些符号必须在要解析的文本中声明.即,我正在解析Bertini input files,为简化起见,其简单示例为here,复杂示例为here,如下所示:

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

  f = x^2 - 1;
  g = y^2 - 4;
 END;

我一直在努力的语法将理想地

>查找声明语句,然后解析以下用逗号分隔的声明类型的符号列表,并将符号的结果矢量存储在要解析的类对象中;例如variable_group x,y;
>找到一个先前声明的符号,后跟一个等号,并且将该符号定义为可评估的数学对象;例如f = x ^ 2-1-;这部分我大部分处于控制之下.
>找到一个之前未声明的符号,后跟=,然后将其解析为子函数.我想我也可以解决.

我一直在努力解决的问题似乎微不足道,但是经过数小时的搜索,我仍然没有到达那里.我已经阅读了数十个Boost Spirit邮件列表帖子,SO帖子,手册和Spirit本身的标题,但仍然不太了解Spirit Spirit解析的一些关键事项.

这是有问题的基本语法定义,将在system_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_;
};

和一些使用它的代码:

#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;
}

它可以在OSX的Clang 4.9.x下编译.当我运行它时,我得到:

断言失败:(px!= 0),函数operator->,文件/usr/local/include/boost/smart_ptr/shared_ptr.hpp,第648行.

或者,如果我使用期望运算符>而不是>>在variable_group_规则的定义中,我得到了我们亲爱的老朋友细分错误:11.

在学习过程中,我遇到了一些很棒的帖子,例如how to tell the type spirit is trying to generateattribute propagationhow to interact with symbolsan example of infinite left recursion会导致段错误,information on parsing into classes, not structs包含使用自定义点的链接(但这些链接中没有示例),the Nabialek trick则将关键字与动作,可能与我要执行的操作最相关dynamic difference parsing,这肯定是我所需要的,因为符号集不断增长,并且由于已经遇到的符号集开始为空,因此我后来不允许将它们用作另一种类型,并且增长-解析规则是动态的.

所以这就是我的位置.我当前的问题是此特定示例生成的断言/段错误.但是,我在某些事情上还不清楚,需要指导性意见,我只是没有从我咨询过的任何资料中收集到指导意见,而希望该要求使该SO问题与之前提出的其他问题脱节的请求是:

>什么时候使用lexeme?我只是不知道何时使用lexeme,而不是.
>何时使用>有哪些准则?而不是>&gt ;?
>我已经看过许多Fusion适应示例,其中有一个要解析的结构以及要执行的一组规则.我的输入文件可能会多次出现函数,变量等的声明,它们都需要放在同一位置,所以我需要能够以任意顺序添加到要解析到的终端类对象的字段中, 多次.我想我想对类对象使用getter / setters,因此解析不是构造对象的唯一途径.这有问题吗?

对此初学者的任何建议都是最欢迎的.

解决方法:

您引用符号变量.但是它们是本地人,因此一旦构造函数返回,它们便不存在.这将调用Undefined Behaviour.任何事情都可能发生.

使symmbol表成为该类的成员.

也简化了周围的舞蹈

>船长(请参见Boost spirit skipper issues).该链接还会回答您的_“何时使用lexeme []是适当的.例如,在您的示例中,您在遭遇到的变量| declarative_symbols附近缺少lexeme [].
>调试宏
>运算符%=,以及一些通常未使用的内容
>猜测您不需要符号的映射类型. (因为没有使用int),简化了那里的初始化

演示

Live On Coliru

#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'

标签:boost-spirit-qi,c,parsing,boost,boost-spirit
来源: https://codeday.me/bug/20191013/1910519.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有