Spirit X3,两个规则合并为一个后不会编译

时间:2018-11-22 06:52:19

标签: c++ boost-spirit boost-spirit-x3

我目前正在学习如何使用x3。如标题所示,我已经成功地创建了带有一些简单规则的语法,但是将这些规则中的两个合并为一个后,代码将不再编译。这是AST部分的代码:

namespace x3 = boost::spirit::x3;

struct Expression;

struct FunctionExpression {
    std::string functionName;
    std::vector<x3::forward_ast<Expression>> inputs;
};

struct Expression: x3::variant<int, double, bool, FunctionExpression> {
    using base_type::base_type;
    using base_type::operator=;
};

我创建的规则以{rangeMin, rangeMax}格式解析输入:

rule<struct basic_exp_class, ast::Expression> const
    basic_exp = "basic_exp";
rule<struct exp_pair_class, std::vector<ast::Expression>> const 
    exp_pair = "exp_pair";
rule<struct range_class, ast::FunctionExpression> const 
    range = "range";

auto const basic_exp_def = double_ | int_ | bool_;
auto const exp_pair_def = basic_expr >> ',' >> basic_expr;
auto const range_def = attr("computeRange") >> '{' >> exp_pair >> '}';

BOOST_SPIRIT_DEFINE(basic_expr, exp_pair_def, range_def);

此代码可以正常编译。但是,如果我尝试将exp_pair规则内联到range_def规则中,就像这样:

rule<struct basic_exp_class, ast::Expression> const
    basic_exp = "basic_exp";
rule<struct range_class, ast::FunctionExpression> const 
    range = "range";

auto const basic_exp_def = double_ | int_ | bool_;
auto const range_def = attr("computeRange") >> '{' >> (
    basic_exp >> ',' >> basic_exp
) >> '}';

BOOST_SPIRIT_DEFINE(basic_expr, range_def);

代码无法编译,出现很长的模板错误,并以以下行结尾:

spirit/include/boost/spirit/home/x3/operator/detail/sequence.hpp:149:9: error: static assertion failed: Size of the passed attribute is less than expected.
     static_assert(
     ^~~~~~~~~~~~~

头文件的static_assert上方还包含以下注释:

// If you got an error here, then you are trying to pass
// a fusion sequence with the wrong number of elements
// as that expected by the (sequence) parser.

但是我不明白为什么代码会失败。根据x3的compound attribute rules,括号中的内联部分应具有类型vector<ast::Expression>的属性,从而使整个规则的类型为tuple<string, vector<ast::Expression>,以便与{{1 }}。相同的逻辑适用于更为冗长的三规则版本,唯一的区别是我专门声明了内部规则,并明确声明其属性必须为ast::FunctionExpression类型。

1 个答案:

答案 0 :(得分:2)

Spirit x3可能会将内联规则的结果视为两个单独的ast::Expression,而不是std::vector<ast::Expression>结构所需的ast::FunctionExpression

要解决此问题,我们可以使用另一个answer中提到的辅助函数as lambda来指定子规则的返回类型。

修改后的range_def将变为:

auto const range_def = attr("computeRange") >> '{' >> as<std::vector<ast::Expression>>(basic_exp >> ',' >> basic_exp) >> '}';