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
}