没有匹配具有补气::重复和可选的解析器 [英] No match with qi::repeat and optional parser

查看:72
本文介绍了没有匹配具有补气::重复和可选的解析器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在尝试齐解析简单,换行分隔
顶点的文件。在下面的格式(例如$ P $在pssed我捏造容易阅读符号):

I've been experimenting with Qi to parse a simple, new-line delimited file of vertices. In the following format (expressed in my made-up easy to read notation):

双两双可选的(或者(INT INT INT可选(INT))或(双两双可选的(双)))

我的测试案例入手重复失败,我找不到错误。在code的意见是希望更多的启发:

My test-cases start failing with repeat and I can't find the error. The comments in the code are hopefully more enlightening:

#include <boost/spirit/include/qi.hpp>
#include <string>
#include <iostream>

using namespace boost::spirit;

qi::rule<std::string::iterator, ascii::space_type> vertexRule = 
  (double_ >> double_ >> double_);

qi::rule<std::string::iterator, ascii::space_type> colorRule = 
  (double_ >> double_ >> double_ >> -(double_)) | (uint_ >> uint_ >> uint_ >> -(uint_));

template<typename Iterator, typename Rule>
bool parseIt(Iterator begin, Iterator end, Rule rule) {
  bool r = qi::phrase_parse(
    begin, end,
    rule,
    ascii::space
    );

  if(begin != end) {
    std::cout << "No full match!" << std::endl;
    while(begin != end)
      std::cout << *begin++;
    return false;
  }
  return r;
}

int main()
{
  qi::rule<std::string::iterator, ascii::space_type> rule1 =
    repeat(3)[vertexRule >> -(colorRule)];

  std::string t1{
    "20.0 20.0 20.0\n"
      "1.0 1.0 1.0 255 0 255 23\n"
      "1.0 1.0 1.0 1.0 0.3 0.2 0.3\n"
        };
  std::cout << std::boolalpha;
  // matches
  std::cout << parseIt(t1.begin(), t1.end(), rule1) << std::endl;

  // 3 double 3 ints
  std::string test{"1.0 1.0 1.0 1 3 2\n"};
  // matches individually
  std::cout << parseIt(test.begin(), test.end(), vertexRule >> -(colorRule)) << std::endl;

  // offending line added at the end
  // but position does not matter
  // also offending 3 double 3 double
  std::string t2{
    "20.0 20.0 20.0\n"
      "1.0 1.0 1.0 255 0 255 23\n"
      "1.0 1.0 1.0 1.0 0.3 0.2 0.3\n"
      "1.0 1.0 1.0 1 3 2\n"
      };

  qi::rule<std::string::iterator, ascii::space_type> rule2 =
    repeat(4)[vertexRule >> -(colorRule)];

  // does not match
  std::cout << parseIt(t2.begin(), t2.end(), rule2) << std::endl;

  // interestingly this matches
  // std::string t2{
  //     "1.0 1.0 1.0 1 3 2\n"
  //     "1.0 1.0 1.0 1 3 2\n"
  //     "1.0 1.0 1.0 1 3 2\n"
  //     "1.0 1.0 1.0 1 3 2\n"
  //     };
}

我是新来的解析器建设,特别是Boost.Spirit。因此,意见指出明显也是AP preciated。

I'm new to parser construction and especially Boost.Spirit. So comments pointing out the obvious are also appreciated.

推荐答案

您的散文描述的和样品投入似乎表明线路两端都有意义你的语法。

Your prose description and sample inputs seem to indicate line-ends have significance to your grammar.

不过,我找不到您尝试前preSS在您的规则的事实的证据。

Yet, I cannot find any evidence of the fact that you tried to express that in your rules.

有与之间的不确定性另一个问题上采取双重_ UINT _ (见下文)。

下面是一个经过改进的样本,增加了自定义的船长(即不会的的的 EOL )。另外,我把它接受任何数量的尾随 EOL 的,但没有别的:

Here is a reworked sample that adds a custom skipper (that will no eat the eol). Also, I made it accept any number of trailing eol, but nothing else:

skipper = qi::char_(" \t");

bool r = qi::phrase_parse(
             begin, end,
             (vertexRule >> -colorRule) % qi::eol >> *qi::eol >> qi::eoi,
             skipper
         );

