Re: X3 employee example with semantic actions

Maarten Verhage <[email protected]> Wed, 6 Jun 2018 00:26:47 +0000
Newsgroups gmane.comp.parsers.spirit.general
Message-ID <HE1P192MB0137C3AD0B610031A16B0AF5BA650@HE1P192MB0137.EURP192.PROD.OUTLOOK.COM>
----- Original Message ----- 
From: "Larry Evans" <[email protected]>
To: <[email protected]>
Sent: Wednesday, June 06, 2018 01:58
Subject: Re: [Spirit-general] X3 employee example with semantic actions


> On 06/05/2018 01:38 PM, Maarten Verhage wrote:
> [snip]
>> In the meantime I've learned by fortunate accident that the parser 
>> directive
>> **raw** will provide me the iterator range I'm after. As a general remark 
>> on
>> this. It is nice if you can immediately understand the facilities 
>> provided
>> in a documentation page like the Parser Directives. If you don't little
>> effort is made to properly present the ideas behind these facilities. 
>> Maybe
>> the Spirit developers are annoyed by what they might consider as naive
>> questions about obvious things in this mailing list. While I believe that 
>> if
>> you improve the documentation and explain for with purpose you provide
>> facilities people can much faster understand it, and the amount of 
>> "stupid"
>> questions can be heavily reduced.
>>
> To supply a real life use case for what's described in the above 
> paragraph,  I've looked at the doc for raw as expressed in the xml
> generated from:
>
> https://github.com/boostorg/spirit/tree/develop/doc/x3
>
> That contains:
>
>  raw[a]
>
>    boost::iterator_range<I>
>
>    Presents the transduction of a as an iterator range
>
> From this I infer that an interator_range<I> is produced
> where I is the Iterator to the parsers.
>
> But how do I use this.  Grep'ing for raw shows:
>
> -*- mode: compilation; default-directory: 
> "~/prog_dev/boost/releases/ro/boost_1_67_0/sandbox/lje/spirit-experiments/include/boost/spirit/home/x3/" 
>  -*-
> Compilation started at Tue Jun  5 18:43:54
>
> find . -name \*.hpp -exec grep -e '\<raw\>' {} \; -ls
>     auto const raw = raw_gen{};
>   9109799     12 -rw-rw-r--   1 evansl   evansl       2534 Jan 19 14:59 
> ./directive/raw.hpp
>         // attr==raw_attribute_type, action wants iterator_range (see 
> raw.hpp)
>   9049853     16 -rw-rw-r--   1 evansl   evansl       4718 Jun  4 22:09 
> ./core/action.hpp
> #include <boost/spirit/home/x3/directive/raw.hpp>
>   9109791     12 -rw-rw-r--   1 evansl   evansl       1286 Jan 19 14:59 
> ./directive.hpp
>
> Compilation finished at Tue Jun  5 18:43:54
>
> so, a brief look at that code still didn't clear things up; so,
> Please, Maarten, could you post the code where you make use
> of raw so I wouldn't have to further guess how to do it?
>
> -hopefully,
> Larry

Hi Larry,

I'm not yet familiar with grep. I assume you do look into the Spirit X3 
source code to learn how to use it? I have just added the raw directive into 
the employee example code. And it did want I was after. In the attached 
source code you can see exactly how.

I've some facility to print a type by the name of utility::type2string. This 
is not needed for the example but I can provide that if you are interested.

Regards, Maarten

------------------------------------------------------------------------------
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/plain, 5.9 KB)
/*=============================================================================
    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 <windows.h>
#include <cstddef>
#include <cstdio>
#include <cstdint>
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/x3/support/ast/position_tagged.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/io.hpp>

#include <iostream>
#include <fstream>
#include <string>
#include <complex>
//#include "utility.h"

uintptr_t addr_storage = -1;

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;

            //std::string str =
            //  utility::type2string< decltype( x3::_attr( ctx ) ) >();

            std::string::const_iterator iter = x3::_attr( ctx ).begin();
            std::string::const_iterator end = x3::_attr( ctx ).end();

            printf( "start offset: %x\n", std::addressof( *iter ) - addr_storage );
            printf( "end offset: %x\n", std::addressof( *end ) - addr_storage );

        }
    };

    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";

        // raw provides iterators
        auto const quoted_string = x3::raw[ 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();

    printf( "storage address: %p\n", storage.data() );
    addr_storage = (uintptr_t)storage.data();
    // column header
    printf( "            0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f\n" );
    for ( std::size_t i = 0; i < storage.length(); ++i )
    {
      if ( i%16 == 0 )
      {
        if ( i != 0 ) putchar('\n');
        // row header
        printf( "%8.8xh: ", i );
      }
      printf( "%2.2x ", storage[i] );
    }
    putchar('\n');

    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;
}
1.txt (text/plain, 44 B)
employee {
66,
"Putin",
"Vladimir",
306000
}