C ++ Boost Spirit,解析数据并存储最大值

时间:2015-04-04 22:33:23

标签: c++ parsing boost boost-spirit

我正在尝试这里给出的代码:Boolean expression (grammar) parser in c++

我想创建一个字符串变量max,它将存储每次解析时遇到的最大变量(例如,在字典顺序上)。

我尝试过这样的事情:

  1. var_ = qi::lexeme[ +alpha ] [_val = _1, if_(phx::ref(m) < _1) [phx::ref(m) = _1]];,但有一个(真的很长)编译错误

  2. var_ = qi::lexeme[ +alpha [_val = _1, if_(phx::ref(m) < _1) [phx::ref(m) = _1]]];但是有了这个,我只得到一个变量的第一个特征,即重新划分。

  3. 我还尝试使用整数而不是字符串来简化变量,但var_ = int_ [...]也不起作用,因为int_已经是一个解析器(我认为)。

    你有什么想法吗?

    提前致谢

3 个答案:

答案 0 :(得分:1)

我会说那个

start = *word [ if_(_1>_val) [_val=_1] ];

应该没问题。但是,由于一个bug(?),单语句语义动作中的Phoenix语句不能编译。您可以使用no-op语句轻松解决它,例如在这种情况下_pass=true

start = *word [ if_(_1>_val) [_val=_1], _pass = true ];

现在,为此我假设

rule<It, std::string()> word = +alpha;

如果你坚持,你可以把它全部塞进一条规则中:

start = *as_string[lexeme[+alpha]] [ if_(_1>_val) [_val=_1], _pass = true ];

我不推荐。

演示

<强> Live On Colir

#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>

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

template <typename It, typename Skipper>
struct max_parser : qi::grammar<It, std::string(), Skipper> {
    max_parser() : max_parser::base_type(start) {
        using namespace qi;
        using phx::if_;

#if 1
        word  = lexeme [ +alpha ];
        start = *word [ if_(_1>_val) [_val=_1], _pass = true ];
#else
        start = *as_string[lexeme[+alpha]] [ if_(_1>_val) [_val=_1], _pass = true ];
#endif
    }

  private:
    qi::rule<It, std::string(), Skipper> start, word;
};


int main() {

    std::string const input("beauty shall be in ze eye of the beholder");
    using It = std::string::const_iterator;
    max_parser<It, qi::space_type> parser;

    std::string data;
    It it = input.begin(), end = input.end();
    bool ok = qi::phrase_parse(it, end, parser, qi::space, data);

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

    if (it != end)
        std::cout << "Remaining unparsed: '" << std::string(it,end) << "'\n";
}

打印:

Parse success: ze

答案 1 :(得分:1)

回复:comment

  

感谢您的回答。我想要进行常规解析并保持遇到的最大字符串,并且它适用于:var_ = *as_string[qi::lexeme[ +digit ]] [if_(phx::ref(m) < _1) [phx::ref(m) = _1], _val = _1];

为了更有趣,为了完全矫枉过正,我想出了一些我觉得有用的东西:

<强> Live On Coliru

int main() {
    do_test<int>(" 1 99 -1312 4 1014", -9999);
    do_test<double>(" 1 NaN -4 7e3 7e4 -31e9");
    do_test<std::string>("beauty shall be in ze eye of the beholder", "", qi::as_string[qi::lexeme[+qi::graph]]);
}

样本打印:

Parse success: 5 elements with maximum of 1014
     values: 1 99 -1312 4 1014 
Parse success: 6 elements with maximum of 70000
     values: 1 nan -4 7000 70000 -3.1e+10 
Parse success: 9 elements with maximum of ze
     values: beauty shall be in ze eye of the beholder 

正如你所看到的,string我们需要帮助圣灵,因为它不知道你如何“定义”一个“单词”。测试驱动程序是完全通用的:

template <typename T, typename ElementParser = typename boost::spirit::traits::create_parser<T>::type>
void do_test(std::string const& input, 
        T const& start_value = std::numeric_limits<T>::lowest(),
        ElementParser const& element_parser = boost::spirit::traits::create_parser<T>::call())
{
    using It = std::string::const_iterator;

    vector_and_max<T> data;
    It it = input.begin(), end = input.end();
    bool ok = qi::phrase_parse(it, end, max_parser<It, T>(start_value, element_parser), qi::space, data);

    if (ok) {
        std::cout << "Parse success: " << data.first.size() << " elements with maximum of " << data.second << "\n";
        std::copy(data.first.begin(), data.first.end(), std::ostream_iterator<T>(std::cout << "\t values: ", " "));
        std::cout << "\n";
    } else {
        std::cout << "Parse failed\n";
    }

    if (it != end)
        std::cout << "Remaining unparsed: '" << std::string(it,end) << "'\n";
}

