我又在为 Boost.Spirit.X3 苦苦挣扎。
我有几个逻辑解析器组(语句、表达式等),每个解析器都由几个文件表示:
group.hpp
- 包含 typedef
年代,BOOST_SPIRIT_DECLARE
和 extern
那些在“外部”使用的解析器的变量声明group_def.hpp
- 包括前一个并包含解析器的实际定义,BOOST_SPIRIT_DEFINE
等group.cpp
- 包括前一个并包含显式模板实例化(通过 BOOST_SPIRIT_INSTANTIATE
)基本上,它或多或少遵循官方tutorial中提出的结构。 .唯一的区别是我的语法要复杂得多,所以我试图把它分成几个翻译单元。然后将所有这些 TU 编译到一个库中,然后将其链接到主可执行文件。
我试着做一个“最小”的例子here (生活在 Wandbox 上)因为在这里列出所有文件会很不方便。
但是它不起作用因为一些 Unresolved external 因素,所以,很可能,我错误地实例化了一些东西,但我已经为此花了大约一周的时间,所以我很绝望,不觉得我能够自己处理这个.
几个问题和答案:
为什么我更喜欢每个“组”使用三个文件?
首先,因为我试图以这样一种方式制作它,即我不想在任何小的更改上重新编译所有内容(不确定我是否成功了),所以我的想法是
somegroup.hpp
只是一个带有声明的“轻量级”标题,somegroup_def.hpp
是带有定义的标题,somegroup.cpp
仅用于创建翻译单元。二、我拆分
_def.hpp
和 .cpp
因为我还包括这些_def.hpp
-文件直接用于测试,我不仅涵盖extern
解析器,还有“内部”辅助的。为什么我使用
extern
变量?我也尝试使用返回解析器的函数(类似于教程中的完成方式)。基本上,这就是它的实现方式和现在的工作方式。我不喜欢它,例如,给定一个解析器
lang::parser::import
,我必须给函数另一个名称( lang::parser::import_
)或将其放在另一个命名空间中(即 lang::import
)。另外,我喜欢直接使用解析器的方式,它是如何在 Spirit 本身中完成的(即没有括号: import
与 import_()
)。我的实际问题如下:
我将不胜感激任何帮助。
最佳答案
Why do I prefer using three files per "group"?
我,我自己,找到分离到
grammar_def.hpp
和 grammar.cpp
没用,但这只是一种意见。Why am I using extern variables?
I tried it also with functions that return parsers instead
不要这样做。这将导致静态初始化命令惨败。规则占位符足够轻量级,可以在每个翻译单元中实例化它们。
How to properly organize the structure if I want to spread my parsers over several translation units?
这是一个关于口味的问题。您只需要在其中一个 TU 中实例化一个规则并拥有一个
x3::rule<...>
+ BOOST_SPIRIT_DECLARE
在使用它的每个其他人中。实现这一目标的最佳方法是拆分
x3::rule<...>
关闭 .cpp
/_def.hpp
放入单独的 header 中(将其放入“轻量级” .hpp
中),并将其包含在需要这些规则的每个 TU 中。见 https://github.com/mapnik/mapnik/pull/4072/files和 https://github.com/boostorg/spirit/pull/493/files
And what exactly am I missing in the example of code above, so that it doesn't link?
std::string::const_iterator
和 std::string::iterator
迭代器。 document_def = eols >> +megarule >> eols
),但不要使用适当的上下文实例化它们。要么干脆不让它们成为规则,要么添加 BOOST_SPIRIT_INSTANTIATE
带有您在错误消息中看到的上下文。 关于c++ - 将 Boost.Spirit.X3 解析器拆分为多个 TU,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59709229/