Simple x3 code cannot compile because nothing is attached to the 2nd ruleTest or the whole parser. Even if we put x3::omit[ruleTest]
around the second ruleTest
it still cannot compile.
void Test(std::string const& str) {
auto const ruleTest = x3::rule<struct _, std::string>{} =
*(x3::char_ - ' ')[([](auto& ctx){x3::_val(ctx)+='x';})];
x3::parse(boost::begin(str), boost::end(str),
ruleTest[([](auto& ctx){std::cout<<x3::_attr(ctx)<<std::endl;})] >>
' ' >>
ruleTest
);
}
Only when we attach a lambda or an attribute to x3::parse or define ruleTest globally with BOOST_SPIRIT_DEFINE could solve the problem.
void Test(std::string const& str) {
auto const ruleTest = x3::rule<struct _, std::string>{} =
*(x3::char_ - ' ')[([](auto& ctx){x3::_val(ctx)+='x';})];
std::string attr;
x3::parse(boost::begin(str), boost::end(str),
ruleTest[([](auto& ctx){std::cout<<x3::_attr(ctx)<<std::endl;})] >>
' ' >>
ruleTest, attr);
}
The crux of the error appears to be
test.cpp|9 col 59| error: no match for ‘operator+=’ (operand types are ‘boost::spirit::x3::unused_type’ and ‘char’)
This is because the compiler sees the actual type of the bound attribute (none) is x3::unused_type
and therefore the semantic action doesn't compile.
I'm not even sure how you would want it work since you cannot update characters to 'x'
in an attribute that doesn't exist.
Here's a proposed "fix":
struct {
void operator()(std::string& s, char c) const { s += c; }
void operator()(...) const { }
} ll;
auto const ruleTest
= x3::rule<struct _, std::string>{}
= *(x3::char_ - ' ') [([ll](auto& ctx){ ll(x3::_val(ctx), 'x');})]
;
See it Live On Coliru
#include <boost/spirit/home/x3.hpp>
#include <iostream>
void Test(std::string const& str) {
namespace x3 = boost::spirit::x3;
struct {
void operator()(std::string& s, char c) const { s += c; }
void operator()(...) const { }
} ll;
auto const ruleTest
= x3::rule<struct _, std::string>{}
= *(x3::char_ - ' ') [([ll](auto& ctx){ ll(x3::_val(ctx), 'x');})]
;
//std::string attr;
auto f = begin(str), l = end(str);
bool ok = x3::parse(f, l,
ruleTest [([](auto& ctx){std::cout<<x3::_attr(ctx)<<std::endl;})]
>> ' ' >> ruleTest);
if (ok) std::cout << "Parse success\n";
else std::cout << "Parse failed\n";
if (f != l) std::cout << "Remaining unparsed: '" << std::string(f,l) << "'\n";
}
int main() {
Test("abc def");
}