回答问题:
- 我的想法是只用
BOOST_FUSION_ADAPT_STRUCT 调整结构的一部分,并用语义动作填充其余部分。愚蠢的想法,还是我做错了?
并非不可想象。不是我的建议(见Boost Spirit: "Semantic actions are evil"?)。但是,是的,你做错了:
如果您不希望 lit("$") 成为暴露属性的一部分,则需要 char_("$")。其实'$'这里就可以了
-
有没有办法绑定语义动作并仍然获得输出?喜欢
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)。
但是,您似乎真的在尝试两次使用相同的输入(原始为fromFile,“熟”为name?)它适得其反,因为自动规则属性传播也是 用您想要的 fromFile 值覆盖 name。
在这里,唯一快速的方法是仅使用 SA。我建议让VariableHolder 的构造函数负责细节。
旁注:它看起来有点好像可选括号暗示了表达式语法。如果是这样,请在语法中明确说明,而不是在规则中为variableName 硬编码特殊情况。如果没有,请继续:)
这是一个尝试修复:
Live On Coliru
#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)')