尝试调整boost精神x3 calc示例来解析可以将函数作为参数的函数.但是它没有编译.
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; }
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中还有一个用户注释
// 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).
但我不是更聪明…
解决方法
我发现了这个老问题. X3在同一时间有所演变,尽管我现在也回答一下.
我怀疑主要问题可能与变体成员的(缺少)(隐式)构造函数一起使用.
无论如何,这是一个更轻巧的语法的现场演示:
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(在不侵入命名空间std的情况下重载运算符<<对于矢量< char>很难/不可能):
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 << ")"; } } }
演示
这有更多(可选)管道,以允许更丰富的调试信息:
//#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,") << 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()))