Boost :: Spirit解析漂浮物并格式化它吗?
我有一个非常酷的浮点计算器实现,boost :: Spirit
。
它可以在boost :: spirit :: qi :: float _
默认情况下使用:它获取std :: string
输入,并计算结果float 。
在操作中看到它在这里。
这是引用的代码:
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;
}
它将表达式
的值计算到ResulteTream
中。
完美工作,对于3*5
它输出:
结果:15
如果我将表达式更改为“ 5/3”,则输出:
结果:1.66667
我的愿望是始终拥有固定数量的数字:
3*5:
结果:15.0
5/3的15.0:
结果:1.7
我知道:将std :: setw
添加到cout
解决此问题。但是我的目标是不同的(!):
我想直接从解析器中将上述格式的结果直接从resulttream
中。
我的想法是让解析器解析更复杂的输入,例如:
3*5%.1 => 15.0
3*5%.2 => 15.00
3*5% => 15%
3*5%.2% => 15.00%
我该如何实现?是否值得更改计算器本身,还是太重了,我应该更喜欢其他一些文本处理技术来解析所需的格式,并且仍然使用std :: SetW
这样的方法来做:
resultstream << setw(required_width) << result;
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;
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
这告诉我您不是创建表达式评估器,而是制作格式规范。我和其他人说:分开您的担忧。
对于值得
setw
没有帮助您,但是std :: fixed
和std :: setPrecision
可能。无论如何, c ++都可以做到的,也可以在语义动作中发生,因此,这种地狱般的构装应该可以起作用。 com/a/20e01563be9d25e8“ rel =“ nofollow noreferrer”> live on Compiler Explorer ,打印:
奖励
关于简介梦的
不值得更改计算器,因为它不是计算器。确实不是,一旦您使用格式化的内容扩展了语法(即非表达的东西),那肯定不再了。
您可以当然会创建这样的语法。让我们描述AST:
现在,我们可以使Toplevel规则返回
formmattedResult
,而不是结果
(即float
):带有一些其他声明:
在编译器资源管理器上活
看到它
让我的个人喜好大放异彩,但请参阅例如 boost spirit:“语义动作是邪恶的”吗?
This tells me you're not so much creating an expression evaluator, but rather making a format specification. I'm with others that say: separate your concerns.
For what it's worth
setw
doesn't help you, butstd::fixed
andstd::setprecision
might. Regardless, anything C++ can do, can also happen in a semantic action, so, this hellish contraption should work¹:See it Live On Compiler Explorer, printing:
BONUS
Regarding the intro dreams:
It's not worth changing the calculator, because it isn't a calculator. It really wasn't, and certainly not anymore once you extend your grammar with formatting things (i.e. non-expression things).
You can of course create such a grammar. Let's describe the AST:
Now, we can make the toplevel rule return
FormmattedResult
instead of justResult
(i.e.float
):With some additional declarations:
See it Live On Compiler Explorer
Prints
¹ I hope I didn't accidentally let my personal preference shine through, but see e.g. Boost Spirit: "Semantic actions are evil"?