【问题标题】:Unintelligible compilation error for a simple X3 grammar简单 X3 语法的无法理解的编译错误
【发布时间】:2020-07-24 20:05:04
【问题描述】:

我尝试使用 boost spirit x3 实现一个非常简单的语法,但没有成功。

它无法编译,并且由于库中使用的所有模板和复杂概念(我知道,它是一个“标题”),编译错误消息太长而无法理解。

我试图评论部分代码以缩小罪魁祸首,但没有成功,因为它归结为几个部分,无论如何我没有看到任何错误。

Edit2:第一条错误消息确实在push_front_impl.hpp 中,突出显示:
::REQUESTED_PUSH_FRONT_SPECIALISATION_FOR_SEQUENCE_DOES_NOT_EXIST::*

我怀疑关键字auto 或者p2 声明与ulong_long...但没有信心。 需要你们的帮助......精神的精英!

低于重现编译错误的最小代码 sn-p。 编辑:使用 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;
}

【问题讨论】:

  • 我无法重现,尝试了多个 Boost 版本,包括开发分支。
  • 我看到的第一个错误是this assert in boost::mpl::push_front_impl:“如果你在这里有一个断言,你正在请求一个不存在的'push_front'专业化。”其中 T = boost::mpl::aux::vector_tag。和你看到的一样吗?请至少编辑您遇到的错误的一些指示。
  • @Rup 你在什么平台/版本上看到它?这可能就像特定平台的标头包含遗漏
  • @sehe Windows 10,最近的 VS 2019(16.6.2,比 OP 高几个版本),带有 VS2019 安装的默认 Windows SDK 10.0.18362.0,以及 Boost 1.70.0 以匹配 OP。

标签: c++ visual-c++ boost-spirit boost-spirit-x3


【解决方案1】:

这是一个已知的 MPL 限制(Issue with X3 and MS VS2017https://github.com/boostorg/spirit/issues/515)+ MSVC/ICC 编译器的错误/实现差异(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 &gt;&gt; lit("x") &gt;&gt; q &gt;&gt; lit(':') &gt;&gt; ... 可能不是您真正想要的,它(带有船长)将允许解析 " x ":。如果您不想这样,只需使用lit("\"x\"") &gt;&gt; lit(':') &gt;&gt; ...

【讨论】:

  • 哈。我离得不远:) 有趣的是,这是特定于平台的。 +1
  • 这两个定义并没有解决问题。我将尝试更新版本的 Boost 和 Visual Studio
  • 你应该做错了什么。 godbolt.org/z/MEnGvrgodbolt.org/z/8zdnzb
  • boost 1.73 和 Visual Studio v16.6.5 (SDK: 10.0.17763.0) 运气不佳
  • 带有前置定义的repro,拼写为godbolt.org/z/8zdnzb,使用Boost 1.73和Visual Studio v16.6.5对我有用。
【解决方案2】:

您的特定平台/版本可能缺少间接包含(如果我不得不猜测这可能是由于使用 Qi 的 istream 迭代器支持标头引起的)。

如果这不是问题,我的注意力会被 where T = boost::mpl::aux::vector_tag&lt;20&gt; (/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,这样它实际上会匹配您的示例输入

  • 假设:表达式在结构上被简化为更具层次性 - 序列由更少的&gt;&gt;-ed 术语组成 - 希望这消除了潜在的mpl::vector 大小限制。

我遗漏了一个缺失的部分,bb_ib,因为当您想要将解析的值实际分配给属性时它会发生变化。让我们这样做:

属性

struct Node {
    enum Type { bb, ib } type;
    uint64_t id;
    std::string label;
};

如您所见,我选择了一个枚举来表示type。最自然的解析方式是使用symbols&lt;&gt;

struct bb_ib_sym : x3::symbols<Node::Type> {
    bb_ib_sym() { this->add("bb", Node::bb)("ib", Node::ib); }
} bb_ib;

现在可以解析成Node的向量了:

演示

Live On Coliru

#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"}

【讨论】:

  • 你永远不会后悔花时间写一个关于精神/x3的好问题。你总是得到十倍的!谢谢。
  • 确实,包装报价是要走的路。尽管对我来说如何做到这一点并不明显,但我更喜欢先有一个工作示例。我会走那条路。
  • 在精美的手册中,据说您应该使用 BOOST_SPIRIT_DEFINES() 将规则声明与其定义联系起来。但是对于auto node= x3::rules&lt;Node,Node&gt; {"node"} = parser_expression,您似乎使用了“=”运算符。这是一种编写规则的新方式吗?
  • 我个人不喜欢宏机制——它非常容易出错并且“神奇”并且限制了迭代器和上下文类型。由于这些,有史诗linker error hunts。我的看法是 Spirit 适合小型、快速的解析器,这些解析器很容易进行单元测试,包含在 TU 中。所以,是的,我会尽可能避开宏 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-13
  • 1970-01-01
  • 1970-01-01
  • 2015-02-03
  • 1970-01-01
  • 2013-07-13
  • 1970-01-01
相关资源
最近更新 更多