【问题标题】:Grammar parsing with Spirit::Qi fails使用 Spirit::Qi 进行语法解析失败
【发布时间】:2013-07-08 17:06:55
【问题描述】:

我是 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' 被添加到编码为浮点数 (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) 如果您提供完整的代码,您有机会获得更多关注 2) 快速浏览... 118 是您的“v”的 ascii 代码,因此它会错误地传播到输出。如果你想避免它,你有两个选择(也许更多): a) qi::lit('v') >> qi::float_ >> qi::float_ >> qi::float_ b) qi::omit [ qi::char_('v') ] >> qi::float_ >> qi::float_ >> qi::float_
  • @G.Civardi 啊。你和我差不多同时发现了这个问题。你错过了罪魁祸首,但我链接到你对浮点精度问题的回答:) 干杯
  • @sehe 没问题,非常感谢 :-) 干杯

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


【解决方案1】:

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

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

但是,看到你的语法,你肯定想看看这些:

【讨论】:

  • 很好的答案!非常感谢。所以你一开始说的是,如果我使用模板,我应该只使用语法结构?另一个问题:按照您描述的方式使用短语解析时,如何实现多个规则?因为最终我还想解析前面有“vn”和“vt”的浮点数,它们都在同一个 *.obj 文件中。我是否只为每个单独的规则运行 phrase_parse 函数?谢谢 :)
  • @KrienLinnenbank 我是说语法结构没有发挥作用。 更多的理由来拥有语法结构,但无论如何你不会在本地定义它。
  • 关于第二个问题:无论如何我都会拆分出一个语法结构,然后按原样解析您的语法(毕竟,这就是您使用解析器生成器的目的! )。 IE。我会通过单独的规则运行单独的行。如果你被卡住了,也许你应该把它作为一个问题。 (现在,请务必访问第一个链接的其他答案以获取想法)
猜你喜欢
  • 2011-01-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-10
相关资源
最近更新 更多