模糊的变体和精神x3 [英] Ambiguous variant and boost spirit x3
问题描述
尝试调整boost精神x3 calc示例来解析可以将函数作为参数的函数。但是它不编译。
Trying to tweak the boost spirit x3 calc example to parse functions that can take functions as arguments. However it does not compile.
namespace client{ namespace ast{
struct ts;
struct fnc;
typedef boost::variant<
ts,
boost::recursive_wrapper<fnc>
> node;
struct ts{
unsigned int id;
};
struct fnc{
std::vector<char> id;
std::vector<node> args;
};
}}
BOOST_FUSION_ADAPT_STRUCT(
client::ast::ts,
(unsigned int, id)
)
BOOST_FUSION_ADAPT_STRUCT(
client::ast::fnc,
(std::vector<char>, id)
(std::vector<client::ast::node>, args)
)
namespace client{
namespace x3 = boost::spirit::x3;
namespace calc_grammar{
using x3::uint_;
using x3::alpha;
using x3::alnum;
using x3::lit;
using x3::char_;
x3::rule<class funct, ast::fnc> const funct("function");
x3::rule<class ts, ast::ts> const ts("timeseries");
x3::rule<class funct_name, std::vector<char>> const funct_name("function_name");
auto const funct_def = funct_name >> lit('(') >> -((ts|funct)%lit(',')) >> lit(')');
auto const ts_def = lit('#') >> uint_ >> lit('#');
auto const funct_name_def = lit('@') >> alpha >> *(alnum|char_('_'));
auto const calc = x3::grammar(
"calc",
funct = funct_def,
ts = ts_def,
funct_name = funct_name_def
);
}
using calc_grammar::calc;
}
错误C2665:'boost :: detail: :variant :: make_initializer_node :: apply :: initializer_node :: initialize':5个重载都不能转换所有的参数类型
error C2665: 'boost::detail::variant::make_initializer_node::apply::initializer_node::initialize': none of the 5 overloads could convert all the argument types
在variant.hpp中还有一个用户注释
There's also a note to user in variant.hpp
// NOTE TO USER :
// Compile error here indicates that the given type is not
// unambiguously convertible to one of the variant's types
// (or that no conversion exists).
但我不是更聪明的...
Yet I am none the wiser...
推荐答案
我发现了这个老问题。
I spotted this old question. X3 has evolved a bit in the mean time and I though I'd answer it now anyways.
我怀疑主要问题可能是(遗漏)(隐含) )构造函数。
I suspected that the main issue might have been with (missing) (implicit) constructors on the variant members.
无论如何,这里是一个更轻量级语法的现场演示:
Anyhow, here's a live demo with a more lightweight grammar:
namespace grammar_def {
using namespace x3;
rule<class funct, ast::fnc> const funct("function");
auto const ts = lexeme [ '#' >> uint_ >> '#' ];
auto const fname = lexeme [ '@' >> raw [ alpha >> *(alnum | '_') ] ];
auto const expr = ts|funct;
auto const funct_def = fname >> '(' >> -expr % ',' >> ')';
BOOST_SPIRIT_DEFINE(funct)
}
输出流助手。请注意为了简单,我为了简单而将 id 类型更改为
std :: string
$ c> operator< <$ / code> for 向量< char>
无入侵 namespace std
:
I also added some output streaming helpers. Note how I changed the id
type to std::string
for simplicity (it's hard/impossible to overload operator<<
for vector<char>
without invading namespace std
):
namespace client { namespace ast {
static std::ostream& operator<<(std::ostream& os, ts const& v) {
using namespace boost::fusion;
return os << tuple_open("") << tuple_close("") << tuple_delimiter("") << as_vector(v);
}
static std::ostream& operator<<(std::ostream& os, fnc const& v) {
using namespace boost::fusion;
return os << tuple_open("") << tuple_close("") << tuple_delimiter("") << as_vector(v);
}
template<typename T>
static std::ostream& operator<<(std::ostream& os, std::vector<T> const& v) {
os << "("; for (auto& el : v) os << (&el==&v[0]?"":", ") << el; return os << ")";
}
} }
演示
b $ b
这有更多(可选)管道以允许更丰富的调试信息:
Demo
This has more (optional) plumbing to allow for richer debug information:
Live On Coliru
//#define BOOST_SPIRIT_X3_DEBUG
#include <iostream>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/as_vector.hpp>
#include <boost/fusion/include/io.hpp>
#include <boost/spirit/home/x3.hpp>
namespace client { namespace ast {
struct ts;
struct fnc;
//using string = std::vector<char>;
using string = std::string; // for easier printing/debugging
struct ts {
unsigned int id;
ts(unsigned id=0):id(id) {}
};
typedef boost::variant<ts, boost::recursive_wrapper<fnc> > node;
struct fnc {
string id;
std::vector<node> args;
};
} }
BOOST_FUSION_ADAPT_STRUCT(client::ast::ts, id)
BOOST_FUSION_ADAPT_STRUCT(client::ast::fnc, id, args)
//namespace std { static ostream& operator<<(ostream&os, vector<char> const& v) { return os.write(&v[0], v.size()); } }
namespace client { namespace ast {
static std::ostream& operator<<(std::ostream& os, ts const& v) {
using namespace boost::fusion;
return os << tuple_open("") << tuple_close("") << tuple_delimiter("") << as_vector(v);
}
static std::ostream& operator<<(std::ostream& os, fnc const& v) {
using namespace boost::fusion;
return os << tuple_open("") << tuple_close("") << tuple_delimiter("") << as_vector(v);
}
template<typename T>
static std::ostream& operator<<(std::ostream& os, std::vector<T> const& v) {
os << "("; for (auto& el : v) os << (&el==&v[0]?"":", ") << el; return os << ")";
}
} }
namespace client {
namespace x3 = boost::spirit::x3;
namespace grammar_def {
using namespace x3;
x3::rule<class funct, ast::fnc> const funct("function");
auto const ts // = x3::rule<class ts, ast::ts> {"timeseries"}
= lexeme [ '#' >> uint_ >> '#' ];
auto const fname // = x3::rule<class fname, ast::string> {"function_name"}
= lexeme [ '@' >> raw [ alpha >> *(alnum | '_') ] ];
auto const expr // = rule<struct expr_, ast::node > {"expr"}
= ts|funct;
auto const funct_def = fname >> '(' >> -expr % ',' >> ')';
BOOST_SPIRIT_DEFINE(funct)
}
auto const& grammar = x3::skip(x3::space) [grammar_def::funct];
}
#include <iostream>
int main() {
std::string const s {
"@pow( #1#, \n"
" @trunc(\n"
" @pi ()\n"
" ) )"};
std::cout << "Parsing '" << s << "'\n";
auto f = s.begin();
client::ast::fnc parsed;
if (parse(f, s.end(), client::grammar, parsed)) {
std::cout << "Parse succeeded: " << parsed << "\n";
} else {
std::cout << "Parse failed\n";
}
if (f != s.end())
std::cout << "Remaining unparsed input: '" << std::string(f, s.end()) << "'\n";
}
列印:
Parsing '@pow( #1#,
@trunc(
@pi ()
) )'
Parse succeeded: pow(1, trunc(pi()))
这篇关于模糊的变体和精神x3的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!