使用Boost :: Spirit解析time_period表达式 [英] Parse time_period expression with Boost::Spirit

查看:225
本文介绍了使用Boost :: Spirit解析time_period表达式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要使用Boost :: Spirit解析以下EBNF表达式。

I need to parse following EBNF expression with Boost::Spirit.

period ::= date_part [time_part] , date_part [time_part]
time_part ::= hours:minutes[:seconds]
date_part ::= day.month.year

例如, 10.06.2014 10:00:15,11.07.2014

1)第一次尝试

    struct Parser: grammar<std::string::const_iterator, space_type>
    {
        Parser(): Parser::base_type(datetime_)
        {
            using boost::spirit::int_;

            using boost::spirit::qi::_1;
            using boost::spirit::qi::_2;

            using boost::spirit::qi::_val;

            datetime_ =
                (date_ >> time_)
                [
                  _val =
                    phoenix::construct<ptime>
                    (
                      date(_1[2]), _1[1], _1[0]),
                hours(_2[0]) + minutes(_2[1]) + seconds[_2[0]]
                    )
                  |
                  _val =
                    phoenix::construct<ptime>
                    (
                      date(_1[2]), _1[1], _1[0]),
                seconds(0)
                    )
                ];

            date_ %= int_ % '.';
            time_ %= int_ % ':';

            BOOST_SPIRIT_DEBUG_NODE(datetime_);
            BOOST_SPIRIT_DEBUG_NODE(date_);
            BOOST_SPIRIT_DEBUG_NODE(time_);
        }

        rule<std::string::const_iterator, std::vector<int>(), space_type> date_, time_;
        rule<std::string::const_iterator, ptime(), space_type> datetime_;
    }

    Parser parser;
    std::string strTest("10.06.2014 10:00:15, 11.07.2014");

    std::string::const_iterator it_begin(strTest.begin());
    std::string::const_iterator it_end(strTest.end());

    bool result = phrase_parse(it_begin, it_end, parser, space);

错误:

/media/Data/Projects/Qt/Planner/parser.h:108:ошибка:没有匹配的函数调用'boost :: gregorian :: date :: date(boost :: phoenix :: detail :: make_index_composite< boost :: phoenix :: actor< boost :: spirit :: argument< 0>>,int> :: type)'

等等。我不能将 boost :: spirit :: argument< 0> 转换为 int date :: years_type 。我尝试 date((int)_1 [2]),(int)_1 [1],(int)_1 [0])) dynamic_cast< int>(_ 1 [2]),但没有成功(。

And so on. I can't cast boost::spirit::argument<0> to int or date::years_type. I tryed date((int)_1[2]), (int)_1[1], (int)_1[0])) and dynamic_cast<int>(_1[2]), but with no success (.

2)第二次尝试

    struct Parser: grammar<std::string::const_itearator, space_type>
    {
        Parser(ConditionTree& a_lTree):
            Parser::base_type(time_period_),
            m_lTree(a_lTree)
        {
            using boost::spirit::int_;

            using boost::spirit::qi::_1;
            using boost::spirit::qi::_2;
            using boost::spirit::qi::_3;
            using boost::spirit::qi::_4;
            using boost::spirit::qi::_5;
            using boost::spirit::qi::_val;

            time_period_ = ( datetime_ > ',' > datetime_ ) [ _val = phoenix::construct<time_period>((int)_1, (int)_3) ];

            datetime_ = (date_ >> time_duration_) [ _val = phoenix::construct<ptime>((int)_1, (int)_2) | _val = phoenix::construct<ptime>((int)_1, seconds(0)) ] ;

            date_ = (int_ > '.' > int_ > '.' > int_) [ _val = phoenix::construct<date>((int)_5, (int)_3, (int)_1) ];

            time_duration_ = (int_ > ':' > int_ > ':' > int_) [ _val = phoenix::construct<time_duration>((int)_1, (int)_3, (int)_5, 0)];

            BOOST_SPIRIT_DEBUG_NODE(time_period_);
            BOOST_SPIRIT_DEBUG_NODE(datetime_);
            BOOST_SPIRIT_DEBUG_NODE(date_);
            BOOST_SPIRIT_DEBUG_NODE(time_duration_);

        }

        rule<std::string::const_itarator, time_period(), space_type> time_period_;
        rule<std::string::const_itarator, ptime(), space_type> datetime_;
        rule<std::string::const_itarator, date(), space_type> date_;
        rule<std::string::const_itarator, time_duration(), space_type> time_duration_;

        ConditionTree& m_lTree;
    };

