段太多,汇编器错误,使用boost :: spirit [英] Too many sections, assembler error, using boost::spirit

查看:314
本文介绍了段太多,汇编器错误,使用boost :: spirit的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为Java的一个子集编写一个编译器,使用 boost :: spirit ,用于lexing和解析。在编译lexer / parser阶段期间,编译器使用 1.6GB 的RAM( g ++(GCC)4.8.1 ),但这不是一个问题,因为这台机器上有大量的内存。



什么是一个问题,是,当编译器完成,开始运行( GNU assembler(GNU Binutils)2.23.52.20130604 ),它与崩溃;

  as:build / src / ast_generate.o:太多部分(33098)
/tmp/cc0ZyvKK.s:汇编消息:
/tmp/cc0ZyvKK.s:致命错误:can 't写build / src / ast_generate.o:文件太大
as:build / src / ast_generate.o:太多节(33098)
/tmp/cc0ZyvKK.s:致命错误:can' t close build / src / ast_generate.o:文件太大
scons:*** [build / src / ast_generate.o]错误1

添加' - Os'到我的编译器标志,允许汇编器处理编译器输出,但是正如我看到的,



检查大小优化的对象文件(<$ c $)使用 objdump 告诉我我正在生成 pe-x86-64

2358 生成的部分,但是对我震惊。主要是因为它似乎已经为 boost :: spirit ;

的每个部分生成了一个部分

  CONTENTS,ALLOC,LOAD,READONLY,DATA,LINK_ONCE_DISCARD 
...
60 .pdata $ _ZNK5boost5lexer6detail8end_node9unique_idEv 0000000c 0000000000000000 0000000000000000 00030750 2 ** 2
61 .text $ _ZNK5boost5lexer6detail8end_node11lexer_stateEv 00000010 0000000000000000 0000000000000000 0003075c 2 ** 4
...


  1. 是错误中的数字(太多的部分(X)

  2. 为什么要为每个数据类型生成一个节?

  3. 什么可以我这样做,以避免将' - Os'传递给我的编译器。

  4. 将词法分析器和语法分析阶段分成两个不同的阶段(和编译单元),只有通过这两个阶段才能解决这个问题, lexer迭代器帮助我?

注意:我正在使用 cygwin64 进行编译。

解决方案

黑客这里,并重构了一个非运行时多态风格:





我希望它不会增加编译时间:)(我实际上没有到\\ em分割语法,但是它更小)。






特色:




  • 更多的堆分配AST节点(甚至不像表达式和/或语句);因此没有更明确的克隆和/或虚假的const成员。

  • 我替换了Maybe.hpp与

      #pragma once 
    #include< boost / optional.hpp>

    template< typename T> using Maybe = boost :: optional< T> ;;

    这很快,但都是编译


  • 我用我自己的小努力替换开放类型切换(我不能让它工作;也用boost-variant它所有内置):

     命名空间visitor_galore //这是我的换行替换typeswitch(我找不到它/使它工作)
    {
    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 ...){}

    使用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 ...}; }
    }

    使用visitor_galore :: make_visitor;

    要了解如何使用它, 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);
    }

    奖金列出分支中的所有类型,例如因为它们都默认调用相同的自由函数(或重载),可以使用多态访问者:

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

    现在你可以替换表达式& 的24个分支:

      :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 )$ {$ {$ exp {$ exp($ exp($ exp())} $ {$ {$ exp {$ exp b $ b [](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);

      boost :: apply_visitor(pretty_print_visitor,exp); 


  • 请注意我已经放置 // TODO // FIXME 注释(注意到 concat


  • 请注意,Ast类明显更简单(尤其是关于内存分配更正确的更正) b $ b

  • 请注意,由于对语义动作和Phoenix适应功能的需求减少,解析器本身缩小了


  • 请注意, 现在关于LexerPosition信息(以前在基类中隐藏,现在已经离开)。有一个编译器教程示例,显示如何使用 qi :: on_error(qi :: success,...) 非常优雅


  • 将来源位置资讯附加到选取的 Ast节点 ast_helpers 我预计可能有一些有用的基于traits的谓词(例如 is_lvalue is_true_const )。我已经选择保留帮助者或多或少按原样(这可能是完全错误,我没有测试任何东西)。


  • 我普遍尝试将传递值的参数替换为传递 const& 比较例如ast_pp.hpp ),但我知道我已经留下了一些点




GIANT免责声明:可能以各种方式打破解析器。我没有试图解析任何东西。这些修改是按照 提供的,并且没有任何声明的有用性。我已经以不同的方式解决了类似的问题(一旦 at_c<>),一个 traits :: tranform_attribute<> 和一些其他方法):



目标是告诉你我提到的可能




  • 显着减少动态多态性,

  • 避免语义动作


  • 显示各种想法,您可以从以下内容中选择喜爱的内容:/


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 compiler consumes 1.6GB of RAM (g++ (GCC) 4.8.1), this is not an issue however, as there's plenty of memory on this machine.

What is an issue however, is that when the compiler is done, and the assembler starts running (GNU assembler (GNU Binutils) 2.23.52.20130604), it crashes with;

as: build/src/ast_generate.o: too many sections (33098)
/tmp/cc0ZyvKK.s: Assembler messages:
/tmp/cc0ZyvKK.s: Fatal error: can't write build/src/ast_generate.o: File too big
as: build/src/ast_generate.o: too many sections (33098)
/tmp/cc0ZyvKK.s: Fatal error: can't close build/src/ast_generate.o: File too big
scons: *** [build/src/ast_generate.o] Error 1

Adding '-Os' to my compiler flags, allows the assembler to process the compiler output, but as I see it, it's only a matter of time, until I'll hit the same issue, even with the small optimization flag.

Inspecting, the size optimized object file (ast_generate.o) using objdump, tells me that I'm generating pe-x86-64, which is what I'd expect on Windows.

The 2358 generated sections, is however a shock to me. Mostly as it seems that a section has been generated for each part of the boost::spirit;

 CONTENTS, ALLOC, LOAD, READONLY, DATA, LINK_ONCE_DISCARD
 ...
 60 .pdata$_ZNK5boost5lexer6detail8end_node9unique_idEv 0000000c  0000000000000000  0000000000000000  00030750  2**2
 61 .text$_ZNK5boost5lexer6detail8end_node11lexer_stateEv 00000010  0000000000000000  0000000000000000  0003075c  2**4
 ...

So my questions are;

  1. Is the number in the error (too many sections (X)), the number of sections to be generated, or is it an error code?
  2. Why is a section generated for each data-type?
  3. What can I do, to avoid having to pass '-Os' to my compiler. That is, what can I do to fix the issue, rather than to work around it?
  4. Would splitting the lexer and parse phase into two distinct phases (and compilation units), only connected through a lexer iterator help me out?

Note; I'm compiling using cygwin64.

解决方案

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 :/

这篇关于段太多,汇编器错误,使用boost :: spirit的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