Building a qi :: rule with a function attribute
I am trying to create a rule that returns function<char(char const *)>
, created by currying a Phoenix expression. For example.
start = int_[_val = xxx];
rule<Iterator, function<char(char const *)> start;
What should it xxx
be so that parsing the string "5"
should give me a function that gives me the fifth character of its input? I've tried things like lambda(_a = arg1)[arg1[_a]](_1)
but I haven't been able to pounce on the magic formula.
In other words, I need the curry attribute arg2[arg1]
on the parse int value
Very grateful for any suggestions. Note that I am on VC2008, so C ++ 11 lambdas is not available.
Mike
source to share
After committing this rule declaration:
typedef boost::function<char(char const*)> Func;
qi::rule<Iterator, Func()> start;
it worked: Live On Coliru (C ++ 03).
UPDATE
Why did I get such a complicated fixture?
qi::_val = px::bind(px::lambda[arg1[arg2]], px::lambda[arg1], qi::_1)
Well. Let me tell you about the joy of complexing functional composition with lazy evaluation (in C ++ template meta-programming, which has these surprises with reference / value semantics): Don't do the following:
qi::_val = px::lambda(_a = qi::_1) [arg1[_a]] // UB!!! DON'T DO THIS
Depending on the compiler, optimization level, it might look like * . But it calls Undefined Behavior [1] . The problem is what will be stored as a reference to the attribute exposed by the parser expression . However, this link after the completion of the parsing context is a deception link. qi::_1
qi::int_
So, evaluating indirect functions through an invalid reference. To avoid this, you must say ( Live On Coliru ):
qi::_val = px::lambda(_a = px::val(qi::_1)) [arg1[_a]]
or even (if you like obscure code):
qi::_val = px::lambda(_a = +qi::_1) [arg1[_a]]
Or, you know, you can stick with the bound nested lambda, since the default binding is semantics-for qi::_1
(if you didn't use the phx::cref
/ wrappers phx::ref
).
Hope the above analysis has brought home what I did in the comments before:
Please note that I would not recommend this style of code. Programming of a higher order with Phoenix is difficult enough without having made them out of lazy participants in some built-in the DSL-template template:
qi::_val = px::bind(px::lambda[arg1[arg2]], px::lambda[arg1], qi::_1)
. 'Nuff said ?
#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/function.hpp>
namespace qi = boost::spirit::qi;
namespace px = boost::phoenix;
typedef boost::function<char(char const*)> Func;
int main()
{
typedef std::string::const_iterator Iterator;
using namespace boost::phoenix::arg_names;
qi::rule<Iterator, Func()> start;
start = qi::int_
[ qi::_val = px::bind(px::lambda[arg1[arg2]], px::lambda[arg1], qi::_1) ];
// or: [ qi::_val = px::lambda(_a = px::val(qi::_1))[arg1[_a]] ];
static char const* inputs[] = { "0", "1", "2", "3", "4", 0 };
for (char const* const* it = inputs; *it; ++it)
{
std::string const input(*it);
Iterator f(input.begin()), l(input.end());
Func function;
bool ok = qi::parse(f, l, start, function);
if (ok)
std::cout << "Parse resulted in function() -> character "
<< function("Hello") << "; "
<< function("World") << "\n";
else
std::cout << "Parse failed\n";
if (f != l)
std::cout << "Remaining unparsed: '" << std::string(f, l) << "'\n";
}
}
Printing
Parse resulted in function() -> character H; W
Parse resulted in function() -> character e; o
Parse resulted in function() -> character l; r
Parse resulted in function() -> character l; l
Parse resulted in function() -> character o; d
[1] (MSVC2013 crashed, gcc might run in -O3, but segfaults in -O0, etc.)
source to share