Re: X3 employee example with semantic actions

Larry Evans <[email protected]> Fri, 1 Jun 2018 13:31:31 -0500
Newsgroups gmane.comp.parsers.spirit.general
Message-ID <[email protected]>
On 06/01/2018 11:21 AM, Maarten Verhage wrote:
[snip]
 > Hi Larry and the other list members,
 >
[snip]

 > Ok, meanwhile I tried this myself. Right now I've instantiated emp in the
 > client namespace like this. And called the 4 argument version of
 > phrase_parse. See attachment.

Attaching a real example such as you've done in this post
is good.  It makes concrete what you are asking.

 >
 > namespace client
 > {
 >      //////////////////////////
 >      //  Our employee parser
 >      //////////////////////////
 >      client::ast::employee emp;

 > And in the semantic actions I now have access to emp. Is this a 
proper way
 > to do so?

It only has access to the current attribute, which is only a
part of emp.

 >
 > I'm also experimenting with the _where iterator range attribute of 
Context.
 > But I've a problem with this. Maybe I did something wrong but what I 
get is
 > an iterator range from the end of the match to the end of input stream
 > (std::string storage). The program output is my attachment result.txt. Is
 > this intended behavior, a bug or did I something wrong?

It looks like the intended behaviour to me.  The iterator
begin and end are to the **remaining** input.  The attribute
for the just parsed input is accessed with _attr as shown in
the attached modification to the code you posted.

The windows #include has been deleted, and printf of the
iterators has been removed since it failed to compile.
Also, the current attribute has been printed out.

HTH.

-regards,
Larry

------------------------------------------------------------------------------
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
test.cpp (text/x-c++src, 5.5 KB)
//The following code was attached to a post to
//the spirit-general mailing list.  The post's headers were:
/*
From: Maarten Verhage <[email protected]>
Newsgroups: gmane.comp.parsers.spirit.general
Subject: Re: X3 employee example with semantic actions
Date: Fri, 1 Jun 2018 16:21:27 +0000
Lines: 231
Approved: [email protected]
Message-ID: <AM5P192MB0131C2581427AF09905BE421BA620@AM5P192MB0131.EURP192.PROD.OUTLOOK.COM>
 */
//====================== 
/*=============================================================================
    Copyright (c) 2002-2015 Joel de Guzman

    Distributed under the Boost Software License, Version 1.0. (See accompanying
    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
=============================================================================*/
///////////////////////////////////////////////////////////////////////////////
//
//  A parser for arbitrary tuples. This example presents a parser
//  for an employee structure.
//
//  [ JDG May 9, 2007 ]
//  [ JDG May 13, 2015 ]    spirit X3
//
///////////////////////////////////////////////////////////////////////////////

#define STRICT 1
#include <cstddef>
#include <cstdio>
#include <cstdint>
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/io.hpp>

#include <iostream>
#include <fstream>
#include <string>
#include <complex>

namespace client { namespace ast
{
    ///////////////////////////////////////////////////////////////////////////
    //  Our employee struct
    ///////////////////////////////////////////////////////////////////////////
    struct employee
    {
        int age;
        std::string surname;
        std::string forename;
        double salary;
    };

    using boost::fusion::operator<<;
}}

// We need to tell fusion about our employee struct
// to make it a first-class fusion citizen. This has to
// be in global scope.

BOOST_FUSION_ADAPT_STRUCT(client::ast::employee,
    age, surname, forename, salary
)

namespace client
{
    ///////////////////////////////////////////////////////////////////////////////
    //  Our employee parser
    ///////////////////////////////////////////////////////////////////////////////
    client::ast::employee emp;

    namespace x3 = boost::spirit::x3;

    struct print_string
    {
        template <typename Context>
        void operator()(Context const& ctx) const
        {
            static int calls = 1;
            printf( "call %d\n", calls );
            ++calls;

            auto attr =boost::spirit::x3::_attr(ctx);
            std::cout<<"attr="<<attr<<'\n';
            auto input=x3::_where( ctx );
            auto iter =input.begin();
            auto end  =input.end();

            for ( ; iter != end; ++iter )
            {
              std::cout << *iter;
            }
            std::cout<<'\n';

        }
    };

    namespace parser
    {
        namespace x3 = boost::spirit::x3;
        namespace ascii = boost::spirit::x3::ascii;

        using x3::int_;
        using x3::lit;
        using x3::double_;
        using x3::lexeme;
        using ascii::char_;

        x3::rule<class employee, ast::employee> const employee = "employee";

        auto const quoted_string = lexeme['"' >> +(char_ - '"') >> '"']
          [client::print_string()];

        auto const employee_def =
            lit("employee")
            >> '{'
            >>  int_ >> ','
            >>  quoted_string >> ','
            >>  quoted_string >> ','
            >>  double_
            >>  '}'
            ;

        BOOST_SPIRIT_DEFINE(employee);
    }
}

////////////////////////////////////////////////////////////////////////////
//  Main program
////////////////////////////////////////////////////////////////////////////
int main( int argc, char **argv )
{
    std::cout << "/////////////////////////////////////////////////////////\n\n";
    std::cout << "\t\tAn employee parser for Spirit...\n\n";
    std::cout << "/////////////////////////////////////////////////////////\n\n";

    char const* filename;
    if (argc > 1)
    {
        filename = argv[1];
    }
    else
    {
        std::cerr << "Error: No input file provided." << std::endl;
        return 1;
    }

    std::ifstream in(filename, std::ios_base::in);

    if (!in)
    {
        std::cerr << "Error: Could not open input file: "
            << filename << std::endl;
        return 1;
    }

    std::string storage; // We will read the contents here.
    in.unsetf( std::ios::skipws ); // No white space skipping!
    std::copy(
        std::istream_iterator<char>(in),
        std::istream_iterator<char>(),
        std::back_inserter(storage) );

    using boost::spirit::x3::ascii::space;
    typedef std::string::const_iterator iterator_type;
    using client::parser::employee;

    iterator_type iter = storage.begin();
    iterator_type const end = storage.end();

    bool r = phrase_parse( iter, end, employee, space );

    if (r && iter == end)
    {
        std::cout << boost::fusion::tuple_open('[');
        std::cout << boost::fusion::tuple_close(']');
        std::cout << boost::fusion::tuple_delimiter(", ");

        std::cout << "-------------------------\n";
        std::cout << "Parsing succeeded\n";
        std::cout << "got: " << client::emp << std::endl;
        std::cout << "\n-------------------------\n";
    }
    else
    {
        std::cout << "-------------------------\n";
        std::cout << "Parsing failed\n";
        std::cout << "-------------------------\n";
    }

    return 0;
}
test.out (text/plain, 316 B)
/////////////////////////////////////////////////////////

		An employee parser for Spirit...

/////////////////////////////////////////////////////////

call 1
attr=Putin
,
"Vladimir",
306000
}

call 2
attr=Vladimir
,
306000
}

-------------------------
Parsing succeeded
got: [0, , , 0]

-------------------------