c++ 在boost spirit中,如何从创建属性的语义动作例程中设置force-rule-to-not-match bool引用参数?

j8ag8udp  于 2023-06-25  发布在  其他
关注(0)|答案(1)|浏览(164)

目前我有这样的东西:

  1. qi::_val = boost::phoenix::bind(
  2. [](const std::string&, const boost::optional<std::string>&)
  3. { return std::string();
  4. },
  5. qi::_1,
  6. qi::_2
  7. )

我想选择使此规则不匹配。关于语义函数的documentation没有说明如何返回创建对象的属性。
我尝试在lambda函数中添加两个额外的参数:

  1. const boost::fusion::unused_type&, bool&

但这行不通。

ct2axkht

ct2axkht1#

记录的签名here

  1. void f(Attrib const&);
  2. void f(Attrib const&, Context&);
  3. void f(Attrib const&, Context&, bool&);
  • 注意函数对象的精度。我认为差异只是由于遗留C++03兼容性 *

低级,我们可以说是“原始”语义动作函数。只有当您是一个库开发人员,希望了解有关Context如何静态组成和动态访问的所有细节时,它们才是有趣的。
上下文包含skippers、本地属性、继承属性、合成属性、绑定属性引用 * 和 * parse-result标志。
人们使用Phoenix表达式来创建具体的语义动作,而不是处理这些签名。Qi defines placeholder actors对应于上下文元素:

  • _1_2 ...,_N

p的第n个属性

  • _val

封闭规则的合成属性。

  • _r1_r2 ...,_rN

封闭规则的第N个继承属性。

  • _a_b ...,_j

封闭规则的局部变量(_a指第一个)。

  • _pass

将false赋给_pass以强制解析器失败。
您已经选择了Phoenix(使用phoenix::bind)。所以我建议你还是采用Phoenix式的动作。让你的例子工作的最简单的方法:

  1. qi::_val = boost::phoenix::bind(
  2. [](const std::string&, const boost::optional<std::string>&, bool& pass)
  3. { pass = rand()%2;
  4. return std::string();
  5. },
  6. qi::_1,
  7. qi::_2,
  8. qi::_pass
  9. )

奖励/升级

但请注意,您也可以***雇用更多的高级Phoenix设施。
我个人更喜欢Phoenix改编的callables。例如,让我们编写一个功能性更强的语义动作:

  1. struct magic_f {
  2. std::string operator()(std::string const& s1, boost::optional<std::string> s2, bool& pass) const {
  3. if (s2) {
  4. std::reverse(s2->begin(), s2->end());
  5. } else {
  6. s2 = s1;
  7. }
  8. pass = (s1 == s2);
  9. return std::move(s2.value());
  10. }
  11. };

它实现的验证逻辑是:如果存在第二个字符串,则它必须与第一个字符串 * 反向 * 匹配。
现在,您可以使用phoenix::function创建相应的actor:

  1. boost::phoenix::function<magic_f> magic;

这意味着您可以简单地编写操作:

  1. word = +qi::graph;
  2. pair = (word >> -word)[ _val = magic(_1, _2, _pass) ];

看到这个**Live On Coliru**

  1. #include <boost/spirit/include/qi.hpp>
  2. #include <boost/phoenix.hpp>
  3. #include <iomanip>
  4. namespace qi = boost::spirit::qi;
  5. using Word = std::string;
  6. template <typename It> struct Demo : qi::grammar<It, Word()> {
  7. Demo() : Demo::base_type(start) {
  8. using namespace qi::labels; // for the phoenix expression placeholders
  9. word = +qi::graph;
  10. pair = (word >> -word)[ _val = magic(_1, _2, _pass) ];
  11. start = qi::skip(qi::space)[ pair ];
  12. }
  13. private:
  14. struct magic_f {
  15. Word operator()(Word const& s1, boost::optional<Word> s2, bool& pass) const {
  16. if (s2)
  17. std::reverse(s2->begin(), s2->end());
  18. else
  19. s2 = s1;
  20. pass = (s1 == s2);
  21. return std::move(s2.value());
  22. }
  23. };
  24. boost::phoenix::function<magic_f> magic;
  25. qi::rule<It, Word()> start, word;
  26. qi::rule<It, Word(), qi::space_type> pair;
  27. };
  28. int main() {
  29. static Demo<Word::const_iterator> const p;
  30. for (std::string const s : {"", "foo", "foo foo", "foo bar", "foo oof", "bar bra", "bar rab"})
  31. if (Word word; parse(begin(s), end(s), p, word))
  32. std::cout << std::setw(12) << quoted(s) << " -> MATCH " << quoted(word) << std::endl;
  33. else
  34. std::cout << std::setw(12) << quoted(s) << " -> FAIL" << std::endl;
  35. }

输出:

  1. "" -> FAIL
  2. "foo" -> MATCH "foo"
  3. "foo foo" -> FAIL
  4. "foo bar" -> FAIL
  5. "foo oof" -> MATCH "foo"
  6. "bar bra" -> FAIL
  7. "bar rab" -> MATCH "bar"

观察结果:

请注意,这样你就不需要把bool& pass作为参数了。相反,你可以返回bool:

  1. struct magic_f {
  2. bool operator()(Word& s1, boost::optional<Word> s2, Word& out) const {
  3. if (s2) {
  4. std::reverse(s2->begin(), s2->end());
  5. if (s1!=s2)
  6. return false;
  7. }
  8. out = std::move(s1);
  9. return true;
  10. }
  11. };

并将动作写为:

  1. pair = (word >> -word)[ _pass = magic(_1, _2, _val) ];

关于exact same results
通常,您可以利用现有的参与者(例如对于标准库函数和运算符),并且根本不使用自定义函数编写,例如匹配一个词,只有当它的长度:

  1. pair %= word >> qi::omit[qi::int_[_pass = size(_val) == _1]];

看到它**Live On Coliru**

C++17甜

在C++17中,由于CTAD,可以方便地使用lambda表达式。这样就可以避免像以前一样定义magic_f类型:

  1. boost::phoenix::function magic = [](auto& s1, auto& s2, bool& pass) {
  2. if (s2)
  3. std::reverse(s2->begin(), s2->end());
  4. else
  5. s2 = s1;
  6. pass = (s1 == s2);
  7. return std::move(s2.value());
  8. };
  9. word = +qi::graph;
  10. pair = (word >> -word)[ _val = magic(_1, _2, _pass) ];

看到它**Live On Coliru**

展开查看全部

相关问题