提升精神X3:“属性没有预期的大小”redux

时间:2018-04-20 01:38:43

标签: c++ boost-spirit

在精灵:: 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;但是还没有完全理解这个问题甚至开始修复代码 - 问题的一部分是程序生成了它解析的内容(就像他们说的那样吃你自己的狗食)所以不知道为什么断言失败我不知道要修改哪个,解析器或输出结构的代码。

在这里,我认为牦牛已经剃光了......

1 个答案:

答案 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);
}

由于您没有使用递归规则,因此实际上不需要_defBOOST_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);
}