【问题标题】:Why doesn't this boost::spirit::qi rule successfully parse?为什么这个 boost::spirit::qi 规则没有成功解析?
【发布时间】:2014-04-29 15:39:54
【问题描述】:

我有以下 boost::spirit::qi 解析器规则:

namespace qi = boost::spirit::qi;
qi::rule<Iterator, BroadbandCurve(), Skipper> Cmd_BBNSET;


Cmd_BBNSET = +(qi::float_ >> qi::float_) >> qi::int_ >> qi::int_ >> lit("BBNSET");

我试图让它发出以下属性:

struct FreqLevelPair
{
    float freq;
    float dbLevel;
};
BOOST_FUSION_ADAPT_STRUCT(
    FreqLevelPair,
    (float, freq)
    (float, dbLevel)
)

struct BroadbandCurve
{
    std::vector<FreqLevelPair> freqPairs;
    int numFreqPairs; //Ignored since we can just count the number of pairs outright...
    int curveNum; //ID number
};
BOOST_FUSION_ADAPT_STRUCT(
    BroadbandCurve,
    (std::vector<FreqLevelPair>, freqPairs)
    (int, numFreqPairs)
    (int, curveNum)
)

如您所见,我试图解析一对或多对浮点数,然后是两个整数,然后是文字“BBNSET”。 所有这些代码都可以编译,但是当我尝试解析以下形式的有效 BBNSET 命令时:

0.0 80.0 50.0 25.0 100.0 10.0 3 0 BBNSET

解析失败。我无法确定原因。我尝试将浮点对包装在词位指令中,并将 + 更改为 *,但无论我尝试什么,该命令仍然无法解析,尽管编译没有问题。

我做错了什么,一旦正确解析,这条规则会按预期发出属性吗?

【问题讨论】:

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


【解决方案1】:

Sharth 很快就注意到了原因。

解决方案,IMO 是使用strict_real_policies

Live On Coliru

#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/include/qi.hpp>

namespace qi = boost::spirit::qi;

struct FreqLevelPair
{
    float freq;
    float dbLevel;
};

BOOST_FUSION_ADAPT_STRUCT(
    FreqLevelPair,
    (float, freq)
    (float, dbLevel)
)

struct BroadbandCurve
{
    std::vector<FreqLevelPair> freqPairs;
    int numFreqPairs; //Ignored since we can just count the number of pairs outright...
    int curveNum; //ID number
};

BOOST_FUSION_ADAPT_STRUCT(
    BroadbandCurve,
    (std::vector<FreqLevelPair>, freqPairs)
    (int, numFreqPairs)
    (int, curveNum)
)

int main()
{
    typedef std::string::const_iterator Iterator;
    typedef qi::space_type Skipper;

    qi::real_parser<double, qi::strict_real_policies<double> > strict_real_;

    qi::rule<Iterator, BroadbandCurve(), Skipper> Cmd_BBNSET;
    Cmd_BBNSET = +(strict_real_ >> strict_real_) >> qi::int_ >> qi::int_ >> qi::lit("BBNSET");

    std::string const input("0.0 80.0 50.0 25.0 100.0 10.0 3 0 BBNSET");
    auto f(input.begin()), l(input.end());
    bool ok = qi::phrase_parse(f, l, Cmd_BBNSET, qi::space);

    if (ok)
    {
        std::cout << "Parse succeeded\n";
    } else
    {
        std::cout << "Parse failed\n";
    }

    if (f!=l)
        std::cout << "Remaining unparsed: '" << std::string(f,l) << "'\n";
}

【讨论】:

  • 感谢您的帮助。我原以为这会起作用,因为在我有限的测试中,它似乎可以解决问题。但是,在野外,解析器在处理未指定小数点的实际文件时遇到问题 (i.e. 0 50 200 100 2 0 BBNSET)。我假设这是因为对解析器施加了 strict_real 要求。是否有可能解决这个问题,以便小数点是可选的?
  • 您的语法似乎有歧义。您的初始规则/出现/取决于整数与浮点数不同的事实。如果不是这种情况,那么只有一种方法:尝试性地解析所有内容,并在确定 numFreqPairs 值后立即解释它的位置。文件格式倾向于将长度字段放在标题中是有原因的,您刚刚发现了原因。
  • @stix 好的,这花了一点时间:coliru.stacked-crooked.com/a/04baceeb4b13b2f4
  • 感谢负载!除了我不得不转向 attr.push_back({a, b});由于我的编译器,进入显式 FreqLevelPair 。 :)
【解决方案2】:

我怀疑您的问题实际上与一般递归下降解析器有关。

Cmd_BBNSET = +(qi::float_ >> qi::float_) >> qi::int_ >> qi::int_ >> lit("BBNSET");

让我们走吧:

0.0 80.0 50.0 25.0 100.0 10.0 3 0 BBNSET
^
Matches +(qi::float_ >> qi::float_)

0.0 80.0 50.0 25.0 100.0 10.0 3 0 BBNSET
         ^
         Matches +(qi::float_ >> qi::float_)

0.0 80.0 50.0 25.0 100.0 10.0 3 0 BBNSET
                   ^
                   Matches +(qi::float_ >> qi::float_)

0.0 80.0 50.0 25.0 100.0 10.0 3 0 BBNSET
                              ^
                          !!! Matches +(qi::float_ >> qi::float_) !!!

0.0 80.0 50.0 25.0 100.0 10.0 3 0 BBNSET
                                  ^
                                  Does not match qi::int_.

【讨论】:

  • 实际上,建议的修复可能不起作用...我不确定3.4 是否与qi::int_ 匹配,只是解析为.
  • 确实会的。 +1虽然。我不会经常被boost-spirit 回答。并有很好的解释。我的回答解决了这个问题,虽然我没有太多时间从各个角度看待它:)
  • @sehe:我希望你能到这里来记录修复它的正确方法。我真的不喜欢我提议的修复:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-11-04
  • 2011-09-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-01
相关资源
最近更新 更多