用Spirit语法解析:齐不及格

Grammar parsing with Spirit::Qi fails

本文关键字:不及格 Spirit 语法      更新时间:2023-10-16

我是Spirit::Qi的新手,我正在尝试编写一个简单的Wavefront Obj解析器。我已经学习了Boost::Spirit文档网站(链接)上的教程,我已经掌握了大部分内联规则。我已经开始尝试语法,但我似乎无法让它们发挥作用。过了一段时间,我确实编译了它,但解析失败了。我真的不知道我做错了什么。

为了简单起见,我创建了一个简单的文本文件,其中包含以下内容:

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在末尾仍然为空。。。

有什么建议吗?

编辑:

在添加添加空格skippers(这是正确的名称吗?)后,只有第一个"v"被添加到编码为浮点(118.0f)的std::向量中,但实际数字没有添加。我的猜测是我的规则不正确。我只想加上数字,跳过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 );
}

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

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

然而,由于您没有在任何东西上模板化语法结构(如迭代器/队长类型),因此使用语法结构是没有意义的。相反,让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),因为自动属性传播规则令人敬畏。

然而,看到你的语法,你肯定会想看到这些:

  • 如何在C++中快速解析空格分隔的浮点?展示了如何解析为结构向量

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

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

  • 使用qi::double_解析器而不是qi::float_,即使您最终分配给单精度float变量也是如此。请参阅Boost精灵浮点数解析器精度