Re: x3 static initialisation problems
Mikael Asplund <[email protected]>
| Newsgroups | gmane.comp.parsers.spirit.general |
|---|---|
| Message-ID | <[email protected]> |
Hi!
Just wanted to share something I sent to Joel earlier, and he seemed to like, but was probably too busy to clean up and use.
It allows you to have rules defined as global variables, but also as init-functions that return a rule. Not necessarily related to your ponderings, but wanted to get it out there....
// *******************************************
template <bool b>
struct fetch_rule_definition {
template <typename T>
static auto call(const T& def) {
return def;
}
};
template <>
struct fetch_rule_definition<true> {
template <typename T>
static auto call(T& def) {
return def();
}
};
#ifdef BOOST_MSVC
#define RULE_TO_TYPE(rule_name) BOOST_PP_CAT(rule_name, _type)
#else
#define RULE_TO_TYPE(rule_name) decltype(rule_name)
#endif
#undef BOOST_SPIRIT_DEFINE_
#define BOOST_SPIRIT_DEFINE_(r, data, rule_name) \
template <typename Iterator, typename Context, typename Attribute> \
inline bool parse_rule( \
RULE_TO_TYPE(rule_name) rule_ \
, Iterator& first, Iterator const& last \
, Context const& context, Attribute& attr) \
{ \
using boost::spirit::x3::unused; \
using boost::is_function; \
typedef decltype(BOOST_PP_CAT(rule_name, _def)) def_type; \
typedef fetch_rule_definition<is_function<def_type>::value> fetch_type; \
static auto const def_ \
= (rule_name = fetch_type::call(BOOST_PP_CAT(rule_name, _def))); \
return def_.parse(first, last, context, unused, attr); \
} \
/***/
// *******************************************
This allows the following code (changed from the AST example in the documentation) to work:
// *******************************************
using rexpr_value_type = x3::rule<class rexpr_value, ast::rexpr_value>;
using rexpr_type = x3::rule<class rexpr, ast::rexpr>;
using rexpr_key_value_type = x3::rule<class rexpr_key_value, ast::rexpr_key_value>;
rexpr_value_type rexpr_value = "rexpr_value";
rexpr_type rexpr = "rexpr";
rexpr_key_value_type rexpr_key_value = "rexpr_key_value";
auto const quoted_string = lexeme['"' >> *(char_ - '"') >> '"'];
auto const rexpr_value_def
= quoted_string | rexpr;
auto rexpr_key_value_def() {
return quoted_string >> '=' >> rexpr_value;
}
auto rexpr_def() {
return '{' >> *rexpr_key_value >> '}';
}
BOOST_SPIRIT_DEFINE(rexpr_value, rexpr, rexpr_key_value);
// *******************************************
Regards,
Mikael
-----Original Message-----
From: Dirk Bonekämper [mailto:[email protected]]
Sent: Sunday, September 24, 2017 11:30
To: spirit general <[email protected]>
Subject: Re: [Spirit-general] x3 static initialisation problems
I guess I need to clarify my previous mail.
Let's look at the expression parser from the 1.65.1 calc9 example.
expression.hpp declares 'parser::expression_type const& expression()'.
This function allows other rules to access the expression rule. It may be called before the static initializers of expression.o have been called.
The definion of expression() is in expression_def.hpp. When it's called before static initialization, two things happen:
- add_keywords() tries to modify uninitialized static x3::symbols<>
objects.
- a reference to an unintialized object is returned.
So I think that this initialization pattern is broken.
In my code I use several separately compiled rules calling each other.
So the Executable is quite prone to SIOF. And yes, the assertion added to x3::traits::get_info<>() fired immediately, showing that some rules were uninitialized and this problem is real.
As a conlusion, I think that the examples need to be fixed.
The solution I came up with:
Let's assume a rule named coordinates. The parser::coordinates() acessor function returns a reference to a function static coordinates_type object. This rnsures that all calls return a valid object.
The static x3::symbols<> parsers used by the coordinates rule are initialized with symbols_gen functions. (Just as the pattern was in
1.60) symbols<> parsers will be properly initialzed before being called from within main().
This solution works for me. It has one little wart, though. One still needs to keep a namespace object called coordinates. The BOOST_SPIRIT_DEFINE_ macro uses it to figure out the type of the rule object.
------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot _______________________________________________
Spirit-general mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/spirit-general
------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot