c++ - 如何更改此示例中的代码
问题描述
如何更改代码源以显示结果?
我无法转换为提升精神 x3
#include <string>
#include <vector>
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/x3/support/ast/variant.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/adapted.hpp>
namespace x3 = boost::spirit::x3;
namespace client { namespace ast {
struct op_or {};
struct op_and {};
struct op_xor {};
struct op_not {};
template <typename tag> struct combination_op;
template <typename tag> struct unop;
typedef std::string var;
typedef boost::variant<
var,
boost::recursive_wrapper<unop<op_not>>,
boost::recursive_wrapper<combination_op<op_and>>,
boost::recursive_wrapper<combination_op<op_xor>>,
boost::recursive_wrapper<combination_op<op_or>>
>expr;
template <typename tag> struct combination_op {
typedef std::vector<expr> operands_t;
combination_op() = default;
combination_op(operands_t const& operands) : operands(operands) {}
operands_t operands;
};
template <typename tag> struct unop {
unop() = default;
unop(const expr& o) : operand(o) {}
expr operand;
};
}}
BOOST_FUSION_ADAPT_STRUCT(client::ast::combination_op<client::ast::op_and>, operands)
BOOST_FUSION_ADAPT_STRUCT(client::ast::combination_op<client::ast::op_xor>, operands)
BOOST_FUSION_ADAPT_STRUCT(client::ast::combination_op<client::ast::op_or>, operands)
BOOST_FUSION_ADAPT_STRUCT(client::ast::unop<client::ast::op_not>, operand)
namespace client { namespace parser {
x3::rule<class var, ast::var> var{ "var" };
x3::rule<class not, ast::unop<ast::op_not>> not{ "not" };
x3::rule<class and, ast::combination_op<ast::op_and>> and{ "and" };
x3::rule<class xor, ast::combination_op<ast::op_xor>> xor{ "xor" };
x3::rule<class or, ast::combination_op<ast::op_or >> or{ "or" };
x3::rule<class expr, ast::expr> expr { "expr" };
auto const expr_def = xor | and | or | not | var;
auto const expr_list = *expr;
auto const or_def = x3::no_case["or"] >> '(' >> expr_list >> ')';
auto const xor_def = x3::no_case["xor"] >> '(' >> expr_list >> ')';
auto const and_def = x3::no_case["and"] >> '(' >> expr_list >> ')';
auto const not_def = x3::no_case["not"] >> expr;
auto const var_def = x3::lexeme[+x3::alpha];
BOOST_SPIRIT_DEFINE(var,not,and,xor,or,expr);
}}
namespace client { namespace ast {
struct printer :boost::static_visitor<void> {
printer() {}
void operator()(const var& v) const{ }
void operator()(const combination_op<op_and>& b) const { recurse(b); }
void operator()(const combination_op<op_xor>& b) const { recurse(b); }
void operator()(const combination_op<op_or>& b) const { recurse(b); }
void operator()(const unop<op_not>& u) const { recurse(u.operand); }
template<typename T>
void recurse(T const& v) const {
//boost::apply_visitor(*this, v);
}
};
}}
int main() {
std::string storage = "a or (b and c)";
client::ast::expr result;
typedef std::string::const_iterator iterator_t;
iterator_t iter = storage.begin(), end = storage.end();
using x3::ascii::space;
bool ok = phrase_parse(iter, end, client::parser::expr, space, result);
if (ok && iter == end) {
boost::apply_visitor(client::ast::printer(), result);
}
return 0;
}
解决方案
void operator()(const combination_op<op_and>& b) const { recurse(b); }
void operator()(const combination_op<op_xor>& b) const { recurse(b); }
void operator()(const combination_op<op_or>& b) const { recurse(b); }
void operator()(const unop<op_not>& u) const { recurse(u.operand); }
What do you suppose these functions do? If you look at the example you linked, you see concrete implementations:
struct printer : boost::static_visitor<void>
{
printer(std::ostream& os) : _os(os) {}
std::ostream& _os;
//
void operator()(const var& v) const { _os << v; }
void operator()(const binop<op_and>& b) const { print(" & ", b.oper1, b.oper2); }
void operator()(const binop<op_or >& b) const { print(" | ", b.oper1, b.oper2); }
void operator()(const binop<op_xor>& b) const { print(" ^ ", b.oper1, b.oper2); }
void print(const std::string& op, const expr& l, const expr& r) const
{
_os << "(";
boost::apply_visitor(*this, l);
_os << op;
boost::apply_visitor(*this, r);
_os << ")";
}
void operator()(const unop<op_not>& u) const
{
_os << "(";
_os << "!";
boost::apply_visitor(*this, u.oper1);
_os << ")";
}
};
std::ostream& operator<<(std::ostream& os, const expr& e)
{ boost::apply_visitor(printer(os), e); return os; }
So you'd expect to write something like:
struct printer {
using result_type = void;
std::ostream& _os;
static auto name(op_and /*unused*/) { return "AND"; }
static auto name(op_not /*unused*/) { return "NOT"; }
static auto name(op_or /*unused*/) { return "OR"; }
static auto name(op_xor /*unused*/) { return "XOR"; }
void operator()(const var& v) const { _os << v; }
template <typename Op>
void operator()(const unop<Op>& u) const {
_os << "(" << name(Op{}) << " ";
operator()(u.operand);
_os << ")";
}
template <typename Op>
void operator()(const combination_op<Op>& b) const {
_os << "(";
bool first = true;
for (auto& e : b.operands) {
if (!std::exchange(first, false)) {
_os << " " << name(Op{}) << " ";
}
operator()(e);
}
_os << ")";
}
void operator()(expr const& v) const {
boost::apply_visitor(*this, v);
}
};
Which prints (Live On Coliru)
"or(a and(b c))" -> (a OR (b AND c))
If you wanted output similar to the thing you parse:
template <typename Op> void operator()(const unop<Op>& u) const {
operator()(combination_op<Op>{{u.operand}});
}
template <typename Op> void operator()(const combination_op<Op>& b) const {
_os << name(Op{}) << "(";
for (auto& e : b.operands) {
_os << " ";
operator()(e);
}
_os << ")";
}
Printing (Live On Coliru):
"or(a and(b c))" -> OR( a AND( b c))
As you can see, I that implementation highlights that the "function call" syntax doesn't essentially require difference between unary and binary operators
Full Listing
First variation:
// #define BOOST_SPIRIT_X3_DEBUG
#include <boost/fusion/adapted.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/x3/support/ast/variant.hpp>
#include <string>
#include <iostream>
#include <iomanip>
#include <vector>
namespace x3 = boost::spirit::x3;
namespace client { namespace ast {
struct op_or {};
struct op_and {};
struct op_xor {};
struct op_not {};
template <typename tag> struct combination_op;
template <typename tag> struct unop;
typedef std::string var;
typedef boost::variant<var, boost::recursive_wrapper<unop<op_not>>,
boost::recursive_wrapper<combination_op<op_and>>,
boost::recursive_wrapper<combination_op<op_xor>>,
boost::recursive_wrapper<combination_op<op_or>>>
expr;
template <typename tag> struct combination_op {
typedef std::vector<expr> operands_t;
combination_op() = default;
combination_op(operands_t const& operands) : operands(operands) {}
operands_t operands;
};
template <typename tag> struct unop {
unop() = default;
unop(const expr& o) : operand(o) {}
expr operand;
};
} }
BOOST_FUSION_ADAPT_STRUCT(client::ast::combination_op<client::ast::op_and>, operands)
BOOST_FUSION_ADAPT_STRUCT(client::ast::combination_op<client::ast::op_xor>, operands)
BOOST_FUSION_ADAPT_STRUCT(client::ast::combination_op<client::ast::op_or>, operands)
BOOST_FUSION_ADAPT_STRUCT(client::ast::unop<client::ast::op_not>, operand)
namespace client { namespace parser {
x3::rule<class var, ast::var> var{ "var" };
x3::rule<class not_, ast::unop<ast::op_not>> not_ { "not" };
x3::rule<class and_, ast::combination_op<ast::op_and>> and_ { "and" };
x3::rule<class xor_, ast::combination_op<ast::op_xor>> xor_ { "xor" };
x3::rule<class or_, ast::combination_op<ast::op_or>> or_ { "or" };
x3::rule<class expr, ast::expr> expr{ "expr" };
auto const expr_def = xor_ | and_ | or_ | not_ | var;
auto const expr_list = *expr;
auto const or__def = x3::no_case["or"] >> '(' >> expr_list >> ')';
auto const xor__def = x3::no_case["xor"] >> '(' >> expr_list >> ')';
auto const and__def = x3::no_case["and"] >> '(' >> expr_list >> ')';
auto const not__def = x3::no_case["not"] >> expr;
auto const var_def = x3::lexeme[+x3::alpha];
BOOST_SPIRIT_DEFINE(var, not_, and_, xor_, or_, expr)
} }
namespace client { namespace ast {
struct printer {
using result_type = void;
std::ostream& _os;
static auto name(op_and /*unused*/) { return "AND"; }
static auto name(op_not /*unused*/) { return "NOT"; }
static auto name(op_or /*unused*/) { return "OR"; }
static auto name(op_xor /*unused*/) { return "XOR"; }
void operator()(const var& v) const { _os << v; }
template <typename Op>
void operator()(const unop<Op>& u) const {
_os << "(" << name(Op{}) << " ";
operator()(u.operand);
_os << ")";
}
template <typename Op>
void operator()(const combination_op<Op>& b) const {
_os << "(";
bool first = true;
for (auto& e : b.operands) {
if (!std::exchange(first, false)) {
_os << " " << name(Op{}) << " ";
}
operator()(e);
}
_os << ")";
}
void operator()(expr const& v) const {
boost::apply_visitor(*this, v);
}
};
} }
int main() {
std::string storage = "or(a and(b c))";
client::ast::expr result;
typedef std::string::const_iterator iterator_t;
iterator_t iter = storage.begin(), end = storage.end();
using x3::ascii::space;
bool ok = phrase_parse(iter, end, client::parser::expr, space, result);
if (ok && iter == end) {
client::ast::printer print{std::cout};
std::cout << std::quoted(storage) << " -> ";
print(result);
std::cout << "\n";
} else {
std::cout << "Failed\n";
}
if (iter != end) {
std::cout << "Remaining: " << std::quoted(std::string(iter, end)) << "\n";
}
}
推荐阅读
- html - 为什么我的图库图像不显示在一行上?
- c++ - 有没有办法通过在 C++ 中使用 fstream 设置“文件结尾”的新位置来调整文件大小?
- javascript - 我无法使用 Jquery 更改按钮的颜色
- ruby-on-rails - 如何使用外键属性作为错误键而不是 belongs_to 关联名称?
- oracle - How to write pl/sql code with return type boolean for user authorization?
- rust - 使用大型全局静态表的典型方法是什么,这些表在 Rust 中初始化一次并实际上用作常量?
- c# - C# 代码上的未知 405 错误 + 微调
- python - python - 如何在python中将一对空格分隔为文本文件?
- java - 登录后执行 ConstraintSet 后按钮不可见
- reactjs - 如何在 React 应用程序中包含 PHP 代码 - 没有 ajax