qi::hold
正如@Andrzej 正确提到的那样,这是一种方法
我想我有一些可能会有所帮助的观察结果以及更好的解决方案。
关键是,Spirit 不会通过设计要求对属性进行“临时”存储。事实上,它不能真正假设属性是可复制的。这就是这里的原因(想象将所有内容解析为单个 std::vector<> 并为每个解析器步骤进行复制?)。
在更本质的层面上,在我看来,这里倒退的不是属性处理,而是解析器表达式本身:它没有说明意图,并且在处理数字表示时会产生各种复杂性......真的不应该。
我的看法是
rule<std::string::iterator, std::string()> zeroTo255, alternatively;
alternatively %= raw [ uint_ [ _pass = (_1 <= 255) ] ];
你看:你让 Spirit 解析一个数字,实际上只是验证范围,这是你首先想要做的。
让我印象深刻的第二件事是,规则公开了一个std::string
属性,而不是unsigned char
例如为什么会这样?
假设这是一个有意识的设计决定,您可以通过明智地使用
- 负前瞻 (
!parser
) - 不影响属性
- 正向前瞻 (
&parser
) - 不影响属性
- 熟悉
qi::as_string
, qi::raw
,qi::lexeme
和qi::no_skip
- 语义动作(不要依赖自动规则)
以下是对原始规则的最小更改:
zeroTo255 = raw [
("25" >> char_("0-5"))
| ('2' >> char_("0-4") >> digit)
| ('1' >> digit >> digit)
| (char_("1-9") >> digit)
| digit
];
这与使用 _hold_ing 属性值的代码具有大致相同的效果,qi::hold
但没有性能缺陷。
希望这可以帮助。
完整示例:在http://liveworkspace.org/code/4v4CQW$0上直播:
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
namespace qi = boost::spirit::qi;
int main()
{
using namespace qi;
rule<std::string::iterator, std::string()> zeroTo255, alternatively;
zeroTo255 = raw [
("25" >> char_("0-5"))
| ('2' >> char_("0-4") >> digit)
| ('1' >> digit >> digit)
| (char_("1-9") >> digit)
| digit
];
alternatively %= raw [ uint_ [ _pass = (_1 <= 255) ] ];
for (auto& input : std::vector<std::string> { "255", "249", "178", "30", "4" })
{
std::string output;
std::cout << "zeroTo255:\t" << std::boolalpha
<< parse(std::begin(input), std::end(input), zeroTo255, output)
<< ": " << output << std::endl;
output.clear();
std::cout << "alternatively:\t" << std::boolalpha
<< parse(std::begin(input), std::end(input), alternatively, output)
<< ": " << output << std::endl;
}
}
输出
zeroTo255: true: 255
alternatively: true: 255
zeroTo255: true: 249
alternatively: true: 249
zeroTo255: true: 178
alternatively: true: 178
zeroTo255: true: 30
alternatively: true: 30
zeroTo255: true: 4
alternatively: true: 4