Boost.Spirit语法的属性:boost :: variant的std:vector错误

TemplateRex

我有一个工作的解析器,用于读取棋盘游戏的位置描述(国际绘画,官方语法):

#include <boost/spirit/home/x3.hpp>
#include <iostream>

namespace x3 = boost::spirit::x3;

auto const colon   = x3::lit(':');
auto const comma   = x3::lit(',');
auto const dash    = x3::lit('-');
auto const dot     = x3::lit('.');    
auto const king    = x3::char_('K');
auto const color   = x3::char_("BW");
auto const num_sq  = x3::int_;

auto const num_pc  = -king >> num_sq;               // Kxx means king on square xx, xx a man on that square
auto const num_rng = num_pc >> dash >> num_sq;      // xx-yy means range of squares xx through yy (inclusive)
auto const num_seq = (num_rng | num_pc) % comma;    // <--- attribute should be std::vector<boost::variant>
auto const ccn     = colon >> color >> -num_seq;
auto const num_not = x3::repeat(2)[ccn];            // need to specify both white and black pieces
auto const fen     = color >> num_not >> -dot;

Live On Coliru

现在,我想从综合属性中提取值,因此我围绕Boost.Fusion等进行了样板舞,

namespace ast {

struct num_pc  { boost::optional<char> k; int sq; };
struct num_rng { boost::optional<char> k; int first, last; };
using rng_or_pc = boost::variant<num_rng, num_pc>;
struct num_seq { std::vector<rng_or_pc> sqrs; };
struct ccn     { char c; boost::optional<num_seq> seq; };
struct num_not { std::vector<ccn> n; };
struct fen     { char c; num_not n; };

}   // namespace ast

BOOST_FUSION_ADAPT_STRUCT(ast::num_pc,  (boost::optional<char>, k), (int, sq))
BOOST_FUSION_ADAPT_STRUCT(ast::num_rng, (boost::optional<char>, k), (int, first), (int, last))
BOOST_FUSION_ADAPT_STRUCT(ast::num_seq, (std::vector<ast::rng_or_pc>, sqrs))
BOOST_FUSION_ADAPT_STRUCT(ast::ccn,     (char, c), (boost::optional<ast::num_seq>, seq))
BOOST_FUSION_ADAPT_STRUCT(ast::num_not, (std::vector<ast::ccn>, n))
BOOST_FUSION_ADAPT_STRUCT(ast::fen,     (char, c), (ast::num_not, n))

x3::rule<class num_pc_class,  ast::num_pc > num_pc  = "num_pc";
x3::rule<class num_rng_class, ast::num_rng> num_rng = "num_rng";
x3::rule<class num_seq_class, ast::num_seq> num_seq = "num_seq";
x3::rule<class ccn_class,     ast::ccn    > ccn     = "ccn";
x3::rule<class num_not_class, ast::num_not> num_not = "num_not";
x3::rule<class fen_class,     ast::fen    > fen     = "fen";

auto const colon   = x3::lit(':');
auto const comma   = x3::lit(',');
auto const dash    = x3::lit('-');
auto const dot     = x3::lit('.');    
auto const king    = x3::char_('K');
auto const color   = x3::char_("BW");
auto const num_sq  = x3::int_;

auto const num_pc_def  = -king >> num_sq;
auto const num_rng_def = num_pc >> dash >> num_sq;
auto const num_seq_def = (num_rng | num_pc) % comma;
auto const ccn_def     = colon >> color >> -num_seq;
auto const num_not_def = x3::repeat(2)[ccn];
auto const fen_def     = color >> num_not >> -dot;

BOOST_SPIRIT_DEFINE(num_pc, num_rng, num_seq, ccn, num_not, fen)

Live On Coliru

但是,我得到一个错误,说

错误:static_assert失败“属性没有预期的大小。”

还有几页:

^ main.cpp:16:8:注意:候选构造函数(隐式move构造函数)不可行:std::vector<boost::variant<ast::num_rng, ast::num_pc>, std::allocator<boost::variant<ast::num_rng, ast::num_pc> > >对于第一个参数struct num_seq { std::vector<rng_or_pc>sqrs;,没有从' '到'ast :: num_seq'的已知转换};

