Попытка совершить такое колдовство без понимания того, как на самом деле общаются Феникс и Дух, чрезвычайно трудна. Давайте попробуем покопаться в этом:
- Параметризация правила происходит через
operator()
из qi::rule
, который создает экземпляр qi::parameterized_nonterminal
синтаксического анализатора.
- Ленивый анализ парсера выполняется следующим образом:
qi::lazy
переносит phoenix::actor
в proto::terminal
, который позднее (метакомпилятором) преобразуется в qi::lazy_parser
/ qi::lazy_directive
.
Итак, в вашем примере актер Phoenix преобразуется в Proto-терминал, а затем оператор вызова создает Proto-выражение, которое мета-компилятор Spirit не понимает.
Я предположил, что это должно быть lazy(phoenix::bind(&get_constant_parser, _r2)(_r1))
, потому что вам нужно назвать это operator()
для действующего правила, но Феникс не позволяет вам вызывать operator()
, как это.
Что должно работать: lazy(phoenix::bind(phoenix::bind(&get_constant_parser, _r2), _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";
}
https://wandbox.org/permlink/m40DpeMikKRYyvH0