I have a very cool float calculator implementation with boost::spirit
.
It works on a boost::spirit::qi::float_
by default: it gets an std::string
input, and calculates the result float
of the expression.
See it in action here.
Here is the code for reference:
namespace calc {
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
///////////////////////////////////////////////////////////////////////////
// Our calculator grammar
///////////////////////////////////////////////////////////////////////////
template <typename Iterator>
struct calculator : qi::grammar<Iterator, float(), ascii::space_type>
{
calculator() : calculator::base_type(expression)
{
using qi::_val;
using qi::_1;
using qi::float_;
expression =
term [_val = _1]
>> *( ('+' >> term [_val += _1])
| ('-' >> term [_val -= _1])
)
;
term =
factor [_val = _1]
>> *( ('*' >> factor [_val *= _1])
| ('/' >> factor [_val /= _1])
)
;
factor =
float_ [_val = _1]
| '(' >> expression [_val = _1] >> ')'
| ('-' >> factor [_val = -_1])
| ('+' >> factor [_val = _1])
;
}
qi::rule<Iterator, float(), ascii::space_type> expression, term, factor;
};
}
typedef calc::calculator<std::string::const_iterator> calculator;
int main()
{
calculator calc;
std::string expression = "3*5";
float result = 0;
std::string::const_iterator iter = expression.begin();
std::string::const_iterator end = expression.end();
std::stringstream resultstream;
bool r = boost::spirit::qi::phrase_parse(iter, end, calc, boost::spirit::ascii::space, result);
if (! (r && iter == end)) {
result = 0;
}
resultstream.clear();
resultstream << result;
std::cout << "Result: " << resultstream.str() << std::endl;
}
It calculates the expression
's value into theresultstream
.
Works perfectly, for 3*5
it outputs:
Result: 15
If I change the expression to "5/3" it outputs:
Result: 1.66667
My desire is to always have a fixed number of digits:
For 3*5:
Result: 15.0
For 5/3:
Result: 1.7
I know: adding std::setw
to cout
solve this. But my goal is different (!):
I want to get the above formatted result into the resultstream
, directly from the parser.
My idea is to allow the parser to parse more complex inputs like:
3*5%.1 => 15.0
3*5%.2 => 15.00
3*5% => 15%
3*5%.2% => 15.00%
How shall I achieve this? Is it worth changing the calculator itself, or it's too heavy and I should prefer some other text processing techniques to parse the required formatting and still do it with std::setw
like this:
resultstream << setw(required_width) << result;