C++ boost::带参数的精神惰性解析器?

C++ boost::带参数的精神惰性解析器?,c++,parsing,boost-spirit,C++,Parsing,Boost Spirit,我在这方面找不到任何东西,除了不祥的暗示,这可能是完全不可能的,但我不想简单地相信这一点,因为在这种情况下,懒惰的解析器似乎毫无用处。我想做的是在解析时根据前面的一些非终结符的结果选择一个解析器。基本上可以归结为: static rule<Constant *(Scope &)> &get_constant_parser(Typename type); rule<Constant *(Scope &, Typename)> constant {

我在这方面找不到任何东西,除了不祥的暗示,这可能是完全不可能的,但我不想简单地相信这一点,因为在这种情况下,懒惰的解析器似乎毫无用处。我想做的是在解析时根据前面的一些非终结符的结果选择一个解析器。基本上可以归结为:

static rule<Constant *(Scope &)> &get_constant_parser(Typename type);

rule<Constant *(Scope &, Typename)> constant {
    lazy(phoenix::bind(&get_constant_parser, _r2))(_r1)
};
那么,我如何为一个懒惰的解析器提供参数呢?如果确实不可能,那么有人知道为什么吗


对不起,这不是一个适当的MWE,现在我希望有人做过它之前,只是知道答案。如果您想积极调查并需要MWE,请告知我;-)

所以很抱歉,我认为这确实是不可能的[*]

然而,一切都没有失去。如果您可以使用
qi::locals
而不是传递“参数”(继承的属性),那么您就可以了

  • 例如,参见此处使用qi::locals的地方
根据您的实际目标,您可以通过调用
非惰性(符号*)
来避开对“
惰性(arg)
”的需求。这一想法是由我的直觉引起的,即您正在尝试进行名称空间/域相关的查找。见例

  • -这有很多不相关的复杂性,但很好地展示了如何匹配不同域上的函数名和变量

[*]


    • 试图在不了解凤凰和精灵是如何交流的情况下进行这种巫术是极其困难的。让我们试着深入探讨一下:

    • 规则参数化是通过
      qi::Rule
      operator()
      实现的,它创建了
      qi::parameterized\u nonterminal
      解析器的实例
    • 惰性解析器的计算是这样执行的:
      qi::Lazy
      phoenix::actor
      包装成
      proto::terminal
      ,然后(通过元编译器)将其转换成
      qi::Lazy\u解析器
      /
      qi::Lazy\u指令
    • 所以,在您的示例中,Phoenix actor被转换为一个Proto终端,然后call操作符创建了一个Spirit元编译器无法理解的Proto表达式

      我猜它应该是惰性的(phoenix::bind(&get_constant_parser,_r2)(_r1))
      ,因为您需要在实际规则中调用
      操作符()
      ,但phoenix不允许您这样调用
      操作符()

      应该工作的是:
      lazy(phoenix::bind(phoenix::bind(&get\u constant\u parser,\u r2),\u r1))


      很久以前,我尝试过像你这样的事情,但也失败了。我还用谷歌搜索了那些说这是不可能的话题,并就此停止。但你的问题引起了我的兴趣,经过短暂的尝试和错误(即挠头和挖掘精神来源),我得出了这个概念证明:

      #include <boost/spirit/include/qi.hpp>
      #include <boost/spirit/include/phoenix.hpp>
      #include <boost/spirit/include/support_argument.hpp>
      #include <iostream>
      
      namespace qi = boost::spirit::qi;
      namespace phx = boost::phoenix;
      
      int main()
      {
          using passed_rule_t = qi::rule<char const*, int(int)>;
          qi::rule<char const*, int(int, passed_rule_t const&)> lazyinvoke
              = qi::lazy(phx::bind(qi::labels::_r2,   // binding is a way to call `operator()` lazily
                                   qi::labels::_r1)); // non-lazy equivalent of this is `_r2(_r1)`
          int v;
          char const* s = nullptr;
          passed_rule_t inout = qi::attr(qi::labels::_r1);
          if (qi::parse(s, s, lazyinvoke(phx::val(123), phx::cref(inout)), v))
              std::cout << "OK: " << v << "\n";
          else
              std::cout << "Failed\n";
      }
      
      #包括
      #包括
      #包括
      #包括
      名称空间qi=boost::spirit::qi;
      名称空间phx=boost::phoenix;
      int main()
      {
      使用通过的规则\u t=qi::rule;
      qi::规则懒散调用
      =qi::lazy(phx::bind)(qi::labels::r2,//绑定是一种延迟调用`operator()`的方法
      qi::labels::_r1));//与之等价的非惰性变量是`_r2(_r1)`
      INTV;
      char const*s=nullptr;
      已通过规则inout=qi::attr(qi::labels::_r1);
      if(qi::parse(s,s,lazyinvoke(phx::val(123),phx::cref(inout)),v))
      
      很有趣,我有点认为沿着这些思路一定是可能的,但我无法理解所需的语法脑筋。不幸的是,它对我来说仍然崩溃,因为在某个地方(我认为在内部
      绑定中
      )我的
      作用域&
      参数被转换为
      常量作用域
      ,这失败了,因为这些东西是不可复制的。我接受这一点,因为这是一个有效的概念证明,非常准确地回答了我的问题。不过,它附带了一些警告,一个重要的警告是,如果你在代码中真的做了类似的事情,每一个代码审阅者将与WTF一样。同样重要的是,一旦你开始考虑这些恶作剧,也许是时候重新考虑你的设计了。关于这一点,请参阅@sehe的答案。太棒了!我能够通过将
      范围&
      转换为
      范围*
      来实现内部绑定,从而使其可复制。这是一个黑客,bu这是一种可以在许多地方将复杂性从O(c^5n)降低到O(c^n)的黑客技术。很有可能这是一个凤凰虫(它还有其他的
      const
      ness问题)。如果你有时间做一个MCVE,我建议你打开一个bug报告。而且,我很高兴旧的误解已经被揭穿。好吧,
      qi::locals
      肯定是不够的,因为信息需要传递。我的关键字本质上是一个类型名,想想例如
      bool
      number
      ,并解析任意的e当然,这些类型的Xpression我必须使用完全不同的非终结符。我还没有真正研究过它,也许符号表可以为我做到这一点。一个问题可能是符号(即类型名称)可能没有被逐字解析,但从以前解析的对象的属性读取。例如,想象一下将布尔赋值给布尔变量引用。
      #include <boost/spirit/include/qi.hpp>
      #include <boost/spirit/include/phoenix.hpp>
      #include <boost/spirit/include/support_argument.hpp>
      #include <iostream>
      
      namespace qi = boost::spirit::qi;
      namespace phx = boost::phoenix;
      
      int main()
      {
          using passed_rule_t = qi::rule<char const*, int(int)>;
          qi::rule<char const*, int(int, passed_rule_t const&)> lazyinvoke
              = qi::lazy(phx::bind(qi::labels::_r2,   // binding is a way to call `operator()` lazily
                                   qi::labels::_r1)); // non-lazy equivalent of this is `_r2(_r1)`
          int v;
          char const* s = nullptr;
          passed_rule_t inout = qi::attr(qi::labels::_r1);
          if (qi::parse(s, s, lazyinvoke(phx::val(123), phx::cref(inout)), v))
              std::cout << "OK: " << v << "\n";
          else
              std::cout << "Failed\n";
      }