Too many sections, assembler error, using boost::spirit

柔情痞子 提交于 2019-11-30 13:12:12

I've done some hacking here and refactored things a to show the non-runtime-polymorphic style:

I hope it doesn't increase compile times :) (I haven't actually gotten around to splitting the grammar up, but it got smaller).


Features:

  • no more heap allocated AST nodes (not even for trees like expression and/or statement); hence no more explicit cloning and/or spurious const members.
  • I have replaced Maybe.hpp with

    #pragma once
    #include <boost/optional.hpp>
    
    template <typename T> using Maybe = boost::optional<T>;
    

    It's quick-and-dirty, but it all compiles

  • I've replace open type-switching with my own minor effort (I couldn't get it to work; also with boost-variant it's all built in):

    namespace visitor_galore // this is my make-shift replacement for typeswitch (I couldn't find it/make it work)
    {
        template<typename T, class...Fs> struct visitor_t;
    
        template<typename T, class F1, class...Fs>
        struct visitor_t<T, F1, Fs...> : F1, visitor_t<T, Fs...>::type {
            typedef visitor_t type;
            visitor_t(F1 head, Fs...tail) : F1(head), visitor_t<T, Fs...>::type(tail...) {}
    
            using F1::operator();
            using visitor_t<T, Fs...>::type::operator();
        };
    
        template<typename T, class F> struct visitor_t<T, F> : F, boost::static_visitor<T> {
            typedef visitor_t type;
            visitor_t(F f) : F(f) {}
            using F::operator();
        };
    
        template<typename T=void, class...Fs>
        typename visitor_t<T, Fs...>::type make_visitor(Fs...x) { return {x...}; }
    }
    
    using visitor_galore::make_visitor;
    

    To see how this is used, have a look at e.g. ast_pp.cpp:

    void pretty_print(expression_incdec const& exp)
    {
         boost::apply_visitor(
                make_visitor(
                    [&exp](inc_dec_op_preinc const& op)  { std::cout << "++"; pretty_print(exp.variable); }, 
                    [&exp](inc_dec_op_predec const& op)  { std::cout << "--"; pretty_print(exp.variable); }, 
                    [&exp](inc_dec_op_postinc const& op) { pretty_print(exp.variable); std::cout << "++"; }, 
                    [&exp](inc_dec_op_postdec const& op) { pretty_print(exp.variable); std::cout << "--"; }
                    )
                , exp.operatur);
    }
    

    BONUS If you don't care much for listing all types in the branches, e.g. because they all default to calling the same free function (or overloads), you can use a polymorphic visitor:

    static const struct pretty_print_visitor_ : boost::static_visitor<>
    {
        template<typename T>
        void operator ()(T const& v) const { pretty_print(v); }
    } pretty_print_visitor;
    

    E.g. now you can replace the 24 branches for expression&:

    boost::apply_visitor(
            make_visitor(
                [](expression_binop const& exp)              { pretty_print(exp); }, 
                [](expression_unop const& exp)               { pretty_print(exp); }, 
                [](expression_integer_constant const& exp)   { pretty_print(exp); }, 
                [](expression_character_constant const& exp) { pretty_print(exp); }, 
                [](expression_string_constant const& exp)    { pretty_print(exp); }, 
                [](expression_boolean_constant const& exp)   { pretty_print(exp); }, 
                [](expression_null const& exp)               { pretty_print(exp); }, 
                [](expression_this const& exp)               { pretty_print(exp); }, 
                [](expression_static_invoke const& exp)      { pretty_print(exp); }, 
                [](expression_non_static_invoke const& exp)  { pretty_print(exp); }, 
                [](expression_simple_invoke const& exp)      { pretty_print(exp); }, 
                [](expression_ambiguous_invoke const& exp)   { pretty_print(exp); }, 
                [](expression_new const& exp)                { pretty_print(exp); }, 
                [](expression_new_array const& exp)          { pretty_print(exp); }, 
                [](expression_lvalue const& exp)             { pretty_print(exp); }, 
                [](expression_assignment const& exp)         { pretty_print(exp); }, 
                [](expression_incdec const& exp)             { pretty_print(exp); }, 
                [](expression_cast const& exp)               { pretty_print(exp); }, 
                [](expression_ambiguous_cast const& exp)     { pretty_print(exp); }, 
                [](expression_instance_of const& exp)        { pretty_print(exp); }, 
                [](expression_parentheses const& exp)        { pretty_print(exp); },
                [](lvalue_non_static_field const& exp)       { pretty_print(exp); },
                [](lvalue_array const& exp)                  { pretty_print(exp); },
                [](lvalue_ambiguous_name const& exp)         { pretty_print(exp); }
           )
            , exp);
    

    by a simple

    boost::apply_visitor(pretty_print_visitor, exp);
    
  • Note a few occasions where I've put // TODO or // FIXME comments (notable with concat, which didn't quite want to compile for me anymore).

  • Note that the Ast classes got noticeably simpler (especially more trivally correct regarding memory allocations)

  • Note that the Parser itself shrunk due to the reduced need for semantic actions and Phoenix adapted functions

  • Note that I opted to forget about LexerPosition information for now (that used to be 'hidden' in the base classes, now gone). There is a compiler tutorial example that shows how to use qi::on_error(qi::success, ...) to very elegantly attach source location information to selected Ast nodes (non-intrusively).

  • Instead of the various predicates in ast_helpers I'd anticipate that there could be a number of helpful traits-based predicates (e.g. is_lvalue or is_true_const). I've elected to "keep" the helpers more or less as-is (which may be totally wrong, I haven't tested anything).

  • I've pervasively tried to replace parameter passing by value to passing by const& (compare e.g. the ast_pp.hpp) but I'm aware I've left some spots behind because the task was big enough as it was.

GIANT DISCLAIMER: I've probably broken the parser in various ways. I haven't tried to parse anything with it. The edits are provided as is and without any claim to usefulness. I've solved similar problems in dissimilar ways (once a traits::tranform_attribute<> specialization, once a largish semantic action with at_c<>, and some other approaches) :

The goal was to show you what I had in mind when I mentioned maybe

  • reducing dynamic polymorphism significantly,
  • avoiding semantic actions
  • embracing boost constructs where possible to get more 'automagic' integration with spirit
  • showing various ideas you can pick your favorite(s) from :/

Try

  • splitting it up in different translation units
  • disabling debug information (frequently, this is what trips up with large file sizes, because debug information gets emitted just like other object data)
  • disabling rtti (last resort)

Turning optimizations on (-O1 flag) solved the problem for me.

Try adding -Wa,-mbig-obj to your CXX_FLAGS. This will work with new enough gcc.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!