解析其他命名集的多个命名集 [英] Parsing a number of named sets of other named sets

查看:94
本文介绍了解析其他命名集的多个命名集的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我想写一个...好...不是那么简单的解析器与boost :: spirit :: qi。我知道提升精神的光明基础,在过去几个小时里第一次熟悉它。



基本上我需要解析这个:

 #comment 

#其他评论

设置Myset A
{
figureAF 1
{
i 0 0 0
i 1 2 5
i 1 1 1
f 3.1 45.11 5.3
i 3 1 5
f 1.1 2.33 5.166
}

figureAF 2
{
i 25 5 1
i 3 1 3
}
}

#comment

setMyset B
{
figureBF 1
{
f 23.1 4.3 5.11
}
}

设置Myset C
{
包括Myset A#包括Myset A的所有数字

数字CF
{
i 1 1 1
f 3.11 5.33 3
}
}

进入:

  struct int_point {int x,y,z; }; 
struct float_point {float x,y,z; };

struct figure
{
string name;
vector< int_point> int_points;
vector< float_point> float_points;
};

struct figure_set
{
string name;
vector< figure>数字
};

矢量< figure_set> figure_sets; //填充输入的数据

现在,显然有人为我写了很多,但你能提供一些提示,什么读,以及如何结构的语法和解析器这个任务吗?



还可能是这种情况那boost:精神不是我可以用于任务的最好的图书馆。如果是,哪一个是?



编辑:
这里是我到目前为止。但我还不确定如何继续: http://liveworkspace.org/code/212c31dfc0b6fbdf6c462d8d931c0e9f



我能够读取一个数字,但我还不知道如何解析一组数字。

解决方案

这是我的收获



我相信,

  figure = eps>> figure
>> name [at_c< 0(_ val)= _1]> '{'>>
*(
ipoints [push_back(at_c'(_ val),_1)]
| fpoints [push_back(at_c 2(_ val),_1)]
) >> '}';

这实际上是一个事实的症状,你解析混合 i f 行分隔成单独的容器。

>



这是我的完整代码: test.cpp

  // #include BOOST_SPIRIT_DEBUG //包括Spirit 
#define BOOST_SPIRIT_USE_PHOENIX_V3
#include< boost / fusion / adapted.hpp>
#include< boost / spirit / include / qi.hpp>
#include< boost / spirit / include / karma.hpp>
#include< boost / spirit / include / phoenix.hpp>
#include< boost / spirit / include / phoenix_fusion.hpp>
#include< fstream>

命名空间格式
{
struct int_point {int x,y,z; };
struct float_point {float x,y,z; };

struct figure
{
std :: string name;
std :: vector< int_point> int_points;
std :: vector& float_point> float_points;

friend std :: ostream& operator<<(std :: ostream& os,figure const& o);
};

struct figure_set
{
std :: string name;
std :: set< std :: string>包括;
std :: vector< figure>人物;

friend std :: ostream& operator<<(std :: ostream& os,figure_set const& o);
};

typedef std :: vector< figure_set> file_data;
}

BOOST_FUSION_ADAPT_STRUCT(Format :: int_point,
(int,x)(int,y)(int,z))
BOOST_FUSION_ADAPT_STRUCT ,
(float,x)(float,y)(float,z))
BOOST_FUSION_ADAPT_STRUCT(Format :: figure,
(std :: string,name)
:: vector< Format :: int_point>,int_points)
(std :: vector< Format :: float_point>,float_points))
BOOST_FUSION_ADAPT_STRUCT(Format :: figure_set,
(std :: string,name)
(std :: set< std :: string> include)
(std :: vector< Format :: figure> figures))

命名空间格式
{
std :: ostream& operator<<<(std :: ostream& os,figure const& o)
{
using namespace boost :: spirit :: karma;
return os<< format_delimited(
\\\
figure< {
& < *(\\\
i<<< *(\\\
f<< float_< <<< float_)
<<\ n}
,'',o)
}

std :: ostream& operator<<<<(std :: ostream& os,figure_set const& o)
{
using namespace boost :: spirit :: karma;
return os<< format_delimited(
\\\
set< {
< ; *(\\\
include< << * stream
< \\\
}
,'',o);
}
}

命名空间/ * anon * /
{
命名空间phx = boost :: phoenix;
namespace qi = boost :: spirit :: qi;

template< typename Iterator> struct skipper
:public qi :: grammar< Iterator>
{
skipper():skipper :: base_type(start,skipper)
{
using namespace qi;

comment ='#'>> *(char_-eol)>> (eol | eoi);
start = comment | qi :: space;

BOOST_SPIRIT_DEBUG_NODE(start);
BOOST_SPIRIT_DEBUG_NODE(comment);
}

private:
qi :: rule< Iterator>开始,评论
};

template< typename Iterator> struct parser
:public qi :: grammar< Iterator,Format :: file_data(),skipper< Iterator> >
{
parser():parser :: base_type(start,parser)
{
using namespace qi;
using phx :: push_back;
using phx :: at_c;

name = eps>> lexeme ['''>> *〜char_('')>> ''';;

include = eps>"" include>> name;
ipoints = eps>>i>> int_> > int_>> int_;
fpoints = eps>>f>> float_>> float_>> float_;

figure = eps >>figure
>> name [at_c< 0>(_ val)= _1]> push_back(at_c 1(_ val),_1)]
| fpoints [push_back(at_c 2(_ val),_1)]
)>>'}';
set = eps>"set>>>>> ;
}

private:
qi :: rule< Iterator,std :: string(),skipper< Iterator>> name,include;
qi: :rule< Iterator,Format :: int_point(),skipper< Iterator> >英语:ipoints
qi :: rule< Iterator,Format :: float_point(),skipper< Iterator> > fpoint;
qi :: rule< Iterator,Format :: figure(),skipper< Iterator> >数字;
qi :: rule< Iterator,Format :: figure_set(),skipper< Iterator> >组;
qi :: rule< Iterator,Format :: file_data(),skipper< Iterator> >开始;
};
}

namespace Parser {

bool parsefile(const std :: string& spec,Format :: file_data& data)
{
std :: ifstream in(spec.c_str());
in.unsetf(std :: ios :: skipws);

std :: string v;
v.reserve(4096);
v.insert(v.end(),std :: istreambuf_iterator< char>(in.rdbuf()),std :: istreambuf_iterator< char>());

if(!in)
return false;

typedef char const * iterator_type;
iterator_type first =& v [0];
iterator_type last = first + v.size();

try
{
parser< iterator_type> p;
skipper< iterator_type> s;
bool r = qi :: phrase_parse(first,last,p,s,data);

r = r&& (first == last);

if(!r)
std :: cerr<< spec<< :parsing failed at:\<< std :: string(first,last)<<\\\\

return r;
}
catch(const qi :: expectation_failure< char const *>& e)
{
std :: cerr< FIXME:expected< e.what_< ,得到< std :: string(e.first,e.last)<< '< std :: endl;
return false;
}
}
}

int main()
{
Format :: file_data data;
bool ok = Parser :: parsefile(input.txt,data);

std :: cerr<< Parse<< (ok?success:failed)<< std :: endl;
std :: cout<< #figure set由karma \\\
\\\
自动导出;

for(auto& set:data)
std :: cout<组;
}

输出解析数据作为验证: output.txt

 解析成功
#由karma自动导出的数字集


设置Myset A
{
figureAF 1
{
i 0 0 0
i 1 2 5
i 1 1 1
i 3 1 5
f 3.1 45.11 5.3
f 1.1 2.33 5.166
}
figureAF 2
{
i 25 5 1
i 3 1 3
}
}
设置Myset B
{
figureBF 1
{
f 23.1 4.3 5.11
}
}
设置Myset C
{
包括Myset A
figureCF
{
i 1 1 1
f 3.11 5.33 3.0
}
}

您会注意到




  • 点线的顺序改变(所有 int_points 先于 float_points

  • 也,添加非有效数字,例如最后一行 3.0 而不是 3 ,以显示float类型。




替代



有原始顺序的实际点行:

  typedef boost :: variant  
struct figure
{
std :: string name;
std :: vector< if_point> if_points;
}

现在规则变得简单:

  name = eps>> lexeme ['''>> *〜char_('')>> ''';; 

include = eps>"" include>> name;
ipoints = eps>>i>> int_> > int_>> int_;
fpoints = eps>>f>> float_>> float_>> float_;

figure = eps >"figure>>>>> name>> >> name>>'{'>> * include>> * figure>>'}';
start = * set;

注意

中的优雅

  = eps>""figure>>>>>> 

并且输出按照输入的确切顺序: output.txt



完整的演示代码(仅限github): test.cpp



奖金更新



最后,我制作了第一个正确的Karma语法输出结果:

  name = no_delimit [''<< string<< ''';; 
include =include<<<< name;
ipoints =\\\
i<< int_<< int_< b fpoints =\\\
f<< float_<< float_<< float_;

figure =figure< {<< *(ipoints | fpoints)<<\\\
};
set =set< b <*(\ n<< include)
<<< *(\\\
<<图<

start =由karma \\\
\\\
自动导出的#图集
<< set%eol;
pre>

这实际上比我预期的更舒服。在最新版本的完全更新的提示 test.hpp


So I want to write a... well... not-so-simple parser with boost::spirit::qi. I know the bare basics of boost spirit, having gotten acquainted with it for the first time in the past couple of hours.

Basically I need to parse this:

# comment

# other comment

set "Myset A"
{
    figure "AF 1"
    {
        i 0 0 0
        i 1 2 5
        i 1 1 1
        f 3.1 45.11 5.3
        i 3 1 5
        f 1.1 2.33 5.166
    }

    figure "AF 2"
    {
        i 25 5 1
        i 3 1 3
    }
}

# comment

set "Myset B"
{
    figure "BF 1"
    {
        f 23.1 4.3 5.11
    }
}

set "Myset C"
{
    include "Myset A" # includes all figures from Myset A

    figure "CF"
    {
        i 1 1 1
        f 3.11 5.33 3
    }
}

Into this:

struct int_point { int x, y, z; };
struct float_point { float x, y, z; };

struct figure
{
    string name;
    vector<int_point> int_points;
    vector<float_point> float_points;
};

struct figure_set
{
    string name;
    vector<figure> figures
};

vector<figure_set> figure_sets; // fill with the data of the input

Now, obviously having somebody write it for me would be too much, but can you please provide some tips on what to read and how to structure the grammar and parsers for this task?

And also... it may be the case that boost::spirit is not the best library I could use for the task. If so, which one is?

EDIT: Here's where I've gotten so far. But I'm not yet sure how to go on: http://liveworkspace.org/code/212c31dfc0b6fbdf6c462d8d931c0e9f

I am able to read a single figure but, I don't yet have an idea how to parse a set of figures.

解决方案

Here's my take on it

I believe the rule that will have been the blocker for you would be

figure  = eps >> "figure" 
    >> name         [ at_c<0>(_val) = _1 ] >> '{' >> 
    *(
            ipoints [ push_back(at_c<1>(_val), _1) ]
          | fpoints [ push_back(at_c<2>(_val), _1) ]
     ) >> '}';

This is actually a symptom of the fact that you parse inter-mixed i and f lines into separate containers.

See below for an alternative.

Here's my full code: test.cpp

//#define BOOST_SPIRIT_DEBUG // before including Spirit
#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/fusion/adapted.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/karma.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>
#include <fstream>

namespace Format
{
    struct int_point   { int x, y, z;   }; 
    struct float_point { float x, y, z; }; 

    struct figure
    {
        std::string              name;
        std::vector<int_point>   int_points;
        std::vector<float_point> float_points;

        friend std::ostream& operator<<(std::ostream& os, figure const& o);
    };

    struct figure_set
    {
        std::string           name;
        std::set<std::string> includes;
        std::vector<figure>   figures;

        friend std::ostream& operator<<(std::ostream& os, figure_set const& o);
    };

    typedef std::vector<figure_set> file_data;
}

BOOST_FUSION_ADAPT_STRUCT(Format::int_point,   
        (int, x)(int, y)(int, z))
BOOST_FUSION_ADAPT_STRUCT(Format::float_point, 
        (float, x)(float, y)(float, z))
BOOST_FUSION_ADAPT_STRUCT(Format::figure,      
        (std::string, name)
        (std::vector<Format::int_point>, int_points)
        (std::vector<Format::float_point>, float_points))
BOOST_FUSION_ADAPT_STRUCT(Format::figure_set,  
        (std::string, name)
        (std::set<std::string>, includes)
        (std::vector<Format::figure>, figures))

namespace Format
{
    std::ostream& operator<<(std::ostream& os, figure const& o)
    {
        using namespace boost::spirit::karma;
        return os << format_delimited(
                "\n    figure" << no_delimit [ '"' << string << '"' ] << "\n    {"
                << *("\n       i" << int_ << int_ << int_)
                << *("\n       f" << float_ << float_ << float_)
                << "\n    }"
                , ' ', o);
    }

    std::ostream& operator<<(std::ostream& os, figure_set const& o)
    {
        using namespace boost::spirit::karma;
        return os << format_delimited(
                "\nset" << no_delimit [ '"' << string << '"' ] << "\n{"
                << *("\n    include " << no_delimit [ '"' << string << '"' ])
                << *stream
                << "\n}"
                , ' ', o);
    }
}

namespace /*anon*/
{
    namespace phx=boost::phoenix;
    namespace qi =boost::spirit::qi;

    template <typename Iterator> struct skipper
        : public qi::grammar<Iterator>
    {
        skipper() : skipper::base_type(start, "skipper")
        {
            using namespace qi;

            comment = '#' >> *(char_ - eol) >> (eol|eoi);
            start   = comment | qi::space;

            BOOST_SPIRIT_DEBUG_NODE(start);
            BOOST_SPIRIT_DEBUG_NODE(comment);
        }

      private:
        qi::rule<Iterator> start, comment;
    };

    template <typename Iterator> struct parser
        : public qi::grammar<Iterator, Format::file_data(), skipper<Iterator> >
    {
        parser() : parser::base_type(start, "parser")
        {
            using namespace qi;
            using phx::push_back;
            using phx::at_c;

            name    = eps >> lexeme [ '"' >> *~char_('"') >> '"' ];

            include = eps >> "include" >> name;
            ipoints = eps >> "i"       >> int_         >> int_   >> int_;
            fpoints = eps >> "f"       >> float_       >> float_ >> float_;

            figure  = eps >> "figure" 
                >> name         [ at_c<0>(_val) = _1 ] >> '{' >> 
                *(
                        ipoints [ push_back(at_c<1>(_val), _1) ]
                      | fpoints [ push_back(at_c<2>(_val), _1) ]
                 ) >> '}';
            set     = eps >> "set" >> name >> '{' >> *include >> *figure >> '}';
            start   = *set;
        }

      private:
        qi::rule<Iterator, std::string()        , skipper<Iterator> > name, include;
        qi::rule<Iterator, Format::int_point()  , skipper<Iterator> > ipoints;
        qi::rule<Iterator, Format::float_point(), skipper<Iterator> > fpoints;
        qi::rule<Iterator, Format::figure()     , skipper<Iterator> > figure;
        qi::rule<Iterator, Format::figure_set() , skipper<Iterator> > set;
        qi::rule<Iterator, Format::file_data()  , skipper<Iterator> > start;
    };
}

namespace Parser {

    bool parsefile(const std::string& spec, Format::file_data& data)
    {
        std::ifstream in(spec.c_str());
        in.unsetf(std::ios::skipws);

        std::string v;
        v.reserve(4096);
        v.insert(v.end(), std::istreambuf_iterator<char>(in.rdbuf()), std::istreambuf_iterator<char>());

        if (!in) 
            return false;

        typedef char const * iterator_type;
        iterator_type first = &v[0];
        iterator_type last = first+v.size();

        try
        {
            parser<iterator_type>  p;
            skipper<iterator_type> s;
            bool r = qi::phrase_parse(first, last, p, s, data);

            r = r && (first == last);

            if (!r)
                std::cerr << spec << ": parsing failed at: \"" << std::string(first, last) << "\"\n";
            return r;
        }
        catch (const qi::expectation_failure<char const *>& e)
        {
            std::cerr << "FIXME: expected " << e.what_ << ", got '" << std::string(e.first, e.last) << "'" << std::endl;
            return false;
        }
    }
}

int main()
{
    Format::file_data data;
    bool ok = Parser::parsefile("input.txt", data);

    std::cerr << "Parse " << (ok?"success":"failed") << std::endl;
    std::cout << "# figure sets exported automatically by karma\n\n";

    for (auto& set : data)
        std::cout << set;
}

It outputs the parsed data as a verification: output.txt

Parse success
# figure sets exported automatically by karma


set "Myset A"
{ 
    figure "AF 1"
    { 
       i 0 0 0 
       i 1 2 5 
       i 1 1 1 
       i 3 1 5 
       f 3.1 45.11 5.3 
       f 1.1 2.33 5.166 
    }  
    figure "AF 2"
    { 
       i 25 5 1 
       i 3 1 3 
    }  
} 
set "Myset B"
{ 
    figure "BF 1"
    { 
       f 23.1 4.3 5.11 
    }  
} 
set "Myset C"
{ 
    include  "Myset A"
    figure "CF"
    { 
       i 1 1 1 
       f 3.11 5.33 3.0 
    }  
}

You will note that

  • the order of the point lines are changed (all int_points precede all float_points)
  • also, non-significant digits are added, e.g. in the last line 3.0 instead of 3 to show that the type if float.
  • you had 'forgotten' (?) about the includes in your question

Alternative

Have something that keeps the actual point lines in original order:

typedef boost::variant<int_point, float_point> if_point;

struct figure
{
    std::string            name;
    std::vector<if_point>  if_points;
}

Now the rules become simply:

name    = eps >> lexeme [ '"' >> *~char_('"') >> '"' ];

include = eps >> "include" >> name;
ipoints = eps >> "i"       >> int_         >> int_   >> int_;
fpoints = eps >> "f"       >> float_       >> float_ >> float_;

figure  = eps >> "figure" >> name >> '{' >> *(ipoints | fpoints) >> '}';
set     = eps >> "set"    >> name >> '{' >> *include >> *figure  >> '}';
start   = *set;

Note the elegance in

figure  = eps >> "figure" >> name >> '{' >> *(ipoints | fpoints) >> '}';

And the output stays in the exact order of the input: output.txt

Once again, full demo code (on github only): test.cpp

Bonus update

Finally, I made my first proper Karma grammar to output the results:

name    = no_delimit ['"' << string << '"'];
include = "include" << name;
ipoints = "\n        i" << int_   << int_   << int_;
fpoints = "\n        f" << float_ << float_ << float_;

figure  = "figure" << name << "\n    {" << *(ipoints | fpoints) << "\n    }";
set     = "set"    << name << "\n{" 
            << *("\n   " << include)
            << *("\n   " << figure)  << "\n}";

start   = "# figure sets exported automatically by karma\n\n" 
            << set % eol;

That was actually considerably more comfortable than I had expected. See it in the lastest version of the fully updated gist: test.hpp

这篇关于解析其他命名集的多个命名集的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