为什么我的 boost::spirit 规则不能编译用于解析列表列表?

Why doesn't my boost::spirit rule compile for parsing a list of lists?

我正在尝试使用 boost::spirit 为 Open Inventor .iv 文件编写解析器。

我有以下 VertexProperty 节点结构:

struct VertexProperty
{
   std::vector<std::vector<float> > vertices;
   std::vector<std::vector<float> > normals;
   std::vector<std::vector<float> > texCoords;
};

BOOST_FUSION_ADAPT_STRUCT(
   VertexProperty,
   (std::vector<std::vector<float> >, vertices)
   (std::vector<std::vector<float> >, normals)
   (std::vector<std::vector<float> >, texCoords)
   )

以及以下解析规则(无法编译):

qi::rule<Iterator, VertexProperty(), Skipper> RULE_VertexProperty;
RULE_VertexProperty = lit("VertexProperty")
   >> char_('{')
   >> lit("vertex") >> char_('[')
   >> repeat(3)[qi::float_] >> *(char_(',') >> repeat(3)[qi::float_])
   >> char_(']')
   >> lit("normal") >> char_('[')
   >> repeat(3)[qi::float_] >> *(char_(',') >> repeat(3)[qi::float_])
   >> char_(']')
   >> lit("texCoord") >> char_('[')
   >> repeat(2)[qi::float] >> *(char_(',') >> repeat(2)[qi::float_])
   >> char_(']') >> char_('}');

根据此规则,以下内容应生成有效的 VertexProperty 解析:

VertexProperty {
   vertex [ 0.0 0.0 1.0,
            1.0 1.0 1.0,
            1.0 0.0 1.0]
   normal [1.0 0.0 0.0,
           0.0 1.0 0.0,
           0.0 0.0 1.0]
   texCoord [0.0 0.0,
             1.0 0.0,
             1.0 1.0]
}

我的假设是问题出在我如何尝试将逗号分隔的元组解析为向量的向量。

解析以下形式的 3 元组和/或 2 元组列表的正确方法是什么:

[float float float, float float float, float float float]

使用 boost::spirit?

EDIT 我看错了问题。这是重写:

Live On Coliru

Live On Coliru(带调试输出)

struct V2 { float a, b;    } ;
struct V3 { float a, b, c; } ;
struct VertexProperty { 
    std::vector<V3> vertices, normals;
    std::vector<V2> texCoords; 
};

BOOST_FUSION_ADAPT_STRUCT(V2, a,b)
BOOST_FUSION_ADAPT_STRUCT(V3, a,b,c)
BOOST_FUSION_ADAPT_STRUCT(VertexProperty, vertices,normals,texCoords)

template <typename Iterator>
struct Parser : qi::grammar<Iterator, VertexProperty()> {
    Parser() : Parser::base_type(start) {
        v2 = qi::double_ >> qi::double_;
        v3 = qi::double_ >> qi::double_ >> qi::double_;

        vertexproperty = qi::lit("VertexProperty")
            >> '{'
            >> "vertex"   >> '[' >> (v3 % ',') >> ']'
            >> "normal"   >> '[' >> (v3 % ',') >> ']'
            >> "texCoord" >> '[' >> (v2 % ',') >> ']'
            >> '}';

        start = qi::skip(qi::space) [vertexproperty];

        BOOST_SPIRIT_DEBUG_NODES((v2)(v3)(vertexproperty))
    }

  private:
    qi::rule<Iterator, VertexProperty()> start;
    qi::rule<Iterator, VertexProperty(), qi::space_type> vertexproperty;
    qi::rule<Iterator, V2(),             qi::space_type> v2;
    qi::rule<Iterator, V3(),             qi::space_type> v3;
};

