一个简单的X3语法的难以理解的编译错误
Unintelligible compilation error for a simple X3 grammar
我有一个非常简单的语法,我尝试使用 boost spirit x3 来实现,但没有成功。
它不编译,并且由于库中使用的所有模板和复杂概念(我知道,它更像是一个“header”),编译错误消息太长了明白了。
我试图评论部分代码以缩小罪魁祸首,但没有成功,因为它归结为几个部分,反正我没有看到任何错误。
Edit2:第一个错误消息确实在 push_front_impl.hpp
中突出显示:
::REQUESTED_PUSH_FRONT_SPECIALISATION_FOR_SEQUENCE_DOES_NOT_EXIST::*
我怀疑关键字 auto
或 p2
语句与 ulong_long
...但没有信心。
需要你们的帮助...精灵精英!
下面是重现编译错误的最小代码片段。
编辑:使用 boost 1.70 和 visual studio 2019 v16.1.6
#include <string>
#include <iostream>
#include "boost/spirit/home/x3.hpp"
#include "boost/spirit/include/support_istream_iterator.hpp"
int main(void)
{
std::string input = \
"\"nodes\":{ {\"type\":\"bb\", \"id\" : 123456567, \"label\" : \"0x12023049\"}," \
"{\"type\":\"bb\", \"id\" : 123123123, \"label\" : \"0x01223234\"}," \
"{\"type\":\"ib\", \"id\" : 223092343, \"label\" : \"0x03020343\"}}";
std::istringstream iss(input);
namespace x3 = boost::spirit::x3;
using x3::char_;
using x3::ulong_long;
using x3::lit;
auto q = lit('\"'); /* q => quote */
auto p1 = q >> lit("type") >> q >> lit(':') >> q >> (lit("bb") | lit("ib")) >> q;
auto p2 = q >> lit("id") >> q >> lit(':') >> ulong_long;
auto p3 = q >> lit("label") >> q >> lit(':') >> q >> (+x3::alpha) >> q;
auto node = lit('{') >> p1 >> lit(',') >> p2 >> lit(',') >> p3 >> lit('}');
auto nodes = q >> lit("nodes") >> q >> lit(':') >> lit('{') >> node % lit(',') >> lit('}');
boost::spirit::istream_iterator f(iss >> std::noskipws), l{};
bool b = x3::phrase_parse(f, l, nodes, x3::space);
return 0;
}
您的特定 platform/version 可能缺少间接包含(如果我不得不猜测这可能是由于使用 Qi 的 istream 迭代器支持 header 引起的)。
如果这不是问题,我的注意力被 where T = boost::mpl::aux::vector_tag<20>
吸引了(/HT @Rup - 数字 20 看起来很可疑,好像它可能是某种限制。
要么我们可以找到超出限制的内容,看看我们是否可以提高它,但为了帮助您和解析器,我将采用“不科学”的方法。
简化表达式
我在您的解析器表达式中看到很多 (lot) 个您不需要的 lit()
节点。我怀疑所有引用的结构都需要是词位,而不是在各处煞费苦心地重复引号,也许将其打包如下:
auto q = [](auto p) { return x3::lexeme['"' >> x3::as_parser(p) >> '"']; };
auto type = q("type") >> ':' >> q(bb_ib);
auto id = q("id") >> ':' >> x3::ulong_long;
auto label = q("label") >> ':' >> q(+x3::alnum);
备注:
我改进了命名,这样阅读起来更自然:
auto node = '{' >> type >> ',' >> id >> ',' >> label >> '}';
我将 alpha
更改为 alnum
所以它实际上会匹配您的样本输入
假设:表达式在结构上被简化为更具层次性 - 序列由更少的 >>
-ed 术语组成 - 希望这消除了潜在的 mpl::vector
大小限制。
我遗漏了一个 bb_ib
部分,因为当您想要实际将已解析的值分配给属性时它会发生变化。让我们这样做:
属性
struct Node {
enum Type { bb, ib } type;
uint64_t id;
std::string label;
};
如您所见,我选择了一个枚举来表示 type
。最自然的解析方式是使用 symbols<>
struct bb_ib_sym : x3::symbols<Node::Type> {
bb_ib_sym() { this->add("bb", Node::bb)("ib", Node::ib); }
} bb_ib;
现在你可以解析成一个向量 Node
:
演示
#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/home/x3.hpp>
#include <iostream>
#include <iomanip>
struct Node {
enum Type { bb, ib } type;
uint64_t id;
std::string label;
};
namespace { // debug output
inline std::ostream& operator<<(std::ostream& os, Node::Type t) {
switch (t) {
case Node::bb: return os << "bb";
case Node::ib: return os << "ib";
}
return os << "?";
}
inline std::ostream& operator<<(std::ostream& os, Node const& n) {
return os << "Node{" << n.type << ", " << n.id << ", " << std::quoted(n.label) << "}";
}
}
// attribute propagation
BOOST_FUSION_ADAPT_STRUCT(Node, type, id, label)
int main() {
std::string input = R"("nodes": {
{
"type": "bb",
"id": 123456567,
"label": "0x12023049"
},
{
"type": "bb",
"id": 123123123,
"label": "0x01223234"
},
{
"type": "ib",
"id": 223092343,
"label": "0x03020343"
}
})";
namespace x3 = boost::spirit::x3;
struct bb_ib_sym : x3::symbols<Node::Type> {
bb_ib_sym() { this->add("bb", Node::bb)("ib", Node::ib); }
} bb_ib;
auto q = [](auto p) { return x3::lexeme['"' >> x3::as_parser(p) >> '"']; };
auto type = q("type") >> ':' >> q(bb_ib);
auto id = q("id") >> ':' >> x3::ulong_long;
auto label = q("label") >> ':' >> q(+x3::alnum);
auto node
= x3::rule<Node, Node> {"node"}
= '{' >> type >> ',' >> id >> ',' >> label >> '}';
auto nodes = q("nodes") >> ':' >> '{' >> node % ',' >> '}';
std::vector<Node> parsed;
auto f = begin(input);
auto l = end(input);
if (x3::phrase_parse(f, l, nodes, x3::space, parsed)) {
for (Node& node : parsed) {
std::cout << node << "\n";
}
} else {
std::cout << "Parse failed\n";
}
if (f!=l) {
std::cout << "Remaining input: " << std::quoted(std::string(f, l)) << "\n";
}
}
版画
Node{bb, 123456567, "0x12023049"}
Node{bb, 123123123, "0x01223234"}
Node{ib, 223092343, "0x03020343"}
这是一个已知的 MPL 限制 (Issue with X3 and MS VS2017, https://github.com/boostorg/spirit/issues/515) + bug/difference of implementation for MSVC/ICC compilers (https://github.com/boostorg/mpl/issues/43)。
我在没有使用 MPL (https://github.com/boostorg/spirit/pull/607) 的情况下重写了一个有问题的部分,它将在 Boost 1.74 中发布,在那之前你应该能够解决问题:
#define BOOST_MPL_CFG_NO_PREPROCESSED_HEADERS
#define BOOST_MPL_LIMIT_VECTOR_SIZE 50
或者,您可以将语法的不同部分包装到规则中,这将减少序列解析器链。
请注意,q >> lit("x") >> q >> lit(':') >> ...
可能不是您真正想要的,它(带有船长)将允许解析 " x ":
。如果您不希望使用 lit("\"x\"") >> lit(':') >> ...
我有一个非常简单的语法,我尝试使用 boost spirit x3 来实现,但没有成功。
它不编译,并且由于库中使用的所有模板和复杂概念(我知道,它更像是一个“header”),编译错误消息太长了明白了。
我试图评论部分代码以缩小罪魁祸首,但没有成功,因为它归结为几个部分,反正我没有看到任何错误。
Edit2:第一个错误消息确实在 push_front_impl.hpp
中突出显示:
::REQUESTED_PUSH_FRONT_SPECIALISATION_FOR_SEQUENCE_DOES_NOT_EXIST::*
我怀疑关键字 auto
或 p2
语句与 ulong_long
...但没有信心。
需要你们的帮助...精灵精英!
下面是重现编译错误的最小代码片段。 编辑:使用 boost 1.70 和 visual studio 2019 v16.1.6
#include <string>
#include <iostream>
#include "boost/spirit/home/x3.hpp"
#include "boost/spirit/include/support_istream_iterator.hpp"
int main(void)
{
std::string input = \
"\"nodes\":{ {\"type\":\"bb\", \"id\" : 123456567, \"label\" : \"0x12023049\"}," \
"{\"type\":\"bb\", \"id\" : 123123123, \"label\" : \"0x01223234\"}," \
"{\"type\":\"ib\", \"id\" : 223092343, \"label\" : \"0x03020343\"}}";
std::istringstream iss(input);
namespace x3 = boost::spirit::x3;
using x3::char_;
using x3::ulong_long;
using x3::lit;
auto q = lit('\"'); /* q => quote */
auto p1 = q >> lit("type") >> q >> lit(':') >> q >> (lit("bb") | lit("ib")) >> q;
auto p2 = q >> lit("id") >> q >> lit(':') >> ulong_long;
auto p3 = q >> lit("label") >> q >> lit(':') >> q >> (+x3::alpha) >> q;
auto node = lit('{') >> p1 >> lit(',') >> p2 >> lit(',') >> p3 >> lit('}');
auto nodes = q >> lit("nodes") >> q >> lit(':') >> lit('{') >> node % lit(',') >> lit('}');
boost::spirit::istream_iterator f(iss >> std::noskipws), l{};
bool b = x3::phrase_parse(f, l, nodes, x3::space);
return 0;
}
您的特定 platform/version 可能缺少间接包含(如果我不得不猜测这可能是由于使用 Qi 的 istream 迭代器支持 header 引起的)。
如果这不是问题,我的注意力被 where T = boost::mpl::aux::vector_tag<20>
吸引了(/HT @Rup - 数字 20 看起来很可疑,好像它可能是某种限制。
要么我们可以找到超出限制的内容,看看我们是否可以提高它,但为了帮助您和解析器,我将采用“不科学”的方法。
简化表达式
我在您的解析器表达式中看到很多 (lot) 个您不需要的 lit()
节点。我怀疑所有引用的结构都需要是词位,而不是在各处煞费苦心地重复引号,也许将其打包如下:
auto q = [](auto p) { return x3::lexeme['"' >> x3::as_parser(p) >> '"']; };
auto type = q("type") >> ':' >> q(bb_ib);
auto id = q("id") >> ':' >> x3::ulong_long;
auto label = q("label") >> ':' >> q(+x3::alnum);
备注:
我改进了命名,这样阅读起来更自然:
auto node = '{' >> type >> ',' >> id >> ',' >> label >> '}';
我将
alpha
更改为alnum
所以它实际上会匹配您的样本输入假设:表达式在结构上被简化为更具层次性 - 序列由更少的
>>
-ed 术语组成 - 希望这消除了潜在的mpl::vector
大小限制。
我遗漏了一个 bb_ib
部分,因为当您想要实际将已解析的值分配给属性时它会发生变化。让我们这样做:
属性
struct Node {
enum Type { bb, ib } type;
uint64_t id;
std::string label;
};
如您所见,我选择了一个枚举来表示 type
。最自然的解析方式是使用 symbols<>
struct bb_ib_sym : x3::symbols<Node::Type> {
bb_ib_sym() { this->add("bb", Node::bb)("ib", Node::ib); }
} bb_ib;
现在你可以解析成一个向量 Node
:
演示
#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/home/x3.hpp>
#include <iostream>
#include <iomanip>
struct Node {
enum Type { bb, ib } type;
uint64_t id;
std::string label;
};
namespace { // debug output
inline std::ostream& operator<<(std::ostream& os, Node::Type t) {
switch (t) {
case Node::bb: return os << "bb";
case Node::ib: return os << "ib";
}
return os << "?";
}
inline std::ostream& operator<<(std::ostream& os, Node const& n) {
return os << "Node{" << n.type << ", " << n.id << ", " << std::quoted(n.label) << "}";
}
}
// attribute propagation
BOOST_FUSION_ADAPT_STRUCT(Node, type, id, label)
int main() {
std::string input = R"("nodes": {
{
"type": "bb",
"id": 123456567,
"label": "0x12023049"
},
{
"type": "bb",
"id": 123123123,
"label": "0x01223234"
},
{
"type": "ib",
"id": 223092343,
"label": "0x03020343"
}
})";
namespace x3 = boost::spirit::x3;
struct bb_ib_sym : x3::symbols<Node::Type> {
bb_ib_sym() { this->add("bb", Node::bb)("ib", Node::ib); }
} bb_ib;
auto q = [](auto p) { return x3::lexeme['"' >> x3::as_parser(p) >> '"']; };
auto type = q("type") >> ':' >> q(bb_ib);
auto id = q("id") >> ':' >> x3::ulong_long;
auto label = q("label") >> ':' >> q(+x3::alnum);
auto node
= x3::rule<Node, Node> {"node"}
= '{' >> type >> ',' >> id >> ',' >> label >> '}';
auto nodes = q("nodes") >> ':' >> '{' >> node % ',' >> '}';
std::vector<Node> parsed;
auto f = begin(input);
auto l = end(input);
if (x3::phrase_parse(f, l, nodes, x3::space, parsed)) {
for (Node& node : parsed) {
std::cout << node << "\n";
}
} else {
std::cout << "Parse failed\n";
}
if (f!=l) {
std::cout << "Remaining input: " << std::quoted(std::string(f, l)) << "\n";
}
}
版画
Node{bb, 123456567, "0x12023049"}
Node{bb, 123123123, "0x01223234"}
Node{ib, 223092343, "0x03020343"}
这是一个已知的 MPL 限制 (Issue with X3 and MS VS2017, https://github.com/boostorg/spirit/issues/515) + bug/difference of implementation for MSVC/ICC compilers (https://github.com/boostorg/mpl/issues/43)。
我在没有使用 MPL (https://github.com/boostorg/spirit/pull/607) 的情况下重写了一个有问题的部分,它将在 Boost 1.74 中发布,在那之前你应该能够解决问题:
#define BOOST_MPL_CFG_NO_PREPROCESSED_HEADERS
#define BOOST_MPL_LIMIT_VECTOR_SIZE 50
或者,您可以将语法的不同部分包装到规则中,这将减少序列解析器链。
请注意,q >> lit("x") >> q >> lit(':') >> ...
可能不是您真正想要的,它(带有船长)将允许解析 " x ":
。如果您不希望使用 lit("\"x\"") >> lit(':') >> ...