全部code所有解析成功返回:

Full code returning success for all parses:

#include <boost/spirit/include/qi.hpp>
#include <string>
#include <iostream>

using namespace boost::spirit;

template<typename Iterator>
bool parseIt(Iterator begin, Iterator end)
{
    qi::rule<Iterator, qi::blank_type> vertexRule, colorRule;

    vertexRule = double_ >> double_ >> double_;
    colorRule  = (double_ >> double_ >> double_ >> -(double_)) | (uint_ >> uint_ >> uint_ >> -(uint_));

    bool r = qi::phrase_parse(
                 begin, end,
                 (vertexRule >> -colorRule) % qi::eol >> *qi::eol >> qi::eoi,
                 qi::blank
             );

    if(begin != end)
    {
        std::cout << "No full match! '" << std::string(begin, end) << std::endl;
        return false;
    }
    return r;
}

int main()
{
    std::string t1
    {
        "20.0 20.0 20.0\n"
        "1.0 1.0 1.0 255 0 255 23\n"
        "1.0 1.0 1.0 1.0 0.3 0.2 0.3\n"
    };
    std::cout << std::boolalpha;
    // matches
    std::cout << parseIt(t1.begin(), t1.end()) << std::endl;

    // 3 double 3 ints
    std::string test {"1.0 1.0 1.0 1 3 2\n"};
    // matches individually
    std::cout << parseIt(test.begin(), test.end()) << std::endl;

    // offending line added at the end
    // but position does not matter
    // also offending 3 double 3 double
    std::string t2
    {
        "20.0 20.0 20.0\n"
        "1.0 1.0 1.0 255 0 255 23\n"
        "1.0 1.0 1.0 1.0 0.3 0.2 0.3\n"
        "1.0 1.0 1.0 1 3 2\n"
    };

    // does not match
    std::cout << parseIt(t2.begin(), t2.end()) << std::endl;

    // interestingly this matches
    // std::string t2{
    //     "1.0 1.0 1.0 1 3 2\n"
    //     "1.0 1.0 1.0 1 3 2\n"
    //     "1.0 1.0 1.0 1 3 2\n"
    //     "1.0 1.0 1.0 1 3 2\n"
    //     };
}

UINT _ 双_

如前所述,也有一个模糊这里潜伏

uint_ versus double_

As mentioned, there is also an ambiguity lurking here:

colorRule  = (double_ >> double_ >> double_ >> -(double_)) | (uint_ >> uint_ >> uint_ >> -(uint_));

因为它的立场,在(uint_&GT;&GT; uint_&GT;&GT; uint_&GT;&GT; - (UINT _)规则的一部分将永远不会被匹配,因为它也将匹配的第一部分(与双_ )。我想简单地改写这个为

As it stands, the (uint_ >> uint_ >> uint_ >> -(uint_) part of the rule will never be matched, as it would also match the first part (with double_). I'd simply rewrite this as

colorRule  = double_ >> double_ >> double_ >> -double_;

当然,除非,如果他们被指定为浮点数(例如uints从0..255去,但双打从0.0..1.0去)的值变化的意义。在这种情况下,我可以看到你为什么会想检测整数的烦躁。您可以通过重新排序实现这个目标。

Unless of course the meaning of the values changes if they are specified as floats (e.g. uints go from 0..255, but doubles go from 0.0..1.0). In that case I can see why you would want to detect integer-ness. You can achieve that by reordering.

colorRule  = (uint_ >> uint_ >> uint_ >> -(uint_))
           | (double_ >> double_ >> double_ >> -(double_));

为了让事情更容易对分析器的用户,我想简单地在任何时候都显露出相同的属性类型,以及使用任何转换适当考虑语义动作的整数双打转换:

To make things easier on the user of the parser, I'd simply expose the same attribute type at all times, and consider a semantic action to convert the integers to doubles using whatever conversion appropriate:

#include <boost/spirit/include/phoenix_operator.hpp>
// ....

qi::rule<Iterator, Skipper, double()> colorInt = uint_ [ _val = _1 / 255.0 ];
colorRule = (colorInt >> colorInt >> colorInt >> -(colorInt))
           | (double_ >> double_ >> double_ >> -(double_));

这篇关于没有匹配具有补气::重复和可选的解析器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