diff options
Diffstat (limited to 'src/boost/libs/spirit/example/karma')
31 files changed, 5132 insertions, 0 deletions
diff --git a/src/boost/libs/spirit/example/karma/Jamfile b/src/boost/libs/spirit/example/karma/Jamfile new file mode 100644 index 00000000..a93cbb7a --- /dev/null +++ b/src/boost/libs/spirit/example/karma/Jamfile @@ -0,0 +1,38 @@ +#============================================================================== +# Copyright (c) 2001-2009 Hartmut Kaiser +# Copyright (c) 2001-2009 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) +#============================================================================== +project spirit-karma-example + : requirements + <c++-template-depth>300 + : + : + ; + +exe actions_example : actions.cpp ; +exe auto_facilities : auto_facilities.cpp ; +exe basic_facilities : basic_facilities.cpp /boost//date_time ; +exe karma_calc2_ast_dump : calc2_ast_dump.cpp ; +exe karma_calc2_ast_rpn : calc2_ast_rpn.cpp ; +exe karma_calc2_ast_vm : calc2_ast_vm.cpp ; +exe classify_char : classify_char.cpp ; +exe karma_complex_number : complex_number.cpp ; +exe karma_complex_number_easier : complex_number_easier.cpp ; +exe karma_complex_number_adapt : complex_number_adapt.cpp ; +exe karma_num_list1 : num_list1.cpp ; +exe karma_num_list2 : num_list2.cpp ; +exe karma_num_list3 : num_list3.cpp ; +exe karma_num_matrix : num_matrix.cpp ; +exe key_value_sequence : key_value_sequence.cpp ; +exe mini_xml_karma : mini_xml_karma.cpp ; +exe printf_style_double_format : printf_style_double_format.cpp ; +exe quick_start1 : quick_start1.cpp ; +exe karma_reference : reference.cpp ; +exe karma_reorder_struct : reorder_struct.cpp ; +exe karma_escaped_string : escaped_string.cpp ; +exe simple_columns_directive : simple_columns_directive.cpp ; +exe quoted_strings : quoted_strings.cpp ; + diff --git a/src/boost/libs/spirit/example/karma/actions.cpp b/src/boost/libs/spirit/example/karma/actions.cpp new file mode 100644 index 00000000..d5b5efe2 --- /dev/null +++ b/src/boost/libs/spirit/example/karma/actions.cpp @@ -0,0 +1,131 @@ +/*============================================================================= + Copyright (c) 2001-2010 Hartmut Kaiser + Copyright (c) 2001-2010 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) +=============================================================================*/ + +#include <boost/config/warning_disable.hpp> +#include <boost/spirit/include/karma.hpp> +#include <boost/lambda/lambda.hpp> +#include <boost/bind.hpp> + +#include <iostream> +#include <sstream> + +// Presented are various ways to attach semantic actions +// * Using plain function pointer +// * Using simple function object +// * Using boost.bind +// * Using boost.lambda + +using boost::spirit::unused_type; + +//[karma_tutorial_semantic_action_functions +namespace client +{ + namespace karma = boost::spirit::karma; + + // A plain function + void read_function(int& i) + { + i = 42; + } + + // A member function + struct reader + { + void print(int& i) const + { + i = 42; + } + }; + + // A function object + struct read_action + { + void operator()(int& i, unused_type, unused_type) const + { + i = 42; + } + }; +} +//] + +/////////////////////////////////////////////////////////////////////////////// +int main() +{ + using boost::spirit::karma::int_; + using boost::spirit::karma::generate; + using client::read_function; + using client::reader; + using client::read_action; + + { // example using plain functions + using namespace boost::spirit; + + std::string generated; + std::back_insert_iterator<std::string> outiter(generated); + + //[karma_tutorial_attach_actions1 + generate(outiter, '{' << int_[&read_function] << '}'); + //] + + std::cout << "Simple function: " << generated << std::endl; + } + + { // example using simple function object + using namespace boost::spirit; + + std::string generated; + std::back_insert_iterator<std::string> outiter(generated); + + //[karma_tutorial_attach_actions2 + generate(outiter, '{' << int_[read_action()] << '}'); + //] + + std::cout << "Simple function object: " << generated << std::endl; + } + + { // example using plain function with boost.bind + std::string generated; + std::back_insert_iterator<std::string> outiter(generated); + + //[karma_tutorial_attach_actions3 + generate(outiter, '{' << int_[boost::bind(&read_function, _1)] << '}'); + //] + + std::cout << "Simple function with Boost.Bind: " << generated << std::endl; + } + + { // example using member function with boost.bind + std::string generated; + std::back_insert_iterator<std::string> outiter(generated); + + //[karma_tutorial_attach_actions4 + reader r; + generate(outiter, '{' << int_[boost::bind(&reader::print, &r, _1)] << '}'); + //] + + std::cout << "Member function: " << generated << std::endl; + } + + { // example using boost.lambda + namespace lambda = boost::lambda; + using namespace boost::spirit; + + std::string generated; + std::back_insert_iterator<std::string> outiter(generated); + + //[karma_tutorial_attach_actions5 + std::stringstream strm("42"); + generate(outiter, '{' << int_[strm >> lambda::_1] << '}'); + //] + + std::cout << "Boost.Lambda: " << generated << std::endl; + } + + return 0; +} + diff --git a/src/boost/libs/spirit/example/karma/auto_facilities.cpp b/src/boost/libs/spirit/example/karma/auto_facilities.cpp new file mode 100644 index 00000000..b094f40a --- /dev/null +++ b/src/boost/libs/spirit/example/karma/auto_facilities.cpp @@ -0,0 +1,244 @@ +// Copyright (c) 2001-2010 Hartmut Kaiser +// +// 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) + +// The main purpose of this example is to show the uniform and easy way of +// output formatting for different container types. +// +// The 'auto_' primitive used below is very similar to the 'stream' primitive +// demonstrated in the example 'basic_facilities.cpp' as it allows to generate +// output from a multitude of data types. The main difference is that it is +// mapped to the correct Karma generator instead of using any available +// operator<<() for the contained data type. Additionally this means, that +// the format descriptions used below will be usable for any contained type as +// long as this type has a defined mapping to a Karma generator. + +// use a larger value for the alignment field width (default is 10) +#define BOOST_KARMA_DEFAULT_FIELD_LENGTH 25 + +#include <boost/config/warning_disable.hpp> + +#include <iostream> +#include <string> +#include <vector> +#include <list> +#include <map> +#include <algorithm> +#include <cstdlib> + +#include <boost/range.hpp> +#include <boost/array.hpp> +#include <boost/fusion/include/std_pair.hpp> +#include <boost/fusion/include/array.hpp> + +#include <boost/spirit/include/karma.hpp> + +using namespace boost::spirit; +using namespace boost::spirit::ascii; + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { namespace spirit { namespace traits +{ + // We add a specialization for the create_generator customization point + // defining a custom output format for the value type of the std::map used + // below (std::pair<int const, std::string>). Generally, any specialization + // for create_generator is expected to return the proto expression to be + // used to generate output for the type the customization point has been + // specialized for. + // + // We need to utilize proto::deep_copy as the expression contains a literal + // (the ':') which normally gets embedded in the proto expression by + // reference only. The deep copy converts the proto tree to hold this by + // value. The deep copy operation can be left out for simpler proto + // expressions (not containing references to temporaries). Alternatively + // you could use the proto::make_expr() facility to build the required + // proto expression. + template <> + struct create_generator<std::pair<int const, std::string> > + { + typedef proto::result_of::deep_copy< + BOOST_TYPEOF(int_ << ':' << string) + >::type type; + + static type call() + { + return proto::deep_copy(int_ << ':' << string); + } + }; +}}} + +/////////////////////////////////////////////////////////////////////////////// +// Output the given containers in list format +// Note: the format description does not depend on the type of the sequence +// nor does it depend on the type of the elements contained in the +// sequence +/////////////////////////////////////////////////////////////////////////////// +template <typename Container> +void output_container(std::ostream& os, Container const& c) +{ + // output the container as a sequence without separators + os << + karma::format( + auto_, // format description + c // data + ) << std::endl << std::endl; + + os << + karma::format( + *auto_, // format description + c // data + ) << std::endl << std::endl; + + // output the container as a space separated sequence + os << + karma::format_delimited( + auto_, // format description + space, // delimiter + c // data + ) << std::endl << std::endl; + + os << + karma::format_delimited( + *auto_, // format description + space, // delimiter + c // data + ) << std::endl << std::endl; + + os << + karma::format_delimited( + '[' << *auto_ << ']', // format description + space, // delimiter + c // data + ) << std::endl << std::endl; + + // output the container as a comma separated list + os << + karma::format( + auto_ % ", ", // format description + c // data + ) << std::endl << std::endl; + + os << + karma::format( + '[' << (auto_ % ", ") << ']', // format description + c // data + ) << std::endl << std::endl; + + os << + karma::format( + '[' << -(auto_ % ", ") << ']', // format description + c // data + ) << std::endl << std::endl; + + os << + karma::format( + '[' << (+auto_ | "empty") << ']', // format description + c // data + ) << std::endl << std::endl; + + // output the container as a comma separated list of items enclosed in '()' + os << + karma::format( + ('(' << auto_ << ')') % ", ", // format description + c // data + ) << std::endl << std::endl; + + os << + karma::format( + '[' << ( + ('(' << auto_ << ')') % ", " + ) << ']', // format description + c // data + ) << std::endl << std::endl; + + // output the container as a HTML list + os << + karma::format_delimited( + "<ol>" << + *verbatim["<li>" << auto_ << "</li>"] + << "</ol>", // format description + '\n', // delimiter + c // data + ) << std::endl; + + // output the container as right aligned column + os << + karma::format_delimited( + *verbatim[ + "|" << right_align[auto_] << "|" + ], // format description + '\n', // delimiter + c // data + ) << std::endl; + + os << std::endl; +} + +int main() +{ + /////////////////////////////////////////////////////////////////////////// + // C-style array + int i[4] = { 3, 6, 9, 12 }; + + std::cout << "-------------------------------------------------------------" + << std::endl; + std::cout << "int i[]" << std::endl; + output_container(std::cout, boost::make_iterator_range(i, i+4)); + + /////////////////////////////////////////////////////////////////////////// + // vector + std::vector<int> v (5); + std::generate(v.begin(), v.end(), std::rand); // randomly fill the vector + + std::cout << "-------------------------------------------------------------" + << std::endl; + std::cout << "std::vector<int>" << std::endl; + output_container(std::cout, v); + + /////////////////////////////////////////////////////////////////////////// + // list + std::list<char> l; + l.push_back('A'); + l.push_back('B'); + l.push_back('C'); + + std::cout << "-------------------------------------------------------------" + << std::endl; + std::cout << "std::list<char>" << std::endl; + output_container(std::cout, l); + + /////////////////////////////////////////////////////////////////////////// + // strings + std::string str("Hello world!"); + + std::cout << "-------------------------------------------------------------" + << std::endl; + std::cout << "std::string" << std::endl; + output_container(std::cout, str); + + /////////////////////////////////////////////////////////////////////////// + // boost::array + boost::array<long, 5> arr; + std::generate(arr.begin(), arr.end(), std::rand); // randomly fill the array + + std::cout << "-------------------------------------------------------------" + << std::endl; + std::cout << "boost::array<long, 5>" << std::endl; + output_container(std::cout, arr); + + /////////////////////////////////////////////////////////////////////////// + // map of int --> string mappings + std::map<int, std::string> mappings; + mappings.insert(std::make_pair(0, "zero")); + mappings.insert(std::make_pair(1, "one")); + mappings.insert(std::make_pair(2, "two")); + + std::cout << "-------------------------------------------------------------" + << std::endl; + std::cout << "std::map<int, std::string>" << std::endl; + output_container(std::cout, mappings); + + return 0; +} + diff --git a/src/boost/libs/spirit/example/karma/basic_facilities.cpp b/src/boost/libs/spirit/example/karma/basic_facilities.cpp new file mode 100644 index 00000000..63514032 --- /dev/null +++ b/src/boost/libs/spirit/example/karma/basic_facilities.cpp @@ -0,0 +1,229 @@ +// Copyright (c) 2001-2010 Hartmut Kaiser +// +// 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) + +// The main purpose of this example is to show the uniform and easy way of +// output formatting for different container types. +// +// Since the 'stream' primitive used below uses the streaming operator defined +// for the container value_type, you must make sure to have a corresponding +// operator<<() available for this contained data type. OTOH this means, that +// the format descriptions used below will be usable for any contained type as +// long as this type has an associated streaming operator defined. + +// use a larger value for the alignment field width (default is 10) +#define BOOST_KARMA_DEFAULT_FIELD_LENGTH 25 + +#include <boost/config/warning_disable.hpp> + +#include <iostream> +#include <string> +#include <vector> +#include <list> +#include <map> +#include <algorithm> +#include <cstdlib> + +#include <boost/range.hpp> +#include <boost/array.hpp> +#include <boost/date_time/gregorian/gregorian.hpp> +#include <boost/fusion/include/std_pair.hpp> + +/////////////////////////////////////////////////////////////////////////////// +// This streaming operator is needed to generate the output from the map below +// Yes, it's heresy, but this operator has to live in namespace std to be +// picked up by the compiler. +namespace std { + inline std::ostream& + operator<<(std::ostream& os, std::pair<int const, std::string> v) + { + os << v.first << ": " << v.second; + return os; + } +} + +#include <boost/spirit/include/karma.hpp> +#include <boost/spirit/include/karma_format.hpp> + +using namespace boost::spirit; +using namespace boost::spirit::ascii; + +/////////////////////////////////////////////////////////////////////////////// +// Output the given containers in list format +// Note: the format description does not depend on the type of the sequence +// nor does it depend on the type of the elements contained in the +// sequence +/////////////////////////////////////////////////////////////////////////////// +template <typename Container> +void output_container(std::ostream& os, Container const& c) +{ + // output the container as a space separated sequence + os << + karma::format( + *stream, // format description + c // data + ) << std::endl << std::endl; + + // output the container as a space separated sequence + os << + karma::format_delimited( + *stream, // format description + space, // delimiter + c // data + ) << std::endl << std::endl; + + os << + karma::format_delimited( + '[' << *stream << ']', // format description + space, // delimiter + c // data + ) << std::endl << std::endl; + + // output the container as a comma separated list + os << + karma::format( + stream % ", ", // format description + c // data + ) << std::endl << std::endl; + + os << + karma::format( + '[' << (stream % ", ") << ']', // format description + c // data + ) << std::endl << std::endl; + + os << + karma::format( + '[' << -(stream % ", ") << ']', // format description + c // data + ) << std::endl << std::endl; + + os << + karma::format( + '[' << (+stream | "empty") << ']', // format description + c // data + ) << std::endl << std::endl; + + // output the container as a comma separated list of items enclosed in '()' + os << + karma::format( + ('(' << stream << ')') % ", ", // format description + c // data + ) << std::endl << std::endl; + + os << + karma::format( + '[' << ( + ('(' << stream << ')') % ", " + ) << ']', // format description + c // data + ) << std::endl << std::endl; + + // output the container as a HTML list + os << + karma::format_delimited( + "<ol>" << + *verbatim["<li>" << stream << "</li>"] + << "</ol>", // format description + '\n', // delimiter + c // data + ) << std::endl; + + // output the container as right aligned column + os << + karma::format_delimited( + *verbatim[ + "|" << right_align[stream] << "|" + ], // format description + '\n', // delimiter + c // data + ) << std::endl; + + os << std::endl; +} + +int main() +{ + /////////////////////////////////////////////////////////////////////////// + // C-style array + int i[4] = { 3, 6, 9, 12 }; + + std::cout << "-------------------------------------------------------------" + << std::endl; + std::cout << "int i[]" << std::endl; + output_container(std::cout, boost::make_iterator_range(i, i+4)); + + /////////////////////////////////////////////////////////////////////////// + // vector + std::vector<int> v (5); + std::generate(v.begin(), v.end(), std::rand); // randomly fill the vector + + std::cout << "-------------------------------------------------------------" + << std::endl; + std::cout << "std::vector<int>" << std::endl; + output_container(std::cout, v); + + /////////////////////////////////////////////////////////////////////////// + // list + std::list<char> l; + l.push_back('A'); + l.push_back('B'); + l.push_back('C'); + + std::cout << "-------------------------------------------------------------" + << std::endl; + std::cout << "std::list<char>" << std::endl; + output_container(std::cout, l); + + /////////////////////////////////////////////////////////////////////////// + // strings + std::string str("Hello world!"); + + std::cout << "-------------------------------------------------------------" + << std::endl; + std::cout << "std::string" << std::endl; + output_container(std::cout, str); + + /////////////////////////////////////////////////////////////////////////// + // boost::array + boost::array<long, 5> arr; + std::generate(arr.begin(), arr.end(), std::rand); // randomly fill the array + + std::cout << "-------------------------------------------------------------" + << std::endl; + std::cout << "boost::array<long, 5>" << std::endl; + output_container(std::cout, arr); + + /////////////////////////////////////////////////////////////////////////// + // vector of boost::date objects + // Note: any registered facets get used! + using namespace boost::gregorian; + std::vector<date> dates; + dates.push_back(date(2005, Jun, 25)); + dates.push_back(date(2006, Jan, 13)); + dates.push_back(date(2007, May, 03)); + + date_facet* facet(new date_facet("%A %B %d, %Y")); + std::cout.imbue(std::locale(std::cout.getloc(), facet)); + + std::cout << "-------------------------------------------------------------" + << std::endl; + std::cout << "std::vector<boost::date>" << std::endl; + output_container(std::cout, dates); + + /////////////////////////////////////////////////////////////////////////// + // map of int --> string mappings + std::map<int, std::string> mappings; + mappings.insert(std::make_pair(0, "zero")); + mappings.insert(std::make_pair(1, "one")); + mappings.insert(std::make_pair(2, "two")); + + std::cout << "-------------------------------------------------------------" + << std::endl; + std::cout << "std::map<int, std::string>" << std::endl; + output_container(std::cout, mappings); + + return 0; +} + diff --git a/src/boost/libs/spirit/example/karma/calc2_ast.hpp b/src/boost/libs/spirit/example/karma/calc2_ast.hpp new file mode 100644 index 00000000..d1ee92e8 --- /dev/null +++ b/src/boost/libs/spirit/example/karma/calc2_ast.hpp @@ -0,0 +1,177 @@ +/*============================================================================= + Copyright (c) 2001-2010 Joel de Guzman + Copyright (c) 2001-2010 Hartmut Kaiser + + 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 Calculator example demonstrating generation of AST which gets dumped into +// a human readable format afterwards. +// +// [ JDG April 28, 2008 ] +// [ HK April 28, 2008 ] +// +/////////////////////////////////////////////////////////////////////////////// + +#if !defined(SPIRIT_EXAMPLE_CALC2_AST_APR_30_2008_1011AM) +#define SPIRIT_EXAMPLE_CALC2_AST_APR_30_2008_1011AM + +#include <boost/variant.hpp> +#include <boost/spirit/include/phoenix_operator.hpp> +#include <boost/spirit/include/phoenix_function.hpp> +#include <boost/spirit/include/phoenix_statement.hpp> +#include <boost/spirit/include/karma_domain.hpp> +#include <boost/spirit/include/support_attributes_fwd.hpp> + +/////////////////////////////////////////////////////////////////////////////// +// Our AST +/////////////////////////////////////////////////////////////////////////////// +struct binary_op; +struct unary_op; +struct nil {}; + +struct expression_ast +{ + typedef + boost::variant< + nil // can't happen! + , int + , boost::recursive_wrapper<binary_op> + , boost::recursive_wrapper<unary_op> + > + type; + + // expose variant types + typedef type::types types; + + // expose variant functionality + int which() const { return expr.which(); } + + // constructors + expression_ast() + : expr(nil()) {} + + expression_ast(unary_op const& expr) + : expr(expr) {} + + expression_ast(binary_op const& expr) + : expr(expr) {} + + expression_ast(unsigned int expr) + : expr(expr) {} + + expression_ast(type const& expr) + : expr(expr) {} + + expression_ast& operator+=(expression_ast const& rhs); + expression_ast& operator-=(expression_ast const& rhs); + expression_ast& operator*=(expression_ast const& rhs); + expression_ast& operator/=(expression_ast const& rhs); + + type expr; +}; + +// expose variant functionality +namespace boost +{ + // this function has to live in namespace boost for ADL to correctly find it + template <typename T> + inline T get(expression_ast const& expr) + { + return boost::get<T>(expr.expr); + } + + namespace spirit { namespace traits + { + // the specialization below tells Spirit to handle expression_ast as + // if it where a 'real' variant (if used with Spirit.Karma) + template <> + struct not_is_variant<expression_ast, karma::domain> + : mpl::false_ {}; + + // the specialization of variant_which allows to generically extract + // the current type stored in the given variant like type + template <> + struct variant_which<expression_ast> + { + static int call(expression_ast const& v) + { + return v.which(); + } + }; + }} +} + +/////////////////////////////////////////////////////////////////////////////// +struct binary_op +{ + binary_op() {} + + binary_op( + char op + , expression_ast const& left + , expression_ast const& right) + : op(op), left(left), right(right) {} + + char op; + expression_ast left; + expression_ast right; +}; + +struct unary_op +{ + unary_op( + char op + , expression_ast const& right) + : op(op), right(right) {} + + char op; + expression_ast right; +}; + +inline expression_ast& expression_ast::operator+=(expression_ast const& rhs) +{ + expr = binary_op('+', expr, rhs); + return *this; +} + +inline expression_ast& expression_ast::operator-=(expression_ast const& rhs) +{ + expr = binary_op('-', expr, rhs); + return *this; +} + +inline expression_ast& expression_ast::operator*=(expression_ast const& rhs) +{ + expr = binary_op('*', expr, rhs); + return *this; +} + +inline expression_ast& expression_ast::operator/=(expression_ast const& rhs) +{ + expr = binary_op('/', expr, rhs); + return *this; +} + +// We should be using expression_ast::operator-. There's a bug +// in phoenix type deduction mechanism that prevents us from +// doing so. Phoenix will be switching to BOOST_TYPEOF. In the +// meantime, we will use a phoenix::function below: +template <char Op> +struct unary_expr +{ + template <typename T> + struct result { typedef T type; }; + + expression_ast operator()(expression_ast const& expr) const + { + return unary_op(Op, expr); + } +}; + +boost::phoenix::function<unary_expr<'+'> > pos; +boost::phoenix::function<unary_expr<'-'> > neg; + +#endif diff --git a/src/boost/libs/spirit/example/karma/calc2_ast_dump.cpp b/src/boost/libs/spirit/example/karma/calc2_ast_dump.cpp new file mode 100644 index 00000000..ac15c7ca --- /dev/null +++ b/src/boost/libs/spirit/example/karma/calc2_ast_dump.cpp @@ -0,0 +1,170 @@ +/*============================================================================= + Copyright (c) 2001-2010 Joel de Guzman + Copyright (c) 2001-2010 Hartmut Kaiser + + 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 Calculator example demonstrating generation of AST which gets dumped into +// a human readable format afterwards. +// +// [ JDG April 28, 2008 ] +// [ HK April 28, 2008 ] +// +/////////////////////////////////////////////////////////////////////////////// +#include <boost/config/warning_disable.hpp> + +#include <iostream> +#include <vector> +#include <string> + +#include "calc2_ast.hpp" + +#include <boost/spirit/include/qi.hpp> +#include <boost/spirit/include/karma.hpp> +#include <boost/fusion/include/adapt_struct.hpp> + +using namespace boost::spirit; +using namespace boost::spirit::ascii; + +/////////////////////////////////////////////////////////////////////////////// +// Our calculator parser grammar +/////////////////////////////////////////////////////////////////////////////// +template <typename Iterator> +struct calculator + : qi::grammar<Iterator, expression_ast(), space_type> +{ + calculator() : calculator::base_type(expression) + { + expression = + term [_val = _1] + >> *( ('+' >> term [_val += _1]) + | ('-' >> term [_val -= _1]) + ) + ; + + term = + factor [_val = _1] + >> *( ('*' >> factor [_val *= _1]) + | ('/' >> factor [_val /= _1]) + ) + ; + + factor = + uint_ [_val = _1] + | '(' >> expression [_val = _1] >> ')' + | ('-' >> factor [_val = neg(_1)]) + | ('+' >> factor [_val = pos(_1)]) + ; + } + + qi::rule<Iterator, expression_ast(), space_type> expression, term, factor; +}; + +// We need to tell fusion about our binary_op and unary_op structs +// to make them a first-class fusion citizen +// +// Note: we register the members exactly in the same sequence as we need them +// in the grammar +BOOST_FUSION_ADAPT_STRUCT( + binary_op, + (expression_ast, left) + (char, op) + (expression_ast, right) +) + +BOOST_FUSION_ADAPT_STRUCT( + unary_op, + (char, op) + (expression_ast, right) +) + +/////////////////////////////////////////////////////////////////////////////// +// Our AST grammar for the generator, this just dumps the AST as a expression +/////////////////////////////////////////////////////////////////////////////// +template <typename OuputIterator> +struct dump_ast + : karma::grammar<OuputIterator, expression_ast(), space_type> +{ + dump_ast() : dump_ast::base_type(ast_node) + { + ast_node %= int_ | binary_node | unary_node; + binary_node %= '(' << ast_node << char_ << ast_node << ')'; + unary_node %= '(' << char_ << ast_node << ')'; + } + + karma::rule<OuputIterator, expression_ast(), space_type> ast_node; + karma::rule<OuputIterator, binary_op(), space_type> binary_node; + karma::rule<OuputIterator, unary_op(), space_type> unary_node; +}; + +/////////////////////////////////////////////////////////////////////////////// +// Main program +/////////////////////////////////////////////////////////////////////////////// +int +main() +{ + std::cout << "/////////////////////////////////////////////////////////\n\n"; + std::cout << "Dump AST's for simple expressions...\n\n"; + std::cout << "/////////////////////////////////////////////////////////\n\n"; + std::cout << "Type an expression...or [q or Q] to quit\n\n"; + + // Our parser grammar definitions + typedef std::string::const_iterator iterator_type; + typedef calculator<iterator_type> calculator; + + calculator calc; + + // Our generator grammar definitions + typedef std::back_insert_iterator<std::string> output_iterator_type; + typedef dump_ast<output_iterator_type> dump_ast; + + dump_ast ast_grammar; + + std::string str; + while (std::getline(std::cin, str)) + { + if (str.empty() || str[0] == 'q' || str[0] == 'Q') + break; + + expression_ast ast; + std::string::const_iterator iter = str.begin(); + std::string::const_iterator end = str.end(); + bool r = qi::phrase_parse(iter, end, calc, space, ast); + + if (r && iter == end) + { + std::string generated; + output_iterator_type outit(generated); + r = karma::generate_delimited(outit, ast_grammar, space, ast); + + if (r) + { + std::cout << "Got AST:" << std::endl << generated + << std::endl; + std::cout << "-------------------------\n"; + } + else + { + std::cout << "-------------------------\n"; + std::cout << "Generating failed\n"; + std::cout << "-------------------------\n"; + } + } + else + { + std::string rest(iter, end); + std::cout << "-------------------------\n"; + std::cout << "Parsing failed\n"; + std::cout << "stopped at: \": " << rest << "\"\n"; + std::cout << "-------------------------\n"; + } + } + + std::cout << "Bye... :-) \n\n"; + return 0; +} + + diff --git a/src/boost/libs/spirit/example/karma/calc2_ast_rpn.cpp b/src/boost/libs/spirit/example/karma/calc2_ast_rpn.cpp new file mode 100644 index 00000000..955f2467 --- /dev/null +++ b/src/boost/libs/spirit/example/karma/calc2_ast_rpn.cpp @@ -0,0 +1,172 @@ +/*============================================================================= + Copyright (c) 2001-2010 Joel de Guzman + Copyright (c) 2001-2010 Hartmut Kaiser + + 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 Calculator example demonstrating generation of AST which gets dumped into +// a reverse polish notation afterwards. +// +// [ JDG April 28, 2008 ] +// [ HK April 28, 2008 ] +// +/////////////////////////////////////////////////////////////////////////////// +#include <boost/config/warning_disable.hpp> + +#include <iostream> +#include <vector> +#include <string> + +#include "calc2_ast.hpp" + +#include <boost/spirit/include/qi.hpp> +#include <boost/spirit/include/karma.hpp> +#include <boost/fusion/include/adapt_struct.hpp> + +using namespace boost::spirit; +using namespace boost::spirit::ascii; + +/////////////////////////////////////////////////////////////////////////////// +// Our calculator parser grammar +/////////////////////////////////////////////////////////////////////////////// +template <typename Iterator> +struct calculator + : qi::grammar<Iterator, expression_ast(), space_type> +{ + calculator() : calculator::base_type(expression) + { + expression = + term [_val = _1] + >> *( ('+' >> term [_val += _1]) + | ('-' >> term [_val -= _1]) + ) + ; + + term = + factor [_val = _1] + >> *( ('*' >> factor [_val *= _1]) + | ('/' >> factor [_val /= _1]) + ) + ; + + factor = + uint_ [_val = _1] + | '(' >> expression [_val = _1] >> ')' + | ('-' >> factor [_val = neg(_1)]) + | ('+' >> factor [_val = pos(_1)]) + ; + } + + qi::rule<Iterator, expression_ast(), space_type> expression, term, factor; +}; + +// We need to tell fusion about our binary_op and unary_op structs +// to make them a first-class fusion citizen +// +// Note: we register the members exactly in the same sequence as we need them +// in the grammar +BOOST_FUSION_ADAPT_STRUCT( + binary_op, + (expression_ast, left) + (expression_ast, right) + (char, op) +) + +BOOST_FUSION_ADAPT_STRUCT( + unary_op, + (expression_ast, right) + (char, op) +) + +/////////////////////////////////////////////////////////////////////////////// +// Our AST grammar for the generator, this prints the AST in reverse polish +// notation +/////////////////////////////////////////////////////////////////////////////// +template <typename OuputIterator> +struct ast_rpn + : karma::grammar<OuputIterator, expression_ast(), space_type> +{ + ast_rpn() : ast_rpn::base_type(ast_node) + { + ast_node %= int_ | binary_node | unary_node; + binary_node %= ast_node << ast_node << char_; + unary_node %= '(' << ast_node << char_ << ')'; + } + + karma::rule<OuputIterator, expression_ast(), space_type> ast_node; + karma::rule<OuputIterator, binary_op(), space_type> binary_node; + karma::rule<OuputIterator, unary_op(), space_type> unary_node; +}; + +/////////////////////////////////////////////////////////////////////////////// +// Main program +/////////////////////////////////////////////////////////////////////////////// +int +main() +{ + std::cout << "/////////////////////////////////////////////////////////\n\n"; + std::cout << "RPN generator for simple expressions...\n\n"; + std::cout << "/////////////////////////////////////////////////////////\n\n"; + std::cout << "Type an expression...or [q or Q] to quit\n\n"; + + // Our parser grammar definitions + typedef std::string::const_iterator iterator_type; + typedef calculator<iterator_type> calculator; + + calculator calc; + + // Our generator grammar definitions + typedef std::back_insert_iterator<std::string> output_iterator_type; + typedef ast_rpn<output_iterator_type> ast_rpn; + + ast_rpn ast_grammar; + + std::string str; + while (std::getline(std::cin, str)) + { + if (str.empty() || str[0] == 'q' || str[0] == 'Q') + break; + + expression_ast ast; // this will hold the generated AST + + std::string::const_iterator iter = str.begin(); + std::string::const_iterator end = str.end(); + bool r = qi::phrase_parse(iter, end, calc, space, ast); + + if (r && iter == end) + { + std::string generated; + output_iterator_type outit(generated); + r = karma::generate_delimited(outit, ast_grammar, space, ast); + + if (r) + { + std::cout << "RPN for '" << str << "': \n" << generated + << std::endl; + std::cout << "-------------------------\n"; + } + else + { + std::cout << "-------------------------\n"; + std::cout << "Generating failed\n"; + std::cout << "-------------------------\n"; + } + } + else + { + std::string rest(iter, end); + std::cout << "-------------------------\n"; + std::cout << "Parsing failed\n"; + std::cout << "stopped at: \": " << rest << "\"\n"; + std::cout << "-------------------------\n"; + } + } + + std::cout << "Bye... :-) \n\n"; + return 0; +} + + diff --git a/src/boost/libs/spirit/example/karma/calc2_ast_vm.cpp b/src/boost/libs/spirit/example/karma/calc2_ast_vm.cpp new file mode 100644 index 00000000..77fab096 --- /dev/null +++ b/src/boost/libs/spirit/example/karma/calc2_ast_vm.cpp @@ -0,0 +1,248 @@ +/*============================================================================= + Copyright (c) 2001-2010 Joel de Guzman + Copyright (c) 2001-2010 Hartmut Kaiser + + 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 Calculator example demonstrating generation of AST from which we generate +// a simple byte code representation being interpreted by a similar virtual +// machine. +// +// [ JDG April 28, 2008 ] +// [ HK May 05, 2008 ] +// +/////////////////////////////////////////////////////////////////////////////// +#include <boost/config/warning_disable.hpp> + +#include <iostream> +#include <vector> +#include <string> + +#include "calc2_ast_vm.hpp" + +#include <boost/spirit/include/qi.hpp> +#include <boost/spirit/include/karma.hpp> +#include <boost/fusion/include/adapt_struct.hpp> + +using namespace boost::spirit; +using namespace boost::spirit::ascii; + +/////////////////////////////////////////////////////////////////////////////// +// Our calculator parser grammar +/////////////////////////////////////////////////////////////////////////////// +template <typename Iterator> +struct calculator + : qi::grammar<Iterator, expression_ast(), space_type> +{ + calculator() : calculator::base_type(expression) + { + expression = + term [_val = _1] + >> *( ('+' >> term [_val += _1]) + | ('-' >> term [_val -= _1]) + ) + ; + + term = + factor [_val = _1] + >> *( ('*' >> factor [_val *= _1]) + | ('/' >> factor [_val /= _1]) + ) + ; + + factor = + uint_ [_val = _1] + | '(' >> expression [_val = _1] >> ')' + | ('-' >> factor [_val = neg(_1)]) + | ('+' >> factor [_val = pos(_1)]) + ; + } + + qi::rule<Iterator, expression_ast(), space_type> expression, term, factor; +}; + +/////////////////////////////////////////////////////////////////////////////// +// The Virtual Machine +/////////////////////////////////////////////////////////////////////////////// +class vmachine +{ +public: + union element { + int code; + char bytes[sizeof(int)]; + }; + + vmachine(unsigned stackSize = 4096) + : stack(stackSize) + , stack_ptr(stack.begin()) + { + } + + int top() const { return stack_ptr[-1]; }; + void execute(std::vector<element> const& code); + +private: + std::vector<int> stack; + std::vector<int>::iterator stack_ptr; +}; + +void vmachine::execute(std::vector<element> const& code) +{ + std::vector<element>::const_iterator pc = code.begin(); + stack_ptr = stack.begin(); + + while ((*pc).code && pc != code.end()) + { + switch ((*pc++).code) + { + case op_neg: + stack_ptr[-1] = -stack_ptr[-1]; + break; + + case op_add: + --stack_ptr; + stack_ptr[-1] += stack_ptr[0]; + break; + + case op_sub: + --stack_ptr; + stack_ptr[-1] -= stack_ptr[0]; + break; + + case op_mul: + --stack_ptr; + stack_ptr[-1] *= stack_ptr[0]; + break; + + case op_div: + --stack_ptr; + stack_ptr[-1] /= stack_ptr[0]; + break; + + case op_int: + *stack_ptr++ = (*pc++).code; + break; + } + } +} + +// We need to tell fusion about our binary_op and unary_op structs +// to make them a first-class fusion citizen +// +// Note: we register the members exactly in the same sequence as we need them +// in the grammar +BOOST_FUSION_ADAPT_STRUCT( + binary_op, + (expression_ast, left) + (expression_ast, right) + (int, op) +) + +BOOST_FUSION_ADAPT_STRUCT( + unary_op, + (expression_ast, right) + (int, op) +) + +/////////////////////////////////////////////////////////////////////////////// +// Our AST grammar for the generator, this just dumps the AST as a expression +/////////////////////////////////////////////////////////////////////////////// +template <typename OuputIterator, typename Delimiter> +struct generate_byte_code + : karma::grammar<OuputIterator, expression_ast(), Delimiter> +{ + generate_byte_code() : generate_byte_code::base_type(ast_node) + { + ast_node %= int_node | binary_node | unary_node; + int_node %= dword(op_int) << dword; + binary_node %= ast_node << ast_node << byte_; + unary_node %= ast_node << byte_; + } + + karma::rule<OuputIterator, expression_ast(), Delimiter> ast_node; + karma::rule<OuputIterator, int(), Delimiter> int_node; + karma::rule<OuputIterator, binary_op(), Delimiter> binary_node; + karma::rule<OuputIterator, unary_op(), Delimiter> unary_node; +}; + +/////////////////////////////////////////////////////////////////////////////// +// helper function helping to deduce the delimiter type +template <typename Delimiter> +bool generate_vm_code(expression_ast const& ast, + std::vector<vmachine::element>& code, Delimiter const& d) +{ + // Our generator grammar definitions + typedef char* output_iterator_type; + typedef generate_byte_code<output_iterator_type, Delimiter> generate_byte_code; + + char* outbuffer = (*code.begin()).bytes; + generate_byte_code gen_vm; + return karma::generate_delimited(outbuffer, gen_vm, d, ast); +} + +/////////////////////////////////////////////////////////////////////////////// +// Main program +/////////////////////////////////////////////////////////////////////////////// +int +main() +{ + std::cout << "/////////////////////////////////////////////////////////\n\n"; + std::cout << "Compile simple expressions to bytecode...\n\n"; + std::cout << "/////////////////////////////////////////////////////////\n\n"; + std::cout << "Type an expression...or [q or Q] to quit\n\n"; + + // Our parser grammar definitions + typedef std::string::const_iterator iterator_type; + typedef calculator<iterator_type> calculator; + + calculator calc; + + std::string str; + while (std::getline(std::cin, str)) + { + if (str.empty() || str[0] == 'q' || str[0] == 'Q') + break; + + expression_ast ast; + std::string::const_iterator iter = str.begin(); + std::string::const_iterator end = str.end(); + bool r = qi::phrase_parse(iter, end, calc, space, ast); + + if (r && iter == end) + { + // we assume a vm code size of 4096 is sufficient + std::vector<vmachine::element> code (4096); + r = generate_vm_code(ast, code, pad(4)); + + if (r) + { + vmachine vm; + vm.execute(code); + std::cout << "\nresult = " << vm.top() << std::endl; + std::cout << "-------------------------\n"; + } + else + { + std::cout << "-------------------------\n"; + std::cout << "Generating failed\n"; + std::cout << "-------------------------\n"; + } + } + else + { + std::string rest(iter, end); + std::cout << "-------------------------\n"; + std::cout << "Parsing failed\n"; + std::cout << "stopped at: \": " << rest << "\"\n"; + std::cout << "-------------------------\n"; + } + } + + std::cout << "Bye... :-) \n\n"; + return 0; +} + + diff --git a/src/boost/libs/spirit/example/karma/calc2_ast_vm.hpp b/src/boost/libs/spirit/example/karma/calc2_ast_vm.hpp new file mode 100644 index 00000000..b3a51149 --- /dev/null +++ b/src/boost/libs/spirit/example/karma/calc2_ast_vm.hpp @@ -0,0 +1,190 @@ +/*============================================================================= + Copyright (c) 2001-2010 Joel de Guzman + Copyright (c) 2001-2010 Hartmut Kaiser + + 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 Calculator example demonstrating generation of AST which gets dumped into +// a human readable format afterwards. +// +// [ JDG April 28, 2008 ] +// [ HK April 28, 2008 ] +// +/////////////////////////////////////////////////////////////////////////////// + +#if !defined(SPIRIT_EXAMPLE_CALC2_AST_APR_30_2008_1011AM) +#define SPIRIT_EXAMPLE_CALC2_AST_APR_30_2008_1011AM + +#include <boost/variant.hpp> +#include <boost/spirit/include/phoenix_operator.hpp> +#include <boost/spirit/include/phoenix_function.hpp> +#include <boost/spirit/include/phoenix_statement.hpp> +#include <boost/spirit/include/karma_domain.hpp> +#include <boost/spirit/include/support_attributes_fwd.hpp> + +/////////////////////////////////////////////////////////////////////////////// +// Our AST +/////////////////////////////////////////////////////////////////////////////// +struct binary_op; +struct unary_op; +struct nil {}; + +struct expression_ast +{ + typedef + boost::variant< + nil // can't happen! + , int + , boost::recursive_wrapper<binary_op> + , boost::recursive_wrapper<unary_op> + > + type; + + // expose variant types + typedef type::types types; + + // expose variant functionality + int which() const { return expr.which(); } + + // constructors + expression_ast() + : expr(nil()) {} + + expression_ast(unary_op const& expr) + : expr(expr) {} + + expression_ast(binary_op const& expr) + : expr(expr) {} + + expression_ast(unsigned int expr) + : expr(expr) {} + + expression_ast(type const& expr) + : expr(expr) {} + + expression_ast& operator+=(expression_ast const& rhs); + expression_ast& operator-=(expression_ast const& rhs); + expression_ast& operator*=(expression_ast const& rhs); + expression_ast& operator/=(expression_ast const& rhs); + + type expr; +}; + +// expose variant functionality +namespace boost +{ + // this function has to live in namespace boost for ADL to correctly find it + template <typename T> + inline T get(expression_ast const& expr) + { + return boost::get<T>(expr.expr); + } + + // the specialization below tells Spirit to handle expression_ast as if it + // where a 'real' variant + namespace spirit { namespace traits + { + // the specialization below tells Spirit to handle expression_ast as + // if it where a 'real' variant (if used with Spirit.Karma) + template <> + struct not_is_variant<expression_ast, karma::domain> + : mpl::false_ {}; + + // the specialization of variant_which allows to generically extract + // the current type stored in the given variant like type + template <> + struct variant_which<expression_ast> + { + static int call(expression_ast const& v) + { + return v.which(); + } + }; + }} +} + +enum byte_code +{ + op_neg = 1, // negate the top stack entry + op_pos, // essentially a no-op (unary plus) + op_add, // add top two stack entries + op_sub, // subtract top two stack entries + op_mul, // multiply top two stack entries + op_div, // divide top two stack entries + op_int, // push constant integer into the stack +}; + +/////////////////////////////////////////////////////////////////////////////// +struct binary_op +{ + binary_op() {} + + binary_op( + int op + , expression_ast const& left + , expression_ast const& right) + : op(op), left(left), right(right) {} + + int op; + expression_ast left; + expression_ast right; +}; + +struct unary_op +{ + unary_op( + int op + , expression_ast const& right) + : op(op), right(right) {} + + int op; + expression_ast right; +}; + +inline expression_ast& expression_ast::operator+=(expression_ast const& rhs) +{ + expr = binary_op(op_add, expr, rhs); + return *this; +} + +inline expression_ast& expression_ast::operator-=(expression_ast const& rhs) +{ + expr = binary_op(op_sub, expr, rhs); + return *this; +} + +inline expression_ast& expression_ast::operator*=(expression_ast const& rhs) +{ + expr = binary_op(op_mul, expr, rhs); + return *this; +} + +inline expression_ast& expression_ast::operator/=(expression_ast const& rhs) +{ + expr = binary_op(op_div, expr, rhs); + return *this; +} + +// We should be using expression_ast::operator-. There's a bug +// in phoenix type deduction mechanism that prevents us from +// doing so. Phoenix will be switching to BOOST_TYPEOF. In the +// meantime, we will use a phoenix::function below: +template <char Op> +struct unary_expr +{ + template <typename T> + struct result { typedef T type; }; + + expression_ast operator()(expression_ast const& expr) const + { + return unary_op(Op, expr); + } +}; + +boost::phoenix::function<unary_expr<op_pos> > pos; +boost::phoenix::function<unary_expr<op_neg> > neg; + +#endif diff --git a/src/boost/libs/spirit/example/karma/classify_char.cpp b/src/boost/libs/spirit/example/karma/classify_char.cpp new file mode 100644 index 00000000..df113f33 --- /dev/null +++ b/src/boost/libs/spirit/example/karma/classify_char.cpp @@ -0,0 +1,103 @@ +// Copyright (c) 2001-2010 Hartmut Kaiser +// +// 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 character classification example +// +// [ HK August 12, 2009 ] spirit2 +// +/////////////////////////////////////////////////////////////////////////////// + +#include <boost/config/warning_disable.hpp> +#include <boost/spirit/include/qi.hpp> +#include <boost/spirit/include/karma.hpp> +#include <boost/spirit/include/phoenix_core.hpp> +#include <boost/spirit/include/phoenix_operator.hpp> +#include <boost/fusion/include/std_pair.hpp> + +#include <iostream> +#include <string> +#include <complex> + +namespace client +{ + /////////////////////////////////////////////////////////////////////////// + // Our character classification generator + /////////////////////////////////////////////////////////////////////////// + //[tutorial_karma_complex_number + template <typename OutputIterator> + bool classify_character(OutputIterator sink, char c) + { + using boost::spirit::ascii::char_; + using boost::spirit::ascii::digit; + using boost::spirit::ascii::xdigit; + using boost::spirit::ascii::alpha; + using boost::spirit::ascii::punct; + using boost::spirit::ascii::space; + using boost::spirit::ascii::cntrl; + using boost::spirit::karma::omit; + using boost::spirit::karma::generate; + + if (!boost::spirit::char_encoding::ascii::isascii_(c)) + return false; + + return generate(sink, + // Begin grammar + ( + "The character '" << char_ << "' is " + << ( &digit << "a digit" + | &xdigit << "a xdigit" + | &alpha << "a alpha" + | &punct << "a punct" + | &space << "a space" + | &cntrl << "a cntrl" + | "of unknown type" + ) + ), + // End grammar + c, c + ); + } + //] +} + +/////////////////////////////////////////////////////////////////////////////// +// Main program +/////////////////////////////////////////////////////////////////////////////// +int main() +{ + std::cout << "/////////////////////////////////////////////////////////\n\n"; + std::cout << "\t\tA character classification micro generator for Spirit...\n\n"; + std::cout << "/////////////////////////////////////////////////////////\n\n"; + + std::cout << "Give me a character to classify\n"; + std::cout << "Type [q or Q] to quit\n\n"; + + std::string str; + while (getline(std::cin, str)) + { + if (str.empty()) + break; + + std::string generated; + std::back_insert_iterator<std::string> sink(generated); + if (!client::classify_character(sink, str[0])) + { + std::cout << "-------------------------\n"; + std::cout << "Generating failed\n"; + std::cout << "-------------------------\n"; + } + else + { + std::cout << generated << "\n"; + } + } + + std::cout << "Bye... :-) \n\n"; + return 0; +} + + diff --git a/src/boost/libs/spirit/example/karma/complex_number.cpp b/src/boost/libs/spirit/example/karma/complex_number.cpp new file mode 100644 index 00000000..d832553b --- /dev/null +++ b/src/boost/libs/spirit/example/karma/complex_number.cpp @@ -0,0 +1,132 @@ +// Copyright (c) 2001-2010 Hartmut Kaiser +// Copyright (c) 2001-2010 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 complex number micro generator. +// +// [ HK July 7, 2009 ] spirit2 +// +/////////////////////////////////////////////////////////////////////////////// + +#include <boost/config/warning_disable.hpp> +#include <boost/spirit/include/qi.hpp> +#include <boost/spirit/include/karma.hpp> +#include <boost/spirit/include/phoenix_core.hpp> +#include <boost/spirit/include/phoenix_operator.hpp> +#include <boost/fusion/include/std_pair.hpp> + +#include <iostream> +#include <string> +#include <complex> + +namespace client +{ + /////////////////////////////////////////////////////////////////////////// + // Our complex number parser/compiler (that's just a copy of the complex + // number example from Qi (see examples/qi/complex_number.cpp) + /////////////////////////////////////////////////////////////////////////// + template <typename Iterator> + bool parse_complex(Iterator first, Iterator last, std::complex<double>& c) + { + using boost::spirit::qi::double_; + using boost::spirit::qi::_1; + using boost::spirit::qi::phrase_parse; + using boost::spirit::ascii::space; + using boost::phoenix::ref; + + double rN = 0.0; + double iN = 0.0; + bool r = phrase_parse(first, last, + ( + '(' >> double_[ref(rN) = _1] + >> -(',' >> double_[ref(iN) = _1]) >> ')' + | double_[ref(rN) = _1] + ), + space); + + if (!r || first != last) // fail if we did not get a full match + return false; + c = std::complex<double>(rN, iN); + return r; + } + + /////////////////////////////////////////////////////////////////////////// + // Our complex number generator + /////////////////////////////////////////////////////////////////////////// + //[tutorial_karma_complex_number + template <typename OutputIterator> + bool generate_complex(OutputIterator sink, std::complex<double> const& c) + { + using boost::spirit::karma::eps; + using boost::spirit::karma::double_; + using boost::spirit::karma::_1; + using boost::spirit::karma::generate; + + return generate(sink, + // Begin grammar + ( + eps(c.imag() != 0) << + '(' << double_[_1 = c.real()] << ", " << double_[_1 = c.imag()] << ')' + | double_[_1 = c.real()] + ) + // End grammar + ); + } + //] +} + +/////////////////////////////////////////////////////////////////////////////// +// Main program +/////////////////////////////////////////////////////////////////////////////// +int main() +{ + std::cout << "/////////////////////////////////////////////////////////\n\n"; + std::cout << "\t\tA complex number micro generator for Spirit...\n\n"; + std::cout << "/////////////////////////////////////////////////////////\n\n"; + + std::cout << "Give me a complex number of the form r or (r) or (r,i) \n"; + std::cout << "Type [q or Q] to quit\n\n"; + + std::string str; + while (getline(std::cin, str)) + { + if (str.empty() || str[0] == 'q' || str[0] == 'Q') + break; + + std::complex<double> c; + if (client::parse_complex(str.begin(), str.end(), c)) + { + std::cout << "-------------------------\n"; + + std::string generated; + std::back_insert_iterator<std::string> sink(generated); + if (!client::generate_complex(sink, c)) + { + std::cout << "-------------------------\n"; + std::cout << "Generating failed\n"; + std::cout << "-------------------------\n"; + } + else + { + std::cout << "-------------------------\n"; + std::cout << "Generated: " << generated << "\n"; + std::cout << "-------------------------\n"; + } + } + else + { + std::cout << "-------------------------\n"; + std::cout << "Parsing failed\n"; + std::cout << "-------------------------\n"; + } + } + + std::cout << "Bye... :-) \n\n"; + return 0; +} + + diff --git a/src/boost/libs/spirit/example/karma/complex_number_adapt.cpp b/src/boost/libs/spirit/example/karma/complex_number_adapt.cpp new file mode 100644 index 00000000..25135e08 --- /dev/null +++ b/src/boost/libs/spirit/example/karma/complex_number_adapt.cpp @@ -0,0 +1,153 @@ +// Copyright (c) 2001-2010 Hartmut Kaiser +// Copyright (c) 2001-2010 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 complex number micro generator - take 3. +// +// Look'ma, still no semantic actions! And no explicit access to member +// functions any more. +// +// [ HK April 6, 2010 ] spirit2 +// +/////////////////////////////////////////////////////////////////////////////// + +#include <boost/config/warning_disable.hpp> +#include <boost/spirit/include/qi.hpp> +#include <boost/spirit/include/karma.hpp> +#include <boost/spirit/include/phoenix_core.hpp> +#include <boost/spirit/include/phoenix_operator.hpp> +#include <boost/fusion/include/std_pair.hpp> +#include <boost/fusion/include/adapt_adt.hpp> +#include <boost/spirit/include/support_adapt_adt_attributes.hpp> + +#include <iostream> +#include <string> +#include <complex> + +/////////////////////////////////////////////////////////////////////////////// +// The following macro adapts the type std::complex<double> as a fusion +// sequence. +//[tutorial_karma_complex_number_adapt_class +// We can leave off the setters as Karma does not need them. +BOOST_FUSION_ADAPT_ADT( + std::complex<double>, + (bool, bool, obj.imag() != 0, /**/) + (double, double, obj.real(), /**/) + (double, double, obj.imag(), /**/) +) +//] + +namespace client +{ + /////////////////////////////////////////////////////////////////////////// + // Our complex number parser/compiler (that's just a copy of the complex + // number example from Qi (see examples/qi/complex_number.cpp) + /////////////////////////////////////////////////////////////////////////// + template <typename Iterator> + bool parse_complex(Iterator first, Iterator last, std::complex<double>& c) + { + using boost::spirit::qi::double_; + using boost::spirit::qi::_1; + using boost::spirit::qi::phrase_parse; + using boost::spirit::ascii::space; + using boost::phoenix::ref; + + double rN = 0.0; + double iN = 0.0; + bool r = phrase_parse(first, last, + ( + '(' >> double_[ref(rN) = _1] + >> -(',' >> double_[ref(iN) = _1]) >> ')' + | double_[ref(rN) = _1] + ), + space); + + if (!r || first != last) // fail if we did not get a full match + return false; + c = std::complex<double>(rN, iN); + return r; + } + + /////////////////////////////////////////////////////////////////////////// + // Our complex number generator + /////////////////////////////////////////////////////////////////////////// + //[tutorial_karma_complex_number_adapt + template <typename OutputIterator> + bool generate_complex(OutputIterator sink, std::complex<double> const& c) + { + using boost::spirit::karma::double_; + using boost::spirit::karma::bool_; + using boost::spirit::karma::true_; + using boost::spirit::karma::omit; + using boost::spirit::karma::generate; + + return generate(sink, + + // Begin grammar + ( + &true_ << '(' << double_ << ", " << double_ << ')' + | omit[bool_] << double_ + ), + // End grammar + + c // Data to output + ); + } + //] +} + +/////////////////////////////////////////////////////////////////////////////// +// Main program +/////////////////////////////////////////////////////////////////////////////// +int main() +{ + std::cout << "/////////////////////////////////////////////////////////\n\n"; + std::cout << "\t\tA complex number micro generator for Spirit...\n\n"; + std::cout << "/////////////////////////////////////////////////////////\n\n"; + + std::cout << "Give me a complex number of the form r or (r) or (r,i) \n"; + std::cout << "Type [q or Q] to quit\n\n"; + + std::string str; + while (getline(std::cin, str)) + { + if (str.empty() || str[0] == 'q' || str[0] == 'Q') + break; + + std::complex<double> c; + if (client::parse_complex(str.begin(), str.end(), c)) + { + std::cout << "-------------------------\n"; + + std::string generated; + std::back_insert_iterator<std::string> sink(generated); + if (!client::generate_complex(sink, c)) + { + std::cout << "-------------------------\n"; + std::cout << "Generating failed\n"; + std::cout << "-------------------------\n"; + } + else + { + std::cout << "-------------------------\n"; + std::cout << "Generated: " << generated << "\n"; + std::cout << "-------------------------\n"; + } + } + else + { + std::cout << "-------------------------\n"; + std::cout << "Parsing failed\n"; + std::cout << "-------------------------\n"; + } + } + + std::cout << "Bye... :-) \n\n"; + return 0; +} + + diff --git a/src/boost/libs/spirit/example/karma/complex_number_easier.cpp b/src/boost/libs/spirit/example/karma/complex_number_easier.cpp new file mode 100644 index 00000000..0fe05149 --- /dev/null +++ b/src/boost/libs/spirit/example/karma/complex_number_easier.cpp @@ -0,0 +1,133 @@ +// Copyright (c) 2001-2010 Hartmut Kaiser +// Copyright (c) 2001-2010 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 complex number micro generator - take 2. Look'ma no semantic actions! +// +// [ HK July 26, 2009 ] spirit2 +// +/////////////////////////////////////////////////////////////////////////////// + +#include <boost/config/warning_disable.hpp> +#include <boost/spirit/include/qi.hpp> +#include <boost/spirit/include/karma.hpp> +#include <boost/spirit/include/phoenix_core.hpp> +#include <boost/spirit/include/phoenix_operator.hpp> +#include <boost/fusion/include/std_pair.hpp> + +#include <iostream> +#include <string> +#include <complex> + +namespace client +{ + /////////////////////////////////////////////////////////////////////////// + // Our complex number parser/compiler (that's just a copy of the complex + // number example from Qi (see examples/qi/complex_number.cpp) + /////////////////////////////////////////////////////////////////////////// + template <typename Iterator> + bool parse_complex(Iterator first, Iterator last, std::complex<double>& c) + { + using boost::spirit::qi::double_; + using boost::spirit::qi::_1; + using boost::spirit::qi::phrase_parse; + using boost::spirit::ascii::space; + using boost::phoenix::ref; + + double rN = 0.0; + double iN = 0.0; + bool r = phrase_parse(first, last, + ( + '(' >> double_[ref(rN) = _1] + >> -(',' >> double_[ref(iN) = _1]) >> ')' + | double_[ref(rN) = _1] + ), + space); + + if (!r || first != last) // fail if we did not get a full match + return false; + c = std::complex<double>(rN, iN); + return r; + } + + /////////////////////////////////////////////////////////////////////////// + // Our complex number generator + /////////////////////////////////////////////////////////////////////////// + //[tutorial_karma_complex_number_easier + template <typename OutputIterator> + bool generate_complex(OutputIterator sink, std::complex<double> const& c) + { + using boost::spirit::karma::double_; + using boost::spirit::karma::omit; + using boost::spirit::karma::generate; + + return generate(sink, + + // Begin grammar + ( + !double_(0.0) << '(' << double_ << ", " << double_ << ')' + | omit[double_] << double_ + ), + // End grammar + + c.imag(), c.real(), c.imag() // Data to output + ); + } + //] +} + +/////////////////////////////////////////////////////////////////////////////// +// Main program +/////////////////////////////////////////////////////////////////////////////// +int main() +{ + std::cout << "/////////////////////////////////////////////////////////\n\n"; + std::cout << "\t\tA complex number micro generator for Spirit...\n\n"; + std::cout << "/////////////////////////////////////////////////////////\n\n"; + + std::cout << "Give me a complex number of the form r or (r) or (r,i) \n"; + std::cout << "Type [q or Q] to quit\n\n"; + + std::string str; + while (getline(std::cin, str)) + { + if (str.empty() || str[0] == 'q' || str[0] == 'Q') + break; + + std::complex<double> c; + if (client::parse_complex(str.begin(), str.end(), c)) + { + std::cout << "-------------------------\n"; + + std::string generated; + std::back_insert_iterator<std::string> sink(generated); + if (!client::generate_complex(sink, c)) + { + std::cout << "-------------------------\n"; + std::cout << "Generating failed\n"; + std::cout << "-------------------------\n"; + } + else + { + std::cout << "-------------------------\n"; + std::cout << "Generated: " << generated << "\n"; + std::cout << "-------------------------\n"; + } + } + else + { + std::cout << "-------------------------\n"; + std::cout << "Parsing failed\n"; + std::cout << "-------------------------\n"; + } + } + + std::cout << "Bye... :-) \n\n"; + return 0; +} + + diff --git a/src/boost/libs/spirit/example/karma/customize_counter.cpp b/src/boost/libs/spirit/example/karma/customize_counter.cpp new file mode 100644 index 00000000..62506928 --- /dev/null +++ b/src/boost/libs/spirit/example/karma/customize_counter.cpp @@ -0,0 +1,127 @@ +/*============================================================================= + Copyright (c) 2001-2011 Hartmut Kaiser + http://spirit.sourceforge.net/ + + 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) +=============================================================================*/ +#include <boost/config/warning_disable.hpp> + +//[customize_karma_counter_includes +#include <boost/spirit/include/karma.hpp> +#include <iostream> +#include <vector> +//] + +/////////////////////////////////////////////////////////////////////////////// +//[customize_karma_counter_data +namespace client +{ + struct counter + { + // expose the current value of the counter as our iterator + typedef int iterator; + + // expose 'int' as the type of each generated element + typedef int type; + + counter(int max_count) + : counter_(0), max_count_(max_count) + {} + + int counter_; + int max_count_; + }; +} +//] + +//[customize_karma_counter_traits +// All specializations of attribute customization points have to be placed into +// the namespace boost::spirit::traits. +// +// Note that all templates below are specialized using the 'const' type. +// This is necessary as all attributes in Karma are 'const'. +namespace boost { namespace spirit { namespace traits +{ + // The specialization of the template 'is_container<>' will tell the + // library to treat the type 'client::counter' as a container providing + // the items to generate output from. + template <> + struct is_container<client::counter const> + : mpl::true_ + {}; + + // The specialization of the template 'container_iterator<>' will be + // invoked by the library to evaluate the iterator type to be used + // for iterating the data elements in the container. + template <> + struct container_iterator<client::counter const> + { + typedef client::counter::iterator type; + }; + + // The specialization of the templates 'begin_container<>' and + // 'end_container<>' below will be used by the library to get the iterators + // pointing to the begin and the end of the data to generate output from. + // These specializations respectively return the initial and maximum + // counter values. + // + // The passed argument refers to the attribute instance passed to the list + // generator. + template <> + struct begin_container<client::counter const> + { + static client::counter::iterator + call(client::counter const& c) + { + return c.counter_; + } + }; + + template <> + struct end_container<client::counter const> + { + static client::counter::iterator + call(client::counter const& c) + { + return c.max_count_; + } + }; +}}} +//] + +//[customize_karma_counter_iterator_traits +// All specializations of attribute customization points have to be placed into +// the namespace boost::spirit::traits. +namespace boost { namespace spirit { namespace traits +{ + // The specialization of the template 'deref_iterator<>' will be used to + // dereference the iterator associated with our counter data structure. + // Since we expose the current value as the iterator we just return the + // current iterator as the return value. + template <> + struct deref_iterator<client::counter::iterator> + { + typedef client::counter::type type; + + static type call(client::counter::iterator const& it) + { + return it; + } + }; +}}} +//] + +/////////////////////////////////////////////////////////////////////////////// +namespace karma = boost::spirit::karma; + +int main() +{ + //[customize_karma_counter + // use the instance of a 'client::counter' instead of a STL vector + client::counter count(4); + std::cout << karma::format(karma::int_ % ", ", count) << std::endl; // prints: '0, 1, 2, 3' + //] + return 0; +} + diff --git a/src/boost/libs/spirit/example/karma/customize_embedded_container.cpp b/src/boost/libs/spirit/example/karma/customize_embedded_container.cpp new file mode 100644 index 00000000..c0c071b4 --- /dev/null +++ b/src/boost/libs/spirit/example/karma/customize_embedded_container.cpp @@ -0,0 +1,108 @@ +/*============================================================================= + Copyright (c) 2001-2011 Hartmut Kaiser + http://spirit.sourceforge.net/ + + 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) +=============================================================================*/ +#include <boost/config/warning_disable.hpp> + +//[customize_karma_embedded_container_includes +#include <boost/spirit/include/karma.hpp> +#include <iostream> +#include <vector> +//] + +/////////////////////////////////////////////////////////////////////////////// +//[customize_karma_embedded_container_data +namespace client +{ + struct embedded_container + { + // expose the iterator of the embedded vector as our iterator + typedef std::vector<int>::const_iterator iterator; + + // expose the type of the held data elements as our type + typedef std::vector<int>::value_type type; + + // this is the vector holding the actual elements we need to generate + // output from + std::vector<int> data; + }; +} +//] + +//[customize_karma_embedded_container_traits +// All specializations of attribute customization points have to be placed into +// the namespace boost::spirit::traits. +// +// Note that all templates below are specialized using the 'const' type. +// This is necessary as all attributes in Karma are 'const'. +namespace boost { namespace spirit { namespace traits +{ + // The specialization of the template 'is_container<>' will tell the + // library to treat the type 'client::embedded_container' as a + // container holding the items to generate output from. + template <> + struct is_container<client::embedded_container const> + : mpl::true_ + {}; + + // The specialization of the template 'container_iterator<>' will be + // invoked by the library to evaluate the iterator type to be used + // for iterating the data elements in the container. We simply return + // the type of the iterator exposed by the embedded 'std::vector<int>'. + template <> + struct container_iterator<client::embedded_container const> + { + typedef client::embedded_container::iterator type; + }; + + // The specialization of the templates 'begin_container<>' and + // 'end_container<>' below will be used by the library to get the iterators + // pointing to the begin and the end of the data to generate output from. + // These specializations simply return the 'begin' and 'end' iterators as + // exposed by the embedded 'std::vector<int>'. + // + // The passed argument refers to the attribute instance passed to the list + // generator. + template <> + struct begin_container<client::embedded_container const> + { + static client::embedded_container::iterator + call(client::embedded_container const& d) + { + return d.data.begin(); + } + }; + + template <> + struct end_container<client::embedded_container const> + { + static client::embedded_container::iterator + call(client::embedded_container const& d) + { + return d.data.end(); + } + }; +}}} +//] + +/////////////////////////////////////////////////////////////////////////////// +namespace karma = boost::spirit::karma; + +int main() +{ + //[customize_karma_embedded_container + client::embedded_container d1; // create some test data + d1.data.push_back(1); + d1.data.push_back(2); + d1.data.push_back(3); + + // use the instance of an 'client::embedded_container' instead of a + // STL vector + std::cout << karma::format(karma::int_ % ", ", d1) << std::endl; // prints: '1, 2, 3' + //] + return 0; +} + diff --git a/src/boost/libs/spirit/example/karma/customize_use_as_container.cpp b/src/boost/libs/spirit/example/karma/customize_use_as_container.cpp new file mode 100644 index 00000000..c0116c8a --- /dev/null +++ b/src/boost/libs/spirit/example/karma/customize_use_as_container.cpp @@ -0,0 +1,164 @@ +/*============================================================================= + Copyright (c) 2001-2011 Hartmut Kaiser + http://spirit.sourceforge.net/ + + 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) +=============================================================================*/ +#include <boost/config/warning_disable.hpp> + +//[customize_karma_use_as_container_includes +#include <boost/spirit/include/karma.hpp> +#include <iostream> +#include <string> +#include <vector> +//] + +/////////////////////////////////////////////////////////////////////////////// +//[customize_karma_use_as_container_data +namespace client +{ + struct use_as_container + { + // Expose a pair holding a pointer to the use_as_container and to the + // current element as our iterator. + // We intentionally leave out having it a 'operator==()' to demonstrate + // the use of the 'compare_iterators' customization point. + struct iterator + { + iterator(use_as_container const* container, int const* current) + : container_(container), current_(current) + {} + + use_as_container const* container_; + int const* current_; + }; + + // expose 'int' as the type of each generated element + typedef int type; + + use_as_container(int value1, int value2, int value3) + : value1_(value1), value2_(value2), value3_(value3) + {} + + int value1_; + std::string dummy1_; // insert some unrelated data + int value2_; + std::string dummy2_; // insert some more unrelated data + int value3_; + }; +} +//] + +//[customize_karma_use_as_container_traits +// All specializations of attribute customization points have to be placed into +// the namespace boost::spirit::traits. +// +// Note that all templates below are specialized using the 'const' type. +// This is necessary as all attributes in Karma are 'const'. +namespace boost { namespace spirit { namespace traits +{ + // The specialization of the template 'is_container<>' will tell the + // library to treat the type 'client::use_as_container' as a + // container holding the items to generate output from. + template <> + struct is_container<client::use_as_container const> + : mpl::true_ + {}; + + // The specialization of the template 'container_iterator<>' will be + // invoked by the library to evaluate the iterator type to be used + // for iterating the data elements in the container. We simply return + // the type of the iterator exposed by the embedded 'std::vector<int>'. + template <> + struct container_iterator<client::use_as_container const> + { + typedef client::use_as_container::iterator type; + }; + + // The specialization of the templates 'begin_container<>' and + // 'end_container<>' below will be used by the library to get the iterators + // pointing to the begin and the end of the data to generate output from. + // + // The passed argument refers to the attribute instance passed to the list + // generator. + template <> + struct begin_container<client::use_as_container const> + { + static client::use_as_container::iterator + call(client::use_as_container const& c) + { + return client::use_as_container::iterator(&c, &c.value1_); + } + }; + + template <> + struct end_container<client::use_as_container const> + { + static client::use_as_container::iterator + call(client::use_as_container const& c) + { + return client::use_as_container::iterator(&c, (int const*)0); + } + }; +}}} +//] + +//[customize_karma_use_as_container_iterator_traits +// All specializations of attribute customization points have to be placed into +// the namespace boost::spirit::traits. +namespace boost { namespace spirit { namespace traits +{ + // The specialization of the template 'deref_iterator<>' will be used to + // dereference the iterator associated with our counter data structure. + template <> + struct deref_iterator<client::use_as_container::iterator> + { + typedef client::use_as_container::type type; + + static type call(client::use_as_container::iterator const& it) + { + return *it.current_; + } + }; + + template <> + struct next_iterator<client::use_as_container::iterator> + { + static void call(client::use_as_container::iterator& it) + { + if (it.current_ == &it.container_->value1_) + it.current_ = &it.container_->value2_; + else if (it.current_ == &it.container_->value2_) + it.current_ = &it.container_->value3_; + else + it.current_ = 0; + } + }; + + template <> + struct compare_iterators<client::use_as_container::iterator> + { + static bool call(client::use_as_container::iterator const& it1 + , client::use_as_container::iterator const& it2) + { + return it1.current_ == it2.current_ && + it1.container_ == it2.container_; + } + }; +}}} +//] + +/////////////////////////////////////////////////////////////////////////////// +namespace karma = boost::spirit::karma; + +int main() +{ + //[customize_karma_use_as_container + client::use_as_container d2 (1, 2, 3); + // use the instance of a 'client::use_as_container' instead of a STL vector + std::cout << karma::format(karma::int_ % ", ", d2) << std::endl; // prints: '1, 2, 3' + //] + return 0; +} + diff --git a/src/boost/libs/spirit/example/karma/escaped_string.cpp b/src/boost/libs/spirit/example/karma/escaped_string.cpp new file mode 100644 index 00000000..f3c2fe6f --- /dev/null +++ b/src/boost/libs/spirit/example/karma/escaped_string.cpp @@ -0,0 +1,66 @@ +// Copyright (c) 2001-2010 Hartmut Kaiser +// +// 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) + +// The purpose of this example is to show how any character sequence can be +// printed while being properly quoted. + +#include <boost/config/warning_disable.hpp> +#include <boost/spirit/include/karma.hpp> + +namespace client +{ + namespace karma = boost::spirit::karma; + + template <typename OutputIterator> + struct escaped_string + : karma::grammar<OutputIterator, std::string(char const*)> + { + escaped_string() + : escaped_string::base_type(esc_str) + { + esc_char.add('\a', "\\a")('\b', "\\b")('\f', "\\f")('\n', "\\n") + ('\r', "\\r")('\t', "\\t")('\v', "\\v")('\\', "\\\\") + ('\'', "\\\'")('\"', "\\\"") + ; + + esc_str = karma::lit(karma::_r1) + << *(esc_char | karma::print | "\\x" << karma::hex) + << karma::lit(karma::_r1) + ; + } + + karma::rule<OutputIterator, std::string(char const*)> esc_str; + karma::symbols<char, char const*> esc_char; + }; +} + +/////////////////////////////////////////////////////////////////////////////// +int main() +{ + namespace karma = boost::spirit::karma; + + typedef std::back_insert_iterator<std::string> sink_type; + + std::string generated; + sink_type sink(generated); + + std::string str("string to escape: \n\r\t\"'\x19"); + char const* quote = "'''"; + + client::escaped_string<sink_type> g; + if (!karma::generate(sink, g(quote), str)) + { + std::cout << "-------------------------\n"; + std::cout << "Generating failed\n"; + std::cout << "-------------------------\n"; + } + else + { + std::cout << "-------------------------\n"; + std::cout << "Generated: " << generated << "\n"; + std::cout << "-------------------------\n"; + } + return 0; +} diff --git a/src/boost/libs/spirit/example/karma/generate_code.cpp b/src/boost/libs/spirit/example/karma/generate_code.cpp new file mode 100644 index 00000000..3a409a77 --- /dev/null +++ b/src/boost/libs/spirit/example/karma/generate_code.cpp @@ -0,0 +1,80 @@ +// Copyright (c) 2001-2010 Hartmut Kaiser +// +// 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) + +/////////////////////////////////////////////////////////////////////////////// +// +// Several small snippets generating different C++ code constructs +// +// [ HK October 08, 2009 ] Spirit V2.2 +// +/////////////////////////////////////////////////////////////////////////////// + +#include <boost/config/warning_disable.hpp> +#include <boost/spirit/include/karma.hpp> +#include <boost/spirit/include/phoenix.hpp> + +#include <iostream> +#include <string> +#include <complex> + +namespace client +{ + namespace karma = boost::spirit::karma; + namespace phoenix = boost::phoenix; + + // create for instance: int name[5] = { 1, 2, 3, 4, 5 }; + template <typename Iterator> + struct int_array : karma::grammar<Iterator, std::vector<int>()> + { + int_array(char const* name) : int_array::base_type(start) + { + using karma::int_; + using karma::uint_; + using karma::eol; + using karma::lit; + using karma::_val; + using karma::_r1; + + start = array_def(phoenix::size(_val)) << " = " << initializer + << ';' << eol; + array_def = "int " << lit(name) << "[" << uint_(_r1) << "]"; + initializer = "{ " << -(int_ % ", ") << " }"; + } + + karma::rule<Iterator, void(unsigned)> array_def; + karma::rule<Iterator, std::vector<int>()> initializer; + karma::rule<Iterator, std::vector<int>()> start; + }; + + typedef std::back_insert_iterator<std::string> iterator_type; + bool generate_array(char const* name, std::vector<int> const& v) + { + std::string generated; + iterator_type sink(generated); + int_array<iterator_type> g(name); + if (karma::generate(sink, g, v)) + { + std::cout << generated; + return true; + } + return false; + } +} + +/////////////////////////////////////////////////////////////////////////////// +// Main program +/////////////////////////////////////////////////////////////////////////////// +int main() +{ + // generate an array of integers with initializers + std::vector<int> v; + v.push_back(1); + v.push_back(2); + v.push_back(3); + v.push_back(4); + client::generate_array("array1", v); + + return 0; +} diff --git a/src/boost/libs/spirit/example/karma/key_value_sequence.cpp b/src/boost/libs/spirit/example/karma/key_value_sequence.cpp new file mode 100644 index 00000000..db2de2cc --- /dev/null +++ b/src/boost/libs/spirit/example/karma/key_value_sequence.cpp @@ -0,0 +1,74 @@ +// Copyright (c) 2001-2010 Hartmut Kaiser +// +// 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) + +// The main purpose of this example is to show how we can generate output from +// a container holding key/value pairs. +// +// For more information see here: http://spirit.sourceforge.net/home/?p=400 + +#include <boost/config/warning_disable.hpp> +#include <boost/spirit/include/karma.hpp> +#include <boost/spirit/include/karma_stream.hpp> +#include <boost/spirit/include/phoenix.hpp> +#include <boost/fusion/include/std_pair.hpp> + +#include <iostream> +#include <map> +#include <algorithm> +#include <cstdlib> + +namespace client +{ + namespace karma = boost::spirit::karma; + + typedef std::pair<std::string, boost::optional<std::string> > pair_type; + + template <typename OutputIterator> + struct keys_and_values + : karma::grammar<OutputIterator, std::vector<pair_type>()> + { + keys_and_values() + : keys_and_values::base_type(query) + { + query = pair << *('&' << pair); + pair = karma::string << -('=' << karma::string); + } + + karma::rule<OutputIterator, std::vector<pair_type>()> query; + karma::rule<OutputIterator, pair_type()> pair; + }; +} + +/////////////////////////////////////////////////////////////////////////////// +int main() +{ + namespace karma = boost::spirit::karma; + + typedef std::vector<client::pair_type>::value_type value_type; + typedef std::back_insert_iterator<std::string> sink_type; + + std::vector<client::pair_type> v; + v.push_back(value_type("key1", boost::optional<std::string>("value1"))); + v.push_back(value_type("key2", boost::optional<std::string>())); + v.push_back(value_type("key3", boost::optional<std::string>(""))); + + std::string generated; + sink_type sink(generated); + client::keys_and_values<sink_type> g; + if (!karma::generate(sink, g, v)) + { + std::cout << "-------------------------\n"; + std::cout << "Generating failed\n"; + std::cout << "-------------------------\n"; + } + else + { + std::cout << "-------------------------\n"; + std::cout << "Generated: " << generated << "\n"; + std::cout << "-------------------------\n"; + } + return 0; +} + diff --git a/src/boost/libs/spirit/example/karma/mini_xml_karma.cpp b/src/boost/libs/spirit/example/karma/mini_xml_karma.cpp new file mode 100644 index 00000000..596fd78c --- /dev/null +++ b/src/boost/libs/spirit/example/karma/mini_xml_karma.cpp @@ -0,0 +1,222 @@ +/*============================================================================= + Copyright (c) 2001-2010 Joel de Guzman + Copyright (c) 2001-2010 Hartmut Kaiser + + 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 mini XML-like parser, Karma is used to print out the generated AST +// +// [ JDG March 25, 2007 ] spirit2 +// [ HK April 02, 2007 ] spirit2 +// +/////////////////////////////////////////////////////////////////////////////// + +#include <boost/config/warning_disable.hpp> + +#include <boost/spirit/include/qi.hpp> +#include <boost/spirit/include/karma.hpp> +#include <boost/spirit/include/phoenix_core.hpp> +#include <boost/spirit/include/phoenix_operator.hpp> +#include <boost/spirit/include/phoenix_fusion.hpp> +#include <boost/spirit/include/phoenix_function.hpp> +#include <boost/spirit/include/phoenix_stl.hpp> +#include <boost/fusion/include/adapt_struct.hpp> +#include <boost/variant/recursive_variant.hpp> + +#include <iostream> +#include <fstream> +#include <string> +#include <vector> + +using namespace boost::spirit; +using namespace boost::spirit::ascii; + +namespace fusion = boost::fusion; +namespace phoenix = boost::phoenix; + +using phoenix::at_c; +using phoenix::push_back; + +/////////////////////////////////////////////////////////////////////////////// +// Our mini XML tree representation +/////////////////////////////////////////////////////////////////////////////// +struct mini_xml; + +typedef + boost::variant< + boost::recursive_wrapper<mini_xml> + , std::string + > +mini_xml_node; + +struct mini_xml +{ + std::string name; // tag name + std::vector<mini_xml_node> children; // children +}; + +// We need to tell fusion about our mini_xml struct +// to make it a first-class fusion citizen +BOOST_FUSION_ADAPT_STRUCT( + mini_xml, + (std::string, name) + (std::vector<mini_xml_node>, children) +) + +/////////////////////////////////////////////////////////////////////////////// +// Our mini XML grammar definition +/////////////////////////////////////////////////////////////////////////////// +template <typename Iterator> +struct mini_xml_parser : + qi::grammar<Iterator, mini_xml(), space_type> +{ + mini_xml_parser() : mini_xml_parser::base_type(xml) + { + text = lexeme[+(char_ - '<') [_val += _1]]; + node = (xml | text) [_val = _1]; + + start_tag = + '<' + >> !lit('/') + >> lexeme[+(char_ - '>') [_val += _1]] + >> '>' + ; + + end_tag = + "</" + >> lit(_r1) + >> '>' + ; + + xml = + start_tag [at_c<0>(_val) = _1] + >> *node [push_back(at_c<1>(_val), _1)] + >> end_tag(at_c<0>(_val)) + ; + } + + qi::rule<Iterator, mini_xml(), space_type> xml; + qi::rule<Iterator, mini_xml_node(), space_type> node; + qi::rule<Iterator, std::string(), space_type> text; + qi::rule<Iterator, std::string(), space_type> start_tag; + qi::rule<Iterator, void(std::string), space_type> end_tag; +}; + +/////////////////////////////////////////////////////////////////////////////// +// A couple of phoenix functions helping to access the elements of the +// generated AST +/////////////////////////////////////////////////////////////////////////////// +template <typename T> +struct get_element +{ + template <typename T1> + struct result { typedef T const& type; }; + + T const& operator()(mini_xml_node const& node) const + { + return boost::get<T>(node); + } +}; + +phoenix::function<get_element<std::string> > _string; +phoenix::function<get_element<mini_xml> > _xml; + +/////////////////////////////////////////////////////////////////////////////// +// The output grammar defining the format of the generated data +/////////////////////////////////////////////////////////////////////////////// +template <typename OutputIterator> +struct mini_xml_generator + : karma::grammar<OutputIterator, mini_xml()> +{ + mini_xml_generator() : mini_xml_generator::base_type(xml) + { + node %= string | xml; + xml = + '<' << string[_1 = at_c<0>(_val)] << '>' + << (*node)[_1 = at_c<1>(_val)] + << "</" << string[_1 = at_c<0>(_val)] << '>' + ; + } + + karma::rule<OutputIterator, mini_xml()> xml; + karma::rule<OutputIterator, mini_xml_node()> node; +}; + +/////////////////////////////////////////////////////////////////////////////// +// Main program +/////////////////////////////////////////////////////////////////////////////// +int main(int argc, char **argv) +{ + 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)); + + typedef mini_xml_parser<std::string::const_iterator> mini_xml_parser; + mini_xml_parser xmlin; // Our grammar definition + mini_xml ast; // our tree + + std::string::const_iterator iter = storage.begin(); + std::string::const_iterator end = storage.end(); + bool r = qi::phrase_parse(iter, end, xmlin, space, ast); + + if (r && iter == end) + { + std::cout << "-------------------------\n"; + std::cout << "Parsing succeeded\n"; + std::cout << "-------------------------\n"; + + typedef std::back_insert_iterator<std::string> outiter_type; + typedef mini_xml_generator<outiter_type> mini_xml_generator; + + mini_xml_generator xmlout; // Our grammar definition + + std::string generated; + outiter_type outit(generated); + bool r = karma::generate(outit, xmlout, ast); + + if (r) + std::cout << generated << std::endl; + return 0; + } + else + { + std::string::const_iterator begin = storage.begin(); + std::size_t dist = std::distance(begin, iter); + std::string::const_iterator some = + iter + (std::min)(storage.size()-dist, std::size_t(30)); + std::string context(iter, some); + std::cout << "-------------------------\n"; + std::cout << "Parsing failed\n"; + std::cout << "stopped at: \": " << context << "...\"\n"; + std::cout << "-------------------------\n"; + return 1; + } +} + + diff --git a/src/boost/libs/spirit/example/karma/num_list1.cpp b/src/boost/libs/spirit/example/karma/num_list1.cpp new file mode 100644 index 00000000..7b079b04 --- /dev/null +++ b/src/boost/libs/spirit/example/karma/num_list1.cpp @@ -0,0 +1,121 @@ +/*============================================================================= + Copyright (c) 2002-2010 Hartmut Kaiser + Copyright (c) 2002-2010 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) +=============================================================================*/ +/////////////////////////////////////////////////////////////////////////////// +// +// This sample demonstrates a generator for a comma separated list of numbers. +// No actions. It is based on the example qi/num_lists.cpp for reading in +// some numbers to generate. +// +/////////////////////////////////////////////////////////////////////////////// + +#include <boost/config/warning_disable.hpp> +#include <boost/spirit/include/qi.hpp> +#include <boost/spirit/include/karma.hpp> + +#include <iostream> +#include <string> +#include <list> + +namespace client +{ + namespace qi = boost::spirit::qi; + namespace karma = boost::spirit::karma; + namespace ascii = boost::spirit::ascii; + + /////////////////////////////////////////////////////////////////////////// + // Our number list parser, please see the example qi/numlist1.cpp for + // more information + /////////////////////////////////////////////////////////////////////////// + template <typename Iterator> + bool parse_numbers(Iterator first, Iterator last, std::list<double>& v) + { + using qi::double_; + using qi::phrase_parse; + using ascii::space; + + bool r = phrase_parse(first, last, double_ >> *(',' >> double_), space, v); + if (first != last) + return false; + return r; + } + + /////////////////////////////////////////////////////////////////////////// + // Our number list generator + /////////////////////////////////////////////////////////////////////////// + //[tutorial_karma_numlist1 + template <typename OutputIterator> + bool generate_numbers(OutputIterator& sink, std::list<double> const& v) + { + using karma::double_; + using karma::generate_delimited; + using ascii::space; + + bool r = generate_delimited( + sink, // destination: output iterator + double_ << *(',' << double_), // the generator + space, // the delimiter-generator + v // the data to output + ); + return r; + } + //] +} + +//////////////////////////////////////////////////////////////////////////// +// Main program +//////////////////////////////////////////////////////////////////////////// +int +main() +{ + std::cout << "/////////////////////////////////////////////////////////\n\n"; + std::cout << "\t\tA comma separated list generator for Spirit...\n\n"; + std::cout << "/////////////////////////////////////////////////////////\n\n"; + + std::cout << "Give me a comma separated list of numbers.\n"; + std::cout << "Type [q or Q] to quit\n\n"; + + std::string str; + while (getline(std::cin, str)) + { + if (str.empty() || str[0] == 'q' || str[0] == 'Q') + break; + + std::list<double> v; // here we put the data to generate + if (client::parse_numbers(str.begin(), str.end(), v)) + { + // ok, we got some numbers, now print them back out + std::cout << "-------------------------\n"; + + std::string generated; + std::back_insert_iterator<std::string> sink(generated); + if (!client::generate_numbers(sink, v)) + { + std::cout << "-------------------------\n"; + std::cout << "Generating failed\n"; + std::cout << "-------------------------\n"; + } + else + { + std::cout << "-------------------------\n"; + std::cout << "Generated: " << generated << "\n"; + std::cout << "-------------------------\n"; + } + } + else + { + std::cout << "-------------------------\n"; + std::cout << "Parsing failed\n"; + std::cout << "-------------------------\n"; + } + } + + std::cout << "Bye... :-) \n\n"; + return 0; +} + + diff --git a/src/boost/libs/spirit/example/karma/num_list2.cpp b/src/boost/libs/spirit/example/karma/num_list2.cpp new file mode 100644 index 00000000..ce16fafe --- /dev/null +++ b/src/boost/libs/spirit/example/karma/num_list2.cpp @@ -0,0 +1,117 @@ +/*============================================================================= + Copyright (c) 2002-2010 Hartmut Kaiser + Copyright (c) 2002-2010 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) +=============================================================================*/ +/////////////////////////////////////////////////////////////////////////////// +// +// This sample demonstrates a generator for a comma separated list of numbers. +// No actions. It is based on the example qi/num_lists.cpp for reading in +// some numbers to generate. +// +/////////////////////////////////////////////////////////////////////////////// + +#include <boost/config/warning_disable.hpp> +#include <boost/spirit/include/qi.hpp> +#include <boost/spirit/include/karma.hpp> + +#include <iostream> +#include <string> +#include <vector> + +namespace client +{ + /////////////////////////////////////////////////////////////////////////// + // Our number list parser, please see the example qi/numlist1.cpp for + // more information + /////////////////////////////////////////////////////////////////////////// + template <typename Iterator> + bool parse_numbers(Iterator first, Iterator last, std::vector<double>& v) + { + using boost::spirit::qi::double_; + using boost::spirit::qi::phrase_parse; + using boost::spirit::ascii::space; + + bool r = phrase_parse(first, last, double_ % ',', space, v); + if (first != last) + return false; + return r; + } + + /////////////////////////////////////////////////////////////////////////// + // Our number list generator + /////////////////////////////////////////////////////////////////////////// + //[tutorial_karma_numlist2 + template <typename OutputIterator, typename Container> + bool generate_numbers(OutputIterator& sink, Container const& v) + { + using boost::spirit::karma::double_; + using boost::spirit::karma::generate_delimited; + using boost::spirit::ascii::space; + + bool r = generate_delimited( + sink, // destination: output iterator + double_ % ',', // the generator + space, // the delimiter-generator + v // the data to output + ); + return r; + } + //] +} + +//////////////////////////////////////////////////////////////////////////// +// Main program +//////////////////////////////////////////////////////////////////////////// +int +main() +{ + std::cout << "/////////////////////////////////////////////////////////\n\n"; + std::cout << "\t\tA comma separated list generator for Spirit...\n\n"; + std::cout << "/////////////////////////////////////////////////////////\n\n"; + + std::cout << "Give me a comma separated list of numbers.\n"; + std::cout << "Type [q or Q] to quit\n\n"; + + std::string str; + while (getline(std::cin, str)) + { + if (str.empty() || str[0] == 'q' || str[0] == 'Q') + break; + + std::vector<double> v; // here we put the data to generate + if (client::parse_numbers(str.begin(), str.end(), v)) + { + // ok, we got some numbers, now print them back out + std::cout << "-------------------------\n"; + + std::string generated; + std::back_insert_iterator<std::string> sink(generated); + if (!client::generate_numbers(sink, v)) + { + std::cout << "-------------------------\n"; + std::cout << "Generating failed\n"; + std::cout << "-------------------------\n"; + } + else + { + std::cout << "-------------------------\n"; + std::cout << "Generated: " << generated << "\n"; + std::cout << "-------------------------\n"; + } + } + else + { + std::cout << "-------------------------\n"; + std::cout << "Parsing failed\n"; + std::cout << "-------------------------\n"; + } + } + + std::cout << "Bye... :-) \n\n"; + return 0; +} + + diff --git a/src/boost/libs/spirit/example/karma/num_list3.cpp b/src/boost/libs/spirit/example/karma/num_list3.cpp new file mode 100644 index 00000000..253de1b4 --- /dev/null +++ b/src/boost/libs/spirit/example/karma/num_list3.cpp @@ -0,0 +1,150 @@ +/*============================================================================= + Copyright (c) 2002-2010 Hartmut Kaiser + Copyright (c) 2002-2010 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) +=============================================================================*/ +/////////////////////////////////////////////////////////////////////////////// +// +// This sample demonstrates a generator for a comma separated list of numbers. +// No actions. It is based on the example qi/num_lists.cpp for reading in +// some numbers to generate. +// +/////////////////////////////////////////////////////////////////////////////// + +#include <boost/config/warning_disable.hpp> +#include <boost/spirit/include/qi.hpp> +#include <boost/spirit/include/karma.hpp> + +#include <iostream> +#include <string> +#include <vector> + +namespace client +{ + /////////////////////////////////////////////////////////////////////////// + // Our number list parser, please see the example qi/numlist1.cpp for + // more information + /////////////////////////////////////////////////////////////////////////// + template <typename Iterator> + bool parse_numbers(Iterator first, Iterator last, std::vector<double>& v) + { + using boost::spirit::qi::double_; + using boost::spirit::qi::phrase_parse; + using boost::spirit::ascii::space; + + bool r = phrase_parse(first, last, double_ % ',', space, v); + if (first != last) + return false; + return r; + } + + //[tutorial_karma_numlist3_complex + // a simple complex number representation z = a + bi + struct complex + { + complex (double a, double b = 0.0) : a(a), b(b) {} + + double a; + double b; + }; + + // the streaming operator for the type complex + std::ostream& + operator<< (std::ostream& os, complex const& z) + { + os << "{" << z.a << "," << z.b << "}"; + return os; + } + //] + + /////////////////////////////////////////////////////////////////////////// + // Our number list generator + /////////////////////////////////////////////////////////////////////////// + //[tutorial_karma_numlist3 + template <typename OutputIterator, typename Container> + bool generate_numbers(OutputIterator& sink, Container const& v) + { + using boost::spirit::karma::stream; + using boost::spirit::karma::generate; + using boost::spirit::karma::eol; + + bool r = generate( + sink, // destination: output iterator + stream % eol, // the generator + v // the data to output + ); + return r; + } + //] +} + +//////////////////////////////////////////////////////////////////////////// +// Main program +//////////////////////////////////////////////////////////////////////////// +int +main() +{ + std::cout << "/////////////////////////////////////////////////////////\n\n"; + std::cout << "\tA comma separated list generator for Spirit...\n\n"; + std::cout << "/////////////////////////////////////////////////////////\n\n"; + + std::cout << "Give me a comma separated list of numbers.\n"; + std::cout << "Type [q or Q] to quit\n\n"; + + std::string str; + while (getline(std::cin, str)) + { + if (str.empty() || str[0] == 'q' || str[0] == 'Q') + break; + + std::vector<double> v; // here we put the data gotten from input + if (client::parse_numbers(str.begin(), str.end(), v)) + { + // ok, we got some numbers, fill a vector of client::complex + // instances and print them back out + std::vector<client::complex> vc; + std::vector<double>::const_iterator end = v.end(); + for (std::vector<double>::const_iterator it = v.begin(); + it != end; ++it) + { + double real(*it); + if (++it != end) + vc.push_back(client::complex(real, *it)); + else { + vc.push_back(client::complex(real)); + break; + } + } + + std::cout << "-------------------------\n"; + + std::string generated; + std::back_insert_iterator<std::string> sink(generated); + if (!client::generate_numbers(sink, vc)) + { + std::cout << "-------------------------\n"; + std::cout << "Generating failed\n"; + std::cout << "-------------------------\n"; + } + else + { + std::cout << "-------------------------\n"; + std::cout << "Generated:\n" << generated << "\n"; + std::cout << "-------------------------\n"; + } + } + else + { + std::cout << "-------------------------\n"; + std::cout << "Parsing failed\n"; + std::cout << "-------------------------\n"; + } + } + + std::cout << "Bye... :-) \n\n"; + return 0; +} + + diff --git a/src/boost/libs/spirit/example/karma/num_matrix.cpp b/src/boost/libs/spirit/example/karma/num_matrix.cpp new file mode 100644 index 00000000..0622e096 --- /dev/null +++ b/src/boost/libs/spirit/example/karma/num_matrix.cpp @@ -0,0 +1,114 @@ +/*============================================================================= + Copyright (c) 2002-2010 Hartmut Kaiser + Copyright (c) 2002-2010 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) +=============================================================================*/ +/////////////////////////////////////////////////////////////////////////////// +// +// This sample demonstrates a generator formatting and printing a matrix +// of integers taken from a simple vector of vectors. The size and the +// contents of the printed matrix is generated randomly. +// +/////////////////////////////////////////////////////////////////////////////// + +#include <boost/config/warning_disable.hpp> +#include <boost/spirit/include/karma.hpp> + +#include <iostream> +#include <string> +#include <vector> +#include <cstdlib> +#include <ctime> + +namespace karma = boost::spirit::karma; + +namespace client +{ + /////////////////////////////////////////////////////////////////////////// + // Our matrix generator + /////////////////////////////////////////////////////////////////////////// + //[tutorial_karma_nummatrix_grammar + template <typename OutputIterator> + struct matrix_grammar + : karma::grammar<OutputIterator, std::vector<std::vector<int> >()> + { + matrix_grammar() + : matrix_grammar::base_type(matrix) + { + using karma::int_; + using karma::right_align; + using karma::eol; + + element = right_align(10)[int_]; + row = '|' << *element << '|'; + matrix = row % eol; + } + + karma::rule<OutputIterator, std::vector<std::vector<int> >()> matrix; + karma::rule<OutputIterator, std::vector<int>()> row; + karma::rule<OutputIterator, int()> element; + }; + //] + + //[tutorial_karma_nummatrix + template <typename OutputIterator> + bool generate_matrix(OutputIterator& sink + , std::vector<std::vector<int> > const& v) + { + matrix_grammar<OutputIterator> matrix; + return karma::generate( + sink, // destination: output iterator + matrix, // the generator + v // the data to output + ); + } + //] +} + +//////////////////////////////////////////////////////////////////////////// +// Main program +//////////////////////////////////////////////////////////////////////////// +int +main() +{ + std::cout << "/////////////////////////////////////////////////////////\n\n"; + std::cout << "\tPrinting integers in a matrix using Spirit...\n\n"; + std::cout << "/////////////////////////////////////////////////////////\n\n"; + + // here we put the data to generate + std::vector<std::vector<int> > v; + + // now, generate the size and the contents for the matrix + std::srand((unsigned int)std::time(NULL)); + std::size_t rows = std::rand() / (RAND_MAX / 10); + std::size_t columns = std::rand() / (RAND_MAX / 10); + + v.resize(rows); + for (std::size_t row = 0; row < rows; ++row) + { + v[row].resize(columns); + std::generate(v[row].begin(), v[row].end(), std::rand); + } + + // ok, we got the matrix, now print it out + std::string generated; + std::back_insert_iterator<std::string> sink(generated); + if (!client::generate_matrix(sink, v)) + { + std::cout << "-------------------------\n"; + std::cout << "Generating failed\n"; + std::cout << "-------------------------\n"; + } + else + { + std::cout << "-------------------------\n"; + std::cout << "Generated:\n" << generated << "\n"; + std::cout << "-------------------------\n"; + } + + return 0; +} + + diff --git a/src/boost/libs/spirit/example/karma/printf_style_double_format.cpp b/src/boost/libs/spirit/example/karma/printf_style_double_format.cpp new file mode 100644 index 00000000..b1c094da --- /dev/null +++ b/src/boost/libs/spirit/example/karma/printf_style_double_format.cpp @@ -0,0 +1,282 @@ +// Copyright (c) 2001-2010 Hartmut Kaiser +// +// 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) + +// The main purpose of this example is to show how a single container type can +// be formatted using different output grammars. + +#include <boost/config/warning_disable.hpp> +#include <boost/spirit/include/qi.hpp> +#include <boost/spirit/include/karma.hpp> +#include <boost/fusion/include/adapt_struct.hpp> + +#include <cmath> + +using namespace boost::spirit; + +/////////////////////////////////////////////////////////////////////////////// +// This policy allows to use printf style formatting specifiers for Karma +// floating point generators. This policy understands the following format: +// +// The format string must conform to the following format, otherwise a +// std::runtime_error will be thrown: +// +// %[flags][fill][width][.precision]type +// +// where: +// flags (only one possible): +// +: Always denote the sign '+' or '-' of a number +// -: Left-align the output +// fill: +// 0: Uses 0 instead of spaces to left-fill a fixed-length field +// width: +// number: Left-pad the output with spaces until it is at least number +// characters wide. if number has a leading '0', that is +// interpreted as a 'fill', the padding is done with '0' +// characters instead of spaces. +// precision: +// number: Causes the decimal portion of the output to be expressed +// in at least number digits +// type (only one possible): +// e: force scientific notation, with a lowercase "e" +// E: force scientific notation, with a uppercase "E" +// f: floating point format +// g: use %e or %f, whichever is shorter +// G: use %E or %f, whichever is shorter +// + +/////////////////////////////////////////////////////////////////////////////// +// define a data structure and a corresponding parser to hold the formatting +// information extracted from the format specification string +namespace client +{ + struct format_data + { + char flag; + char fill; + int width; + int precision; + char type; + }; +} + +// We need to tell fusion about our format_data struct +// to make it a first-class fusion citizen +BOOST_FUSION_ADAPT_STRUCT( + client::format_data, + (char, flag) + (char, fill) + (int, width) + (int, precision) + (char, type) +) + +namespace client +{ + /////////////////////////////////////////////////////////////////////////// + // Grammar for format specification string as described above + template <typename Iterator> + struct format_grammar : qi::grammar<Iterator, format_data()> + { + format_grammar() : format_grammar::base_type(format) + { + using qi::uint_; + using qi::attr; + using ascii::char_; + using ascii::no_case; + + format %= '%' >> flags >> fill >> width >> prec >> type; + + // default flags is right aligned + flags = char_('+') | char_('-') | attr(' '); + fill = char_('0') | attr(' '); // default fill is space + width = uint_ | attr(-1); + prec = '.' >> uint_ | attr(3); // default is 3 digits + type = no_case[char_('e')] | char_('f') | no_case[char_('g')]; + }; + + qi::rule<Iterator, format_data()> format; + qi::rule<Iterator, char()> flags; + qi::rule<Iterator, char()> fill; + qi::rule<Iterator, int()> width; + qi::rule<Iterator, int()> prec; + qi::rule<Iterator, char()> type; + }; +} + +/////////////////////////////////////////////////////////////////////////////// +// real_policies implementation allowing to use a printf style format +// specification for Karma floating pointing number generators +template <typename T> +struct format_policies : karma::real_policies<T> +{ + typedef karma::real_policies<T> base_policy_type; + + /////////////////////////////////////////////////////////////////////////// + // This real_policies implementation requires the output_iterator to + // implement buffering and character counting. This needs to be reflected + // in the properties exposed by the generator + typedef boost::mpl::int_< + karma::generator_properties::countingbuffer + > properties; + + /////////////////////////////////////////////////////////////////////////// + format_policies(char const* fmt = "%f") + { + char const* last = fmt; + while (*last) + last++; + + client::format_grammar<char const*> g; + if (!qi::parse(fmt, last, g, format_)) + throw std::runtime_error("bad format string"); + } + + /////////////////////////////////////////////////////////////////////////// + // returns the overall format: scientific or fixed + int floatfield(T n) const + { + if (format_.type == 'e' || format_.type == 'E') + return base_policy_type::fmtflags::scientific; + + if (format_.type == 'f') + return base_policy_type::fmtflags::fixed; + + BOOST_ASSERT(format_.type == 'g' || format_.type == 'G'); + return this->base_policy_type::floatfield(n); + } + + /////////////////////////////////////////////////////////////////////////// + // returns whether to emit a sign even for non-negative numbers + bool const force_sign(T) const + { + return format_.flag == '+'; + } + + /////////////////////////////////////////////////////////////////////////// + // returns the number of required digits for the fractional part + unsigned precision(T) const + { + return format_.precision; + } + + /////////////////////////////////////////////////////////////////////////// + // emit the decimal dot + template <typename OutputIterator> + static bool dot (OutputIterator& sink, T n, unsigned precision) + { + // don't print the dot if no fractional digits are to be emitted + if (precision == 0) + return true; + return base_policy_type::dot(sink, n, precision); + } + + template <typename CharEncoding, typename Tag, typename OutputIterator> + bool exponent (OutputIterator& sink, long n) const + { + if (format_.type == 'E' || format_.type == 'G') { + // print exponent symbol in upper case + return this->base_policy_type:: + template exponent<char_encoding::ascii, tag::upper>(sink, n); + } + return this->base_policy_type:: + template exponent<CharEncoding, Tag>(sink, n); + } + + /////////////////////////////////////////////////////////////////////////// + // this gets called by the numeric generators at the top level, it allows + // to do alignment and other high level things + template <typename Inserter, typename OutputIterator, typename Policies> + bool call (OutputIterator& sink, T n, Policies const& p) const + { + bool r = false; + if (format_.flag == '-') { // left align + // wrap the given output iterator to allow counting + karma::detail::enable_counting<OutputIterator> counting(sink); + + // first generate the actual floating point number + r = Inserter::call_n(sink, n, p); + + // pad the output until the max width is reached + while(r && int(counting.count()) < format_.width) + r = karma::generate(sink, ' '); + } + else { // right align + // wrap the given output iterator to allow left padding + karma::detail::enable_buffering<OutputIterator> buffering( + sink, format_.width); + + // first generate the actual floating point number + { + karma::detail::disable_counting<OutputIterator> nocounting(sink); + r = Inserter::call_n(sink, n, p); + } + + buffering.disable(); // do not perform buffering any more + + // generate the left padding + karma::detail::enable_counting<OutputIterator> counting( + sink, buffering.buffer_size()); + while(r && int(counting.count()) < format_.width) + r = karma::generate(sink, format_.fill); + + // copy the buffered output to the target output iterator + if (r) + buffering.buffer_copy(); + } + return r; + } + + client::format_data format_; +}; + +/////////////////////////////////////////////////////////////////////////////// +// This is the generator usable in any Karma output format expression, it needs +// to be utilized as +// +// generate(sink, real("%6.3f"), 3.1415926536); // prints: ' 3.142' +// +// and it supports the format specification as described above. +typedef karma::real_generator<double, format_policies<double> > real; + +/////////////////////////////////////////////////////////////////////////////// +int main() +{ + std::cout << "/////////////////////////////////////////////////////////////\n\n"; + std::cout << "A format driven floating point number generator for Spirit...\n\n"; + std::cout << "/////////////////////////////////////////////////////////////\n\n"; + + std::cout << "Give me a printf style format\n"; + std::cout << "Type [enter] to quit\n\n"; + + std::string str; + while (getline(std::cin, str)) + { + if (str.empty()) + break; + + try { + std::string generated; + std::back_insert_iterator<std::string> sink(generated); + if (!karma::generate(sink, real(str.c_str()), 4*std::atan(1.0))) + { + std::cout << "-------------------------\n"; + std::cout << "Generating failed\n"; + std::cout << "-------------------------\n"; + } + else + { + std::cout << ">" << generated << "<\n"; + } + } + catch (std::runtime_error const&) { + std::cout << "-------------------------\n"; + std::cout << "Invalid format specified!\n"; + std::cout << "-------------------------\n"; + } + } + + return 0; +} + diff --git a/src/boost/libs/spirit/example/karma/quick_start1.cpp b/src/boost/libs/spirit/example/karma/quick_start1.cpp new file mode 100644 index 00000000..4a99b95c --- /dev/null +++ b/src/boost/libs/spirit/example/karma/quick_start1.cpp @@ -0,0 +1,119 @@ +// Copyright (c) 2001-2010 Hartmut Kaiser +// +// 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) + +// The main purpose of this example is to show how a single container type can +// be formatted using different output grammars. + +#include <boost/config/warning_disable.hpp> +#include <boost/spirit/include/karma.hpp> +#include <boost/spirit/include/karma_stream.hpp> + +#include <iostream> +#include <vector> +#include <algorithm> +#include <cstdlib> + +using namespace boost::spirit; +using namespace boost::spirit::ascii; + +/////////////////////////////////////////////////////////////////////////////// +int main() +{ + /////////////////////////////////////////////////////////////////////////// + // vector + std::vector<int> v (8); + std::generate(v.begin(), v.end(), std::rand); // randomly fill the vector + + std::cout << "Output 8 integers from a std::vector<int>..." << std::endl; + + // output the container as a sequence without any separation + std::cout << "...without any separation" << std::endl; + std::cout << + karma::format( + *int_, // format description + v // data + ) << std::endl << std::endl; + + // output the container as a space separated sequence + std::cout << "...as space delimited list" << std::endl; + std::cout << + karma::format_delimited( + *int_, // format description + space, // delimiter + v // data + ) << std::endl << std::endl; + + std::cout << + karma::format_delimited( + '[' << *int_ << ']', // format description + space, // delimiter + v // data + ) << std::endl << std::endl; + + // output the container as a comma separated list + std::cout << "...as comma separated list" << std::endl; + std::cout << + karma::format( + int_ % ", ", // format description + v // data + ) << std::endl << std::endl; + + std::cout << + karma::format( + '[' << (int_ % ", ") << ']', // format description + v // data + ) << std::endl << std::endl; + + // output the container as a comma separated list of double's + std::cout << "...as comma separated list of doubles" << std::endl; + std::cout << + karma::format( + double_ % ", ", // format description + v // data + ) << std::endl << std::endl; + + // output the container as a comma separated list of items enclosed in '()' + std::cout << "..as list of ints enclosed in '()'" << std::endl; + std::cout << + karma::format( + ('(' << int_ << ')') % ", ", // format description + v // data + ) << std::endl << std::endl; + + std::cout << + karma::format( + '[' << ( + ('(' << int_ << ')') % ", " + ) << ']', // format description + v // data + ) << std::endl << std::endl; + + // output the container as a HTML list + std::cout << "...as HTML bullet list" << std::endl; + std::cout << + karma::format_delimited( + "<ol>" << + // no delimiting within verbatim + *verbatim[" <li>" << int_ << "</li>"] + << "</ol>", // format description + '\n', // delimiter + v // data + ) << std::endl; + + // output the container as right aligned column + std::cout << "...right aligned in a column" << std::endl; + std::cout << + karma::format_delimited( + *verbatim[ + "|" << right_align[int_] << "|" + ], // format description + '\n', // delimiter + v // data + ) << std::endl; + + std::cout << std::endl; + return 0; +} + diff --git a/src/boost/libs/spirit/example/karma/quoted_strings.cpp b/src/boost/libs/spirit/example/karma/quoted_strings.cpp new file mode 100644 index 00000000..ecbdd969 --- /dev/null +++ b/src/boost/libs/spirit/example/karma/quoted_strings.cpp @@ -0,0 +1,70 @@ +// Copyright (c) 2001-2010 Hartmut Kaiser +// +// 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) + +// The purpose of this example is to demonstrate how to utilize alternatives +// and the built in matching capabilities of Karma generators to emit output +// in different formats based on the content of an attribute (not its type). + +#include <boost/config/warning_disable.hpp> + +#include <string> +#include <vector> + +#include <boost/spirit/include/karma.hpp> +#include <boost/spirit/include/phoenix_stl.hpp> + +namespace client +{ + namespace karma = boost::spirit::karma; + namespace phx = boost::phoenix; + + template <typename OutputIterator> + struct quoted_strings + : karma::grammar<OutputIterator, std::vector<std::string>()> + { + quoted_strings() + : quoted_strings::base_type(strings) + { + strings = (bareword | qstring) % ' '; + bareword = karma::repeat(phx::size(karma::_val)) + [ karma::alnum | karma::char_("-.,_$") ]; + qstring = '"' << karma::string << '"'; + } + + karma::rule<OutputIterator, std::vector<std::string>()> strings; + karma::rule<OutputIterator, std::string()> bareword, qstring; + }; +} + +int main() +{ + namespace karma = boost::spirit::karma; + + typedef std::back_insert_iterator<std::string> sink_type; + + std::string generated; + sink_type sink(generated); + + std::vector<std::string> v; + v.push_back("foo"); + v.push_back("bar baz"); + v.push_back("hello"); + + client::quoted_strings<sink_type> g; + if (!karma::generate(sink, g, v)) + { + std::cout << "-------------------------\n"; + std::cout << "Generating failed\n"; + std::cout << "-------------------------\n"; + } + else + { + std::cout << "-------------------------\n"; + std::cout << "Generated: " << generated << "\n"; + std::cout << "-------------------------\n"; + } + return 0; +} + diff --git a/src/boost/libs/spirit/example/karma/reference.cpp b/src/boost/libs/spirit/example/karma/reference.cpp new file mode 100644 index 00000000..dd11f26e --- /dev/null +++ b/src/boost/libs/spirit/example/karma/reference.cpp @@ -0,0 +1,911 @@ +/*============================================================================= + Copyright (c) 2001-2011 Hartmut Kaiser + http://spirit.sourceforge.net/ + + 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) +=============================================================================*/ +#include <boost/config/warning_disable.hpp> + +//[reference_karma_includes +#include <boost/spirit/include/karma.hpp> +#include <boost/spirit/include/support_utree.hpp> +#include <boost/spirit/include/phoenix_core.hpp> +#include <boost/spirit/include/phoenix_operator.hpp> +#include <boost/fusion/include/std_pair.hpp> +#include <iostream> +#include <string> +//] + +//[reference_karma_includes_simple +#include <boost/spirit/include/karma.hpp> +#include <iostream> +#include <string> +//] + +//[reference_karma_output_iterator +typedef std::back_insert_iterator<std::string> output_iterator_type; +//] + +//[reference_karma_test +template <typename G> +void test_generator(char const* expected, G const& g) +{ + std::string s; + std::back_insert_iterator<std::string> out(s); + if (boost::spirit::karma::generate(out, g) && s == expected) + std::cout << "ok" << std::endl; + else + std::cout << "fail" << std::endl; +} +//] + +//[reference_karma_test_attr +template <typename G, typename T> +void test_generator_attr(char const* expected, G const& g, T const& attr) +{ + std::string s; + std::back_insert_iterator<std::string> out(s); + if (boost::spirit::karma::generate(out, g, attr) && s == expected) + std::cout << "ok" << std::endl; + else + std::cout << "fail" << std::endl; +} +//] + +//[reference_karma_test_attr2 +template <typename G, typename T1, typename T2> +void test_generator_attr(char const* expected, G const& g, T1 const& attr1, + T2 const& attr2) +{ + std::string s; + std::back_insert_iterator<std::string> out(s); + if (boost::spirit::karma::generate(out, g, attr1, attr2) && s == expected) + std::cout << "ok" << std::endl; + else + std::cout << "fail" << std::endl; +} +//] + +//[reference_karma_test_attr_delim +template <typename G, typename Delimiter, typename T> +void test_generator_attr_delim(char const* expected, G const& g, Delimiter const& d, T const& attr) +{ + std::string s; + std::back_insert_iterator<std::string> out(s); + if (boost::spirit::karma::generate_delimited(out, g, d, attr) && s == expected) + std::cout << "ok" << std::endl; + else + std::cout << "fail" << std::endl; +} +//] + +//[reference_karma_binary_test +template <typename G> +void test_binary_generator(char const* expected, std::size_t size, G const& g) +{ + std::string s; + std::back_insert_iterator<std::string> out(s); + if (boost::spirit::karma::generate(out, g) && !std::memcmp(s.c_str(), expected, size)) + std::cout << "ok" << std::endl; + else + std::cout << "fail" << std::endl; +} +//] + +//[reference_karma_binary_test_attr +template <typename G, typename T> +void test_binary_generator_attr(char const* expected, std::size_t size, G const& g, T const& attr) +{ + std::string s; + std::back_insert_iterator<std::string> out(s); + if (boost::spirit::karma::generate(out, g, attr) && !std::memcmp(s.c_str(), expected, size)) + std::cout << "ok" << std::endl; + else + std::cout << "fail" << std::endl; +} +//] + +//[reference_karma_complex +// a simple complex number representation z = a + bi +struct complex +{ + complex (double a, double b) + : a(a), b(b) + {} + + double a; + double b; +}; +//] + +//[reference_karma_stream_complex +// define streaming operator for the type complex +std::ostream& +operator<< (std::ostream& os, complex const& z) +{ + os << "{" << z.a << "," << z.b << "}"; + return os; +} +//] + +//[reference_karma_auto_complex +/*`The following construct is required to allow the `complex` data structure + to be utilized as a __fusion__ sequence. This is required as we will + emit output for this data structure with a __karma__ sequence: + `'{' << karma::double_ << ',' << karma::double_ << '}'`. +*/ +BOOST_FUSION_ADAPT_STRUCT( + complex, + (double, a) + (double, b) +) + +/*`We add a specialization for the create_generator customization point + defining a custom output format for the complex type. Generally, any + specialization for create_generator is expected to return the proto + expression to be used to generate output for the type the customization + point has been specialized for. + */ +/*`We need to utilize `proto::deep_copy` as the expression contains literals + (the `'{'`, `','`, and `'}'`) which normally get embedded in the proto + expression by reference only. The deep copy converts the proto tree to + hold this by value. The deep copy operation can be left out for simpler + proto expressions (not containing references to temporaries). Alternatively + you could use the `proto::make_expr` facility to build the required + proto expression. +*/ +namespace boost { namespace spirit { namespace traits +{ + template <> + struct create_generator<complex> + { + typedef proto::result_of::deep_copy< + BOOST_TYPEOF('{' << karma::double_ << ',' << karma::double_ << '}') + >::type type; + + static type call() + { + return proto::deep_copy( + '{' << karma::double_ << ',' << karma::double_ << '}'); + } + }; +}}} +//] + +//[reference_karma_auxiliary_attr_cast_data1 +// this is just a test structure we want to use in place of an int +struct int_data +{ + int i; +}; + +// we provide a custom attribute transformation to allow its use as an int +namespace boost { namespace spirit { namespace traits +{ + template <> + struct transform_attribute<int_data const, int, karma::domain> + { + typedef int type; + static int pre(int_data const& d) { return d.i; } + }; +}}} +//] + +namespace client +{ + using boost::spirit::karma::grammar; + using boost::spirit::karma::rule; + using boost::spirit::ascii::space_type; + + //[karma_reference_grammar_definition + /*`Basic grammar usage: + */ + struct num_list : grammar<output_iterator_type, space_type, std::vector<int>()> + { + num_list() : base_type(start) + { + using boost::spirit::int_; + num = int_; + start = num << *(',' << num); + } + + rule<output_iterator_type, space_type, std::vector<int>()> start; + rule<output_iterator_type, space_type, int()> num; + }; + //] +} + +int main() +{ + /////////////////////////////////////////////////////////////////////////// + // Operators + /////////////////////////////////////////////////////////////////////////// + { + //[reference_karma_using_declarations_sequence + using boost::spirit::karma::double_; + //] + + //[reference_karma_sequence + test_generator_attr("1.0,2.0", double_ << ',' << double_, std::make_pair(1.0, 2.0)); + //] + } + + { + //[reference_karma_using_declarations_alternative + using boost::spirit::karma::double_; + using boost::spirit::karma::ascii::string; + //] + + //[reference_karma_alternative1 + boost::variant<std::string, double> v1(1.0); + test_generator_attr("1.0", string | double_, v1); + test_generator_attr("2.0", string | double_, 2.0); + //] + + //[reference_karma_alternative2 + boost::variant<std::string, double> v2("example"); + test_generator_attr("example", string | double_, v2); + test_generator_attr("example", string | double_, "example"); + //] + } + + { + //[reference_karma_using_declarations_kleene + using boost::spirit::karma::double_; + using boost::spirit::karma::space; + //] + + //[reference_karma_kleene + std::vector<double> v; + v.push_back(1.0); + v.push_back(2.0); + v.push_back(3.0); + test_generator_attr_delim("1.0 2.0 3.0 ", *double_, space, v); + //] + } + + { + //[reference_karma_using_declarations_plus + using boost::spirit::karma::double_; + using boost::spirit::karma::space; + //] + + //[reference_karma_plus1 + std::vector<double> v1; + v1.push_back(1.0); + v1.push_back(2.0); + v1.push_back(3.0); + test_generator_attr_delim("1.0 2.0 3.0 ", +double_, space, v1); + //] + + //[reference_karma_plus2 + std::vector<double> v2; // empty container + test_generator_attr("empty", +double_ | "empty", v2); + //] + } + + { + //[reference_karma_using_declarations_list + using boost::spirit::karma::double_; + //] + + //[reference_karma_list + std::vector<double> v1; + v1.push_back(1.0); + test_generator_attr("1.0", double_ % ',', v1); + + v1.push_back(2.0); + test_generator_attr("1.0,2.0", double_ % ',', v1); + //] + } + + { + //[reference_karma_using_declarations_optional + using boost::spirit::karma::double_; + //] + + //[reference_karma_optional1 + boost::optional<double> val(1.0); + test_generator_attr("1.0", -double_, val); + test_generator_attr("2.0", -double_, 2.0); + //] + } + { + using boost::spirit::karma::double_; + + //[reference_karma_optional2 + boost::optional<double> val; // empty optional + test_generator_attr("", -double_, val); + //] + } + + { + //[reference_karma_using_declarations_and_predicate + using boost::spirit::karma::double_; + using boost::spirit::karma::ascii::char_; + using boost::spirit::karma::ascii::string; + using boost::phoenix::ref; + //] + + //[reference_karma_and_predicate + test_generator_attr("b", &char_('a') << 'b' | 'c', 'a'); + test_generator_attr("c", &char_('a') << 'b' | 'c', 'x'); + + test_generator_attr("abc", &string("123") << "abc" | "def", "123"); + test_generator_attr("def", &string("123") << "abc" | "def", "456"); + //] + } + + { + //[reference_karma_using_declarations_not_predicate + using boost::spirit::karma::double_; + using boost::spirit::karma::ascii::char_; + using boost::spirit::karma::ascii::string; + using boost::phoenix::ref; + //] + + //[reference_karma_not_predicate + test_generator_attr("c", !char_('a') << 'b' | 'c', 'a'); + test_generator_attr("b", !char_('a') << 'b' | 'c', 'x'); + + test_generator_attr("def", !string("123") << "abc" | "def", "123"); + test_generator_attr("abc", !string("123") << "abc" | "def", "456"); + //] + } + + /////////////////////////////////////////////////////////////////////////// + // Directives + /////////////////////////////////////////////////////////////////////////// + { + //[reference_karma_using_declarations_alignment + using boost::spirit::karma::double_; + using boost::spirit::karma::left_align; + using boost::spirit::karma::center; + using boost::spirit::karma::right_align; + //] + + //[reference_karma_alignment + std::pair<double, double> p (1.0, 2.0); + test_generator_attr("1.0 |2.0", left_align(8)[double_] << '|' << double_, p); + test_generator_attr(" 1.0 |2.0", center(8)[double_] << '|' << double_, p); + test_generator_attr(" 1.0|2.0", right_align(8)[double_] << '|' << double_, p); + //] + } + + { + //[reference_karma_using_declarations_repeat + using boost::spirit::karma::double_; + using boost::spirit::karma::repeat; + //] + + //[reference_karma_repeat + std::vector<double> v; + v.push_back(1.0); + v.push_back(2.0); + v.push_back(3.0); + + test_generator_attr("[1.0][2.0][3.0]", repeat['[' << double_ << ']'], v); + test_generator_attr("[1.0][2.0]", repeat(2)['[' << double_ << ']'], v); + + // fails because of insufficient number of items + test_generator_attr("", repeat(4)['[' << double_ << ']'], v); + //] + } + + { + //[reference_karma_using_declarations_delimit + using boost::spirit::karma::double_; + using boost::spirit::karma::delimit; + using boost::spirit::karma::verbatim; + //] + + //[reference_karma_delimit + test_generator_attr("[ 2.0 , 4.3 ] ", + delimit['[' << double_ << ',' << double_ << ']'], 2.0, 4.3); + test_generator_attr("[*2.0*,*4.3*]*", + delimit('*')['[' << double_ << ',' << double_ << ']'], 2.0, 4.3); + test_generator_attr("[2.0, 4.3 ] ", + delimit[verbatim['[' << double_ << ','] << double_ << ']'], 2.0, 4.3); + //] + } + + { + //[reference_karma_using_declarations_upperlower + using boost::spirit::karma::double_; + using boost::spirit::ascii::upper; + using boost::spirit::ascii::lower; + //] + + //[reference_karma_upperlower + test_generator_attr("abc:2.0e-06", lower["ABC:" << double_], 2e-6); + test_generator_attr("ABC:2.0E-06", upper["abc:" << double_], 2e-6); + //] + } + + { + //[reference_karma_using_declarations_maxwidth + using boost::spirit::karma::double_; + using boost::spirit::karma::maxwidth; + using boost::spirit::karma::left_align; + using boost::spirit::karma::right_align; + //] + + //[reference_karma_maxwidth + test_generator("01234", maxwidth(5)["0123456789"]); + test_generator(" 012", maxwidth(5)[right_align(12)["0123456789"]]); + test_generator("0123 ", maxwidth(8)[left_align(8)["0123"]]); + //] + } + + { + //[reference_karma_using_declarations_buffer + using boost::spirit::karma::double_; + using boost::spirit::karma::buffer; + //] + + //[reference_karma_buffer + std::vector<double> v; // empty container + test_generator_attr("", -buffer['[' << +double_ << ']'], v); + + v.push_back(1.0); // now, fill the container + v.push_back(2.0); + test_generator_attr("[1.02.0]", buffer['[' << +double_ << ']'], v); + //] + } + + { + //[reference_karma_using_declarations_omit + using boost::spirit::karma::double_; + using boost::spirit::karma::omit; + //] + + //[reference_karma_omit + std::pair<double, double> p (1.0, 2.0); + test_generator_attr("2.0", omit[double_] << double_, p); + //] + } + + { + //[reference_karma_using_declarations_duplicate + using boost::spirit::karma::double_; + using boost::spirit::karma::duplicate; + using boost::spirit::karma::space; + //] + + //[reference_karma_duplicate + test_generator_attr("2.02.0", duplicate[double_ << double_], 2.0); + test_generator_attr_delim("2.0 2.0 ", duplicate[double_ << double_], space, 2.0); + //] + } + + { + //[reference_karma_using_declarations_columns + using boost::spirit::karma::double_; + using boost::spirit::karma::columns; + using boost::spirit::karma::space; + //] + + //[reference_karma_columns + std::vector<double> v; + v.push_back(1.0); + v.push_back(2.0); + v.push_back(3.0); + test_generator_attr("1.0\n2.0\n3.0\n", columns(1)[*double_], v); + test_generator_attr_delim("1.0 2.0 \n3.0 \n", columns(2)[*double_], space, v); + //] + } + + { + //[reference_karma_using_declarations_bool + using boost::spirit::karma::bool_; + using boost::spirit::karma::lit; + //] + + //[reference_karma_bool + test_generator("true", lit(true)); + test_generator("false", bool_(false)); + test_generator_attr("true", bool_(true), true); + test_generator_attr("", bool_(true), false); // fails (as true != false)! + test_generator_attr("false", bool_, false); + //] + } + + { + //[reference_karma_using_declarations_int + using boost::spirit::karma::int_; + using boost::spirit::karma::lit; + //] + + //[reference_karma_int + test_generator("-2", lit(-2)); + test_generator("-2", int_(-2)); + test_generator_attr("-2", int_(-2), -2); + test_generator_attr("", int_(-2), 3); // fails (as -2 != 3)! + test_generator_attr("-2", int_, -2); + //] + } + + { + //[reference_karma_using_declarations_uint + using boost::spirit::karma::uint_; + using boost::spirit::karma::lit; + //] + + //[reference_karma_uint + test_generator("2", lit(2U)); + test_generator("2", uint_(2)); + test_generator_attr("2", uint_(2), 2); + test_generator_attr("", uint_(2), 3); // fails (as 2 != 3)! + test_generator_attr("2", uint_, 2); + //] + } + + { + //[reference_karma_using_declarations_real + using boost::spirit::karma::double_; + using boost::spirit::karma::lit; + //] + + //[reference_karma_real + test_generator("2.0", lit(2.0)); + test_generator("2.0", double_(2)); + test_generator_attr("2.0", double_(2.0), 2.0); + test_generator_attr("", double_(2.0), 3.0); // fails (as 2.0 != 3.0)! + test_generator_attr("-2.0", double_, -2.0); + + test_generator_attr("1.234e05", double_, 1234.0e2); + test_generator_attr("1.234e-06", double_, 0.000001234); + //] + } + + { + //[reference_karma_using_declarations_char + using boost::spirit::karma::lit; + using boost::spirit::ascii::char_; + //] + + //[reference_karma_char + test_generator("A", 'A'); + test_generator("A", lit('A')); + + test_generator_attr("a", char_, 'a'); + test_generator("A", char_('A')); + test_generator_attr("A", char_('A'), 'A'); + test_generator_attr("", char_('A'), 'B'); // fails (as 'A' != 'B') + + test_generator_attr("A", char_('A', 'Z'), 'A'); + test_generator_attr("", char_('A', 'Z'), 'a'); // fails (as 'a' does not belong to 'A'...'Z') + + test_generator_attr("k", char_("a-z0-9"), 'k'); + test_generator_attr("", char_("a-z0-9"), 'A'); // fails (as 'A' does not belong to "a-z0-9") + //] + } + + { + //[reference_karma_using_declarations_char_class + using boost::spirit::karma::alpha; + using boost::spirit::karma::upper; + //] + + //[reference_karma_char_class + test_generator_attr("a", alpha, 'a'); + test_generator_attr("A", alpha, 'A'); + test_generator_attr("", alpha, '1'); // fails (as isalpha('1') is false) + test_generator_attr("A", upper[alpha], 'A'); + test_generator_attr("", upper[alpha], 'a'); // fails (as isupper('a') is false) + //] + } + + /////////////////////////////////////////////////////////////////////////// + // string + { + //[reference_karma_using_declarations_string + using boost::spirit::karma::lit; + using boost::spirit::ascii::string; + //] + + //[reference_karma_string + test_generator("abc", "abc"); + test_generator("abc", lit("abc")); + test_generator("abc", lit(std::string("abc"))); + + test_generator_attr("abc", string, "abc"); + test_generator("abc", string("abc")); + test_generator("abc", string(std::string("abc"))); + + test_generator_attr("abc", string("abc"), "abc"); + test_generator_attr("", string("abc"), "cba"); // fails (as "abc" != "cba") + //] + } + + /////////////////////////////////////////////////////////////////////////// + // auxiliary + { + //[reference_karma_using_declarations_eol + using boost::spirit::karma::eol; + //] + + //[reference_karma_eol + test_generator("\n", eol); + test_generator("abc\n", "abc" << eol); + //] + } + + { + //[reference_karma_using_declarations_attr_cast + using boost::spirit::karma::int_; + //] + + //[reference_karma_attr_cast1 + int_data d = { 1 }; + test_generator_attr("1", boost::spirit::karma::attr_cast(int_), d); + //] + } + + { + //[reference_karma_using_declarations_eps + using boost::spirit::karma::eps; + using boost::phoenix::val; + //] + + //[reference_karma_eps + test_generator("abc", eps[std::cout << val("starting eps example")] << "abc"); + test_generator("abc", eps(true) << "abc"); + test_generator("", eps(false) << "abc"); // fails as eps expression is 'false' + //] + } + + { + //[reference_karma_using_declarations_lazy + namespace karma = boost::spirit::karma; + using boost::spirit::karma::_1; + using boost::spirit::ascii::string; + using boost::phoenix::val; + //] + + //[reference_karma_lazy + test_generator_attr("abc", karma::lazy(val(string)), "abc"); + test_generator("abc", karma::lazy(val(string))[_1 = "abc"]); + //] + } + + /////////////////////////////////////////////////////////////////////////// + // stream module + { + //[reference_karma_using_declarations_stream + using boost::spirit::karma::stream; + //] + + //[reference_karma_stream + test_generator_attr("abc", stream, "abc"); + test_generator("abc", stream("abc")); + test_generator_attr("{1.2,2.4}", stream, complex(1.2, 2.4)); + test_generator("{1.2,2.4}", stream(complex(1.2, 2.4))); + //] + } + + /////////////////////////////////////////////////////////////////////////// + // auto module + { + //[reference_karma_using_declarations_auto + using boost::spirit::karma::auto_; + //] + + //[reference_karma_auto + /*`Emit a simple string using the `karma::string` generator: + */ + test_generator_attr("abc", auto_, "abc"); + test_generator("abc", auto_("abc")); + + /*`Emit instances of the `complex` data type as defined above using the + generator defined by the customization point for `complex`: + */ + test_generator_attr("{1.2,2.4}", auto_, complex(1.2, 2.4)); + test_generator("{1.2,2.4}", auto_(complex(1.2, 2.4))); + //] + } + + /////////////////////////////////////////////////////////////////////////// + // binary module + { + //[reference_karma_using_declarations_native_binary + using boost::spirit::karma::byte_; + using boost::spirit::karma::word; + using boost::spirit::karma::dword; + using boost::spirit::karma::qword; + //] + + //[reference_karma_native_binary_little + test_binary_generator("\x01", 1, byte_(0x01)); + test_binary_generator("\x01\x02", 2, word(0x0201)); + test_binary_generator("\x01\x02\x03\x04", 4, dword(0x04030201)); + test_binary_generator("\x01\x02\x03\x04\x05\x06\x07\x08", 8, qword(0x0807060504030201LL)); + + test_binary_generator_attr("\x01", 1, byte_, 0x01); + test_binary_generator_attr("\x01\x02", 2, word, 0x0201); + test_binary_generator_attr("\x01\x02\x03\x04", 4, dword, 0x04030201); + test_binary_generator_attr("\x01\x02\x03\x04\x05\x06\x07\x08", 8, qword, 0x0807060504030201LL); + //] + + //[reference_karma_native_binary_big + test_binary_generator("\x01", 1, byte_(0x01)); + test_binary_generator("\x02\x01", 2, word(0x0201)); + test_binary_generator("\x04\x03\x02\x01", 4, dword(0x04030201)); + test_binary_generator("\x08\x07\x06\x05\x04\x03\x02\x01", 8, qword(0x0807060504030201LL)); + + test_binary_generator_attr("\x01", 1, byte_, 0x01); + test_binary_generator_attr("\x02\x01", 2, word, 0x0201); + test_binary_generator_attr("\x04\x03\x02\x01", 4, dword, 0x04030201); + test_binary_generator_attr("\x08\x07\x06\x05\x04\x03\x02\x01", 8, qword, 0x0807060504030201LL); + //] + } + + { + //[reference_karma_using_declarations_little_binary + using boost::spirit::karma::little_word; + using boost::spirit::karma::little_dword; + using boost::spirit::karma::little_qword; + //] + + //[reference_karma_little_binary + test_binary_generator("\x01\x02", 2, little_word(0x0201)); + test_binary_generator("\x01\x02\x03\x04", 4, little_dword(0x04030201)); + test_binary_generator("\x01\x02\x03\x04\x05\x06\x07\x08", 8, little_qword(0x0807060504030201LL)); + + test_binary_generator_attr("\x01\x02", 2, little_word, 0x0201); + test_binary_generator_attr("\x01\x02\x03\x04", 4, little_dword, 0x04030201); + test_binary_generator_attr("\x01\x02\x03\x04\x05\x06\x07\x08", 8, little_qword, 0x0807060504030201LL); + //] + } + + { + //[reference_karma_using_declarations_big_binary + using boost::spirit::karma::big_word; + using boost::spirit::karma::big_dword; + using boost::spirit::karma::big_qword; + //] + + //[reference_karma_big_binary + test_binary_generator("\x02\x01", 2, big_word(0x0201)); + test_binary_generator("\x04\x03\x02\x01", 4, big_dword(0x04030201)); + test_binary_generator("\x08\x07\x06\x05\x04\x03\x02\x01", 8, big_qword(0x0807060504030201LL)); + + test_binary_generator_attr("\x02\x01", 2, big_word, 0x0201); + test_binary_generator_attr("\x04\x03\x02\x01", 4, big_dword, 0x04030201); + test_binary_generator_attr("\x08\x07\x06\x05\x04\x03\x02\x01", 8, big_qword, 0x0807060504030201LL); + //] + } + + // action + { + //[reference_karma_using_declarations_action + using boost::spirit::karma::int_; + using boost::spirit::karma::string; + using boost::spirit::karma::_1; + using boost::phoenix::ref; + using boost::phoenix::val; + //] + + //[reference_karma_action + int i = 42; + test_generator("42", int_[_1 = ref(i)]); + test_generator("abc", string[_1 = val("abc")]); + //] + } + + // rule + { + //[karma_reference_rule + //`Some using declarations: + using boost::spirit::karma::rule; + using boost::spirit::karma::int_; + using boost::spirit::ascii::space; + using boost::spirit::ascii::space_type; + + /*`Basic rule: + */ + rule<output_iterator_type> r; + r = int_(123); + test_generator("123", r); + + /*`Rule with consumed attribute: + */ + rule<output_iterator_type, int()> ra; + ra = int_; + test_generator_attr("123", ra, 123); + + /*`Rule with delimiter and consumed attribute: + */ + rule<output_iterator_type, std::vector<int>(), space_type> rs; + rs = *int_; + std::vector<int> v; + v.push_back(123); + v.push_back(456); + v.push_back(789); + test_generator_attr_delim("123 456 789", rs, space, v); + //] + } + + // grammar + { + using client::num_list; + + //[karma_reference_grammar_using + //`Some using declarations: + using boost::spirit::ascii::space_type; + using boost::spirit::ascii::space; + using boost::spirit::int_; + using boost::spirit::karma::grammar; + using boost::spirit::karma::rule; + //] + + //[karma_reference_grammar + //`How to use the example grammar: + num_list nlist; + std::vector<int> v; + v.push_back(123); + v.push_back(456); + v.push_back(789); + test_generator_attr_delim("123 , 456 , 789", nlist, space, v); + //] + } + + // symbols + { + //[reference_karma_using_declarations_symbols + using boost::spirit::karma::symbols; + //] + + //[reference_karma_symbols + symbols<char, char const*> sym; + + sym.add + ('a', "Apple") + ('b', "Banana") + ('o', "Orange") + ; + + test_generator_attr("Banana", sym, 'b'); + //] + } + + // as + { + //[reference_karma_using_declarations_as + using boost::spirit::utree; + using boost::spirit::utree_type; + using boost::spirit::utf8_symbol_type; + using boost::spirit::karma::as; + using boost::spirit::karma::as_string; + using boost::spirit::karma::char_; + using boost::spirit::karma::double_; + //] + + //[reference_karma_as + /*`To properly handle string concatenation with __utree__, we + make use of `as_string[]`. We also use `as<T>` to explicitly extract + a __utree__ symbol node.*/ + + typedef as<utf8_symbol_type> as_symbol_type; + as_symbol_type const as_symbol = as_symbol_type(); + + utree ut; + ut.push_back("xyz"); + ut.push_back(1.23); + + test_generator_attr("xyz1.23", as_string[*char_] << double_, ut); + test_generator_attr("xyz1.23", as<std::string>()[*char_] << double_, ut); + + ut.clear(); + + ut.push_back(utf8_symbol_type("xyz")); + ut.push_back(1.23); + + test_generator_attr("xyz1.23", as_symbol[*char_] << double_, ut); + test_generator_attr("xyz1.23", as<utf8_symbol_type>()[*char_] << double_, ut); + //] + } + + return 0; +} diff --git a/src/boost/libs/spirit/example/karma/reorder_struct.cpp b/src/boost/libs/spirit/example/karma/reorder_struct.cpp new file mode 100644 index 00000000..8e5b0149 --- /dev/null +++ b/src/boost/libs/spirit/example/karma/reorder_struct.cpp @@ -0,0 +1,105 @@ +// Copyright (c) 2001-2010 Hartmut Kaiser +// +// 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) + +// The main purpose of this example is to show how a single fusion sequence +// can be used to generate output of the elements in different sequences + +#include <boost/config/warning_disable.hpp> +#include <boost/spirit/include/karma.hpp> +#include <boost/fusion/include/struct.hpp> +#include <boost/fusion/include/nview.hpp> +#include <boost/assign/std/vector.hpp> + +namespace fusion = boost::fusion; +namespace karma = boost::spirit::karma; + +/////////////////////////////////////////////////////////////////////////////// +namespace client +{ + // Our employee struct + struct employee + { + std::string surname; + std::string forename; + int age; + double salary; + std::string department; + }; + + // define iterator type + typedef std::back_insert_iterator<std::string> iterator_type; + + // This is the output routine taking a format description and the data to + // print + template <typename Generator, typename Sequence> + void generate(Generator const& g, Sequence const& s) + { + std::string generated; + iterator_type sink(generated); + karma::generate(sink, g, s); + std::cout << generated << std::endl; + } +} + +// We need to tell fusion about our employee struct to make it a first-class +// fusion citizen. This has to be in global scope. Note that we don't need to +// list the members of our struct in the same sequence a they are defined +BOOST_FUSION_ADAPT_STRUCT( + client::employee, + (int, age) + (std::string, surname) + (std::string, forename) + (std::string, department) + (double, salary) +) + +/////////////////////////////////////////////////////////////////////////////// +int main() +{ + std::string str; + + // some employees + client::employee john = { "John", "Smith", 25, 2000.50, "Sales" }; + client::employee mary = { "Mary", "Higgins", 23, 2200.36, "Marketing" }; + client::employee tom = { "Tom", "Taylor", 48, 3200.00, "Boss" }; + + // print data about employees in different formats + { + // print forename and age + client::generate( + karma::string << ", " << karma::int_, + fusion::as_nview<2, 0>(john)); + + // print surname, forename, and salary + client::generate( + karma::string << ' ' << karma::string << ": " << karma::double_, + fusion::as_nview<1, 2, 4>(mary)); + + // print forename, age, and department + client::generate( + karma::string << ": " << karma::int_ << " (" << karma::string << ')', + fusion::as_nview<2, 0, 3>(tom)); + } + + // now make a list of all employees and print them all + std::vector<client::employee> employees; + { + using namespace boost::assign; + employees += john, mary, tom; + } + + // print surname, forename, and salary for all employees + { + typedef + fusion::result_of::as_nview<client::employee const, 1, 2, 4>::type + names_and_salary; + + karma::rule<client::iterator_type, names_and_salary()> r = + karma::string << ' ' << karma::string << ": " << karma::double_; + + client::generate(r % karma::eol, employees); + } + return 0; +} diff --git a/src/boost/libs/spirit/example/karma/simple_columns_directive.cpp b/src/boost/libs/spirit/example/karma/simple_columns_directive.cpp new file mode 100644 index 00000000..3a5348af --- /dev/null +++ b/src/boost/libs/spirit/example/karma/simple_columns_directive.cpp @@ -0,0 +1,49 @@ +// Copyright (c) 2001-2010 Hartmut Kaiser +// +// 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) + +// The purpose of this example is to show how a simple custom generator +// directive can be written. We develop a custom generator allowing to wrap +// the generated output after each 5th column. +// +// For more information see: http://boost-spirit.com/home/?page_id=659 + +#include <boost/spirit/include/karma_generate_attr.hpp> +#include <boost/spirit/include/karma_char.hpp> +#include <boost/spirit/include/karma_operator.hpp> +#include <boost/spirit/include/karma_numeric.hpp> + +#include <string> +#include "simple_columns_directive.hpp" + +namespace karma = boost::spirit::karma; + +int main() +{ + using custom_generator::columns; + + std::vector<int> v; + for (int i = 0; i < 17; ++i) + v.push_back(i); + + std::string generated; + std::back_insert_iterator<std::string> sink(generated); + + bool result = karma::generate_delimited( + sink, columns[*karma::int_], karma::space, v); + if (result) + { + std::cout << "-------------------------------- \n"; + std::cout << "Generation succeeded\n"; + std::cout << "generated output: " << "\n" << generated << "\n"; + std::cout << "-------------------------------- \n"; + } + else + { + std::cout << "-------------------------------- \n"; + std::cout << "Generation failed\n"; + std::cout << "-------------------------------- \n"; + } + return 0; +} diff --git a/src/boost/libs/spirit/example/karma/simple_columns_directive.hpp b/src/boost/libs/spirit/example/karma/simple_columns_directive.hpp new file mode 100644 index 00000000..56403f33 --- /dev/null +++ b/src/boost/libs/spirit/example/karma/simple_columns_directive.hpp @@ -0,0 +1,133 @@ +// Copyright (c) 2001-2010 Hartmut Kaiser +// +// 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) + +#if !defined(COLUMNS_DEC_05_2009_0716PM) +#define COLUMNS_DEC_05_2009_0716PM + +#include <boost/spirit/include/karma_generate.hpp> + +/////////////////////////////////////////////////////////////////////////////// +// definition the place holder +namespace custom_generator +{ + BOOST_SPIRIT_TERMINAL(columns) +} + +/////////////////////////////////////////////////////////////////////////////// +// implementation the enabler +namespace boost { namespace spirit +{ + // We want custom_generator::columns to be usable as a directive only, + // and only for generator expressions (karma::domain). + template <> + struct use_directive<karma::domain, custom_generator::tag::columns> + : mpl::true_ {}; +}} + +/////////////////////////////////////////////////////////////////////////////// +// implementation of the generator +namespace custom_generator +{ + // special delimiter wrapping the original one while additionally emitting + // the column delimiter after each 5th invocation + template <typename Delimiter> + struct columns_delimiter + { + columns_delimiter(Delimiter const& delim) + : delimiter(delim), count(0) {} + + // This function is called during the actual delimiter output + template <typename OutputIterator, typename Context + , typename Delimiter_, typename Attribute> + bool generate(OutputIterator& sink, Context&, Delimiter_ const& + , Attribute const&) const + { + // first invoke the wrapped delimiter + if (!karma::delimit_out(sink, delimiter)) + return false; + + // now we count the number of invocations and emit the column + // delimiter after each 5th column + if ((++count % 5) == 0) + *sink++ = '\n'; + return true; + } + + // Generate a final column delimiter if the last invocation didn't + // emit one + template <typename OutputIterator> + bool final_delimit_out(OutputIterator& sink) const + { + if (count % 5) + *sink++ = '\n'; + return true; + } + + Delimiter const& delimiter; // wrapped delimiter + mutable unsigned int count; // invocation counter + }; + + // That's the actual columns generator + template <typename Subject> + struct simple_columns_generator + : boost::spirit::karma::unary_generator< + simple_columns_generator<Subject> > + { + // Define required output iterator properties + typedef typename Subject::properties properties; + + // Define the attribute type exposed by this parser component + template <typename Context, typename Iterator> + struct attribute + : boost::spirit::traits::attribute_of<Subject, Context, Iterator> + {}; + + simple_columns_generator(Subject const& s) + : subject(s) + {} + + // This function is called during the actual output generation process. + // It dispatches to the embedded generator while supplying a new + // delimiter to use, wrapping the outer delimiter. + template <typename OutputIterator, typename Context + , typename Delimiter, typename Attribute> + bool generate(OutputIterator& sink, Context& ctx + , Delimiter const& delimiter, Attribute const& attr) const + { + columns_delimiter<Delimiter> d(delimiter); + return subject.generate(sink, ctx, d, attr) && d.final_delimit_out(sink); + } + + // This function is called during error handling to create + // a human readable string for the error context. + template <typename Context> + boost::spirit::info what(Context& ctx) const + { + return boost::spirit::info("columns", subject.what(ctx)); + } + + Subject subject; + }; +} + +/////////////////////////////////////////////////////////////////////////////// +// instantiation of the generator +namespace boost { namespace spirit { namespace karma +{ + // This is the factory function object invoked in order to create + // an instance of our simple_columns_generator. + template <typename Subject, typename Modifiers> + struct make_directive<custom_generator::tag::columns, Subject, Modifiers> + { + typedef custom_generator::simple_columns_generator<Subject> result_type; + + result_type operator()(unused_type, Subject const& s, unused_type) const + { + return result_type(s); + } + }; +}}} + +#endif |