使用Spirit :: Qi语法解析失败

时间:2013-07-08 17:06:56

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

我是Spirit :: Qi的新手,我正在尝试编写一个简单的Wavefront Obj解析器。我已经按照Boost :: Spirit文档站点(link)的教程进行了操作,并且我使大多数内联规则正常工作。我已经开始尝试使用语法,但我似乎无法让它们正常工作。过了一会儿我确实把它编译好了,但解析失败了。我真的不知道我做错了什么。

首先,我创建了一个包含以下内容的简单文本文件:

v  -1.5701 33.8087 0.3592
v  -24.0119 0.0050 21.7439
v  20.8717 0.0050 21.7439
v  20.8717 0.0050 -21.0255
v  -24.0119 0.0050 -21.0255
v  -1.5701 0.0050 0.3592

只是为了确定:读取输入文件可以正常工作。

我写了一个应该解析输入字符串的小函数,但由于某种原因它失败了:

bool Model::parseObj( std::string &data, std::vector<float> &v )
{
    struct objGram : qi::grammar<std::string::const_iterator, float()>
    {
        objGram() : objGram::base_type(vertex)
        {
            vertex = 'v' >> qi::float_
                         >> qi::float_
                         >> qi::float_; 
        }

        qi::rule<std::string::const_iterator, float()> vertex;
    };

    objGram grammar;

    return qi::phrase_parse( data.cbegin(), data.cend(),
                                grammar, iso8859::space, v );
}

qi :: phrase_parse一直返回false,而std :: vector v最后仍为空...

有什么建议吗?

编辑:

添加空格标签后(是正确的名称?),只有第一个'v'被添加到编码为float(118.0f)的std :: vector中,但实际的数字不会被添加。我的猜测是我的规则不正确。我想只添加数字并跳过v。

这是我修改过的功能:

bool Model::parseObj( std::string &data, std::vector<float> &v )
{
    struct objGram : qi::grammar<std::string::const_iterator, float(), iso8859::space_type>
    {
        objGram() : objGram::base_type(vertex)
        {
            vertex = qi::char_('v') >> qi::float_
                         >> qi::float_
                         >> qi::float_; 
        }

        qi::rule<std::string::const_iterator, float(), iso8859::space_type> vertex;
    } objGrammar;

    return qi::phrase_parse( data.cbegin(), data.cend(),
                                objGrammar, iso8859::space, v );
}

1 个答案:

答案 0 :(得分:2)

您的规则声明了错误的公开属性。改变它:

qi::rule<std::string::const_iterator, std::vector<float>(), iso8859::space_type> vertex;

但是,既然你没有在任何东西上模板化你的语法结构(比如iterator / skipper类型),那么拥有一个语法结构是没有意义的。相反,让phrase_parse只是简单地推导出迭代器,队长和规则类型并写入:

bool parseObj(std::string const& data, std::vector<float> &v )
{
    return qi::phrase_parse( 
            data.cbegin(), data.cend(),
            'v' >> qi::float_ >> qi::float_ >> qi::float_, 
            qi::space, v);
}

我认为你会同意这一点。作为奖励,由于自动属性传播规则的强大功能,它“正常工作”(TM)。

然而,看到你的语法,你肯定希望看到这些:

  • How to parse space-separated floats in C++ quickly?显示如何解析结构的向量

    struct float3 {
        float x,y,z;
    };
    
    typedef std::vector<float3> data_t;
    

    很少或没有额外的工作。哦,它会根据竞争的fscanfatod调用对阅读500Mb文件的精神方法进行基准测试。因此,它一次解析多行:)

  • 即使您最终分配给单精度qi::double_变量,也请使用qi::float_解析器而不是float 。请参阅Boost spirit floating number parser precision