【问题标题】:Simple boost::spirit grammar SIGSEGV on AndroidAndroid 上的简单 boost::spirit 语法 SIGSEGV
【发布时间】:2015-09-16 14:37:19
【问题描述】:

解析器

        namespace qi = boost::spirit::qi;

        template<typename T>
        class action
        {
        public:
            action(std::vector<std::shared_ptr<part>>& parts) : m_parts{ parts } {}

            void operator()(const std::vector<char>& cc, qi::unused_type, qi::unused_type) const
            {
                std::string s(cc.begin(), cc.end());
                if (s.length() > 0) {
                    auto p = new T(s);
                    m_parts.push_back(std::shared_ptr<part>(p));
                }
            }
        private:
            std::vector<std::shared_ptr<part>>& m_parts;
        };

        std::vector<std::shared_ptr<part>> parse(const std::string& source) {
            namespace ascii = boost::spirit::ascii;

            using ascii::char_;
            using qi::lit;

            std::vector<std::shared_ptr<part>> parts;

            auto prop_g = lit("{{=")
                >> *char_(' ')
                >> (*(char_ - char_("} ")))[action<property_part>(parts)]
                >> *char_(' ')
                >> "}}"
                ;
            auto text_g = (+(char_ - '{'))[action<text_part>(parts)];
            auto g = -text_g >> +(prop_g >> text_g);

            qi::parse(source.begin(), source.end(), g);
            return parts;
        }

在 Kitkat 设备上测试时导致 qi::parse 调用出错。错误发生在调用任何语义操作之前。相同的代码适用于 Xcode 6/iOS 8.4 和 VS 2015。我们使用的是 Boost 1.59。

我们可以将 Spirit 替换为 Bison,暗示一个额外的构建步骤,或者将 Clang 与 Android NDK 一起使用,让我们摆脱常规。

能否通过构建配置修复此错误,或者我们可以探索其他选项吗?

【问题讨论】:

    标签: c++ gcc boost android-ndk boost-spirit-qi


    【解决方案1】:

    当然可以修复错误。 您没有展示语法请参阅更新不过,您展示了许多带有未知数的解析器表达式,因此我们甚至无法开始推理您的代码。 p>

    不过,确实的一件事是(ab)使用auto

    一个快速的谷歌应该指出你关于 SO 的大约 6 个问题,这些问题会对此提出警告。

    您不能将auto 与 Spirit 的表达式模板一起使用。除了非常非常微不足道的情况(未参数化的无状态终端)之外,这直接导致Undefined Behaviour

    尝试使用

    • qi::rule&lt;&gt; 包含/分组表达式
    • boost::spirit::copyboost::proto::deep_copy

    更新

    对于已编辑的问题:确实语法由于未定义的行为而崩溃(如果这曾经“看起来有效”,那么您只是(不)幸运!)。

    这是一个固定版本,作为奖励,我删除了 action&lt;&gt; 东西,将其替换为现有的 Phoenix 机制和属性传播。

    您可能需要并排研究这些更改,以确切了解我所做的更改。

    Live On Coliru

    #include <boost/spirit/include/qi.hpp>
    #include <boost/spirit/include/phoenix.hpp>
    
    struct part {
        part(std::string s="") : _value(std::move(s)) {}
        virtual ~part() { }
        virtual void do_print(std::ostream& os) const = 0;
      protected:
        std::string _value;
    };
    
    struct property_part : part { 
        using part::part; 
        void do_print(std::ostream& os) const { os << "{{=" << _value << "}}"; }
    };
    struct text_part     : part { 
        using part::part; 
        void do_print(std::ostream& os) const { os << "'" << _value << "'"; }
    };
    
    std::vector<std::shared_ptr<part>> parse(const std::string& source) {
        namespace qi = boost::spirit::qi;
        namespace px = boost::phoenix;
        using boost::spirit::ascii::char_;
        using qi::lit;
    
        typedef std::shared_ptr<part> pptr;
        qi::rule<std::string::const_iterator, pptr()> prop_g, text_g;
    
        // this is ok: purely stateless expression template
        prop_g = lit("{{=")
            >> *char_(' ')
            >> qi::as_string [ +~char_("} ") ] [ qi::_val = px::construct<pptr>(px::new_<property_part>(qi::_1)) ]
            >> *char_(' ')
            >> "}}"
            ;
    
        text_g = qi::as_string [ +~char_('{') ] [ qi::_val = px::construct<pptr>(px::new_<text_part>(qi::_1)) ];
    
        std::vector<pptr> parts;
        qi::parse(source.begin(), source.end(), -text_g >> +(prop_g >> text_g), parts);
    
        return parts;
    }
    
    int main() {
        auto result = parse("My book is about {{= this-is-a-(bogus)-property-part }} else entirely {{=byebye}}");
        assert(result.size() == 4);
    
        for(auto item : result)
            item->do_print(std::cout);
    }
    

    打印

    'My book is about '{{=this-is-a-(bogus)-property-part}}' else entirely '{{=byebye}}
    

    【讨论】:

    • 谢谢,我会试试你的建议。我已将语义操作添加到代码 sn-p 以完成解析器。
    • 我仍然需要在那里添加一些东西:/ 使用固定语法查看更新的答案。考虑保持规则静态/共享(它们可以是 const)。另请注意,看起来您正在执行宏扩展,但非常(非常!!)效率低下。看看this very flexible sample,这个simple one using spirit,同样的not using spirit
    • 如果您真的想重用模板并且高效,this answer uses Spirit + ICL to parse templates 可以非常有效地重复扩展。
    猜你喜欢
    • 2012-02-28
    • 2013-05-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-11
    • 2011-03-05
    相关资源
    最近更新 更多