I created a parser based on the spirit x3 calc8/calc9 examples. A Linker error (see below ) is the result when using the following definition:
const auto statement_def = expression > x3::eps > expression;
with the following struct:
struct statement
{
expression lhs;
expression rhs;
};
// ...
BOOST_FUSION_ADAPT_STRUCT(ast::statement, lhs, rhs)
but the following works without problems:
const auto statement_def = expression > expression;
this also works:
const auto statement_def = expression > expression > x3::eps;
this also works:
Changing the statement
struct to struct statement : std::list<expression> {}
compiles and works.
The Compound Attribute Rules should make it equivalent:
a: A, b: Unused --> (a >> b): A
a: A, b: A --> (a >> b): vector<A>
Why does the unused attribute parser cause problems?
This is the linker error I get:
statement.cpp.o: In function `bool boost::spirit::x3::rule<parser::expression_class, ast::expression, false>::parse<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, boost::spirit::x3::context<boost::spirit::x3::error_handler_tag, std::reference_wrapper<boost::spirit::x3::error_handler<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > const, boost::spirit::x3::context<boost::spirit::x3::skipper_tag, boost::spirit::x3::char_class<boost::spirit::char_encoding::ascii, boost::spirit::x3::space_tag> const, boost::spirit::x3::unused_type> >, boost::fusion::iterator_range<boost::fusion::basic_iterator<boost::fusion::struct_iterator_tag, boost::fusion::random_access_traversal_tag, ast::statement, 0>, boost::fusion::basic_iterator<boost::fusion::struct_iterator_tag, boost::fusion::random_access_traversal_tag, ast::statement, 1> > >(__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >&, __gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, boost::spirit::x3::context<boost::spirit::x3::error_handler_tag, std::reference_wrapper<boost::spirit::x3::error_handler<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > const, boost::spirit::x3::context<boost::spirit::x3::skipper_tag, boost::spirit::x3::char_class<boost::spirit::char_encoding::ascii, boost::spirit::x3::space_tag> const, boost::spirit::x3::unused_type> > const&, boost::spirit::x3::unused_type, boost::fusion::iterator_range<boost::fusion::basic_iterator<boost::fusion::struct_iterator_tag, boost::fusion::random_access_traversal_tag, ast::statement, 0>, boost::fusion::basic_iterator<boost::fusion::struct_iterator_tag, boost::fusion::random_access_traversal_tag, ast::statement, 1> >&) const':
statement.cpp:(.text._ZNK5boost6spirit2x34ruleIN6parser16expression_classEN3ast10expressionELb0EE5parseIN9__gnu_cxx17__normal_iteratorIPKcNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEENS1_7contextINS1_17error_handler_tagEKSt17reference_wrapperINS1_13error_handlerISJ_EEENSK_INS1_11skipper_tagEKNS1_10char_classINS0_13char_encoding5asciiENS1_9space_tagEEENS1_11unused_typeEEEEENS_6fusion14iterator_rangeINS11_14basic_iteratorINS11_19struct_iterator_tagENS11_27random_access_traversal_tagENS5_9statementELi0EEENS13_IS14_S15_S16_Li1EEEEEEEbRT_RKS1A_RKT0_SY_RT1_[_ZNK5boost6spirit2x34ruleIN6parser16expression_classEN3ast10expressionELb0EE5parseIN9__gnu_cxx17__normal_iteratorIPKcNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEENS1_7contextINS1_17error_handler_tagEKSt17reference_wrapperINS1_13error_handlerISJ_EEENSK_INS1_11skipper_tagEKNS1_10char_classINS0_13char_encoding5asciiENS1_9space_tagEEENS1_11unused_typeEEEEENS_6fusion14iterator_rangeINS11_14basic_iteratorINS11_19struct_iterator_tagENS11_27random_access_traversal_tagENS5_9statementELi0EEENS13_IS14_S15_S16_Li1EEEEEEEbRT_RKS1A_RKT0_SY_RT1_]+0x37): undefined reference to `bool parser::parse_rule<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, boost::spirit::x3::context<boost::spirit::x3::error_handler_tag, std::reference_wrapper<boost::spirit::x3::error_handler<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > const, boost::spirit::x3::context<boost::spirit::x3::skipper_tag, boost::spirit::x3::char_class<boost::spirit::char_encoding::ascii, boost::spirit::x3::space_tag> const, boost::spirit::x3::unused_type> >, boost::fusion::iterator_range<boost::fusion::basic_iterator<boost::fusion::struct_iterator_tag, boost::fusion::random_access_traversal_tag, ast::statement, 0>, boost::fusion::basic_iterator<boost::fusion::struct_iterator_tag, boost::fusion::random_access_traversal_tag, ast::statement, 1> > >(boost::spirit::x3::rule<parser::expression_class, ast::expression, false>, __gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >&, __gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, boost::spirit::x3::context<boost::spirit::x3::error_handler_tag, std::reference_wrapper<boost::spirit::x3::error_handler<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > const, boost::spirit::x3::context<boost::spirit::x3::skipper_tag, boost::spirit::x3::char_class<boost::spirit::char_encoding::ascii, boost::spirit::x3::space_tag> const, boost::spirit::x3::unused_type> > const&, boost::fusion::iterator_range<boost::fusion::basic_iterator<boost::fusion::struct_iterator_tag, boost::fusion::random_access_traversal_tag, ast::statement, 0>, boost::fusion::basic_iterator<boost::fusion::struct_iterator_tag, boost::fusion::random_access_traversal_tag, ast::statement, 1> >&)'
collect2: error: ld returned 1 exit status
I suspect it has something to do with boost::fusion::iterator_range<boost::fusion::basic_iterator<boost::fusion::struct_iterator_tag, boost::fusion::random_access_traversal_tag, ast::statement, 0>, boost::fusion::basic_iterator<boost::fusion::struct_iterator_tag, boost::fusion::random_access_traversal_tag, ast::statement, 1> >
.
Here is the code: https://wandbox.org/permlink/csfB0mdeYRE8Os9L
I could also reproduce this by slightly modifying the x3 calc8/calc9 examples: Simply change the assignment rule from
auto const assignment_def =
variable
> '='
> expression
> ';'
;
to
auto const assignment_def =
expression
> '='
> expression
> ';'
;
and change the type of assignment.lhs
to expression
(plus fix the occurrences of lhs
)
Boost version: 1.63 Comiler: gcc (Ubuntu) 5.4