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

前端 未结 4 744
清歌不尽
清歌不尽 2021-01-02 06:44

I\'m in the progress of writing a compiler for a subset of Java, using boost::spirit, for lexing and parsing. During compilation of the lexer/parser phase, the

相关标签:
4条回答
  • 2021-01-02 07:16

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

    0 讨论(0)
  • 2021-01-02 07:18

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

    0 讨论(0)
  • 2021-01-02 07:22

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

    • https://bitbucket.org/sehe/joos2compiler-refactor (based on your 12d01e5 commit).

    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 :/
    0 讨论(0)
  • 2021-01-02 07:29

    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)
    0 讨论(0)
提交回复
热议问题