网上有很多例子如何用 Boost Spirit 实现一个计算器。还回答了有关如何向其添加幂运算符的问题,例如this one。
但是,当涉及到幂运算符和一元否定运算符的组合时,这些示例就失败了。
考虑以下表达式:
-4^2
-(12/3)^2
你认为答案应该是什么?任何理智的数学家都会回答-16。因为求幂运算优先于一元求反运算。
但是,根据网络上共享的示例执行语法规则的计算器将回答 16。
但是,更值得注意的是,尝试在 Microsoft Excel 中输入这些公式。你会得到16!(感叹号,不是阶乘)。维基百科中甚至有一条关于微软对该规则的“例外”的注释。
但是对于我们这些构建工程应用程序的开发人员来说,这当然是不可接受的。它必须是 -16,否则飞机将开始分崩离析。所以,问题是如何调整示例语法规则以遵循它。
这是我们使用 Boost Spirit "Classic" 的计算器版本:
definition(calculator const & self ) {
expression
= factor
>> *( ('+' >> factor)[self.add_op]
| ('-' >> factor)[self.sub_op]
)
;
factor
= powerterm
>> *( ('*' >> powerterm)[self.mult_op]
| ('/' >> powerterm)[self.div_op]
)
;
powerterm
= term
>> *( ('^' >> powerterm)[self.exp_op]
| ("**" >> powerterm)[self.exp_op]
)
;
term
= boost::spirit::classic::real_p[self.real_op]
| '(' >> expression >> ')'
| ('-' >> term)[self.neg_op]
| ('+' >> term)
;
}
它生成的输出虽然与 Excel 匹配,但不可接受:
info = parse("-4^2", calc, scspirit::space_p);
// generates PUSH(-4);PUSH(2);EXPONENTIATE; which is 16
info = parse("-(12/3)^2", calc, scspirit::space_p);
// generates PUSH(12);PUSH(3);DIVIDE;NEGATE;PUSH(2);EXPONENTIATE; which is 16