来自 Boost.Spirit 语法的属性:来自 std:vector of boost::variant 的错误 [英] Attributes from Boost.Spirit grammar: error from std:vector of boost::variant

查看:31
本文介绍了来自 Boost.Spirit 语法的属性:来自 std:vector of boost::variant 的错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I got a working parser for reading position descriptions for a board game (international draughts, official grammar):

#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;

生活在 Coliru

现在我想从合成属性中提取值,所以我围绕 Boost.Fusion 等做了样板舞,

Now I want to extract the values from the synthesized attributes, so I did the boilerplate dance around Boost.Fusion etc.,

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)

在 Coliru 上直播

但是,我收到一个错误提示

However, I then get an error saying that

错误:static_assert 失败属性没有预期的大小."

error: static_assert failed "Attribute does not have the expected size."

再往下几页:

^ main.cpp:16:8:注意:候选构造函数(隐式移动构造函数)不可行:没有已知的转换来自'std::vector,std::allocator>>' 到'ast::num_seq' 用于第一个参数 struct num_seq {std::vector sqrs;};

^ main.cpp:16:8: note: candidate constructor (the implicit move constructor) not viable: no known conversion from 'std::vector<boost::variant<ast::num_rng, ast::num_pc>, std::allocator<boost::variant<ast::num_rng, ast::num_pc> > >' to 'ast::num_seq' for 1st argument struct num_seq { std::vector<rng_or_pc> sqrs; };

^ main.cpp:16:8: 注意:候选构造函数(隐式复制构造函数)不可行:没有已知的转换自'std::vector,std::allocator>>' 到'const ast::num_seq' 用于第一个参数 struct num_seq {std::vector sqrs;};

^ main.cpp:16:8: note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'std::vector<boost::variant<ast::num_rng, ast::num_pc>, std::allocator<boost::variant<ast::num_rng, ast::num_pc> > >' to 'const ast::num_seq' for 1st argument struct num_seq { std::vector<rng_or_pc> sqrs; };

问题:这个错误来自哪里,如何解决?显然,我的 num_seq 规则的合成属性不等于 std::vector>.我该如何纠正?

Question: where is this error coming from, and how to resolve it? Apparently the synthesized attribute of my num_seq rule is not equal to std::vector<boost::variant>>. How can I correct this?

推荐答案

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

I've spent some time trying to understand the grammar.

我强烈建议使用可读的标识符.很难理解发生了什么,虽然我有强烈的印象它实际上是一个非常简单的语法

我建议使用如下所示的简化版本.

I suggest a simplification version shown below.

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

  • Because your grammar doesn't use recursion there's no real need for the rule and tagged parser types.
  • Also use a namespace for the parser artefacts.
  • Consider encapsulation the use of a skipper instead of letting the caller decide (x3::skip[])
  • Add a few helpers to be able to print the AST for verification:

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; }

  • 我也会避免不必要地包装另一个向量:

  • I'd avoid wrapping the other vector unnecessarily too:

    using num_not = std::vector<ccn>;
    

  • 使用现代 ADAPT 宏(因为您使用的是 C++14 定义):

  • Use the modern ADAPT macros (as you're using C++14 by definition):

    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)
    

  • ——

    在 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 << "
    ";
            if (ok) {
                std::cout << "Parsed: " << boost::fusion::as_vector(data) << "
    ";
            } else {
                std::cout << "Parse failed:
    ";
                std::cout << "	 on input: " << t << "
    ";
            }
            if (b != e)
                std::cout << "	 Remaining unparsed: '" << std::string(b, e) << '
    ';
        }
    }
    

    打印:

    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 } })
    

    这篇关于来自 Boost.Spirit 语法的属性:来自 std:vector of boost::variant 的错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