Question

When I tried to express the grammar (small subset of Lua, nearly identical to mini_c; not so somplex), then I faced the problem: g++ driver feeds the gas and gas crushed after a while (when reached about 500MB of total memory consumption on system with 8GB RAM). I look over the Compiler Tutorial and found, that we should to decompose our complex grammar into smaller ones.

The question is is it mandatory, that we should to make the classes (which consist of the sets of the rules) themselves grammars (i.e. make them inherited from boost::spirit::qi::grammar)? IOW, can we divide rules into subsets and distribute them between simple classes declarations, as fields, with intention to define (say, in separate header) and explicitly instantiate each class (in practice, class template) into separate translation unit to avoid the crash described above? If answer is positive, then what to do with using of macro BOOST_SPIRIT_DEBUG_NODES and seat of constructions like:

using namespace boost::spirit;
qi::on_error< qi::fail >(function_definition_,
                                 error_handler_function(_error_handler)(
                                     "Error! Expecting ", qi::_4, qi::_3));

and

using namespace boost::spirit;
qi::on_success(function_name_,
                       annotation_function(_error_handler.iters_)(qi::_val, qi::_1));

?

Where they should be placed (e.g., if we have the chain of classes like: expression_level --> statement_level --> function_list_level, — then they must be placed in each (respectively) or, instead, in the last class in the chain?)?

The main point of such issue is to reduce the compilation complexity (and, thouse, compilation time) by means of simplification of the means of expression of the grammar.

Was it helpful?

Solution

Remember: it's just C++ classes.

So,

  1. you can split your assets into TUs anywhich way you like.
  2. AFAICT on_error and debug attach to their subject rules by reference, so you can put them wherever
  3. yes, you can have classes act as "dumb" containers of rules. In fact, if your iterator/skipper doesn't vary, you could just use namespaces:

    //header
    namespace G1 { extern const qi::rule<It, attr()> R1; }
    
    //cpp
    namespace G1 { const qi::rule<It, attr()> R1 = qi::eps /* ... */; }
    

    I think this approach is largely taken with Spirit X3 (?)

  4. favour composition over inheritance (gives your compiler more freedom)

  5. disable debug information (-g0)
  6. Try optimizing for size -Os or no optimization (-O0)
  7. Disable costly features:

    • BOOST_SPIRIT_DEBUG
    • Use BOOST_SPIRIT_NO_PREDEFINED_TERMINALS
    • Avoid semantic actions

Also, pimpl/file-static anonymous namespaces are there in case you wish to hide all of spirit from your public interface.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top