Re: x3 beginner semantic actions

Henri Menke <[email protected]> Wed, 25 Apr 2018 11:09:06 +1200
Newsgroups gmane.comp.parsers.spirit.general
Message-ID <[email protected]>
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.

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.6 KB)
#define BOOST_SPIRIT_X3_DEBUG

#include <fstream>
#include <iostream>
#include <map>
#include <string>
#include <vector>

#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/home/x3.hpp>

namespace x3 = boost::spirit::x3;

struct tosses {
	int heads;
	int tails;
};

BOOST_FUSION_ADAPT_STRUCT(tosses, heads, tails)

int main()
{
	std::string buf("++--+-++++-");
	auto iter = buf.begin(), end = buf.end();
	auto peek = [&](auto& ctx){
		std::cout << "peek["
		          << boost::spirit::x3::_attr(ctx)
		          << ']' << std::endl;
		};
	auto zerotosses = [&](auto& ctx){
		boost::spirit::x3::_val(ctx) = {0,0};
		};
	auto addhead = [&](auto& ctx){
		boost::spirit::x3::_val(ctx).heads++;
		};
	auto addtail = [&](auto& ctx){
		boost::spirit::x3::_val(ctx).tails++;
		};
	auto parser = [&]{
		using namespace boost::spirit::x3;

		auto const head
			= lit('+') [addhead]
			;
		auto const tail
			= lit('-') [addtail]
			;
		auto const toss
			= head | tail
			;
		auto const tosses
			= eps [zerotosses]
			>> (+toss)
			;

		return rule<struct _, struct tosses> {"parser"} = skip(space) [ tosses ];
	};

	tosses res;
	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;
}