^ main.cpp:16:8:注意:候选构造函数(隐式副本构造函数)不可行:std::vector<boost::variant<ast::num_rng, ast::num_pc>, std::allocator<boost::variant<ast::num_rng, ast::num_pc> > >对于第一个参数struct num_seq { std::vector<rng_or_pc>sqrs;,没有从' '到'const ast :: num_seq'的已知转换};

问题:此错误来自何处,如何解决?显然,我的num_seq规则的综合属性不等于std::vector<boost::variant>>我该如何纠正?

看到

我花了一些时间试图理解语法。

我强烈建议使用可读的标识符。很难理解正在发生的事情,虽然我印象深刻,但这实际上是一个非常简单的语法

我建议如下所示的简化版本。

  • 因为您的语法不使用递归,所以实际上不需要规则和标记的解析器类型。
  • 还为解析器工件使用名称空间。
  • 考虑封装而不是让调用者决定(x3::skip[]),而是使用跳过器
  • 添加一些帮助程序,以便能够打印AST以进行验证:

    template <typename T> std::ostream& operator<<(std::ostream& os, std::vector<T> const& v) {
        os << "{"; for (auto& el : v) os << el << " "; return os << "}";
    }
    std::ostream& operator<<(std::ostream& os, num_pc const& p)  { if (p.k) os << p.k; return os << p.sq; }
    std::ostream& operator<<(std::ostream& os, num_rng const& r) { return os << r.pc << "-" << r.last; }
    std::ostream& operator<<(std::ostream& os, ccn const& o)     { return os << o.c << " " << o.seq;                      } 
    std::ostream& operator<<(std::ostream& os, num_not const& nn) { return os << nn.n; }
    
  • 我也避免不必要地包装其他向量:

    using num_not = std::vector<ccn>;
    
  • 使用现代的ADAPT宏(根据定义,您正在使用C ++ 14):

    BOOST_FUSION_ADAPT_STRUCT(ast::num_pc,  k, sq)
    BOOST_FUSION_ADAPT_STRUCT(ast::num_rng, pc, last)
    BOOST_FUSION_ADAPT_STRUCT(ast::ccn,     c, seq)
    BOOST_FUSION_ADAPT_STRUCT(ast::fen,     c, n)
    
  • --

现场演示

Live On Coliru

#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/as_vector.hpp>
#include <boost/fusion/include/io.hpp>
#include <boost/optional/optional_io.hpp>
#include <boost/optional.hpp>
#include <boost/spirit/home/x3.hpp>
#include <boost/variant.hpp>
#include <iostream>
#include <vector>

namespace ast {

    struct num_pc {
        boost::optional<char> k;
        int sq;
    };

    struct num_rng {
        num_pc pc;
        int last;
    };

    using rng_or_pc = boost::variant<num_rng, num_pc>;
    using num_seq = std::vector<rng_or_pc>;

    struct ccn {
        char c;
        boost::optional<num_seq> seq;
    };

    using num_not = std::vector<ccn>;

    struct fen {
        char c;
        num_not n;
    };

    template <typename T> std::ostream& operator<<(std::ostream& os, std::vector<T> const& v) {
        os << "{"; for (auto& el : v) os << el << " "; return os << "}";
    }
    std::ostream& operator<<(std::ostream& os, num_pc const& p)  { if (p.k) os << p.k; return os << p.sq; }
    std::ostream& operator<<(std::ostream& os, num_rng const& r) { return os << r.pc << "-" << r.last; }
    std::ostream& operator<<(std::ostream& os, ccn const& o)     { return os << o.c << " " << o.seq;                      } 
}

BOOST_FUSION_ADAPT_STRUCT(ast::num_pc,  k, sq)
BOOST_FUSION_ADAPT_STRUCT(ast::num_rng, pc, last)
BOOST_FUSION_ADAPT_STRUCT(ast::ccn,     c, seq)
BOOST_FUSION_ADAPT_STRUCT(ast::fen,     c, n)

namespace FEN {
    namespace x3 = boost::spirit::x3;

    namespace grammar
    {
        using namespace x3;

