Re: X3 employee example with semantic actions

Larry Evans <[email protected]> Fri, 1 Jun 2018 22:19:30 -0500
Newsgroups gmane.comp.parsers.spirit.general
Message-ID <[email protected]>
On 06/01/2018 05:54 PM, Larry Evans wrote:
> On 06/01/2018 05:09 PM, Larry Evans wrote:
[snip]
>> OOPS :(
>> I failed to notice the printout of the attribute after parse
>> did not reflect the input to the parse.
>>
>> I'm now trying to figure out why that's so.
>>
>> I guess that was your main concern.
>> [snip]
> 
> Specifying the rule default attribute, force_attribute=true, changed the 
> output so that it reflected the input for me.  IOW:
> 
>          x3::rule<employee_id, ast::employee, true> const
>         employee = "employee";
> 
> See if that doesn't get you better results.
> 

Although making force_attribute=true gets correct result, I don't
understand why.  In addition, when the semantic actions are removed,
then it works when force_attribute=false.

That seems very counter-intuitive.  Is it a bug?

Attached is a revised test.cpp with 2 macros:

   USE_ACTIONS
   FORCE_ATTRIBUTE

to switch on and off the 2 changes.  See if you get same results.

-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.9 KB)
//The following code was slightly modified from an attachment 
//to a post to the spirit-general mailing list.  
//That 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
//
///////////////////////////////////////////////////////////////////////////////

#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>

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
    ///////////////////////////////////////////////////////////////////////////////

    namespace x3 = boost::spirit::x3;

    struct print_string
    {
        static int calls;
        template <typename Context>
        void operator()(Context const& ctx) const
        {
            std::cout<<"call "<<calls<<"\n";
            ++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';

        }
    };
    
    int print_string::calls=1;

    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
        #define FORCE_ATTRIBUTE 0
        #if FORCE_ATTRIBUTE
          //This works
          , true
        #else
          //This doesn't work, i.e. attribute
          //passed to phrase_parse below is
          //not changed by phrase_parse.
        #endif
          > const 
        employee = "employee";

      #define USE_ACTIONS 0
        auto const quoted_string = lexeme['"' >> +(char_ - '"') >> '"']
      #if USE_ACTIONS  
          [client::print_string()]
      #endif
          ;

        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.
    std::copy(
        std::istream_iterator<char>(in),
        std::istream_iterator<char>(),
        std::back_inserter(storage) );
        
    std::cout<<"USE_ACTIONS="<<USE_ACTIONS<<"\n";
    std::cout<<"FORCE_ATTRIBUTE="<<FORCE_ATTRIBUTE<<"\n";
    std::cout<<"input=[\n"<<storage<<"\n]\n";

    using boost::spirit::x3::ascii::space;
    typedef std::string::const_iterator iterator_type;
    using client::parser::employee;
    
    client::ast::employee emp;
    iterator_type iter = storage.begin();
    iterator_type const end = storage.end();
    bool r = phrase_parse(iter, end, employee, space, emp);

    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: " << emp << std::endl;
        std::cout << "\n-------------------------\n";
    }
    else
    {
        std::cout << "-------------------------\n";
        std::cout << "Parsing failed\n";
        std::cout << "-------------------------\n";
    }

    return 0;
}