I'm struggling with Boost.Spirit.X3 again.
I have several logical groups of parsers (statements, expressions, etc.), each of which is represented by several files:
group.hpp- containstypedefs,BOOST_SPIRIT_DECLAREandexternvariable declaration for those parsers that are used "outside"group_def.hpp- includes the previous one and contains actual definitions of parsers,BOOST_SPIRIT_DEFINE, etc.group.cpp- includes the previous one and contains explicit template instantiations (viaBOOST_SPIRIT_INSTANTIATE)
Basically, it more or less follows the structure proposed in the official tutorial. The only difference is that my grammar is much more complicated so I'm trying to split it into several translation units. All these TUs are then compiled into one library which, in turn, is linked then to the main executable.
I've tried to make a "minimal" example here (live on Wandbox) as it would be inconvenient to list all the files here. It doesn't work though because of some unresolved externals, so, most probably, I instantiate something incorrectly, but I've already spent about a week for this, so I'm quite desperate and don't feel like I'm able to handle this on my own.
A few questions and answers:
Why do I prefer using three files per "group"?
First, because I tried to make it in such a way that I don't want to recompile everything on any small change (not sure if I succeeded in this), so the idea is that somegroup.hpp is just a "lightweight" header with declarations, somegroup_def.hpp is a header with definitions, and somegroup.cpp is just used in order to create a translation unit.
Second, I split _def.hpp and .cpp because I also include these _def.hpp-files directly to tests where I cover not only extern parsers but also "internal" auxiliary ones.
Why am I using extern variables?
I tried it also with functions that return parsers instead (similar to how it is done in the tutorial). Basically, this is the way how it is implemented and does work now. I don't like it because, for instance, given a parser lang::parser::import, I have to either give a function another name (lang::parser::import_) or place it within another namespace (i.e. lang::import). Also, I like the way to use parsers directly how it is done in the Spirit itself (i.e. without parentheses: import vs import_()).
My actual questions are the following:
- How to properly organize the structure if I want to spread my parsers over several translation units?
- And what exactly am I missing in the example of code above, so that it doesn't link?
I would appreciate any help.