- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
这个问题是针对
Boost Spirit x3 conditional (ternary) operator parser
原始问题上下文没有显示ast属性(我不好!),因此答案无法考虑所有 Activity 部分。现在,此问题说明ast属性的外观以及如何使用ast通过符号表评估表达式。
因此,接下来的问题是正确拼写的三元条件应该如何改变ast类型以及条件和表达式如何相互作用(根据我的理解,由于它将从主要对象中删除,因此现在不属于x3::variant的一部分)解析器选择)
这是ast属性和声明的符号定义的样子
namespace x3 = boost::spirit::x3;
namespace ast {
struct nil {};
struct unary_op;
struct binary_op;
struct conditional_op;
struct expression;
struct operand : x3::variant<
nil
, double
, std::string
, x3::forward_ast<unary_op>
, x3::forward_ast<binary_op>
//, x3::forward_ast<conditional_op> // conditional_op not here?
, x3::forward_ast<expression>
> {
using base_type::base_type;
using base_type::operator=;
};
struct unary_op {
double (*op)(double);
operand rhs;
};
struct binary_op {
double (*op)(double, double);
operand lhs;
operand rhs;
};
/*
struct conditional_op {
operand lhs;
operand rhs_true;
operand rhs_false;
};
*/
struct conditional_op {
expression lhs;
// how the exact type is spelled?
optional<expression, expression> maybe_rhs;
};
struct operation {
double (*op)(double, double);
operand rhs;
};
// what is the type of expression ?
struct expression {
conditional_op conditional;
};
/*
struct expression {
operand lhs;
std::list<operation> rhs;
};
*/
} // namespace ast
struct constant_ : x3::symbols<double> {
constant_() {
add
("e" , boost::math::constants::e<double>())
("pi" , boost::math::constants::pi<double>())
;
}
} constant;
struct ufunc_ : x3::symbols<double (*)(double)> {
ufunc_() {
add
("abs" , static_cast<double (*)(double)>(&std::abs))
;
}
} ufunc;
struct bfunc_ : x3::symbols<double (*)(double, double)> {
bfunc_() {
add
("max" , static_cast<double (*)(double, double)>(&std::fmax))
;
}
} bfunc;
struct unary_op_ : x3::symbols<double (*)(double)> {
unary_op_() {
add
("+", static_cast<double (*)(double)>(&math::plus))
("-", static_cast<double (*)(double)>(&math::minus))
("!", static_cast<double (*)(double)>(&math::unary_not))
;
}
} unary_op;
struct additive_op_ : x3::symbols<double (*)(double, double)> {
additive_op_() {
add
("+", static_cast<double (*)(double, double)>(&math::plus))
("-", static_cast<double (*)(double, double)>(&math::minus))
;
}
} additive_op;
struct multiplicative_op_ : x3::symbols<double (*)(double, double)> {
multiplicative_op_() {
add
("*", static_cast<double (*)(double, double)>(&math::multiplies))
("/", static_cast<double (*)(double, double)>(&math::divides))
("%", static_cast<double (*)(double, double)>(&std::fmod))
;
}
} multiplicative_op;
struct logical_op_ : x3::symbols<double (*)(double, double)> {
logical_op_() {
add
("&&", static_cast<double (*)(double, double)>(&math::logical_and))
("||", static_cast<double (*)(double, double)>(&math::logical_or))
;
}
} logical_op;
struct relational_op_ : x3::symbols<double (*)(double, double)> {
relational_op_() {
add
("<" , static_cast<double (*)(double, double)>(&math::less))
("<=", static_cast<double (*)(double, double)>(&math::less_equals))
(">" , static_cast<double (*)(double, double)>(&math::greater))
(">=", static_cast<double (*)(double, double)>(&math::greater_equals))
;
}
} relational_op;
struct equality_op_ : x3::symbols<double (*)(double, double)> {
equality_op_() {
add
("==", static_cast<double (*)(double, double)>(&math::equals))
("!=", static_cast<double (*)(double, double)>(&math::not_equals))
;
}
} equality_op;
struct power_ : x3::symbols<double (*)(double, double)> {
power_() {
add
("**", static_cast<double (*)(double, double)>(&std::pow))
;
}
} power;
struct expression_class;
struct logical_class;
struct equality_class;
struct relational_class;
struct additive_class;
struct multiplicative_class;
struct factor_class;
struct primary_class;
struct unary_class;
struct binary_class;
struct conditional_class;
struct variable_class;
// Rule declarations
auto const expression = x3::rule<expression_class , ast::expression >{"expression"};
auto const logical = x3::rule<logical_class , ast::expression >{"logical"};
auto const equality = x3::rule<equality_class , ast::expression >{"equality"};
auto const relational = x3::rule<relational_class , ast::expression >{"relational"};
auto const additive = x3::rule<additive_class , ast::expression >{"additive"};
auto const multiplicative = x3::rule<multiplicative_class, ast::expression >{"multiplicative"};
auto const factor = x3::rule<factor_class , ast::expression >{"factor"};
auto const primary = x3::rule<primary_class , ast::operand >{"primary"};
auto const unary = x3::rule<unary_class , ast::unary_op >{"unary"};
auto const binary = x3::rule<binary_class , ast::binary_op >{"binary"};
auto const conditional = x3::rule<conditional_class , ast::conditional_op>{"conditional"};
auto const variable = x3::rule<variable_class , std::string >{"variable"};
// Rule defintions
/* This is a bit of magic to me. Does this definition now say that expression
itself is now initializer list constructible from the conditional (which is spelled below)?
*/
auto const expression_def =
conditional
;
/* now ast::conditional_op type should be constructible from an initialization list consisting
of of an expression and optional<tuple<expression,expression>> ? How these types should be
spelled in the struct? There is a circular reference between expression and conditional :D ?
*/
auto const conditional_def =
logical >> -('?' > expression > ':'> expression)
;
auto const logical_def =
equality >> *(logical_op > equality)
;
auto const equality_def =
relational >> *(equality_op > relational)
;
auto const relational_def =
additive >> *(relational_op > additive)
;
auto const additive_def =
multiplicative >> *(additive_op > multiplicative)
;
auto const multiplicative_def =
factor >> *(multiplicative_op > factor)
;
auto const factor_def =
primary >> *( power > factor )
;
auto const unary_def =
ufunc > '(' > expression > ')'
;
auto const binary_def =
bfunc > '(' > expression > ',' > expression > ')'
;
auto const primary_def =
x3::double_
| ('(' > expression > ')')
| (unary_op > primary)
| binary
| unary
// | conditional // by removing the conditional from primary implies the type of x3::variant changes
| variable
;
BOOST_SPIRIT_DEFINE(
expression,
logical,
equality,
relational,
additive,
multiplicative,
factor,
primary,
unary,
binary,
conditional,
variable
)
namespace ast {
// Evaluator
struct Evaluator {
using result_type = double;
explicit Evaluator(std::map<std::string, double> sym);
double operator()(nil) const;
double operator()(double n) const;
double operator()(std::string const &c) const;
double operator()(operation const &x, double lhs) const;
double operator()(unary_op const &x) const;
double operator()(binary_op const &x) const;
double operator()(conditional_op const &x) const;
double operator()(expression const &x) const;
private:
std::map<std::string, double> st;
};
Evaluator::Evaluator(std::map<std::string, double> sym)
: st(std::move(sym)) {}
double Evaluator::operator()(nil) const {
BOOST_ASSERT(0);
return 0;
}
double Evaluator::operator()(double n) const { return n; }
double Evaluator::operator()(std::string const &c) const {
auto it = st.find(c);
if (it == st.end()) {
throw std::invalid_argument("Unknown variable " + c);
}
return it->second;
}
double Evaluator::operator()(operation const &x, double lhs) const {
double rhs = boost::apply_visitor(*this, x.rhs);
return x.op(lhs, rhs);
}
double Evaluator::operator()(unary_op const &x) const {
double rhs = boost::apply_visitor(*this, x.rhs);
return x.op(rhs);
}
double Evaluator::operator()(binary_op const &x) const {
double lhs = boost::apply_visitor(*this, x.lhs);
double rhs = boost::apply_visitor(*this, x.rhs);
return x.op(lhs, rhs);
}
double Evaluator::operator()(conditional_op const &x) const {
return static_cast<bool>(boost::apply_visitor(*this, x.lhs))
? boost::apply_visitor(*this, x.rhs_true)
: boost::apply_visitor(*this, x.rhs_false);
}
double Evaluator::operator()(expression const &x) const {
double state = boost::apply_visitor(*this, x.lhs);
for (operation const &oper : x.rhs) {
state = (*this)(oper, state);
}
return state;
}
} // namespace ast
最佳答案
因此,公开的顶级属性是expression
,坦率地说,它根本不表示表达式。
相反,它表示表达式输入语法的虚假单位,可能被称为“operation_chain”。
这也将使您难以使用AST进行语义上正确的转换(例如表达式评估),因为诸如操作优先级之类的关键信息未在其中进行编码。
In fact, if we're not careful it's very possible that this information - if present in the input - would be lost. I think it's possible in practice to go from your AST and reconstruct the operation tree with dependent operations in order of their precedence. But I usually err on the safe side of explicitly modeling the expression tree to reflect the operation dependencies.
conditional_op
不是链式二进制操作,因此不适合该模型。我建议使“顶层”规则改为公开
ast::operand
(这样就可以同时适合
conditional_op
或
expression
)。
auto const conditional_def =
logical [([](auto& ctx) { _val(ctx) = _attr(ctx); })]
>> -('?' > expression > ':' > expression) [make_conditional_op]
;
auto make_conditional_op = [](auto& ctx) {
using boost::fusion::at_c;
x3::_val(ctx) = ast::conditional_op {
x3::_val(ctx),
at_c<0>(x3::_attr(ctx)),
at_c<1>(x3::_attr(ctx)) };
};
//#define BOOST_SPIRIT_X3_DEBUG
//#define DEBUG_SYMBOLS
#include <iostream>
#include <functional>
#include <iomanip>
#include <list>
#include <boost/fusion/adapted/struct.hpp>
#include <boost/math/constants/constants.hpp>
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/x3/support/ast/variant.hpp>
namespace x3 = boost::spirit::x3;
namespace ast {
struct nil {};
struct unary_op;
struct binary_op;
struct conditional_op;
struct expression;
using UnFunc = std::function<double(double)>;
using BinFunc = std::function<double(double, double)>;
struct operand : x3::variant<
nil
, double
, std::string
, x3::forward_ast<unary_op>
, x3::forward_ast<binary_op>
, x3::forward_ast<conditional_op>
, x3::forward_ast<expression> >
{
using base_type::base_type;
using base_type::operator=;
};
struct unary_op {
UnFunc op;
operand rhs;
};
struct binary_op {
BinFunc op;
operand lhs;
operand rhs;
};
struct conditional_op {
operand lhs;
operand rhs_true;
operand rhs_false;
};
struct operation {
BinFunc op;
operand rhs;
};
struct expression {
operand lhs;
std::list<operation> rhs;
};
} // namespace ast
BOOST_FUSION_ADAPT_STRUCT(ast::expression, lhs, rhs)
BOOST_FUSION_ADAPT_STRUCT(ast::operation, op, rhs)
BOOST_FUSION_ADAPT_STRUCT(ast::conditional_op, lhs, rhs_true, rhs_false)
BOOST_FUSION_ADAPT_STRUCT(ast::binary_op, op, lhs, rhs)
BOOST_FUSION_ADAPT_STRUCT(ast::unary_op, op, rhs)
namespace P {
struct ehbase {
template <typename It, typename Ctx>
x3::error_handler_result on_error(It f, It l, x3::expectation_failure<It> const& e, Ctx const& /*ctx*/) const {
std::cout << std::string(f,l) << "\n"
<< std::setw(1+std::distance(f, e.where())) << "^"
<< "-- expected: " << e.which() << "\n";
return x3::error_handler_result::fail;
}
};
struct expression_class : ehbase {};
struct logical_class : ehbase {};
struct equality_class : ehbase {};
struct relational_class : ehbase {};
struct additive_class : ehbase {};
struct multiplicative_class : ehbase {};
struct factor_class : ehbase {};
struct primary_class : ehbase {};
struct unary_class : ehbase {};
struct binary_class : ehbase {};
struct conditional_class : ehbase {};
struct variable_class : ehbase {};
// Rule declarations
auto const expression = x3::rule<expression_class , ast::operand >{"expression"};
auto const conditional = x3::rule<conditional_class , ast::operand >{"conditional"};
auto const primary = x3::rule<primary_class , ast::operand >{"primary"};
auto const logical = x3::rule<logical_class , ast::expression >{"logical"};
auto const equality = x3::rule<equality_class , ast::expression >{"equality"};
auto const relational = x3::rule<relational_class , ast::expression >{"relational"};
auto const additive = x3::rule<additive_class , ast::expression >{"additive"};
auto const multiplicative = x3::rule<multiplicative_class, ast::expression >{"multiplicative"};
auto const factor = x3::rule<factor_class , ast::expression >{"factor"};
auto const unary = x3::rule<unary_class , ast::unary_op >{"unary"};
auto const binary = x3::rule<binary_class , ast::binary_op >{"binary"};
auto const variable = x3::rule<variable_class , std::string >{"variable"};
struct constant_ : x3::symbols<double> {
constant_() {
this->add
("e" , boost::math::constants::e<double>())
("pi" , boost::math::constants::pi<double>())
;
}
} constant;
struct ufunc_ : x3::symbols<ast::UnFunc> {
ufunc_() {
this->add
("abs" , &std::abs<double>)
;
}
} ufunc;
struct bfunc_ : x3::symbols<ast::BinFunc> {
bfunc_() {
this->add
("max" , [](double a,double b){ return std::fmax(a,b); })
("min" , [](double a,double b){ return std::fmin(a,b); })
("pow" , [](double a,double b){ return std::pow(a,b); })
;
}
} bfunc;
struct unary_op_ : x3::symbols<ast::UnFunc> {
unary_op_() {
this->add
("+", [](double v) { return +v; })
("-", std::negate{})
("!", [](double v) { return !v; })
;
}
} unary_op;
struct additive_op_ : x3::symbols<ast::BinFunc> {
additive_op_() {
this->add
("+", std::plus{})
("-", std::minus{})
;
}
} additive_op;
struct multiplicative_op_ : x3::symbols<ast::BinFunc> {
multiplicative_op_() {
this->add
("*", std::multiplies<>{})
("/", std::divides<>{})
("%", [](double a, double b) { return std::fmod(a, b); })
;
}
} multiplicative_op;
struct logical_op_ : x3::symbols<ast::BinFunc> {
logical_op_() {
this->add
("&&", std::logical_and{})
("||", std::logical_or{})
;
}
} logical_op;
struct relational_op_ : x3::symbols<ast::BinFunc> {
relational_op_() {
this->add
("<" , std::less{})
("<=", std::less_equal{})
(">" , std::greater{})
(">=", std::greater_equal{})
;
}
} relational_op;
struct equality_op_ : x3::symbols<ast::BinFunc> {
equality_op_() {
this->add
("==", std::equal_to{})
("!=", std::not_equal_to{})
;
}
} equality_op;
struct power_ : x3::symbols<ast::BinFunc> {
power_() {
this->add
("**", [](double v, double exp) { return std::pow(v, exp); })
;
}
} power;
auto const variable_def = x3::lexeme[x3::alpha >> *x3::alnum];
// Rule defintions
auto const expression_def =
conditional
;
auto make_conditional_op = [](auto& ctx) {
using boost::fusion::at_c;
x3::_val(ctx) = ast::conditional_op {
x3::_val(ctx),
at_c<0>(x3::_attr(ctx)),
at_c<1>(x3::_attr(ctx)) };
};
auto const conditional_def =
logical [([](auto& ctx) { _val(ctx) = _attr(ctx); })]
>> -('?' > expression > ':' > expression) [make_conditional_op]
;
auto const logical_def =
equality >> *(logical_op > equality)
;
auto const equality_def =
relational >> *(equality_op > relational)
;
auto const relational_def =
additive >> *(relational_op > additive)
;
auto const additive_def =
multiplicative >> *(additive_op > multiplicative)
;
auto const multiplicative_def =
factor >> *(multiplicative_op > factor)
;
auto const factor_def =
primary >> *( power > factor )
;
auto const unary_def
= (unary_op > primary)
| (ufunc > '(' > expression > ')')
;
auto const binary_def =
bfunc > '(' > expression > ',' > expression > ')'
;
auto const primary_def =
x3::double_
| ('(' > expression > ')')
//| (unary_op > primary)
| binary
| unary
| constant
| variable
;
BOOST_SPIRIT_DEFINE(expression)
BOOST_SPIRIT_DEFINE(logical)
BOOST_SPIRIT_DEFINE(equality)
BOOST_SPIRIT_DEFINE(relational)
BOOST_SPIRIT_DEFINE(additive)
BOOST_SPIRIT_DEFINE(multiplicative)
BOOST_SPIRIT_DEFINE(factor)
BOOST_SPIRIT_DEFINE(primary)
BOOST_SPIRIT_DEFINE(unary)
BOOST_SPIRIT_DEFINE(binary)
BOOST_SPIRIT_DEFINE(conditional)
BOOST_SPIRIT_DEFINE(variable)
}
int main() {
for (std::string const input : {
"x+(3**pow(2,8))",
"1 + (2 + abs(x))",
"min(x,1+y)",
"(x > y ? 1 : 0) * (y - z)",
"min(3**4,7))",
"3***4",
"(3,4)",
})
{
std::cout << " ===== " << std::quoted(input) << " =====\n";
auto f = begin(input), l = end(input);
ast::operand out;
if (phrase_parse(f, l, P::expression, x3::space, out)) {
std::cout << "Success\n";
} else {
std::cout << "Failed\n";
}
if (f!=l) {
std::cout << "Unparsed: " << std::quoted(std::string(f,l)) << "\n";
}
}
}
===== "x+(3**pow(2,8))" =====
Success
===== "1 + (2 + abs(x))" =====
Success
===== "min(x,1+y)" =====
Success
===== "(x > y ? 1 : 0) * (y - z)" =====
Success
===== "min(3**4,7))" =====
Success
Unparsed: ")"
===== "3***4" =====
3***4
^-- expected: factor
Failed
Unparsed: "3***4"
===== "(3,4)" =====
(3,4)
^-- expected: ')'
Failed
Unparsed: "(3,4)"
关于c++ - Boost Spirit x3条件(三元)运算符解析器(后续问题),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59828544/
我之前让 dll 注入(inject)器变得简单,但我有 Windows 7,我用 C# 和 C++ 做了它,它工作得很好!但是现在当我在 Windows 8 中尝试相同的代码时,它似乎没有以正确的方
我正在尝试制作一个名为 core-splitter 的元素,该元素在 1.0 中已弃用,因为它在我们的项目中起着关键作用。 如果您不知道 core-splitter 的作用,我可以提供一个简短的描述。
我有几个不同的蜘蛛,想一次运行所有它们。基于 this和 this ,我可以在同一个进程中运行多个蜘蛛。但是,我不知道如何设计一个信号系统来在所有蜘蛛都完成后停止 react 器。 我试过了: cra
有没有办法在达到特定条件时停止扭曲 react 器。例如,如果一个变量被设置为某个值,那么 react 器应该停止吗? 最佳答案 理想情况下,您不会将变量设置为一个值并停止 react 器,而是调用
https://code.angularjs.org/1.0.0rc9/angular-1.0.0rc9.js 上面的链接定义了外部js文件,我不知道Angular-1.0.0rc9.js的注入(in
我正在尝试运行一个函数并将服务注入(inject)其中。我认为这可以使用 $injector 轻松完成.所以我尝试了以下(简化示例): angular.injector().invoke( [ "$q
在 google Guice 中,我可以使用函数 createInjector 创建基于多个模块的注入(inject)器。 因为我使用 GWT.create 在 GoogleGin 中实例化注入(in
我在 ASP.NET Core 1.1 解决方案中使用配置绑定(bind)。基本上,我在“ConfigureServices Startup”部分中有一些用于绑定(bind)的简单代码,如下所示: s
我在 Spring MVC 中设置 initBinder 时遇到一些问题。我有一个 ModelAttribute,它有一个有时会显示的字段。 public class Model { privat
我正在尝试通过jquery post发布knockoutjs View 模型 var $form = $('#barcodeTemplate form'); var data = ko.toJS(vm
如何为包含多态对象集合的复杂模型编写自定义模型绑定(bind)程序? 我有下一个模型结构: public class CustomAttributeValueViewModel { publi
您好,我正在尝试实现我在 this article 中找到的扩展方法对于简单的注入(inject)器,因为它不支持开箱即用的特定构造函数的注册。 根据这篇文章,我需要用一个假的委托(delegate)
你好,我想自动注册我的依赖项。 我现在拥有的是: public interface IRepository where T : class public interface IFolderReposi
我正在使用 Jasmine 测试一些 Angular.js 代码。为此,我需要一个 Angular 注入(inject)器: var injector = angular.injector(['ng'
我正在使用 Matlab 代码生成器。不可能包含代码风格指南。这就是为什么我正在寻找一个工具来“ reshape ”、重命名和重新格式化生成的代码,根据我的: 功能横幅约定 文件横幅约定 命名约定 等
这个问题在这里已经有了答案: Where and why do I have to put the "template" and "typename" keywords? (8 个答案) 关闭 8
我开发了一种工具,可以更改某些程序的外观。为此,我需要在某些进程中注入(inject)一个 dll。 现在我基本上使用这个 approach .问题通常是人们无法注入(inject) dll,因为他们
我想使用 swing、spring 和 hibernate 编写一个 java 应用程序。 我想使用数据绑定(bind)器用 bean 的值填充 gui,并且我还希望它反射(reflect) gui
我有这段代码,当两个蜘蛛完成后,程序仍在运行。 #!C:\Python27\python.exe from twisted.internet import reactor from scrapy.cr
要点是 Spring Batch (v2) 测试框架具有带有 @Autowired 注释的 JobLauncherTestUtils.setJob。我们的测试套件有多个 Job 类提供者。因为这个类不
我是一名优秀的程序员,十分优秀!