There are many examples online how to implement a calculator with Boost Spirit. There are also answered questions on how to add an exponentiation operator to it, for example this one.
But, when it comes to a combination of exponentiation operator AND unary negation operator, these examples fail.
Consider the following expressions:
-4^2
-(12/3)^2
What do you think the answers should be? Any sane mathematician will answer -16. Because exponentiation operation has a precedence over unary negation operation.
But the calculators implementing grammatical rules from the examples shared on the web will answer 16.
But, even more remarkable, try to enter these formula in Microsoft Excel. What you will get is 16! (exclamation mark, not a factorial). There is even a note in Wikipedia about this Microsoft's "exception" of the rule.
But to us, developers building engineering applications, it is unacceptable of course. It has to be -16, or planes will start falling apart. So, the question is how to tweak the example grammar rules to follow it.
Here is our version of the calculator using 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)
;
}
The output it generates, while matches Excel, is unacceptable:
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