Android 上的简单 boost::spirit 语法 SIGSEGV
Simple boost::spirit grammar SIGSEGV on Android
解析器
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 一起使用,让我们远离常规。
能否通过构建配置修复此错误,或者是否有其他我们可以探索的选项?
当然可以修复错误。 你没有展示语法见更新你展示了很多带有未知数的解析器表达式,所以我们甚至无法开始推理关于您的代码。
突出的一件事是 auto
的(滥用)使用。
快速 google 应该会在 SO 上指出 ~6 个警告此问题的问题。
You can not use auto
with Spirit's expression templates. In all but the very very trivial cases (unparameterized stateless terminals) this leads directly to Undefined Behaviour
尝试使用
qi::rule<>
到 contain/group 表达式
boost::spirit::copy
或 boost::proto::deep_copy
更新
对于已编辑的问题:确实由于未定义的行为导致语法崩溃(如果这 "appeared to work",你只是(不)幸运!)。
这是一个固定版本,作为奖励,我删除了 action<>
用现有的 Phoenix 机制和属性传播替换它的东西。
您可能想要并排研究这些更改,以准确了解我所做的更改。
#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}}
解析器
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 一起使用,让我们远离常规。
能否通过构建配置修复此错误,或者是否有其他我们可以探索的选项?
当然可以修复错误。 你没有展示语法见更新你展示了很多带有未知数的解析器表达式,所以我们甚至无法开始推理关于您的代码。
突出的一件事是 auto
的(滥用)使用。
快速 google 应该会在 SO 上指出 ~6 个警告此问题的问题。
You can not use
auto
with Spirit's expression templates. In all but the very very trivial cases (unparameterized stateless terminals) this leads directly to Undefined Behaviour
尝试使用
qi::rule<>
到 contain/group 表达式boost::spirit::copy
或boost::proto::deep_copy
更新
对于已编辑的问题:确实由于未定义的行为导致语法崩溃(如果这 "appeared to work",你只是(不)幸运!)。
这是一个固定版本,作为奖励,我删除了 action<>
用现有的 Phoenix 机制和属性传播替换它的东西。
您可能想要并排研究这些更改,以准确了解我所做的更改。
#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}}