diff options
Diffstat (limited to 'src/boost/libs/spirit/example/x3/annotation.cpp')
-rw-r--r-- | src/boost/libs/spirit/example/x3/annotation.cpp | 246 |
1 files changed, 246 insertions, 0 deletions
diff --git a/src/boost/libs/spirit/example/x3/annotation.cpp b/src/boost/libs/spirit/example/x3/annotation.cpp new file mode 100644 index 00000000..12dacfbb --- /dev/null +++ b/src/boost/libs/spirit/example/x3/annotation.cpp @@ -0,0 +1,246 @@ +/*============================================================================= + Copyright (c) 2002-2018 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) +=============================================================================*/ +/////////////////////////////////////////////////////////////////////////////// +// +// Based on the employee parser (see employee.cpp), this example shows how +// to annotate the AST with the iterator positions for access to the source +// code when post processing. This example also shows how to "inject" client +// data, using the "with" directive, that the handlers can access. +// +// [ JDG May 9, 2007 ] +// [ JDG May 13, 2015 ] spirit X3 +// [ JDG Feb 22, 2018 ] Parser annotations for spirit X3 +// +// I would like to thank Rainbowverse, llc (https://primeorbial.com/) +// for sponsoring this work and donating it to the community. +// +/////////////////////////////////////////////////////////////////////////////// + +#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 <string> + +namespace client { namespace ast +{ + /////////////////////////////////////////////////////////////////////////// + // Our AST (employee and person structs) + /////////////////////////////////////////////////////////////////////////// + namespace x3 = boost::spirit::x3; + + struct person : x3::position_tagged + { + person( + std::string const& first_name = "" + , std::string const& last_name = "" + ) + : first_name(first_name) + , last_name(last_name) + {} + + std::string first_name, last_name; + }; + + struct employee : x3::position_tagged + { + int age; + person who; + 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::person, + first_name, last_name +) + +BOOST_FUSION_ADAPT_STRUCT(client::ast::employee, + age, who, salary +) + +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 employee parser + /////////////////////////////////////////////////////////////////////// + + using x3::int_; + using x3::double_; + using x3::lexeme; + using ascii::char_; + + struct quoted_string_class; + struct person_class; + struct employee_class; + + x3::rule<quoted_string_class, std::string> const quoted_string = "quoted_string"; + x3::rule<person_class, ast::person> const person = "person"; + x3::rule<employee_class, ast::employee> const employee = "employee"; + + auto const quoted_string_def = lexeme['"' >> +(char_ - '"') >> '"']; + auto const person_def = quoted_string >> ',' >> quoted_string; + + auto const employee_def = + '{' + >> int_ >> ',' + >> person >> ',' + >> double_ + >> '}' + ; + + auto const employees = employee >> *(',' >> employee); + + BOOST_SPIRIT_DEFINE(quoted_string, person, employee); + + struct quoted_string_class {}; + struct person_class : annotate_position {}; + struct employee_class : annotate_position {}; + } +} + +/////////////////////////////////////////////////////////////////////////////// +// Main program +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// Our main parse entry point +/////////////////////////////////////////////////////////////////////////////// + +using iterator_type = std::string::const_iterator; +using position_cache = boost::spirit::x3::position_cache<std::vector<iterator_type>>; + +std::vector<client::ast::employee> +parse(std::string const& input, position_cache& positions) +{ + using boost::spirit::x3::ascii::space; + + std::vector<client::ast::employee> ast; + iterator_type iter = input.begin(); + iterator_type const end = input.end(); + + using boost::spirit::x3::with; + + // Our parser + using client::parser::employees; + using client::parser::position_cache_tag; + + 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, ast); + + 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"; + + for (auto const& emp : ast) + { + std::cout << "got: " << emp << std::endl; + } + std::cout << "\n-------------------------\n"; + + } + else + { + std::cout << "-------------------------\n"; + std::cout << "Parsing failed\n"; + std::cout << "-------------------------\n"; + ast.clear(); + } + return ast; +} + +// 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 +} +)"; + +int +main() +{ + position_cache positions{input.begin(), input.end()}; + auto ast = parse(input, positions); + + // Get the source of the 2nd employee and print it + auto pos = positions.position_of(ast[1]); // zero based of course! + std::cout << "Here's the 2nd employee:" << std::endl; + std::cout << std::string(pos.begin(), pos.end()) << std::endl; + std::cout << "-------------------------\n"; + return 0; +} |