将数据分配给规则内向量中的给定元素

发布于 2024-11-25 18:33:03 字数 3914 浏览 0 评论 0原文

我正在尝试设置一个解析器,给定一个值,它可以将其分配给向量的某个元素,但我不完全确定如何实现它。

假设以下代码片段解析字符串 (0){**+*+}。它应该为每个 + 增加一次 bar.a[0] 一次,为每个 *< 增加一次 bar.b[0] 。 /代码>。我遇到的问题是我不确定如何使用 _a 获取对向量元素的引用:

#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <vector>

//The struct containing the vector.
struct testStruct {
    std::vector<int> a, b;
};

BOOST_FUSION_ADAPT_STRUCT (
    testStruct,
    (std::vector<int>, a)
    (std::vector<int>, b)
)

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

template<typename Iterator>
struct foo : qi::grammar<Iterator, testStruct(), qi::locals<unsigned>, ascii::space_type> {
    foo() : foo::base_type(start) {
        using namespace qi::labels;
        using qi::eps;
        using qi::lit;
        using qi::uint_;
        using phoenix::at_c;

        start = lit('(')
                >> uint_                [_a = _1]
                >> ')'
                >> '{'
                >>  starsOrPlus(
                        at_c<_a>(at_c<0>(_val)),    //This is where I'm not sure what to do.
                        at_c<_a>(at_c<1>(_val))
                    )
                >> '}'
                ;

        starsOrPlus = eps               [_r1 = 0]
                                        [_r2 = 0]
            >> (
                * (
                    (
                        +lit('+')       [_r1 += 1]
                    )
                    ^ (
                        +lit('*')       [_r2 += 1]
                    )
                )
            )
        ;
    }

    qi::rule<Iterator, testStruct(), qi::locals<unsigned>, ascii::space_type> start;

    //Parses stars and pluses. Sets the first uint8_t to the number of *, and the
    //second to the number of +.
    qi::rule<Iterator, void(int&, int&), ascii::space_type> starsOrPlus;
};

//Main program
int main() {
    std::string testString = "(2){**++*+}";

    typedef foo<std::string::const_iterator> foo;
    foo grammar;

    testStruct bar;
    std::string::const_iterator iter = testString.begin();
    std::string::const_iterator end = testString.end();
    bool parsed = phrase_parse(iter, end, grammar, ascii::space, bar);

    if (parsed) {
        //Do something with the data...
    }

    return 0;
}

这无法编译并出现以下错误:

main.cpp||In constructor 'foo<Iterator>::foo()':|
main.cpp|36|error: 'boost::spirit::_a' cannot appear in a constant-expression|
main.cpp|36|error: no matching function for call to 'at_c(boost::phoenix::actor<boost::phoenix::composite<boost::phoenix::at_eval<0>, boost::fusion::vector<boost::spirit::attribute<0>, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_> > >&)'|
main.cpp|37|error: 'boost::spirit::_a' cannot appear in a constant-expression|
main.cpp|37|error: no matching function for call to 'at_c(boost::phoenix::actor<boost::phoenix::composite<boost::phoenix::at_eval<1>, boost::fusion::vector<boost::spirit::attribute<0>, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_> > >&)'|

所以,很明显,我不能使用at_c 中的占位符值。我还知道,即使可以,如果给定位置超出范围,也会存在重新调整向量大小的问题。

我将如何实现这样的事情?我的处理方式完全错误吗?

I'm trying to set up a parser which, given a value, can assign it to a certain element of a vector, but I'm not entirely sure how to implement it.

Let's say the following piece of code parses the string (0){**+*+}. It should increment bar.a[0] once for every +, and bar.b[0] once for every *. The issue I'm encountering is that I'm not sure how to get a reference to a vector's element using _a:

#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <vector>

//The struct containing the vector.
struct testStruct {
    std::vector<int> a, b;
};

