summaryrefslogtreecommitdiffstats
path: root/src/boost/libs/spirit/example/x3/annotation.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/boost/libs/spirit/example/x3/annotation.cpp')
-rw-r--r--src/boost/libs/spirit/example/x3/annotation.cpp246
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;
+}