在精灵:: x3中似乎有些东西改变了,这打破了我那个花哨的小asdl解析器。当我从Qi移植它(在最初的x3错误修正进入fedora之后)它工作得很好但现在失败了:
/usr/include/boost/spirit/home/x3/operator/detail/sequence.hpp:143:9:错误:静态断言失败:属性没有预期的大小。
#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include "asdl.h"
typedef boost::variant<asdl::ast::Product, asdl::ast::Sum> type_variant;
typedef std::vector<asdl::ast::Field> field_vec;
BOOST_FUSION_ADAPT_STRUCT(
asdl::ast::Module,
(std::string, id)
(std::vector<asdl::ast::Type>, dfns))
BOOST_FUSION_ADAPT_STRUCT(
asdl::ast::Type,
(std::string, name)
(type_variant, value))
BOOST_FUSION_ADAPT_STRUCT(
asdl::ast::Field,
(std::string, type)
(boost::optional<char>, flag)
(boost::optional<std::string>, name))
BOOST_FUSION_ADAPT_STRUCT(
asdl::ast::Constructor,
(std::string, name)
(boost::optional<field_vec>, fields))
BOOST_FUSION_ADAPT_STRUCT(
asdl::ast::Sum,
(std::vector<asdl::ast::Constructor>, types)
(boost::optional<field_vec>, attributes))
BOOST_FUSION_ADAPT_STRUCT(
asdl::ast::Product,
(field_vec, fields))
namespace asdl
{
namespace x3 = boost::spirit::x3;
namespace ascii = boost::spirit::x3::ascii;
x3::rule<class module, ast::Module > const module = "module";
x3::rule<class definitions, ast::Type > const definitions = "definitions";
x3::rule<class type, type_variant > const type = "type";
x3::rule<class fields, field_vec > const fields = "fields";
x3::rule<class field, ast::Field > const field = "field";
x3::rule<class product, ast::Product > const product = "product";
x3::rule<class sum, ast::Sum > const sum = "sum";
x3::rule<class constructor, ast::Constructor> const constructor = "constructor";
auto const alpha = '_' | ascii::upper | ascii::lower;
auto const alpha_num = alpha | ascii::digit;
auto const typ_id = x3::lexeme[ascii::lower >> *alpha_num];
auto const con_id = x3::lexeme[ascii::upper >> *alpha_num];
auto const id = typ_id | con_id;
auto const module_def = "module" >> id >> '{' >> *definitions >> '}';
auto const definitions_def = typ_id >> '=' >> type;
auto const type_def = product | sum;
auto const product_def = fields;
auto const sum_def = constructor % '|' >> -("attributes" >> fields);
auto const constructor_def = con_id >> -fields;
auto const fields_def = '(' >> field % ',' >> ')';
auto const field_def = typ_id >> -(ascii::char_('?') | ascii::char_('*')) >> -id;
BOOST_SPIRIT_DEFINE(module, definitions, type, product, sum, constructor, fields, field);
bool parse(const std::string &input, ast::Module &mod) {
std::string::const_iterator iter = input.begin();
std::string::const_iterator end = input.end();
return (x3::phrase_parse(iter, end, module, ascii::space, mod) && iter == end);
}
} //namespace asdl
注意:BOOST_FUSION_ADAPT_STRUCT是具有完全相同字段的裸结构的直接包装。
我搜索了所有(2)其他对&#34的引用;属性没有预期的大小&#34;但是还没有完全理解这个问题甚至开始修复代码 - 问题的一部分是程序生成了它解析的内容(就像他们说的那样吃你自己的狗食)所以不知道为什么断言失败我不知道要修改哪个,解析器或输出结构的代码。
在这里,我认为牦牛已经剃光了......
答案 0 :(得分:4)
与其他链接答案一样,属性传播/兼容性规则与Qi中的不同。
有时这很令人惊讶,有时可能是一个错误。
你总是可以通过包装规则使属性类型显式化。几乎所有的时间都可以解决这个问题。
注意:在Boost 1.66.0中,有针对更高版本修复的回归:How to make a recursive rule in boost spirit x3 in VS2017
在您的情况下,id规则不会神奇地分配给字符串。帮帮忙吧:
auto const typ_id = as<std::string>(x3::lexeme[ascii::lower >> *alpha_num]);
auto const con_id = as<std::string>(x3::lexeme[ascii::upper >> *alpha_num]);
auto const id = typ_id | con_id;
as
是一个简单的帮手:
template <typename T> static auto as = [](auto p) { return x3::rule<struct tag, T> {"as"} = p; };
请注意,代码可以更简单一些:
<强> Live On Coliru 强>
#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
namespace asdl { namespace ast {
struct Field {
std::string type;
boost::optional<char> flag;
boost::optional<std::string> name;
};
typedef std::vector<asdl::ast::Field> field_vec;
struct Constructor {
std::string name;
boost::optional<field_vec> fields;
};
struct Sum {
std::vector<Constructor> types;
boost::optional<field_vec> attributes;
};
struct Product {
field_vec fields;
};
typedef boost::variant<Product, Sum> type_variant;
struct Type {
std::string name;
type_variant value;
};
struct Module {
std::string id;
std::vector<Type> dfns;
};
} }
BOOST_FUSION_ADAPT_STRUCT(asdl::ast::Module, id, dfns)
BOOST_FUSION_ADAPT_STRUCT(asdl::ast::Type, name, value)
BOOST_FUSION_ADAPT_STRUCT(asdl::ast::Field, type, flag, name)
BOOST_FUSION_ADAPT_STRUCT(asdl::ast::Constructor, name, fields)
BOOST_FUSION_ADAPT_STRUCT(asdl::ast::Sum, types, attributes)
BOOST_FUSION_ADAPT_STRUCT(asdl::ast::Product, fields)
namespace asdl
{
namespace x3 = boost::spirit::x3;
namespace ascii = boost::spirit::x3::ascii;
using ast::type_variant;
using ast::field_vec;
x3::rule<class module, ast::Module > const module = "module";
x3::rule<class definitions, ast::Type > const definitions = "definitions";
x3::rule<class type, type_variant > const type = "type";
x3::rule<class fields, field_vec > const fields = "fields";
x3::rule<class field, ast::Field > const field = "field";
x3::rule<class product, ast::Product > const product = "product";
x3::rule<class sum, ast::Sum > const sum = "sum";
x3::rule<class constructor, ast::Constructor> const constructor = "constructor";
template <typename T> static auto as = [](auto p) { return x3::rule<struct tag, T> {"as"} = p; };
auto const alpha = '_' | ascii::upper | ascii::lower;
auto const alpha_num = alpha | ascii::digit;
auto const typ_id = as<std::string>(x3::lexeme[ascii::lower >> *alpha_num]);
auto const con_id = as<std::string>(x3::lexeme[ascii::upper >> *alpha_num]);
auto const id = typ_id | con_id;
auto const module_def = "module" >> id >> '{' >> *definitions >> '}';
auto const definitions_def = typ_id >> '=' >> type;
auto const type_def = product | sum;
auto const product_def = fields;
auto const sum_def = constructor % '|' >> -("attributes" >> fields);
auto const constructor_def = con_id >> -fields;
auto const fields_def = '(' >> field % ',' >> ')';
auto const field_def = typ_id >> -(ascii::char_('?') | ascii::char_('*')) >> -id;
BOOST_SPIRIT_DEFINE(module, definitions, type, product, sum, constructor, fields, field)
bool parse(const std::string &input, ast::Module &mod) {
std::string::const_iterator iter = input.begin();
std::string::const_iterator end = input.end();
return x3::phrase_parse(iter, end, module >> x3::eoi, ascii::space, mod);
}
} //namespace asdl
int main() {
asdl::ast::Module mod;
asdl::parse("", mod);
}
由于您没有使用递归规则,因此实际上不需要_def
和BOOST_SPIRIT_DEFINE
等:
<强> Live On Coliru 强>
namespace x3 = boost::spirit::x3;
namespace ascii = boost::spirit::x3::ascii;
using ast::type_variant;
using ast::field_vec;
template <typename T> static auto as = [](auto p) { return x3::rule<struct tag, T> {"as"} = p; };
auto const alpha = '_' | ascii::upper | ascii::lower;
auto const alpha_num = alpha | ascii::digit;
auto const typ_id = as<std::string>(x3::lexeme[ascii::lower >> *alpha_num]);
auto const con_id = as<std::string>(x3::lexeme[ascii::upper >> *alpha_num]);
auto const id = typ_id | con_id;
auto const field
= x3::rule<class constructor, ast::Field> {"field"}
= as<ast::Field>(typ_id >> -(ascii::char_('?') | ascii::char_('*')) >> -id);
auto const fields
= x3::rule<class sum, field_vec>{ "fields" }
= '(' >> field % ',' >> ')';
auto const constructor
= x3::rule<class product, ast::Constructor>{ "constructor" }
= as<ast::Constructor>(con_id >> -fields);
auto const sum
= x3::rule<class field, ast::Sum>{ "sum" }
= as<ast::Sum>(constructor % '|' >> -("attributes" >> fields));
auto const product
= x3::rule<class fields, ast::Product>{ "product" }
= as<ast::Product>(fields);
auto const type
= x3::rule<class type, type_variant>{ "type" }
= product | sum;
auto const definitions
= x3::rule<class definitions, ast::Type>{ "definitions" }
= as<ast::Type>(typ_id >> '=' >> type);
auto const module
= x3::rule<class module, ast::Module>{ "module" }
= "module" >> id >> '{' >> *definitions >> '}';
bool parse(const std::string &input, ast::Module &mod) {
std::string::const_iterator iter = input.begin();
std::string::const_iterator end = input.end();
return x3::phrase_parse(iter, end, module >> x3::eoi, ascii::space, mod);
}