来自Boost.Spirit语法的属性:来自std的错误:boost :: variant的向量(Attributes from Boost.Spirit grammar: error from st

编程入门 行业动态 更新时间:2024-10-23 16:28:01
来自Boost.Spirit语法的属性:来自std的错误:boost :: variant的向量(Attributes from Boost.Spirit grammar: error from std:vector of boost::variant)

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

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

住在科利鲁

现在我想从合成属性中提取值,所以我在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)

住在科利鲁

但是,我接着说错了

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

并且几页下来:

^ main.cpp:16:8:注意:候选构造函数(隐式移动构造函数)不可行:没有来自' std::vector<boost::variant<ast::num_rng, ast::num_pc>, std::allocator<boost::variant<ast::num_rng, ast::num_pc> > >已知转换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; };

^ main.cpp:16:8:注意:候选构造函数(隐式复制构造函数)不可行:没有来自' std::vector<boost::variant<ast::num_rng, ast::num_pc>, std::allocator<boost::variant<ast::num_rng, ast::num_pc> > >已知转换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'代表第一个参数struct num_seq { std::vector<rng_or_pc> sqrs; };

问题 :此错误来自何处以及如何解决? 显然,我的num_seq规则的合成属性不等于std::vector<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;

Live On Coliru

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)

Live On Coliru

However, I then get an error saying that

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

and a couple of pages down:

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

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?

最满意答案

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

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

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

因为你的语法不使用递归,所以不需要规则和标记的解析器类型。 还为解析器工件使用命名空间。 考虑封装使用船长而不是让调用者决定( 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) -

现场演示

住在科利鲁

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

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

I strongly suggest readable identifiers. It's very hard to understand what's going on, while I have the strong impression it's actually a really simple grammar

I suggest a simplification version shown below.

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

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

Live Demo

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

Prints:

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

更多推荐

本文发布于:2023-08-06 05:38:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1444794.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:向量   语法   属性   错误   Boost

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!