BOOST_FUSION_ADAPT_STRUCT (
    testStruct,
    (std::vector<int>, a)
    (std::vector<int>, b)
)

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

template<typename Iterator>
struct foo : qi::grammar<Iterator, testStruct(), qi::locals<unsigned>, ascii::space_type> {
    foo() : foo::base_type(start) {
        using namespace qi::labels;
        using qi::eps;
        using qi::lit;
        using qi::uint_;
        using phoenix::at_c;

        start = lit('(')
                >> uint_                [_a = _1]
                >> ')'
                >> '{'
                >>  starsOrPlus(
                        at_c<_a>(at_c<0>(_val)),    //This is where I'm not sure what to do.
                        at_c<_a>(at_c<1>(_val))
                    )
                >> '}'
                ;

        starsOrPlus = eps               [_r1 = 0]
                                        [_r2 = 0]
            >> (
                * (
                    (
                        +lit('+')       [_r1 += 1]
                    )
                    ^ (
                        +lit('*')       [_r2 += 1]
                    )
                )
            )
        ;
    }

    qi::rule<Iterator, testStruct(), qi::locals<unsigned>, ascii::space_type> start;

    //Parses stars and pluses. Sets the first uint8_t to the number of *, and the
    //second to the number of +.
    qi::rule<Iterator, void(int&, int&), ascii::space_type> starsOrPlus;
};

//Main program
int main() {
    std::string testString = "(2){**++*+}";

    typedef foo<std::string::const_iterator> foo;
    foo grammar;

    testStruct bar;
    std::string::const_iterator iter = testString.begin();
    std::string::const_iterator end = testString.end();
    bool parsed = phrase_parse(iter, end, grammar, ascii::space, bar);

    if (parsed) {
        //Do something with the data...
    }

    return 0;
}

This fails to compile with the following errors:

main.cpp||In constructor 'foo<Iterator>::foo()':|
main.cpp|36|error: 'boost::spirit::_a' cannot appear in a constant-expression|
main.cpp|36|error: no matching function for call to 'at_c(boost::phoenix::actor<boost::phoenix::composite<boost::phoenix::at_eval<0>, boost::fusion::vector<boost::spirit::attribute<0>, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_> > >&)'|
main.cpp|37|error: 'boost::spirit::_a' cannot appear in a constant-expression|
main.cpp|37|error: no matching function for call to 'at_c(boost::phoenix::actor<boost::phoenix::composite<boost::phoenix::at_eval<1>, boost::fusion::vector<boost::spirit::attribute<0>, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_> > >&)'|

So, clearly, I can't use a placeholder value within at_c. I'm also aware that, even if I could, there would also be the issue of re-sizing the vector if the given position is out of range.

How would I implement something like this? Am I just going about this entirely the wrong way?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

把梦留给海 2024-12-02 18:33:03

这应该可以帮助您开始:

#include <vector>
#include <string>
#include <iostream>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>

struct testStruct
{
    std::vector<int> a, b;
};

BOOST_FUSION_ADAPT_STRUCT
(
    testStruct,
    (std::vector<int>, a)
    (std::vector<int>, b)
)

namespace bp = boost::phoenix;
namespace bs = boost::spirit;
namespace bsq = bs::qi;

template<typename Iterator>
struct foo : bsq::grammar<Iterator, testStruct(), bsq::locals<unsigned> >
{
    foo() : foo::base_type(start)
    {
        using namespace bs::labels;
        using bp::at_c;
        using bp::resize;
        using bs::lit;
        using bs::uint_;

        start
            =   '('
                >> uint_
                   [
                       _a = _1,
                       resize(at_c<0>(_val), _1 + 1),
                       resize(at_c<1>(_val), _1 + 1)
                   ]
                >> "){"
                >> starsOrPlus(at_c<0>(_val)[_a], at_c<1>(_val)[_a])
                >> '}'
            ;

        starsOrPlus
            =  *(
                    lit('+')[_r1 += 1]
                |   lit('*')[_r2 += 1]
                )
            ;
    }

