Re: x3 semantic action and attribute transformation
Olaf Peter <[email protected]>
| Newsgroups | gmane.comp.parsers.spirit.general |
|---|---|
| Message-ID | <[email protected]> |
Hello Seth,
thank you much!
> On 08-03-17 10:35, Olaf Peter wrote:
>> auto combine_to_uint = [](auto &ctx) {
>> auto const &v = x3::_val(ctx);
>> std::ostringstream ss;
>> std::copy(v.begin(), v.end(), std::ostream_iterator<int>(ss, ""));
>> uint int_ { 0 };
>> x3::_pass(ctx) = x3::parse(ss.str().begin(), ss.str().end(),
>> x3::uint_, int_);
>> std::cout << int_ << '\n';
>> x3::_attr(ctx) = int_;
>> };
>
> Here it seems you mainly confused `_attr` and `_val`. Avoid confusing
> names like `int_`.
maybe it was left from prior test; _attr is the attribute from rule and
_val from lexeme which calls the semantic action, isn't it?
> Here's your own sample "fixed" (I still think it's too complicated):
> http://coliru.stacked-crooked.com/a/a6e053b5f552f766
thank you for this approach, I did try to solve the overflow problem and
come to this solution attached (for some reason, stacked-crooked doesn't
share my code), which works so far but looks quite complicated.
Also, I changed the rule to be more restrict, but this requires changes
in the 'combine' lambda function. These are required to cover the last 4
test cases which aren't valid ints.
Thanks,
Olaf
---8<---
#include <iosfwd>
//#define BOOST_SPIRIT_X3_DEBUG
#include <boost/spirit/home/x3.hpp>
#include <iostream>
namespace parser {
namespace x3 = boost::spirit::x3;
using x3::char_;
typedef x3::rule<struct integer_class, uint32_t> integer_type;
integer_type const integer { "integer" };
constexpr uint32_t digit_treshold(auto i) {
return std::numeric_limits<decltype(i)>::max() % 10;
}
auto const combine = [](auto &ctx) {
//typedef decltype(x3::_attr(ctx)) base_type; // =>> templated?
typedef uint32_t base_type;
base_type result { 0 };
uint32_t iter_cnt { 0 };
for (auto&& ch : x3::_attr(ctx)) {
switch (ch) {
case '_': break;
default:
if(iter_cnt > std::numeric_limits<base_type>::digits10) {
x3::_pass(ctx) = false;
continue;
}
if(iter_cnt++ <
std::numeric_limits<base_type>::digits10) {
result = result*10 + (ch - '0');
}
else {
#if 0
switch(ch - '0') {
case 0: // [[fallthrough]]
case 1: // [[fallthrough]]
case 2: // [[fallthrough]]
case 3: // [[fallthrough]]
case 4: // [[fallthrough]]
case 5:
result = result*10 + (ch - '0');
break;
default:
x3::_pass(ctx) = false;
}
#else
if((unsigned)(ch - '0') > digit_treshold(result)) {
x3::_pass(ctx) = false;
}
else {
result = result*10 + (ch - '0');
}
#endif
}
}
}
x3::_val(ctx) = result;
};
// Parse '1_000' as 1000
auto const integer_def =
//x3::lexeme [ char_("0-9") >> *(char_("0-9_")) ] [combine] /*
_val(ctx) => uint */
x3::lexeme [ +char_("0-9_") ] [combine]
;
BOOST_SPIRIT_DEFINE(integer)
}
int main()
{
namespace x3 = boost::spirit::x3;
std::vector<std::string> const test_cases {
"0",
"1",
"01",
"1_000",
"42_666_4711",
"4_294_967_295", // uint32::max
// below must fail to parse
"4_294_967_296",
"4_294_967_295_0",
"4_294_967_295_00",
"_42", "42_",
" 4 2 ", "4 _2"
};
typedef std::string::const_iterator iterator_type;
for(auto str: test_cases) {
iterator_type iter = str.begin();
iterator_type const end = str.end();
auto& rule = parser::integer;
std::cout << "parse `" << str << "´:\n";
uint32_t i;
bool r = x3::phrase_parse(iter, end, rule, x3::space, i);
if (r && iter == end) {
std::cout << "succeeded: \"" << str << "\" -> " << i << "\n";
} else {
std::cout << "failed\n";
}
}
return 0;
}
--->8---
------------------------------------------------------------------------------
Announcing the Oxford Dictionaries API! The API offers world-renowned
dictionary content that is easy and intuitive to access. Sign up for an
account today to start using our lexical data to power your apps and
projects. Get started today and enter our developer competition.
http://sdm.link/oxford