Boost:spirit解析为结构并重用其中的一部分 [英] Boost:spirit Parsing into structure and reusing parts of it
问题描述
我必须在句子中找到变量并将其替换为它们的值.变量可以用不同的形式编写,例如$ varName或$(varName).
I have to find variables in a sentence and replace them by their value. Variables can be written in different forms, like $varName, or $(varName) for example.
我希望拥有一个VariableHolder结构以方便地访问两者:
I'd like to have a struct VariableHolder to have easy access to both :
struct VariableHolder
{
string name; // contains "varName"
string fromFile; // contains "$(varName)" or "$varName"
void setName(ustring n) { name = n; }
}
很显然,我想避免进行多次传递和调用多个解析器.到目前为止,我是这样的:
Obviously, I'd like to avoid doing multiple passes and calling multiple parsers. What I have so far is this :
BOOST_FUSION_ADAPT_STRUCT(VariableHolder,
(ustring, fromFile)
)
// variableName is another parser that returns a string
qi::rule<Iterator, VariableHolder()> variable %=
(qi::char_("$")
>> (variableName[phoenix::bind(&VariableHolder::setName, qi::_val, qi::_1)]
| (qi::char_("(")
>> variableName[phoenix::bind(&VariableHolder::setName, qi::_val, qi::_1)]
>> qi::char_(")")))
);
这不起作用.名称已正确设置,但是fromFile变量仅包含"$",并且没有其他任何内容.
Which doesn't work. The name is correctly set, but the fromFile variable only contains a "$", and never anything else.
好吧,我对您的问题:
- 我的想法是仅使用BOOST_FUSION_ADAPT_STRUCT调整结构的一部分,并用语义动作填充其余部分.愚蠢的主意,还是我做错了?
-
有没有办法绑定语义动作并仍然获取输出?像
- My idea was to only adapt part of the structure with BOOST_FUSION_ADAPT_STRUCT, and fill the rest with semantic actions. Stupid idea, or am I just doing it wrong?
Is there a way to bind a semantic action and still get the output? Like
char_ [doSomething]//这两者都可以调用doSomething并解析字符吗?
char_[doSomething] // Can this both call doSomething, and parse a char?
推荐答案
解决问题:
- 我的想法是只使用
BOOST_FUSION_ADAPT_STRUCT
修改结构的一部分,并用语义动作填充其余部分.愚蠢的主意,还是我做错了?
- My idea was to only adapt part of the structure with
BOOST_FUSION_ADAPT_STRUCT
, and fill the rest with semantic actions. Stupid idea, or am I just doing it wrong?
并非不可思议.不是我的建议(请参阅 Boost Spirit:语义行为是邪恶的"?).但是,是的,您做错了:
Not unthinkable. Not my recommendation (see Boost Spirit: "Semantic actions are evil"?). But yeah you're doing it wrong:
如果您不希望它成为公开属性的一部分,则希望使用 lit("$")
而不是 char _("$")
.实际上,'$'
将在此处执行
You want lit("$")
instead of char_("$")
if you don't want it to be part of the exposed attribute. In fact, '$'
will do here
-
有没有办法绑定语义动作并仍然获取输出?喜欢
Is there a way to bind a semantic action and still get the output? Like
char_[doSomething] // Can this both call doSomething, and parse a char?
是的.您正在执行此操作,它之所以有效,是因为您使用了 operator%=
而不是 operator =
(请参阅文档: http://www.boost.org/doc/libs/1_61_0/libs/spirit/doc/html/spirit/qi/reference/nonterminal/rule.html#spirit.qi.reference.nonterminal.rule.expression_semantics ).
Yes. You're doing it right now, and it works because of operator%=
you used instead of operator=
(see the docs: http://www.boost.org/doc/libs/1_61_0/libs/spirit/doc/html/spirit/qi/reference/nonterminal/rule.html#spirit.qi.reference.nonterminal.rule.expression_semantics).
但是,您似乎真的在尝试两次使用相同的输入(原始为 fromFile
和"cooked"为 name
?),因为它会自动生效规则属性传播还用您想要的 fromFile
值覆盖 name
.
However, it seems you are really trying to use the same input twice (raw as fromFile
and "cooked" as name
?) it backfires, because the auto-rule attribute propagation also overwrites name
with the value you want for fromFile
.
这里唯一快速的解决方法是仅使用SA.我建议尽管使 VariableHolder
的构造函数负责细节.
The only quick way out, here, is to use SA only. I'd suggest making VariableHolder
's constructor responsible for details though.
旁注:看起来有点像可选的括号暗示了表达式语法.如果是这样,请在语法中使其明确,而不是在
variableName
的规则中对特殊情况进行硬编码.如果没有,继续:)
Side note: it looks a bit as if the optional parentheses suggest an expression grammar. If so, make that explicit in the grammar, instead of hardcoding a special case in the rule for a
variableName
. If not, carry on :)
这是尝试的解决方法:
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
namespace qi = boost::spirit::qi;
namespace phoenix = boost::phoenix;
struct VariableHolder {
std::string name; // contains "varName"
std::string fromFile; // contains "$(varName)" or "$varName"
};
template <typename It, typename Skipper = qi::ascii::space_type> struct P : qi::grammar<It, VariableHolder(), Skipper> {
P() : P::base_type(start) {
auto _name = phoenix::bind(&VariableHolder::name, qi::_val);
auto _fromFile = phoenix::bind(&VariableHolder::fromFile, qi::_val);
variableName = qi::alpha >> +qi::alnum;
variable = '$' >> (variableName | '(' >> variableName >> ')');
start = qi::as_string [ qi::raw [
variable [ _name = qi::_1 ]]
] [ _fromFile = qi::_1 ];
BOOST_SPIRIT_DEBUG_NODES((start)(variable)(variableName))
}
private:
qi::rule<It, std::string(), Skipper> variable;
qi::rule<It, VariableHolder(), Skipper> start;
// lexemes
qi::rule<It, std::string()> variableName;
};
int main() {
using It = std::string::const_iterator;
P<It> const p;
for (std::string const input : {
"$foo1",
"$(bar2)"
})
{
It f = input.begin(), l = input.end();
VariableHolder data;
bool ok = qi::phrase_parse(f, l, p, qi::ascii::space, data);
if (ok) {
std::cout << "Parse success: " << data.name << " (source: '" << data.fromFile << "')\n";
} else {
std::cout << "Parse failure ('" << input << "')\n";
}
if (f != l) {
std::cout << "Remaining unparsed input: '" << std::string(f, l) << "'\n";
}
}
}
打印
Parse success: foo1 (source: '$foo1')
Parse success: bar2 (source: '$(bar2)')
这篇关于Boost:spirit解析为结构并重用其中的一部分的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!