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