太多的部分,汇编程序错误,使用boost :: spirit

时间:2013-09-09 08:46:35

标签: c++ gcc boost-spirit sections object-files

我正在使用boost::spirit编写Java子集的编译器,以进行lexing和解析。在编译词法分析器/解析器阶段期间,编译器消耗1.6GB的RAM(g++ (GCC) 4.8.1),但这不是问题,因为这台机器上有足够的内存。

然而,问题在于,当编译器完成并且汇编程序开始运行(GNU assembler (GNU Binutils) 2.23.52.20130604)时,它会崩溃;

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

'-Os'添加到我的编译器标志中,允许汇编器处理编译器输出,但正如我所看到的,这只是时间问题,直到我遇到同样的问题,即使是小优化标志。

使用ast_generate.o检查大小优化的目标文件(objdump),告诉我我正在生成pe-x86-64,这是我在Windows上所期望的。

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. 错误中的数字(too many sections (X)),要生成的部分数量,还是错误代码?
  2. 为什么为每种数据类型生成一个部分?
  3. 我可以做些什么,以避免将'-Os'传递给我的编译器。也就是说,我该怎么做才能解决问题,而不是解决它?
  4. 将词法分析器和解析阶段分成两个不同的阶段(和编译单元),只通过词法分析器连接帮助我吗?
  5. 请注意;我正在使用cygwin64进行编译。

4 个答案:

答案 0 :(得分:8)

我在这里做了一些黑客攻击并重构了一些东西来展示非运行时多态的风格:

我希望它不会增加编译时间:)(我实际上并没有把分割语法,但它变小了)。


特点:

  • 不再有堆分配的AST节点(甚至不包括像expression和/或statement这样的树);因此没有更明确的克隆和/或虚假的const成员。
  • 我用

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

    它既快又脏,但都编译

  • 我用自己的小努力替换了开放式切换(我无法使用它;还有boost-variant它都是内置的):

    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;
    

    要了解如何使用它,请查看例如: 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 如果您不太关心在分支机构中列出所有类型,例如因为它们都默认调用相同的自由函数(或重载),所以可以使用多态访问者:

    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。现在您可以替换expression&的24个分支:

    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);
    

    简单

    boost::apply_visitor(pretty_print_visitor, exp);
    
  • 请注意我在某些情况下放置// TODO// FIXME条评论(以concat着称,我不想再为我编译了。)< / p>

  • 请注意,Ast类明显更简单(特别是关于内存分配更为正确)

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

  • 请注意,我现在选择忘记关于LexerPosition信息(以前在基类中隐藏',现在已经消失了)。有一个编译器教程示例,演示如何非常优雅地使用qi::on_error(qi::success, ...) 将源位置信息附加到选定的 Ast节点(非-intrusively)。

  • 而不是ast_helpers中的各种谓词,我预计会有许多有用的基于特征的谓词(例如is_lvalueis_true_const)。我选择或多或少地“保持”帮助者 as-is (这可能是完全错误的,我没有测试任何东西)。

  • 我已经普遍尝试将值传递的参数替换为const&compare e.g. the ast_pp.hpp),但我知道我已经留下了一些点,因为任务足够大照原样。

GIANT DISCLAIMER :我可能已经以各种方式破解了解析器。我没有尝试用它解析任何东西。编辑按提供,并且没有任何有用的声明。我以不同的方式解决了类似的问题(一旦traits::tranform_attribute<>专业化,一旦用at_c<>进行大的语义动作,以及其他一些方法):

目标是向我展示当我提到的时候我的想法

  • 显着降低动态多态性,
  • 避免语义行为
  • 在可能的情况下拥抱boost构造以获得更多与“精神”的“自动化”整合
  • 展示各种想法,您可以从:/
  • 中选择您喜欢的

答案 1 :(得分:3)

尝试

  • 将其拆分为不同的翻译单元
  • 禁用调试信息(通常情况下,这会导致文件大小增加,因为调试信息会像其他对象数据一样发出)
  • 禁用rtti(最后手段)

答案 2 :(得分:2)

开启优化(-O1标志)解决了我的问题。

答案 3 :(得分:0)

尝试将-Wa,-mbig-obj添加到CXX_FLAGS。这将适用于足够新的gcc