Skip to content

Instantly share code, notes, and snippets.

@cppljevans
Last active June 6, 2018 14:35
Show Gist options
  • Save cppljevans/0f4351f127c2e651d8094877a9510e5a to your computer and use it in GitHub Desktop.
Save cppljevans/0f4351f127c2e651d8094877a9510e5a to your computer and use it in GitHub Desktop.
x3 employees using alternative to position_tagged
/*=============================================================================
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
// [ LJE June 2, 2018]
// Illustrate how to satisfy m_r_verhage@hotmail.com's requirement
// "to get the two iterators of a rule match" as he expressed in
// expressed in posts:
// https://sourceforge.net/p/spirit/mailman/message/36332995/
// https://sourceforge.net/p/spirit/mailman/message/36333543/
// using annotated attributes as in:
// https://github.com/boostorg/spirit/blob/develop/example/x3/annotation.cpp
//
///////////////////////////////////////////////////////////////////////////////
#include <boost/config/warning_disable.hpp>
//#define BOOST_SPIRIT_X3_DEBUG
#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 <string>
namespace client { namespace ast
{
namespace x3 = boost::spirit::x3;
struct employee : x3::position_tagged
{
//#define EMPTY_TAGGED
#ifndef EMPTY_TAGGED
int age;
std::string first_name;
std::string last_name;
double salary;
friend std::ostream& operator<<(std::ostream& sout, employee const& x)
{
sout
<<"{ age="<<x.age<<"\n"
<<", first_name="<<x.first_name<<"\n"
<<", last_name="<<x.last_name<<"\n"
<<", salary="<<x.salary<<"\n"
<<"}\n";
return sout;
}
#endif
};
}}
// We need to tell fusion about our employee struct
// to make it a first-class fusion citizen. This has to
// be in global scope.
#ifndef EMPTY_TAGGED
BOOST_FUSION_ADAPT_STRUCT(client::ast::employee
, age, first_name, last_name, salary
)
#else
BOOST_FUSION_ADAPT_STRUCT(client::ast::employee
)
#endif
namespace client
{
namespace parser
{
namespace x3 = boost::spirit::x3;
namespace ascii = boost::spirit::x3::ascii;
///////////////////////////////////////////////////////////////////////
// Our annotation handler
///////////////////////////////////////////////////////////////////////
// tag used to get the position cache from the context
struct position_cache_tag;
struct annotate_position
{
template <typename T, typename Iterator, typename Context>
inline void on_success(Iterator const& first, Iterator const& last
, T& ast, Context const& context)
{
auto& position_cache = x3::get<position_cache_tag>(context).get();
position_cache.annotate(ast, first, last);
}
};
///////////////////////////////////////////////////////////////////////
// Our annotated rule_id's
///////////////////////////////////////////////////////////////////////
struct employee_class : annotate_position {};
///////////////////////////////////////////////////////////////////////
// Our employee parser
///////////////////////////////////////////////////////////////////////
using x3::int_;
using x3::double_;
using x3::lexeme;
using ascii::char_;
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<employee_class, ast::employee> const employee = "employee";
auto const quoted_string = lexeme['"' >> +(char_ - '"') >> '"'];
auto const employee_def = employee
= '{' >> int_
>> ',' >> quoted_string
>> ',' >> quoted_string
>> ',' >> double_
>> '}'
;
auto const employees = employee_def >> *(',' >> employee_def);
}
}
// Sample input:
std::string input = R"(
{
23,
"Amanda",
"Stefanski",
1000.99
},
{
35,
"Angie",
"Chilcote",
2000.99
},
{
43,
"Dannie",
"Dillinger",
3000.99
},
{
22,
"Dorene",
"Dole",
2500.99
},
{
38,
"Rossana",
"Rafferty",
5000.99
}
)";
////////////////////////////////////////////////////////////////////////////
// Main program
////////////////////////////////////////////////////////////////////////////
int
main()
{
std::cout << "/////////////////////////////////////////////////////////\n\n";
std::cout << "\t\tAn employee parser for Spirit...\n\n";
std::cout << "/////////////////////////////////////////////////////////\n\n";
using boost::spirit::x3::ascii::space;
using iterator_type = std::string::const_iterator;
using position_cache = boost::spirit::x3::position_cache<std::vector<iterator_type>>;
using client::parser::employees;
iterator_type iter = input.begin();
iterator_type const end = input.end();
std::vector<client::ast::employee> emps;
using boost::spirit::x3::with;
// Our parser
using client::parser::employees;
using client::parser::position_cache_tag;
position_cache positions{iter, end};
auto const parser =
// we pass our position_cache to the parser so we can access
// it later in our on_sucess handlers
with<position_cache_tag>(std::ref(positions))
[
employees
];
bool r = phrase_parse(iter, end, parser, space, emps);
if (r && iter == end)
{
std::cout << "-------------------------\n";
std::cout << "Parsing succeeded\n";
std::cout << "got:\n";
for(auto emp:emps)
{
#ifndef EMPTY_TAGGED
std::cout << "***struct output***\n";
std::cout<<emp;
#endif
auto pos = positions.position_of(emp);
std::cout << "***string output***\n";
std::cout << std::string(pos.begin(), pos.end()) << std::endl;
std::cout << "-------------------------\n";
}
std::cout << ".\n";
std::cout << "\n-------------------------\n";
}
else
{
std::cout << "-------------------------\n";
std::cout << "Parsing failed\n";
std::cout << "-------------------------\n";
}
return 0;
}
/*=============================================================================
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
// [ LJE June 2, 2018]
// Illustrate how to satisfy m_r_verhage@hotmail.com's requirement
// "to get the two iterators of a rule match" as he expressed in
// posts:
// https://sourceforge.net/p/spirit/mailman/message/36332995/
// https://sourceforge.net/p/spirit/mailman/message/36333543/
//
///////////////////////////////////////////////////////////////////////////////
#include <boost/config/warning_disable.hpp>
//#define BOOST_SPIRIT_X3_DEBUG
#include <boost/spirit/home/x3.hpp>
#include <iostream>
#include <string>
namespace client
{
///////////////////////////////////////////////////////////////////////////////
// Our employee parser
///////////////////////////////////////////////////////////////////////////////
namespace parser
{
using iterator_type=std::string::const_iterator;
}
}
namespace client { namespace ast
{
///////////////////////////////////////////////////////////////////////////
// Our employee struct
///////////////////////////////////////////////////////////////////////////
struct employee
{
client::parser::iterator_type beg;
client::parser::iterator_type end;
friend std::ostream& operator<<(std::ostream& sout, employee const& x)
{
return sout << std::string(x.beg,x.end);
}
};
}}
namespace client
{
///////////////////////////////////////////////////////////////////////////////
// Our employee parser
///////////////////////////////////////////////////////////////////////////////
namespace parser
{
namespace x3 = boost::spirit::x3;
namespace ascii = boost::spirit::x3::ascii;
using x3::int_;
using x3::lit;
using x3::double_;
using x3::eps;
using x3::lexeme;
using ascii::char_;
using x3::_val;
using x3::_where;
auto employee_act_beg = [](auto& ctx)
{
auto iter=_where(ctx).begin();
_val(ctx).beg=iter;
};
auto employee_act_end = [](auto& ctx)
{
auto iter=_where(ctx).begin();
_val(ctx).end=iter;
std::cout<<"employee_act_end:iter_beg..iter_end=\n";
std::cout<<_val(ctx);
std::cout<<".\n";
};
x3::rule<class employee, ast::employee> const employee = "employee";
auto const quoted_string = lexeme['"' >> +(char_ - '"') >> '"'];
auto const employee_def = employee
= eps[employee_act_beg]
>> '{' >> int_
>> ',' >> quoted_string
>> ',' >> quoted_string
>> ',' >> double_
>> '}'
>> eps[employee_act_end]
;
auto const employees = employee_def >> *(',' >> employee_def);
}
}
// Sample input:
std::string input = R"(
{
23,
"Amanda",
"Stefanski",
1000.99
},
{
35,
"Angie",
"Chilcote",
2000.99
},
{
43,
"Dannie",
"Dillinger",
3000.99
},
{
22,
"Dorene",
"Dole",
2500.99
},
{
38,
"Rossana",
"Rafferty",
5000.99
}
)";
////////////////////////////////////////////////////////////////////////////
// Main program
////////////////////////////////////////////////////////////////////////////
int
main()
{
std::cout << "/////////////////////////////////////////////////////////\n\n";
std::cout << "\t\tAn employee parser for Spirit...\n\n";
std::cout << "/////////////////////////////////////////////////////////\n\n";
using boost::spirit::x3::ascii::space;
using client::parser::iterator_type;
using client::parser::employees;
iterator_type iter = input.begin();
iterator_type const end = input.end();
std::vector<client::ast::employee> emps;
bool r = phrase_parse(iter, end, employees, space, emps);
if (r && iter == end)
{
std::cout << "-------------------------\n";
std::cout << "Parsing succeeded\n";
std::cout << "got:\n";
for(auto emp:emps)
{
std::cout << emp << ";\n";
}
std::cout << ".\n";
std::cout << "\n-------------------------\n";
}
else
{
std::cout << "-------------------------\n";
std::cout << "Parsing failed\n";
std::cout << "-------------------------\n";
}
return 0;
}
/*=============================================================================
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
// [ LJE June 2, 2018]
// Illustrate how to satisfy m_r_verhage@hotmail.com's requirement
// "to get the two iterators of a rule match" as he expressed in
// using raw directive.
//
///////////////////////////////////////////////////////////////////////////////
#include <boost/config/warning_disable.hpp>
//#define BOOST_SPIRIT_X3_DEBUG
#include <boost/spirit/home/x3.hpp>
#include <iostream>
#include <string>
namespace client { namespace ast
{
///////////////////////////////////////////////////////////////////////////
// Our employee attribute
// (== raw directive attribute, converted to std::string)
///////////////////////////////////////////////////////////////////////////
using employee=std::string;
}}
namespace client
{
///////////////////////////////////////////////////////////////////////////////
// Our employee parser
///////////////////////////////////////////////////////////////////////////////
namespace parser
{
namespace x3 = boost::spirit::x3;
using x3::int_;
using x3::double_;
using x3::lexeme;
using x3::ascii::char_;
x3::rule<class employee, ast::employee> const employee = "employee";
auto const quoted_string = lexeme['"' >> +(char_ - '"') >> '"'];
auto const employee_def = employee = x3::raw
[ '{' >> int_
>> ',' >> quoted_string
>> ',' >> quoted_string
>> ',' >> double_
>> '}'
]
;
auto const employees = employee_def >> *(',' >> employee_def);
}
}
// Sample input:
std::string input = R"(
{
23,
"Amanda",
"Stefanski",
1000.99
},
{
35,
"Angie",
"Chilcote",
2000.99
},
{
43,
"Dannie",
"Dillinger",
3000.99
},
{
22,
"Dorene",
"Dole",
2500.99
},
{
38,
"Rossana",
"Rafferty",
5000.99
}
)";
////////////////////////////////////////////////////////////////////////////
// Main program
////////////////////////////////////////////////////////////////////////////
int
main()
{
std::cout << "/////////////////////////////////////////////////////////\n\n";
std::cout << "\t\tAn employee parser for Spirit...\n\n";
std::cout << "/////////////////////////////////////////////////////////\n\n";
using boost::spirit::x3::ascii::space;
using iterator_type=std::string::const_iterator;
using client::parser::employees;
iterator_type iter = input.begin();
iterator_type const end = input.end();
std::vector<client::ast::employee> emps;
bool r = phrase_parse(iter, end, employees, space, emps);
if (r && iter == end)
{
std::cout << "-------------------------\n";
std::cout << "Parsing succeeded\n";
std::cout << "got:\n";
for(auto emp:emps)
{
//std::cout << std::string(emp.begin(),emp.end()) << ";\n";
std::cout << emp << ";\n";
}
std::cout << ".\n";
std::cout << "\n-------------------------\n";
}
else
{
std::cout << "-------------------------\n";
std::cout << "Parsing failed\n";
std::cout << "-------------------------\n";
}
return 0;
}
/////////////////////////////////////////////////////////
An employee parser for Spirit...
/////////////////////////////////////////////////////////
-------------------------
Parsing succeeded
got:
{
23,
"Amanda",
"Stefanski",
1000.99
};
{
35,
"Angie",
"Chilcote",
2000.99
};
{
43,
"Dannie",
"Dillinger",
3000.99
};
{
22,
"Dorene",
"Dole",
2500.99
};
{
38,
"Rossana",
"Rafferty",
5000.99
};
.
-------------------------
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment