除了不祥的暗示它可能是完全不可能的,我找不到任何东西,但是我不想简单地相信它,因为在这种情况下,懒惰的解析器似乎没用。我想做的是根据先前某些非终端的结果在解析时选择一个解析器。本质上可以归结为:
static rule<Constant *(Scope &)> &get_constant_parser(Typename type);
rule<Constant *(Scope &, Typename)> constant {
lazy(phoenix::bind(&get_constant_parser, _r2))(_r1)
};
因此get_constant_parser
返回一个适合给定类型名称的解析器,但是该解析器需要一个Scope &
类型的参数。因此,直观地讲,我将其记录下来,并将参数添加到惰性解析器中。但是,这给了我一个无效的表达式:
/usr/include/boost/spirit/home/qi/nonterminal/rule.hpp:177:13: error: static assertion failed: error_invalid_expression
BOOST_SPIRIT_ASSERT_MATCH(qi::domain, Expr);
^~~~~~~~~~~~~~~~~~~~~~~~~
那么我该如何为懒惰的解析器提供参数呢?如果确实不可能,那么有谁知道为什么?
对不起,这不是适当的MWE,现在我希望有人以前做过,并且知道答案。如果您要积极调查并需要MWE,请告诉我;-)
答案 0 :(得分:2)
在不了解Phoenix和Spirit实际交流方式的情况下尝试进行此类魔术非常困难。让我们尝试深入研究:
operator()
解析器实例的qi::rule
中的qi::parameterized_nonterminal
进行规则参数化。qi::lazy
将phoenix::actor
包装到proto::terminal
中,随后将其(由元编译器转换成qi::lazy_parser
/ qi::lazy_directive
。因此,在您的示例中,Phoenix actor被转换为Proto终端,然后调用运算符创建了Spirit元编译器无法理解的Proto表达式。
我的猜测是应该为lazy(phoenix::bind(&get_constant_parser, _r2)(_r1))
,因为您需要在实际规则上调用该operator()
,但是Phoenix不允许您这样调用operator()
。
应该起作用的是:lazy(phoenix::bind(phoenix::bind(&get_constant_parser, _r2), _r1))
。
很久以前,我尝试过类似您正在执行的操作,但也失败了。我还用谷歌搜索那些说不可能的话题,然后就停止了。但是您的问题引起了我的兴趣,经过短暂的尝试和错误(例如,挠头并挖掘Spirit的来源),我得到了这一概念证明:
#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";
}
答案 1 :(得分:1)
所以我很遗憾地说我认为这确实是不可能的[*]
但是,一切并没有丢失。如果您可以使用qi::locals
而不是传递“参数”(继承的属性),则应该没事。
根据您的实际目标,尽管您可以通过调用lazy(arg)
来减少对“ non_lazy(symbols*)
”的需求。这种想法是由我的直觉提示的,您正在尝试进行与名称空间/域相关的查找。参见例如
[*]