c++ - 使用 Spirit::Qi 进行语法解析失败

标签 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 );
}

最佳答案

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

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),因为自动属性传播规则非常棒。

但是,看到您的语法,您肯定会希望看到这些:

  • How to parse space-separated floats in C++ quickly?展示如何解析为结构 vector

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

    几乎不需要额外的工作。哦,它对读取 500Mb 文件的 Spirit 方法与竞争的 fscanfatod 调用进行了基准测试。因此,它一次解析多行:)

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

关于c++ - 使用 Spirit::Qi 进行语法解析失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17532235/

相关文章:

c++ - spirit x3 如何将 vector 添加到 AST

c++ - boost::bind 不编译

c++ - C的简单问题

c++ - 为我在 C++ 中创建的对象声明一个变量

C++ 时间() 函数

c++ - 装饰者模式 vs. 调用 super 反模式

perl - Parse::RecDescent 语法没有按预期工作

lisp - 如何使用 Lisp 表达 BNF?

grammar - 确定是否可以在 CFG 中模糊地派生字符串

c++ - boost 灵气——条件解析