Re: x3 beginner semantic actions
Henri Menke <[email protected]> Wed, 25 Apr 2018 11:20:48 +1200
| Newsgroups | gmane.comp.parsers.spirit.general |
|---|---|
| Message-ID | <[email protected]> |
On Wed, 2018-04-25 at 11:09 +1200, Henri Menke wrote:
> On Tue, 2018-04-24 at 15:48 +0100, Patrick Welche wrote:
> >
> > In a bid to understand semantic actions a bit better, I thought I would
> > try to write an x3 program to count the number of + and - (think heads
> > and tails) in a sequence. The aim was to see:
> >
> > 1) how to deal with matching on a char, but wanting to use an int as
> > attribute,
> > i.e., not the expected type of attribute.
> > 2) how to select which int buried inside a struct to use
> > 3) how to initialise said int
> >
> > 1) might be doable with e.g.
> >
> > auto const head
> > = rule<class _, int, true>
> > = lit('+') // [addhead]
> > ;
> >
> > 2) given that toss is int or int, it is just an int, so presumably
> > tosses.heads always gets sent to head or tail?
> >
> > 3) I don't see how to not overwrite the result with the initialisation
> >
> > Presumably this is just the wrong way of looking at it. (I don't want to
> > "cheat" and have external variables which the lambda change directly -
> > or is that the only way?)
> - Use eps [zerotosses] to initialize the attribute to zero. I use aggregate
> initialization because this is C++14.
>
> auto zerotosses = [&](auto& ctx){
> boost::spirit::x3::_val(ctx) = {0,0};
> };
>
> - addhead and addtail should increment the heads and tails members.
>
> auto addhead = [&](auto& ctx){
> boost::spirit::x3::_val(ctx).heads++;
> };
> auto addtail = [&](auto& ctx){
> boost::spirit::x3::_val(ctx).tails++;
> };
>
> You shouldn't use semantic actions for this at all but I guess you know that.
> Use x3::symbols instead.
Attached you can find how I'd do it with x3::symbols. I still need one semantic
action for adding the attribute to the value. Maybe one could even get rid of
that but I don't know how. I'm not a Spirit expert either.
Cheers, Henri
>
> Cheers, Henri
>
> >
> >
> >
> > Cheers,
> >
> > Patrick
> > ----------------------------------------------------------------------------
> > --
> > Check out the vibrant tech community on one of the world's most
> > engaging tech sites, Slashdot.org! http://sdm.link/slashdot
> > _______________________________________________
> > Spirit-general mailing list
> > [email protected]
> > https://lists.sourceforge.net/lists/listinfo/spirit-general
------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
Spirit-general mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/spirit-general
coin.cpp
(text/x-c++src, 1.4 KB)
#define BOOST_SPIRIT_X3_DEBUG
#include <iostream>
#include <string>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/home/x3.hpp>
namespace x3 = boost::spirit::x3;
struct tosses {
int heads;
int tails;
tosses& operator+=(tosses const &other) {
heads += other.heads;
tails += other.tails;
return *this;
}
};
struct head_or_tail_ : x3::symbols<tosses> {
head_or_tail_() {
add
("+", tosses{1,0})
("-", tosses{0,1})
;
}
} head_or_tail;
int main()
{
std::string buf("++--+-++++-");
auto iter = buf.begin(), end = buf.end();
auto const parser = [] {
using namespace boost::spirit::x3;
auto const add = [](auto &ctx) { _val(ctx) += _attr(ctx); };
auto const toss
= x3::rule<class toss, tosses>{"tosses"}
= +head_or_tail [add];
return toss;
};
tosses res{0,0};
boost::spirit::x3::ascii::space_type space;
bool ok = boost::spirit::x3::phrase_parse(iter, end, parser(), space, res);
if (ok) {
std::cout << "Parse success\n";
}
else {
std::cout << "Parsing failed\n";
}
if (iter != end) {
std::cout << "Bit left over at the end: " << std::string(iter, end) << std::endl;
}
else {
std::cout << "heads: " << res.heads << std::endl
<< "tails: " << res.tails << std::endl;
}
return 0;
}