1

我又在为 Boost.Spirit.X3 苦苦挣扎。

我有几个逻辑解析器组(语句、表达式等),每个解析器都由几个文件表示:

  • group.hpp- 包含“外部”使用的解析器typedef的 sBOOST_SPIRIT_DECLAREextern变量声明
  • group_def.hpp- 包括前一个并包含解析器的实际定义BOOST_SPIRIT_DEFINE,等等。
  • group.cpp- 包括前一个并包含显式模板实例化(通过BOOST_SPIRIT_INSTANTIATE

基本上,它或多或少遵循官方教程中提出的结构。唯一的区别是我的语法要复杂得多,所以我试图把它分成几个翻译单元。然后将所有这些 TU 编译到一个库中,然后将其链接到主可执行文件。

我试图在这里做一个“最小”的例子(活在 Wandbox 上),因为在这里列出所有文件会很不方便。 由于一些未解决的外部因素,它不起作用,所以,很可能,我错误地实例化了一些东西,但我已经为此花了大约一周的时间,所以我很绝望,不觉得我能我自己来处理这个。

几个问题和答案:

为什么我更喜欢每个“组”使用三个文件?

首先,因为我试图以这样一种方式制作它,即我不想在任何小的更改上重新编译所有内容(不确定我是否成功了),所以这个想法somegroup.hpp只是一个带有声明的“轻量级”标题,somegroup_def.hpp是带有定义的标题,somegroup.cpp仅用于创建翻译单元。

其次,我拆分_def.hpp.cpp因为我还将这些_def.hpp文件直接包含到测试中,我不仅涵盖extern解析器,还涵盖“内部”辅助解析器。

为什么我要使用extern变量?

我也尝试使用返回解析器的函数(类似于教程中的完成方式)。基本上,这就是它的实现方式和现在的工作方式。我不喜欢它,因为例如,给定一个解析器lang::parser::import,我必须给一个函数另一个名称(lang::parser::import_)或将它放在另一个名称空间中(即lang::import)。此外,我喜欢直接使用解析器的方式,它是如何在 Spirit 本身中完成的(即不带括号:importvs import_())。

我的实际问题如下:

  • 如果我想将解析器分布在多个翻译单元上,如何正确组织结构?
  • 我在上面的代码示例中究竟遗漏了什么,所以它没有链接?

我将不胜感激任何帮助。

4

1 回答 1

3

为什么我更喜欢每个“组”使用三个文件?

我,我自己,发现分离grammar_def.hppgrammar.cpp无用,但这只是一种观点。

为什么我使用外部变量?

我也尝试使用返回解析器的函数

不要这样做。这将导致静态初始化命令惨败。规则占位符足够轻量级,可以在每个翻译单元中实例化它们。

如果我想将解析器分布在多个翻译单元上,如何正确组织结构?

这是一个关于口味的问题。您只需要在其中一个 TU 中实例化一个规则,并在使用它的每个其他TU 中都有一个x3::rule<...>+ 。BOOST_SPIRIT_DECLARE

实现这一点的最佳方法是将/x3::rule<...>拆分为单独的标头(将其放入“轻量级”中),并将其包含在需要这些规则的每个 TU 中。.cpp_def.hpp.hpp

请参阅https://github.com/mapnik/mapnik/pull/4072/fileshttps://github.com/boostorg/spirit/pull/493/files

我在上面的代码示例中究竟遗漏了什么,所以它没有链接?

  1. 您正在混合std::string::const_iteratorstd::string::iterator迭代器。
  2. 您正在使用您的一些船长作为解析器(f.ex. document_def = eols >> +megarule >> eols),但不要使用适当的上下文实例化它们。要么不让它们成为规则,要么添加BOOST_SPIRIT_INSTANTIATE您在错误消息中看到的上下文。
于 2020-01-21T12:58:19.977 回答