/*============================================================================= Copyright (c) 2001-2010 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 //[reference_karma_includes #include #include #include #include #include #include //] //[reference_karma_includes_simple #include #include #include //] //[reference_karma_output_iterator typedef std::back_insert_iterator output_iterator_type; //] //[reference_karma_test template void test_generator(char const* expected, G const& g) { std::string s; std::back_insert_iterator 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 void test_generator_attr(char const* expected, G const& g, T const& attr) { std::string s; std::back_insert_iterator 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 void test_generator_attr(char const* expected, G const& g, T1 const& attr1, T2 const& attr2) { std::string s; std::back_insert_iterator 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 void test_generator_attr_delim(char const* expected, G const& g, Delimiter const& d, T const& attr) { std::string s; std::back_insert_iterator 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 void test_binary_generator(char const* expected, std::size_t size, G const& g) { std::string s; std::back_insert_iterator 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 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 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 { 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 { 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()> { num_list() : base_type(start) { using boost::spirit::int_; num = int_; start = num << *(',' << num); } rule()> start; rule 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 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 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 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 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 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 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 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 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 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 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 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 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 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 r; r = int_(123); test_generator("123", r); /*`Rule with consumed attribute: */ rule ra; ra = int_; test_generator_attr("123", ra, 123); /*`Rule with delimiter and consumed attribute: */ rule(), space_type> rs; rs = *int_; std::vector 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 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 sym; sym.add ('a', "Apple") ('b', "Banana") ('o', "Orange") ; test_generator_attr("Banana", sym, 'b'); //] } return 0; }