1

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

Markus
  • 592
  • 3
  • 13
  • 1
    Seems to be related to [this](https://github.com/boostorg/spirit/pull/219) which is sadly still unresolved. In the comments they suggest `const auto statement_def = expression > (x3::eps > expression);` as a workaround (and it seems to work in your case). – llonesmiz Jun 23 '17 at 13:42
  • It seems to work in this case, infact this problem only occured in the small minimum-running-example I created. I created this minimum-running-example to examinate _another_ linker bug/error when using `boost::optional`. Sadly `spirit x3` is still in the experimental stage and not much progress going on. – Markus Jul 13 '17 at 15:04

0 Answers0