    bsq::rule<Iterator, testStruct(), bsq::locals<unsigned> > start;
    bsq::rule<Iterator, void(int&, int&)> starsOrPlus;
};

void printvec(std::vector<int> const& vec)
{
    bool first = true;
    for (std::vector<int>::const_iterator it = vec.begin(), it_end = vec.end();
         it != it_end;
         ++it)
    {
        if (first)
            first = false;
        else
            std::cout << ", ";
        std::cout << *it;
    }
}

int main()
{
    foo<std::string::const_iterator> grammar;
    testStruct bar;
    std::string const input = "(2){**++*}";
    std::string::const_iterator first = input.begin(), last = input.end();
    if (bsq::parse(first, last, grammar, bar) && first == last)
    {
        std::cout << "bar.a: ";
        printvec(bar.a);
        std::cout << "\nbar.b: ";
        printvec(bar.b);
        std::cout << '\n';
    }
    else
        std::cout << "parse failed\n";
}

这里值得注意的变化是:

  • testStruct 内部的 vector 必须调整为足以使所需索引成为有效
  • 运算符的 大小使用 [] 代替 boost::phoenix::at_c 来访问 vector 的索引,就像在“正常”代码中一样

请注意我拿出了跳过解析器来简化事情(因为这似乎没有必要);如果需要的话,将其添加回来——它在这里没有真正的相关性。

This should get you started:

#include <vector>
#include <string>
#include <iostream>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>

struct testStruct
{
    std::vector<int> a, b;
};

BOOST_FUSION_ADAPT_STRUCT
(
    testStruct,
    (std::vector<int>, a)
    (std::vector<int>, b)
)

namespace bp = boost::phoenix;
namespace bs = boost::spirit;
namespace bsq = bs::qi;

template<typename Iterator>
struct foo : bsq::grammar<Iterator, testStruct(), bsq::locals<unsigned> >
{
    foo() : foo::base_type(start)
    {
        using namespace bs::labels;
        using bp::at_c;
        using bp::resize;
        using bs::lit;
        using bs::uint_;

        start
            =   '('
                >> uint_
                   [
                       _a = _1,
                       resize(at_c<0>(_val), _1 + 1),
                       resize(at_c<1>(_val), _1 + 1)
                   ]
                >> "){"
                >> starsOrPlus(at_c<0>(_val)[_a], at_c<1>(_val)[_a])
                >> '}'
            ;

        starsOrPlus
            =  *(
                    lit('+')[_r1 += 1]
                |   lit('*')[_r2 += 1]
                )
            ;
    }

    bsq::rule<Iterator, testStruct(), bsq::locals<unsigned> > start;
    bsq::rule<Iterator, void(int&, int&)> starsOrPlus;
};

void printvec(std::vector<int> const& vec)
{
    bool first = true;
    for (std::vector<int>::const_iterator it = vec.begin(), it_end = vec.end();
         it != it_end;
         ++it)
    {
        if (first)
            first = false;
        else
            std::cout << ", ";
        std::cout << *it;
    }
}

int main()
{
    foo<std::string::const_iterator> grammar;
    testStruct bar;
    std::string const input = "(2){**++*}";
    std::string::const_iterator first = input.begin(), last = input.end();
    if (bsq::parse(first, last, grammar, bar) && first == last)
    {
        std::cout << "bar.a: ";
        printvec(bar.a);
        std::cout << "\nbar.b: ";
        printvec(bar.b);
        std::cout << '\n';
    }
    else
        std::cout << "parse failed\n";
}

The notable changes here are:

  • The vectors inside of testStruct must be resized to a size sufficient for the desired index to be valid
  • operator[] is used instead of boost::phoenix::at_c to access the index of a vector, just as one would in "normal" code

Note that I took out the skip parser to simplify things (and because it didn't appear to be necessary); add it back if you need to -- it had no real relevance here.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文