Is it possible to create a rule in Spirit X3 that parses a single character and generates a string?
I'd like to use this in the context of a parser for version numbers, where each numeric identifier can be either a single digit, or a non-zero digit followed by one or more digits:
auto const positive_digit = char_(L"123456789");
auto const digit = char_(L"0123456789");
auto const digits = x3::rule<class digits, std::wstring>{"digits"} = +digit;
auto const numeric_identifier = (positive_digit >> digits) | digit;
The problem I see is that the type numeric_identifier
synthesizes is not compatible with a string (see full example here).
To solve this, I would need to create a rule that matches a digit and synthesizes a string. The only solution that I can think of is to use semantic actions, but this causes errors when the rule is used in a situation where backtracking is necessary (see full example here).
It's not completely clear to me what you're trying to do. If the goal is to valid the format of a string but parse match the input string exactly, why not use x3::raw
?
E.g.
auto num_id = x3::uint_;
auto version = x3::raw[num_id % '.'];
Now you can directly parse typical version strings into a string:
int main() {
for (sv input : {"0", "1", "1.4", "1.6.77.0.1234",}) {
std::string parsed;
std::cout << "Parsing " << std::quoted(input);
auto f = begin(input), l = end(input);
if (parse(f, l, version, parsed)) {
std::cout << " -> " << std::quoted(parsed) << "\n";
} else {
std::cout << " -- FAILED\n";
}
if (f != l) {
std::cout << "Remaining unparsed: " << std::quoted(sv{f, l}) << "\n";
}
}
}
Prints
Parsing "0" -> "0"
Parsing "1" -> "1"
Parsing "1.4" -> "1.4"
Parsing "1.6.77.0.1234" -> "1.6.77.0.1234"
To add the restriction that id numbers not begin with 0
unless they're literally zero
:
auto num_id = x3::char_('0') | x3::uint_;
Of course you can be less clever or more blunt:
auto num_id
= !x3::lit('0') >> x3::uint_
| x3::uint_parser<unsigned, 10, 1, 1>{};
The effect would be equivalent. I like the first one a bit better.