        template<typename T>
            auto as = [](auto p) { return rule<struct _, T>{} = as_parser(p); };

        uint_type const number {};
        auto const color   = char_("BW");
        auto const num_pc  = as<ast::num_pc>  ( -char_('K') >> number          ); 
        auto const num_rng = as<ast::num_rng> ( num_pc >> '-' >> number        ); 
        auto const num_seq = as<ast::num_seq> ( (num_rng | num_pc) % ','       ); 
        auto const ccn     = as<ast::ccn>     ( ':' >> color >> -num_seq       ); 
        auto const num_not = as<ast::num_not> ( repeat(2)[ccn]                 ); 
        auto const fen     = as<ast::fen>     ( color >> num_not >> -lit('.')  ); 
    }

    using grammar::fen;
}

int main() {
    for (std::string const t : {
        "B:W18,24,27,28,K10,K15:B12,16,20,K22,K25,K29",
        "B:W18,19,21,23,24,26,29,30,31,32:B1,2,3,4,6,7,9,10,11,12",
        "W:B1-20:W31-50",   // initial position
        "W:B:W",            // empty board
        "W:B1:W",           // only black pieces
        "W:B:W50"           // only white pieces
    }) {
        auto b = t.begin(), e = t.end();
        ast::fen data;
        bool ok = phrase_parse(b, e, FEN::fen, FEN::x3::space, data);

        std::cout << t << "\n";
        if (ok) {
            std::cout << "Parsed: " << boost::fusion::as_vector(data) << "\n";
        } else {
            std::cout << "Parse failed:\n";
            std::cout << "\t on input: " << t << "\n";
        }
        if (b != e)
            std::cout << "\t Remaining unparsed: '" << std::string(b, e) << '\n';
    }
}

印刷品:

B:W18,24,27,28,K10,K15:B12,16,20,K22,K25,K29
Parsed: (B {W  {18 24 27 28  K10  K15 } B  {12 16 20  K22  K25  K29 } })
B:W18,19,21,23,24,26,29,30,31,32:B1,2,3,4,6,7,9,10,11,12
Parsed: (B {W  {18 19 21 23 24 26 29 30 31 32 } B  {1 2 3 4 6 7 9 10 11 12 } })
W:B1-20:W31-50
Parsed: (W {B  {1-20 } W  {31-50 } })
W:B:W
Parsed: (W {B -- W -- })
W:B1:W
Parsed: (W {B  {1 } W -- })
W:B:W50
Parsed: (W {B -- W  {50 } })

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

解析复合语法时内部Boost :: Spirit代码段错误

使用boost :: spirit解析为vector <vector <double >>

如何将boost :: spirit :: qi :: lexeme的属性转换为std :: string?

如何使用带有std :: vector <token_type>而不是std :: string的boost :: spirit :: qi

Boost Spirit:将子语法附加到字符串?

使用std :: array作为boost :: spirit :: x3的属性

使用boost :: spirit :: x3解析为vector <boost :: string_view>

std :: variant和boost :: variant之间有什么区别?

嵌套Boost :: variant的分段错误

Boost Karma:使用boost :: optional <boost :: variant <... >>编写规则

boost :: spirit :: qi ::语法和可变参数模板

在Boost Spirit语法中获取当前行

无法获取Boost Spirit语法以将已知键用于std :: map <>

将Boost Spirit解析器从boost :: variant过渡到std :: variant 2

Boost Spirit x3:复合属性编译时错误(枚举类)

将boost-spirit语法分析嵌入到结构中的另一个语法中会导致编译错误

Boost-variant的向量

使用Boost Spirit解析语法的未处理异常

boost :: spirit :: qi具有相同简单适应结构属性的规则会产生编译错误

从boost :: variant检索对象

Boost Spirit队长-编译时错误

错误编译非常简单的boost :: spirit语法

Boost Spirit Qi-高效的报价语法

将boost :: spirit符号表传递给语法作为继承属性

如何在boost :: spirit :: qi语法中实现#ifdef?

增量boost :: variant值

boost :: variant。boost :: visitor重载功能

Boost.spirit 使用复合语法解析时的分段错误

std::variant 是否提供类似于 boost::variant<>::types 的功能?