备注:

  • 使用类型元素而不是 'just' 矢量
  • 为 V3 使用单独的规则
  • 使用文字 (qi::lit) 而不是 qi::char_ 因为您不想暴露匹配的标点符号
  • 使用列表运算符(a % b 已经匹配 a [b a]...

更新:完整的现场演示

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

namespace qi = boost::spirit::qi;

struct V2 { float a, b;    } ;
struct V3 { float a, b, c; } ;
struct VertexProperty { 
    std::vector<V3> vertices, normals;
    std::vector<V2> texCoords; 
};

BOOST_FUSION_ADAPT_STRUCT(V2, a,b)
BOOST_FUSION_ADAPT_STRUCT(V3, a,b,c)
BOOST_FUSION_ADAPT_STRUCT(VertexProperty, vertices,normals,texCoords)

template <typename Iterator>
struct Parser : qi::grammar<Iterator, VertexProperty()> {
    Parser() : Parser::base_type(start) {
        v2 = qi::double_ >> qi::double_;
        v3 = qi::double_ >> qi::double_ >> qi::double_;

        vertexproperty = qi::lit("VertexProperty")
            >> '{'
            >> "vertex"   >> '[' >> (v3 % ',') >> ']'
            >> "normal"   >> '[' >> (v3 % ',') >> ']'
            >> "texCoord" >> '[' >> (v2 % ',') >> ']'
            >> '}';

        start = qi::skip(qi::space) [vertexproperty];

        BOOST_SPIRIT_DEBUG_NODES((v2)(v3)(vertexproperty))
    }

  private:
    qi::rule<Iterator, VertexProperty()> start;
    qi::rule<Iterator, VertexProperty(), qi::space_type> vertexproperty;
    qi::rule<Iterator, V2(),             qi::space_type> v2;
    qi::rule<Iterator, V3(),             qi::space_type> v3;
};

int main() {
    using Iterator = std::string::const_iterator;

    std::string const sample = "VertexProperty {\n"
        " vertex [ 0.0 0.0 1.0,\n"
        "     1.0 1.0 1.0,\n"
        "     1.0 0.0 1.0]\n"
        " normal [1.0 0.0 0.0,\n"
        "     0.0 1.0 0.0,\n"
        "     0.0 0.0 1.0]\n"
        " texCoord [0.0 0.0,\n"
        "     1.0 0.0,\n"
        "     1.0 1.0]\n"
        "}";

    auto f = sample.begin(), l = sample.end();
    VertexProperty data;
    bool ok = qi::parse(f, l, Parser<Iterator>(), data);

    if (ok) {
        std::cout << "Parsed: " << data.vertices.size() << ", " << data.normals.size() << ", " << data.texCoords.size() << "\n";
    } else {
        std::cout << "Parse failed\n";
    }

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

版画

Parsed: 3, 3, 3

有调试信息

<vertexproperty>
  <try>VertexProperty {\n ve</try>
  <v3>
    <try> 0.0 0.0 1.0,\n     1</try>
    <success>,\n     1.0 1.0 1.0,\n</success>
    <attributes>[[0, 0, 1]]</attributes>
  </v3>
  <v3>
    <try>\n     1.0 1.0 1.0,\n </try>
    <success>,\n     1.0 0.0 1.0]\n</success>
    <attributes>[[1, 1, 1]]</attributes>
  </v3>
  <v3>
    <try>\n     1.0 0.0 1.0]\n </try>
    <success>]\n normal [1.0 0.0 0</success>
    <attributes>[[1, 0, 1]]</attributes>
  </v3>
  <v3>
    <try>1.0 0.0 0.0,\n     0.</try>
    <success>,\n     0.0 1.0 0.0,\n</success>
    <attributes>[[1, 0, 0]]</attributes>
  </v3>
  <v3>
    <try>\n     0.0 1.0 0.0,\n </try>
    <success>,\n     0.0 0.0 1.0]\n</success>
    <attributes>[[0, 1, 0]]</attributes>
  </v3>
  <v3>
    <try>\n     0.0 0.0 1.0]\n </try>
    <success>]\n texCoord [0.0 0.0</success>
    <attributes>[[0, 0, 1]]</attributes>
  </v3>
  <v2>
    <try>0.0 0.0,\n     1.0 0.</try>
    <success>,\n     1.0 0.0,\n    </success>
    <attributes>[[0, 0]]</attributes>
  </v2>
  <v2>
    <try>\n     1.0 0.0,\n     </try>
    <success>,\n     1.0 1.0]\n}</success>
    <attributes>[[1, 0]]</attributes>
  </v2>
  <v2>
    <try>\n     1.0 1.0]\n}</try>
    <success>]\n}</success>
    <attributes>[[1, 1]]</attributes>
  </v2>
  <success></success>
  <attributes>[[[[0, 0, 1], [1, 1, 1], [1, 0, 1]], [[1, 0, 0], [0, 1, 0], [0, 0, 1]], [[0, 0], [1, 0], [1, 1]]]]</attributes>
</vertexproperty>