Boost Spirit将整数解析为自定义列表模板 [英] Boost spirit parse integer to custom list template

查看:79
本文介绍了Boost Spirit将整数解析为自定义列表模板的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在提升精神方面遇到麻烦,无法解析这样的文件:

I have trouble with boost spirit to parse a file like that :

int       [int, int, int] [ int, int]

...

没什么难的,下面的语法可以解决这个问题:

Nothing really hard, the following grammar works for that:

template<typename Iterator>
struct parser_expression : qi::grammar<Iterator,ascii::space_type> 
{
    parser_expression() : parser_expression::base_type(start) {
        using qi::double_;
        using qi::int_;
        using boost::spirit::qi::char_; 
        using qi::alpha;
        using qi::alnum;
        using qi::digit;
        using qi::eps;
        using qi::_val;
        using boost::phoenix::bind;

        start = int_ >> list1 >> list2 >> char_('=');

        list1 = ('[' >> int_ >> *(char_(',') >> int_ ) >> char_(']')) | (char_('[') >> char_(']'));
        list2 = ('[' >> int_ >> *(char_(',') >> int_ ) >> char_(']')) | -(char_('[') >> char_(']'));
    }



    qi::rule<Iterator,ascii::space_type> start;

    qi::rule<Iterator,ascii::space_type> list1;
    qi::rule<Iterator,ascii::space_type> list2;
};

我的问题是我需要保存解析结果. 例如,我需要将int的list1和list2保存到自定义列表模板中:

My problem is that I need to save the result of parsing. For example, I need to save the list1 and list2 of int to a custom list template :

template <typename T>
class SimpleLinkList {
private:
    ChainLink<T>* head;

...
}

ChainLink为:

where ChainLink is :

template<typename T>
class ChainLink {
private:
    T object;
    ChainLink* next;
...
}

我像矢量一样在SimpleLinkList中有一个方法回推,但是我不了解如何解析int,将其保存到ChainLink并将其添加到SimpleLinkList.

I have a method pushback in SimpleLinkList just like vector but I don't understand how to parse int, save it to a ChainLink and add it to a SimpleLinkList.

我已经在我需要一个自定义的LinkList,以便能够在循环播放时删除和添加项目.

I need a custom LinkList to be able to delete and add items while looping on it.

我需要帮助以了解如何安排所有这些内容以成功解析我的文件.

I need help to understand how I can arrange all of that to successfully parse my file.

感谢您的帮助.

推荐答案

您可能正在寻找容器属性自定义点:

You're probably looking for the container attribute customization points:

  • boost::spirit::traits::container_value
  • boost::spirit::traits::push_back
  • boost::spirit::traits::clear_value

对于您的类型,它看起来像:

For your type, it would look like:

namespace boost { namespace spirit { namespace traits {
    template <typename T>
        struct container_value<SimpleLinkList<T>, void> {
            typedef T type;
        };

    template <typename T>
        struct push_back_container<SimpleLinkList<T>, T, void> {
            static bool call(SimpleLinkList<T>& c, T const& val) {
                c.push_back(val);
                return true;
            }
        };
}}}

一个简单的演示(使用SimpleLinkList的虚拟实现):

A simple demonstration (using a dummy implementation of SimpleLinkList):

struct AbstractDataType
{
    int number;
    SimpleLinkList<int> list1, list2;
};

BOOST_FUSION_ADAPT_STRUCT(AbstractDataType, (int, number)(SimpleLinkList<int>, list1)(SimpleLinkList<int>, list2))

template<typename Iterator>
struct parser_expression : qi::grammar<Iterator, AbstractDataType(), qi::space_type> 
{
    parser_expression() : parser_expression::base_type(start) 
    {
        list  = '[' >> -(qi::int_ % ',') >> ']';
        start = qi::int_ >> list >> -list >> '=';

        BOOST_SPIRIT_DEBUG_NODES((list)(start))
    }

    qi::rule<Iterator, AbstractDataType(),    qi::space_type> start;
    qi::rule<Iterator, SimpleLinkList<int>(), qi::space_type> list;
};

注意

  • 在可能的情况下,我用(隐式)qi::lit替换了qi::char_,因为您实际上并不希望将标点符号解析为属性(对吗?)
  • 我使用列表解析器运算符%代替了详细的替代方法
  • 我使用了解析器运算符-将元素列表设为可选(允许零个元素)
  • 类似地使用list >> -list使第二个列表一起成为可选列表.
  • I replaced qi::char_ by (implicit) qi::lit where possible, because you don't actually want to parse the punctuation characters into the attribute (right?)
  • I used the list parser operator % instead of the verbose alternative
  • I used parser operator - to make the element list optional (allow zero elements)
  • Similarly used list >> -list to make the second list optional alltogether.

以下测试用例:

void test(const std::string input)
{
    static const parser_expression<std::string::const_iterator> p;

    AbstractDataType parsed;
    auto f(input.begin()), l(input.end());
    bool ok = qi::phrase_parse(f, l, p, qi::space, parsed);

    if (ok)
        std::cout << "Result: " << parsed.number << " " << parsed.list1 << parsed.list2 << "\n";
    else
        std::cout << "Parse failed\n";

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

int main()
{
    test("1 [2, 3, 4] [5, 6] =");
    test("2 []        [6, 7] =");
    test("3 [4, 5, 6] [    ] =");
    test("4 [5, 6, 7]        =");
}

打印输出:

Result: 1 [2 3 4 ][5 6 ]
Result: 2 [][6 7 ]
Result: 3 [4 5 6 ][]
Result: 4 [5 6 7 ][]

将其集成在一起: http://ideone.com/odqhBz .防止linkrot:

See it all integrated: http://ideone.com/odqhBz. Preventing linkrot:

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

namespace qi = boost::spirit::qi;

template <typename T> struct ChainLink;

template <typename T>
class SimpleLinkList {
  public:
    void push_back(T const& v) { /* todo */ _for_debug.push_back(v); }

    std::list<int> _for_debug;
    friend std::ostream& operator<<(std::ostream& os, SimpleLinkList const& list) {
        os << "["; std::copy(list._for_debug.begin(), list._for_debug.end(), std::ostream_iterator<T>(os, " ")); return os << "]";
    }
  private:
    ChainLink<T>* head;
};

namespace boost { namespace spirit { namespace traits {
    template <typename T>
        struct container_value<SimpleLinkList<T>, void> {
            typedef T type;
        };

    template <typename T>
        struct push_back_container<SimpleLinkList<T>, T, void> {
            static bool call(SimpleLinkList<T>& c, T const& val) {
                c.push_back(val);
                return true;
            }
        };
}}}

struct AbstractDataType
{
    int number;
    SimpleLinkList<int> list1, list2;
};

BOOST_FUSION_ADAPT_STRUCT(AbstractDataType, (int, number)(SimpleLinkList<int>, list1)(SimpleLinkList<int>, list2))

template<typename Iterator>
struct parser_expression : qi::grammar<Iterator, AbstractDataType(), qi::space_type> 
{
    parser_expression() : parser_expression::base_type(start) 
    {
        list  = '[' >> -(qi::int_ % ',') >> ']';
        start = qi::int_ >> list >> -list >> '=';

        BOOST_SPIRIT_DEBUG_NODES((list)(start))
    }

    qi::rule<Iterator, AbstractDataType(),    qi::space_type> start;
    qi::rule<Iterator, SimpleLinkList<int>(), qi::space_type> list;
};

void test(const std::string input)
{
    static const parser_expression<std::string::const_iterator> p;

    AbstractDataType parsed;
    auto f(input.begin()), l(input.end());
    bool ok = qi::phrase_parse(f, l, p, qi::space, parsed);

    if (ok)
        std::cout << "Result: " << parsed.number << " " << parsed.list1 << parsed.list2 << "\n";
    else
        std::cout << "Parse failed\n";

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

int main()
{
    test("1 [2, 3, 4] [5, 6] =");
    test("2 []        [6, 7] =");
    test("3 [4, 5, 6] [    ] =");
    test("4 [5, 6, 7]        =");
}

这篇关于Boost Spirit将整数解析为自定义列表模板的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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