错误:

/media/Data/Projects/Qt/Planner/parser.h:114:ошибка:从类型const _1_type {aka const boost :: phoenix :: actor< boost :: spirit :: argument< 0> >}'to type'int' ...

为什么我不能强制转换boost :: spirit :: argument& to int ????

Why I can't cast boost::spirit::argument<0> to int????

推荐答案

更好的问题,为什么能够将一个占位符类型转换为特定的原始类型?

Better question, why would you be able to cast a placeholder type to a specific primitive type?

占位符只是一个懒惰的演员,所以你应该使用Phoenix cast _ :这不是必需的): Live on Coliru

The place holder is a lazy actor only, so you should use Phoenix cast_ to cast it, if at all (hint: this should not be necessary): Live On Coliru

输出

<period_>
<try>10.06.2014 10:00:15,</try>
<date_>
    <try>10.06.2014 10:00:15,</try>
    <success> 10:00:15, 11.07.201</success>
    <attributes>[[10, 6, 2014]]</attributes>
</date_>
<time_>
    <try> 10:00:15, 11.07.201</try>
    <success>, 11.07.2014</success>
    <attributes>[[10, 0, 15]]</attributes>
</time_>
<date_>
    <try> 11.07.2014</try>
    <success></success>
    <attributes>[[11, 7, 2014]]</attributes>
</date_>
<time_>
    <try></try>
    <fail/>
</time_>
<success></success>
<attributes>[[[[10, 6, 2014], [10, 0, 15]], [[11, 7, 2014], [empty]]]]</attributes>
</period_>
Parse success



完整示例



Full Sample

#define BOOST_SPIRIT_DEBUG
#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>

namespace qi  = boost::spirit::qi;
namespace phx = boost::phoenix;

namespace Ast {
    using boost::optional;
    struct date { unsigned day, month, year; };
    struct time { unsigned hours, minutes, seconds; };
    struct date_time { date date_part; optional<time> time_part; };

    struct period { date_time start, end; };
}

BOOST_FUSION_ADAPT_STRUCT(Ast::date, (unsigned,day)(unsigned,month)(unsigned,year))
BOOST_FUSION_ADAPT_STRUCT(Ast::time, (unsigned,hours)(unsigned,minutes)(unsigned,seconds))
BOOST_FUSION_ADAPT_STRUCT(Ast::date_time, (Ast::date,date_part)(Ast::optional<Ast::time>, time_part))
BOOST_FUSION_ADAPT_STRUCT(Ast::period, (Ast::date_time,start)(Ast::date_time,end))

template <typename Iterator>
struct Parser : qi::grammar<Iterator, Ast::period(), qi::space_type>
{
    int test;
    Parser() : Parser::base_type(period_)
    {
        using namespace qi;

        static const int_parser<unsigned, 10, 2, 2> _2digit = {};
        static const int_parser<unsigned, 10, 4, 4> _4digit = {};

        time_      = _2digit >> ":" >> _2digit >> ":" >> _2digit;
        date_      = _2digit >> "." >> _2digit >> "." >> _4digit;
        date_time_ = date_ >> -time_;
        period_    = date_time_ >> "," >> date_time_;

        BOOST_SPIRIT_DEBUG_NODES((period_)(time_)(date_))
    }

  private:
    qi::rule<Iterator, Ast::period(),    qi::space_type> period_;
    qi::rule<Iterator, Ast::date(),      qi::space_type> date_;
    qi::rule<Iterator, Ast::time(),      qi::space_type> time_;
    qi::rule<Iterator, Ast::date_time(), qi::space_type> date_time_;
};


int main()
{
    using It = std::string::const_iterator;

    Parser<It> parser;
    std::string input("10.06.2014 10:00:15, 11.07.2014");

    It f(input.begin()), l(input.end());

    Ast::period parsed;
    bool ok = qi::phrase_parse(f, l, parser, qi::space, parsed);

    if (ok)
    {
        std::cout << "Parse success\n";
    }
    else
    {
        std::cout << "Parse failed\n";
    }

    if (f!=l)
        std::cout << "Remaining unparsed input: '" << std::string(f,l) << "'\n";
}

这篇关于使用Boost :: Spirit解析time_period表达式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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