start-element和element-parser被传递给我们语法的构造函数:

template <typename T>
    using vector_and_max = std::pair<std::vector<T>, T>;

template <typename It, typename T, typename Skipper = qi::space_type>
struct max_parser : qi::grammar<It, vector_and_max<T>(), Skipper> {
    template <typename ElementParser>
    max_parser(T const& start_value, ElementParser const& element_parser) : max_parser::base_type(start) {
        using namespace qi;
        using phx::if_;

        _a_type running_max;

        vector_with_max %= 
            eps    [ running_max = start_value ]
            >> *boost::proto::deep_copy(element_parser) 
                    [ if_(_1>running_max) [running_max=_1], _pass = true ]
            >> attr(running_max)
            ;

        start = vector_with_max;
    }

private:
    qi::rule<It, vector_and_max<T>(), Skipper> start;
    qi::rule<It, vector_and_max<T>(), Skipper, qi::locals<T> > vector_with_max;
};

完整列表

供参考

<强> Live On Coliru

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

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

template <typename T>
    using vector_and_max = std::pair<std::vector<T>, T>;

template <typename It, typename T, typename Skipper = qi::space_type>
struct max_parser : qi::grammar<It, vector_and_max<T>(), Skipper> {
    template <typename ElementParser>
    max_parser(T const& start_value, ElementParser const& element_parser) : max_parser::base_type(start) {
        using namespace qi;
        using phx::if_;

        _a_type running_max;

        vector_with_max %= 
               eps    [ running_max = start_value ]
            >> *boost::proto::deep_copy(element_parser) 
                      [ if_(_1>running_max) [running_max=_1], _pass = true ]
            >> attr(running_max)
            ;

        start = vector_with_max;
    }

  private:
    qi::rule<It, vector_and_max<T>(), Skipper> start;
    qi::rule<It, vector_and_max<T>(), Skipper, qi::locals<T> > vector_with_max;
};

template <typename T, typename ElementParser = typename boost::spirit::traits::create_parser<T>::type>
void do_test(std::string const& input, 
        T const& start_value = std::numeric_limits<T>::lowest(),
        ElementParser const& element_parser = boost::spirit::traits::create_parser<T>::call())
{
    using It = std::string::const_iterator;

    vector_and_max<T> data;
    It it = input.begin(), end = input.end();
    bool ok = qi::phrase_parse(it, end, max_parser<It, T>(start_value, element_parser), qi::space, data);

    if (ok) {
        std::cout << "Parse success: " << data.first.size() << " elements with maximum of " << data.second << "\n";
        std::copy(data.first.begin(), data.first.end(), std::ostream_iterator<T>(std::cout << "\t values: ", " "));
        std::cout << "\n";
    } else {
        std::cout << "Parse failed\n";
    }

    if (it != end)
        std::cout << "Remaining unparsed: '" << std::string(it,end) << "'\n";
}

int main() {
    do_test<int>(" 1 99 -1312 4 1014");
    do_test<double>(" 1 NaN -4 7e3 7e4 -31e9");
    do_test<std::string>("beauty shall be in ze eye of the beholder", "", qi::as_string[qi::lexeme[+qi::graph]]);
}

答案 2 :(得分:0)

只是为了好玩,这里是如何做大致¹与我的其他答案相同,等等,但根本没有使用提升精神:

<强> Live On Coliru

#include <algorithm>
#include <sstream>
#include <iterator>
#include <iostream>

int main() {
    std::istringstream iss("beauty shall be in ze eye of the beholder");

    std::string top2[2];
    auto end = std::partial_sort_copy(
            std::istream_iterator<std::string>(iss), {},
            std::begin(top2), std::end(top2),
            std::greater<std::string>());

    for (auto it=top2; it!=end; ++it)
        std::cout << "(Next) highest word: '" << *it << "'\n";
}

输出:

(Next) highest word: 'ze'
(Next) highest word: 'the'

¹我们对此处isalphaisspace字符类型的具体描述并不那么具体