Internal compiler error with Boost.Spirit

619 Views Asked by At

I'm trying to compile the following seemingly simple code using GCC 3.4.6 and Boost 1.43 and it's generating an internal compiler error:

#include <string>
#include <boost/spirit/include/lex_lexertl.hpp>
#include <boost/spirit/include/qi.hpp>

namespace lex    = boost::spirit::lex;
namespace qi     = boost::spirit::qi;

typedef lex::lexertl::token<std::string::iterator> TokenT;
typedef lex::lexertl::actor_lexer<TokenT> LexerT;

template <typename LexerT>
struct Tokens: public lex::lexer<LexerT>
{};

int main()
{
   typedef Tokens<LexerT>::iterator_type IteratorT;
   qi::rule<IteratorT, int> expression;

   expression = (qi::int_ >> qi::int_) [ qi::_val = qi::_1 ];
}

The generated error:

.../boost/mpl/aux_/preprocessed/gcc/template_arity.hpp:83: internal compiler error: in lookup_member, at cp/search.c:1300

The last line in main() is generating this error. This error goes away by either letting the expression rule work on an std::string::iterator instead of IteratorT.

Any help with fixing the error while still working with a lexer is much appreciated.

Thanks!

1

There are 1 best solutions below

4
sehe On

You missed the parens:

qi::rule<IteratorT, int()> expression;

This might fix the compile error (allthough I can't check, since both gcc, clang and msvc happily compiled it)


You may want to reduce the compiler stress:

  • increase available RAM
  • decrease limits (see below)
  • disable debug information (-g0)
  • and optimizations (-O0; alternatively, optimize for size -Os)

Possibly more in that region.

LIMITS

I did a simple

grep -EoRh '\<\w+_LIMIT\>' ~/custom/boost_1_50_0/boost/spirit/home/ -h | sort -u

to get a list of possible defines, and based a following change on it:

#ifdef LEAN
#define PHOENIX_ACTOR_LIMIT      3 // boost 1_50 default: 10
#define PHOENIX_ARG_LIMIT        5 // boost 1_50 default: 10
#define PHOENIX_CATCH_LIMIT      1 // boost 1_50 default:  9
#define PHOENIX_COMPOSITE_LIMIT  5 // boost 1_50 default: 10
#define PHOENIX_DYNAMIC_LIMIT    1 // boost 1_50 default: 10
#define PHOENIX_LIMIT            5 // boost 1_50 default: 10
#define PHOENIX_LOCAL_LIMIT      3 // boost 1_50 default: 10
#define PHOENIX_MEMBER_LIMIT     3 // boost 1_50 default:  8
#define SPIRIT_ARGUMENTS_LIMIT   5 // boost 1_50 default: 10
#define SPIRIT_ATTRIBUTES_LIMIT  5 // boost 1_50 default: 10
#endif

#include <string>
#include <boost/spirit/include/lex_lexertl.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_function.hpp>
#include <boost/spirit/include/phoenix.hpp>

namespace lex    = boost::spirit::lex;
namespace qi     = boost::spirit::qi;
namespace phx    = boost::phoenix;

struct funcImpl
{
   template <typename T>
   struct result { typedef int type; };

   template <typename T>
   int operator()(T& x) const {
      return 0;
   }
};

typedef lex::lexertl::token<std::string::iterator> TokenT;
typedef lex::lexertl::actor_lexer<TokenT> LexerT;

template <typename LexerT>
struct Tokens: public lex::lexer<LexerT>
{};

int main()
{
   //typedef Tokens<LexerT>::iterator_type IteratorT;
   typedef char* IteratorT;
   qi::rule<IteratorT, int()> expression;

   phx::function<funcImpl> func = funcImpl();
   expression = (qi::int_ >> qi::int_) [ qi::_val = func(qi::_1) ];


   std::cout   << "#define PHOENIX_ACTOR_LIMIT "                       << PHOENIX_ACTOR_LIMIT                       << '\n';
   std::cout   << "#define PHOENIX_ARG_LIMIT "                         << PHOENIX_ARG_LIMIT                         << '\n';
   std::cout   << "#define PHOENIX_CATCH_LIMIT "                       << PHOENIX_CATCH_LIMIT                       << '\n';
   std::cout   << "#define PHOENIX_COMPOSITE_LIMIT "                   << PHOENIX_COMPOSITE_LIMIT                   << '\n';
   std::cout   << "#define PHOENIX_DYNAMIC_LIMIT "                     << PHOENIX_DYNAMIC_LIMIT                     << '\n';
   std::cout   << "#define PHOENIX_LIMIT "                             << PHOENIX_LIMIT                             << '\n';
   std::cout   << "#define PHOENIX_LOCAL_LIMIT "                       << PHOENIX_LOCAL_LIMIT                       << '\n';
   std::cout   << "#define PHOENIX_MEMBER_LIMIT "                      << PHOENIX_MEMBER_LIMIT                      << '\n';
   std::cout   << "#define SPIRIT_ARGUMENTS_LIMIT "                    << SPIRIT_ARGUMENTS_LIMIT                    << '\n';
   std::cout   << "#define SPIRIT_ATTRIBUTES_LIMIT "                   << SPIRIT_ATTRIBUTES_LIMIT                   << '\n';
   //std::cout << "#define BOOST_PHOENIX_LIMIT "                       << BOOST_PHOENIX_LIMIT                       << '\n';
   //std::cout << "#define BOOST_SPIRIT_CLOSURE_LIMIT "                << BOOST_SPIRIT_CLOSURE_LIMIT                << '\n';
   //std::cout << "#define BOOST_SPIRIT_GRAMMAR_STARTRULE_TYPE_LIMIT " << BOOST_SPIRIT_GRAMMAR_STARTRULE_TYPE_LIMIT << '\n';
   //std::cout << "#define BOOST_SPIRIT_RULE_SCANNERTYPE_LIMIT "       << BOOST_SPIRIT_RULE_SCANNERTYPE_LIMIT       << '\n';
   //std::cout << "#define BOOST_SPIRIT_SELECT_LIMIT "                 << BOOST_SPIRIT_SELECT_LIMIT                 << '\n';
   //std::cout << "#define BOOST_SPIRIT_SWITCH_CASE_LIMIT "            << BOOST_SPIRIT_SWITCH_CASE_LIMIT            << '\n';
   //std::cout << "#define PHOENIX_CONSTRUCT_LIMIT "                   << PHOENIX_CONSTRUCT_LIMIT                   << '\n';
   //std::cout << "#define SPIRIT_CLOSURE_LIMIT "                      << SPIRIT_CLOSURE_LIMIT                      << '\n';
}

Now, the following size changes happen (in LoC preprocessed):

sehe@mint12:/tmp$ g++ -g0 -O0 -I /home/sehe/custom/boost_1_50_0/ test.cpp -E | wc -l
193011
sehe@mint12:/tmp$ g++ -g0 -O0 -I ./boost_1_43_0/ test.cpp -DLEAN -E | wc -l
168862

basically, a >10% reduction in code lines. It just might help.