【问题标题】:boost spirit selects unmatched result提升精神选择无与伦比的结果
【发布时间】:2014-05-27 23:35:20
【问题描述】:

我有一个格式如下的文件

metal 1 1.2 2.2
wire 1.1 2.3
metal 2 3.2 12.2
...

这是一种非常简单的格式。 “金属”和“电线”是关键字。 “metal”后面是 1 uint 和 2 double,而“wire”后面是 2 double。 我尝试使用 Boost::Qi 来解析它,但结果很奇怪,我不知道为什么。

#include <iostream>
#include <string>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/phoenix_bind.hpp>
#include <boost/bind.hpp>
#include <boost/lambda/lambda.hpp>
#include <boost/spirit/include/lex_lexertl.hpp>
using std::cout;
using std::endl;
using std::string;

using namespace boost::spirit;

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

    // grammar 
    template <typename Iterator>
    struct TimingLibGrammar : 
        qi::grammar<Iterator, ascii::space_type>
    {
        qi::rule<Iterator, ascii::space_type> expression;

        TimingLibGrammar() : TimingLibGrammar::base_type(expression)
        {
            using qi::uint_;
            using qi::int_;
            using qi::double_;
            using qi::char_;
            using qi::_1;
            using qi::_2;
            using qi::_3;
            using qi::_val;
            using qi::lexeme;
            using qi::lit;

            expression = 
                +(
                    ((
                      "metal" 
                    >> uint_
                    >> double_
                    >> double_)[cout << "metal" << " "<< _1 << " " << _2 << " " << _3 << endl])
                        | 
                    ((
                      "wire"
                    >> double_
                    >> double_)[cout << "wire" << " "<< _1 << " " << _2 << endl])
                );

        }
    };
}


int main()
{
    using boost::spirit::ascii::space;
    using namespace client;
    string str = "metal 3 1.0 2.0";
    TimingLibGrammar<string::const_iterator> tlg;
    string::const_iterator iter = str.begin();
    string::const_iterator end = str.end();

    client::qi::phrase_parse(iter, end, tlg, space);

            return 0;
}

代码的主要部分实际上很短。请忽略那些无用的包含。

当我尝试解析一行时

metal 3 1.0 2.0,

解析器给我的结果如下:

wire metal 3 1 2

这个结果不正确。它应该输出“metal 3 1 2”,但我不知道这个“wire”是从哪里来的。我还尝试遵循 boost 库中的几个示例代码。但它仍然未能正确处理。 代码使用带有 -std=c++11 标志的 g++ 4.7.2 编译。

任何建议都会有所帮助。我是提振精神的新手,所以我希望能学到一些东西。提前致谢。

【问题讨论】:

    标签: c++ boost-spirit boost-spirit-qi


    【解决方案1】:

    罪魁祸首是这样的行:

    cout << "metal" << " "<< _1 << " " << _2 << " " << _3 << endl
    
    cout << "wire" << " "<< _1 << " " << _2 << endl
    

    请记住,Boost 中的 lambda(Boost.Phoenix 和 Boost.Lambda 变体)是运算符重载的结果。 cout &lt;&lt; _1(相当于operator&lt;&lt;(cout, _1))创建了一个lambda,因为_1是由Phoenix定义的(并导入到Spirit.Qi的命名空间中)。但是,cout &lt;&lt; "wire" &lt;&lt; _1operator&lt;&lt;(operator&lt;&lt;(cout, "wire"), _1)。它会立即打印出“wire”,并使用operator&lt;&lt;(cout, "wire") - cout - 的返回值来构造lambda。内部的operator&lt;&lt; 是标准库函数。

    要解决这个问题,请将它们包装在phoenix::val

    cout << phoenix::val("metal") << " "<< _1 << " " << _2 << " " << _3 << endl
    
    cout << phoenix::val("wire") << " "<< _1 << " " << _2 << endl
    

    【讨论】:

    • 顺便说一句,如果我想让“metal”不区分大小写,你知道怎么做吗?在 flex&bison 中,我知道就像 [Mm][Ee][Tt][Aa][Ll]。
    • 我只是按照你的建议做了,得到了我想要的。真的很感激。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-25
    • 2013-06-09
    相关资源
    最近更新 更多