diff options
Diffstat (limited to 'src/boost/libs/spirit/classic/example/intermediate')
10 files changed, 1412 insertions, 0 deletions
diff --git a/src/boost/libs/spirit/classic/example/intermediate/ipv4.cpp b/src/boost/libs/spirit/classic/example/intermediate/ipv4.cpp new file mode 100644 index 00000000..93453bac --- /dev/null +++ b/src/boost/libs/spirit/classic/example/intermediate/ipv4.cpp @@ -0,0 +1,304 @@ +/*============================================================================= + Copyright (c) 2002-2003 Joel de Guzman + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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/spirit/include/classic_core.hpp> +#include <boost/spirit/include/classic_push_back_actor.hpp> +#include <boost/spirit/include/classic_if.hpp> +#include <boost/spirit/include/classic_for.hpp> +#include <boost/spirit/include/phoenix1.hpp> +#include <iostream> +#include <string> +#include <vector> +#include <algorithm> + +/////////////////////////////////////////////////////////////////////////////// +// +// Sample parser for binary data. This sample highlights the use of dynamic +// parsing where the result of actions direct the actual parsing behavior. +// We shall demonstrate 1) the use of phoenix to implement lambda (unnamed) +// functions, 2) dynamic looping using for_p, 3) the push_back_a actor for +// stuffing data into a vector, and 4) the if_p parser for choosing parser +// branches based on semantic conditions. +// +// << Sample idea by Florian Weimer >> +// +// For simplicity, we shall use bytes as atoms (and not 16-bit quantities +// in big-endian format or something similar, which would be more realistic) +// and PASCAL strings. +// +// A packet is the literal octet with value 255, followed by a variable +// octet N (denoting the total length of the packet), followed by N-2 octets +// (the payload). The payload contains a variable-length header, followed +// by zero or more elements. +// +// The header contains a single PASCAL string. +// +// An element is a PASCAL string (alternative: an element is an octet M, +// followed by [M/8] bytes, i.e. the necessary number of bytes to store M +// bits). +// +// (This data structure is inspired by the format of a BGP UPDATE message.) +// +// Packet layout: +// +// .-------------------. +// | 0xff | ^ +// +-------------------+ | +// | packet length | | +// +-------------------+ | number of bytes indicated by packet length +// : : | +// : payload : | +// | | v +// `-------------------' +// +// Payload layout: +// +// .-------------------. +// | header length | +// +-------------------+ +// | header octets | ^ +// : : | number of octets given by header length +// : : | +// : : v +// +-------------------+ +// | IPv4 prefix | ^ +// : : | IPv4 prefixes have variable length (see +// +-------------------+ | below). The number of prefixes is +// | IPv4 prefix | | determined by the packet length. +// : : | +// +-------------------+ | +// : : | +// : : v +// +// +// IPv4 prefix layout comes in five variants, depending on the first +// octet: +// +// .-------------------. +// | 0x00 | single octet, corresponds to 0.0.0.0/0 +// `-------------------' +// +// .-------------------. +// | 0x01 to 0x08 | two octets, prefix lengths up to /8. +// +-------------------+ +// | MSB of network | +// `-------------------' +// +// .-------------------. +// | 0x09 to 0x10 | three octets, prefix lengths up to /16. +// +-------------------+ +// | MSB of network | +// +-------------------+ +// | next octet | +// `-------------------' +// +// .-------------------. +// | 0x11 to 0x18 | four octets, prefix lengths up to /24. +// +-------------------+ +// | MSB of network | +// +-------------------+ +// | next octet | +// +-------------------+ +// | next octet | +// `-------------------' +// +// .-------------------. +// | 0x19 to 0x20 | five octets, prefix lengths up to /32. +// +-------------------+ +// | MSB of network | +// +-------------------+ +// | next octet | +// +-------------------+ +// | next octet | +// +-------------------+ +// | LSB of network | +// `-------------------' +// +/////////////////////////////////////////////////////////////////////////////// +using namespace std; +using namespace BOOST_SPIRIT_CLASSIC_NS; +using namespace phoenix; + +struct ipv4_prefix_data +{ + char prefix_len, n0, n1, n2, n3; + + ipv4_prefix_data() + : prefix_len(0),n0(0),n1(0),n2(0),n3(0) {} +}; + +struct ipv4_data +{ + char packet_len, header_len; + std::string header; + std::vector<ipv4_prefix_data> prefixes; + + ipv4_data() + : packet_len(0),header_len(0){} + +}; + +struct ipv4 : public grammar<ipv4> +{ + template <typename ScannerT> + struct definition + { + definition(ipv4 const& self) + { + packet = + '\xff' + >> anychar_p[var(self.data.packet_len) = arg1] + >> payload + ; + + payload = + anychar_p[var(self.data.header_len) = arg1] + >> for_p(var(i) = 0, var(i) < var(self.data.header_len), ++var(i)) + [ + anychar_p[var(self.data.header) += arg1] + ] + >> *ipv4_prefix + ; + + ipv4_prefix = + anychar_p + [ + var(temp.prefix_len) = arg1, + var(temp.n0) = 0, + var(temp.n1) = 0, + var(temp.n2) = 0, + var(temp.n3) = 0 + ] + + >> if_p(var(temp.prefix_len) > 0x00) + [ + anychar_p[var(temp.n0) = arg1] + >> if_p(var(temp.prefix_len) > 0x08) + [ + anychar_p[var(temp.n1) = arg1] + >> if_p(var(temp.prefix_len) > 0x10) + [ + anychar_p[var(temp.n2) = arg1] + >> if_p(var(temp.prefix_len) > 0x18) + [ + anychar_p[var(temp.n3) = arg1] + ] + ] + ] + ] + [ + push_back_a(self.data.prefixes, temp) + ] + ; + } + + int i; + ipv4_prefix_data temp; + rule<ScannerT> packet, payload, ipv4_prefix; + rule<ScannerT> const& + start() const { return packet; } + }; + + ipv4(ipv4_data& data) + : data(data) {} + + ipv4_data& data; +}; + +//////////////////////////////////////////////////////////////////////////// +// +// Main program +// +//////////////////////////////////////////////////////////////////////////// +int +as_byte(char n) +{ + if (n < 0) + return n + 256; + return n; +} + +void +print_prefix(ipv4_prefix_data const& prefix) +{ + cout << "prefix length = " << as_byte(prefix.prefix_len) << endl; + cout << "n0 = " << as_byte(prefix.n0) << endl; + cout << "n1 = " << as_byte(prefix.n1) << endl; + cout << "n2 = " << as_byte(prefix.n2) << endl; + cout << "n3 = " << as_byte(prefix.n3) << endl; +} + +void +parse_ipv4(char const* str, unsigned len) +{ + ipv4_data data; + ipv4 g(data); + parse_info<> info = parse(str, str+len, g); + + if (info.full) + { + cout << "-------------------------\n"; + cout << "Parsing succeeded\n"; + + cout << "packet length = " << as_byte(data.packet_len) << endl; + cout << "header length = " << as_byte(data.header_len) << endl; + cout << "header = " << data.header << endl; + + for_each(data.prefixes.begin(), data.prefixes.end(), print_prefix); + cout << "-------------------------\n"; + } + else + { + cout << "Parsing failed\n"; + cout << "stopped at:"; + for (char const* s = info.stop; s != str+len; ++s) + cout << static_cast<int>(*s) << endl; + } +} + +// Test inputs: + +// The string in the header is "empty", the prefix list is empty. +char const i1[8] = +{ + 0xff,0x08,0x05, + 'e','m','p','t','y' +}; + +// The string in the header is "default route", the prefix list +// has just one element, 0.0.0.0/0. +char const i2[17] = +{ + 0xff,0x11,0x0d, + 'd','e','f','a','u','l','t',' ', + 'r','o','u','t','e', + 0x00 +}; + +// The string in the header is "private address space", the prefix list +// has the elements 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16. +char const i3[32] = +{ + 0xff,0x20,0x15, + 'p','r','i','v','a','t','e',' ', + 'a','d','d','r','e','s','s',' ', + 's','p','a','c','e', + 0x08,0x0a, + 0x0c,0xac,0x10, + 0x10,0xc0,0xa8 +}; + +int +main() +{ + parse_ipv4(i1, sizeof(i1)); + parse_ipv4(i2, sizeof(i2)); + parse_ipv4(i3, sizeof(i3)); + return 0; +} + diff --git a/src/boost/libs/spirit/classic/example/intermediate/ipv4_opt.cpp b/src/boost/libs/spirit/classic/example/intermediate/ipv4_opt.cpp new file mode 100644 index 00000000..ed5429fd --- /dev/null +++ b/src/boost/libs/spirit/classic/example/intermediate/ipv4_opt.cpp @@ -0,0 +1,213 @@ +/*============================================================================= + Copyright (c) 2002-2003 Joel de Guzman + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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/spirit/include/classic_core.hpp> +#include <boost/spirit/include/classic_push_back_actor.hpp> +#include <boost/spirit/include/classic_if.hpp> +#include <boost/spirit/include/classic_for.hpp> +#include <boost/spirit/include/phoenix1.hpp> +#include <iostream> +#include <string> +#include <vector> +#include <algorithm> + +/////////////////////////////////////////////////////////////////////////////// +// +// Please check it out ipv4.cpp sample first! +// << See ipv4.cpp sample for details >> +// +// This is a variation of the ipv4.cpp sample. The original ipv4.cpp code +// compiles to 36k on MSVC7.1. Not bad! Yet, we want to shave a little bit +// more. Is it possible? Yes! This time, we'll use subrules and just store +// the rules in a plain old struct. We are parsing at the char level anyway, +// so we know what type of rule we'll need: a plain rule<>. The result: we +// shaved off another 20k. Now the code compiles to 16k on MSVC7.1. +// +// Could we have done better? Yes, but only if only we had typeof! << See +// the techniques section of the User's guide >> ... Someday... :-) +// +/////////////////////////////////////////////////////////////////////////////// +using namespace std; +using namespace BOOST_SPIRIT_CLASSIC_NS; +using namespace phoenix; + +struct ipv4_prefix_data +{ + char prefix_len, n0, n1, n2, n3; + + ipv4_prefix_data() + : prefix_len(0),n0(0),n1(0),n2(0),n3(0) {} +}; + +struct ipv4_data +{ + char packet_len, header_len; + std::string header; + std::vector<ipv4_prefix_data> prefixes; + + ipv4_data() + : packet_len(0),header_len(0){} + +}; + +struct ipv4 +{ + ipv4(ipv4_data& data) + : data(data) + { + start = + ( + packet = + '\xff' + >> anychar_p[var(data.packet_len) = arg1] + >> payload + , + + payload = + anychar_p[var(data.header_len) = arg1] + >> for_p(var(i) = 0, var(i) < var(data.header_len), ++var(i)) + [ + anychar_p[var(data.header) += arg1] + ] + >> *ipv4_prefix + , + + ipv4_prefix = + anychar_p + [ + var(temp.prefix_len) = arg1, + var(temp.n0) = 0, + var(temp.n1) = 0, + var(temp.n2) = 0, + var(temp.n3) = 0 + ] + + >> if_p(var(temp.prefix_len) > 0x00) + [ + anychar_p[var(temp.n0) = arg1] + >> if_p(var(temp.prefix_len) > 0x08) + [ + anychar_p[var(temp.n1) = arg1] + >> if_p(var(temp.prefix_len) > 0x10) + [ + anychar_p[var(temp.n2) = arg1] + >> if_p(var(temp.prefix_len) > 0x18) + [ + anychar_p[var(temp.n3) = arg1] + ] + ] + ] + ] + [ + push_back_a(data.prefixes, temp) + ] + ); + } + + int i; + ipv4_prefix_data temp; + + rule<> start; + subrule<0> packet; + subrule<1> payload; + subrule<2> ipv4_prefix; + ipv4_data& data; +}; + +//////////////////////////////////////////////////////////////////////////// +// +// Main program +// +//////////////////////////////////////////////////////////////////////////// +int +as_byte(char n) +{ + if (n < 0) + return n + 256; + return n; +} + +void +print_prefix(ipv4_prefix_data const& prefix) +{ + cout << "prefix length = " << as_byte(prefix.prefix_len) << endl; + cout << "n0 = " << as_byte(prefix.n0) << endl; + cout << "n1 = " << as_byte(prefix.n1) << endl; + cout << "n2 = " << as_byte(prefix.n2) << endl; + cout << "n3 = " << as_byte(prefix.n3) << endl; +} + +void +parse_ipv4(char const* str, unsigned len) +{ + ipv4_data data; + ipv4 g(data); + parse_info<> info = parse(str, str+len, g.start); + + if (info.full) + { + cout << "-------------------------\n"; + cout << "Parsing succeeded\n"; + + cout << "packet length = " << as_byte(data.packet_len) << endl; + cout << "header length = " << as_byte(data.header_len) << endl; + cout << "header = " << data.header << endl; + + for_each(data.prefixes.begin(), data.prefixes.end(), print_prefix); + cout << "-------------------------\n"; + } + else + { + cout << "Parsing failed\n"; + cout << "stopped at:"; + for (char const* s = info.stop; s != str+len; ++s) + cout << static_cast<int>(*s) << endl; + } +} + +// Test inputs: + +// The string in the header is "empty", the prefix list is empty. +char const i1[8] = +{ + 0xff,0x08,0x05, + 'e','m','p','t','y' +}; + +// The string in the header is "default route", the prefix list +// has just one element, 0.0.0.0/0. +char const i2[17] = +{ + 0xff,0x11,0x0d, + 'd','e','f','a','u','l','t',' ', + 'r','o','u','t','e', + 0x00 +}; + +// The string in the header is "private address space", the prefix list +// has the elements 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16. +char const i3[32] = +{ + 0xff,0x20,0x15, + 'p','r','i','v','a','t','e',' ', + 'a','d','d','r','e','s','s',' ', + 's','p','a','c','e', + 0x08,0x0a, + 0x0c,0xac,0x10, + 0x10,0xc0,0xa8 +}; + +int +main() +{ + parse_ipv4(i1, sizeof(i1)); + parse_ipv4(i2, sizeof(i2)); + parse_ipv4(i3, sizeof(i3)); + return 0; +} + diff --git a/src/boost/libs/spirit/classic/example/intermediate/lazy_parser.cpp b/src/boost/libs/spirit/classic/example/intermediate/lazy_parser.cpp new file mode 100644 index 00000000..6035fd80 --- /dev/null +++ b/src/boost/libs/spirit/classic/example/intermediate/lazy_parser.cpp @@ -0,0 +1,126 @@ +/*============================================================================= + Copyright (c) 2003 Vaclav Vesely + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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 example demonstrates the lazy_p parser. You should read +// "The Lazy Parser" in the documentation. +// +// We want to parse nested blocks of numbers like this: +// +// dec { +// 1 2 3 +// bin { +// 1 10 11 +// } +// 4 5 6 +// } +// +// where the numbers in the "dec" block are wrote in the decimal system and +// the numbers in the "bin" block are wrote in the binary system. We want +// parser to return the overall sum. +// +// To achive this when base ("bin" or "dec") is parsed, in semantic action +// we store a pointer to the appropriate numeric parser in the closure +// variable block.int_rule. Than, when we need to parse a number we use lazy_p +// parser to invoke the parser stored in the block.int_rule pointer. +// +//----------------------------------------------------------------------------- +#include <boost/assert.hpp> +#include <boost/cstdlib.hpp> +#include <boost/spirit/include/phoenix1.hpp> +#include <boost/spirit/include/classic_core.hpp> +#include <boost/spirit/include/classic_symbols.hpp> +#include <boost/spirit/include/classic_attribute.hpp> +#include <boost/spirit/include/classic_dynamic.hpp> + +using namespace boost; +using namespace BOOST_SPIRIT_CLASSIC_NS; +using namespace phoenix; + +//----------------------------------------------------------------------------- +// my grammar + +struct my_grammar + : public grammar<my_grammar, parser_context<int> > +{ + // grammar definition + template<typename ScannerT> + struct definition + { + typedef rule<ScannerT> rule_t; + typedef stored_rule<ScannerT, parser_context<int> > number_rule_t; + + struct block_closure; + typedef boost::spirit::classic::closure< + block_closure, + int, + typename number_rule_t::alias_t> + closure_base_t; + + struct block_closure : closure_base_t + { + typename closure_base_t::member1 sum; + typename closure_base_t::member2 int_rule; + }; + + // block rule type + typedef rule<ScannerT, typename block_closure::context_t> block_rule_t; + + block_rule_t block; + rule_t block_item; + symbols<number_rule_t> base; + + definition(my_grammar const& self) + { + block = + base[ + block.sum = 0, + // store a number rule in a closure member + block.int_rule = arg1 + ] + >> "{" + >> *block_item + >> "}" + ; + + block_item = + // use the stored rule + lazy_p(block.int_rule)[block.sum += arg1] + | block[block.sum += arg1] + ; + + // bind base keywords and number parsers + base.add + ("bin", bin_p) + ("dec", uint_p) + ; + } + + block_rule_t const& start() const + { + return block; + } + }; +}; + +//----------------------------------------------------------------------------- + +int main() +{ + my_grammar gram; + parse_info<> info; + + int result; + info = parse("bin{1 dec{1 2 3} 10}", gram[var(result) = arg1], space_p); + BOOST_ASSERT(info.full); + BOOST_ASSERT(result == 9); + + return exit_success; +} + +//----------------------------------------------------------------------------- diff --git a/src/boost/libs/spirit/classic/example/intermediate/parameters.cpp b/src/boost/libs/spirit/classic/example/intermediate/parameters.cpp new file mode 100644 index 00000000..b93fb0ec --- /dev/null +++ b/src/boost/libs/spirit/classic/example/intermediate/parameters.cpp @@ -0,0 +1,216 @@ +/*============================================================================= + Copyright (c) 2001-2003 Hartmut Kaiser + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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 show the usage of parser parameters. +// +// Parser parameters are used to pass some values from the outer parsing scope +// to the next inner scope. They can be imagined as the opposite to the return +// value paradigm, which returns some value from the inner to the next outer +// scope. See the "Closures" chapter in the User's Guide. + +#include <string> +#include <iostream> +#include <cassert> + +#if defined(_MSC_VER) /*&& !defined(__COMO__)*/ +#pragma warning(disable: 4244) +#pragma warning(disable: 4355) +#endif // defined(_MSC_VER) && !defined(__COMO__) + +#include <boost/spirit/include/classic_core.hpp> +#include <boost/spirit/include/classic_symbols.hpp> +#include <boost/spirit/include/classic_closure.hpp> + +#include <boost/spirit/include/phoenix1_tuples.hpp> +#include <boost/spirit/include/phoenix1_tuple_helpers.hpp> +#include <boost/spirit/include/phoenix1_primitives.hpp> + +/////////////////////////////////////////////////////////////////////////////// +// used namespaces +using namespace BOOST_SPIRIT_CLASSIC_NS; +using namespace phoenix; +using namespace std; + +/////////////////////////////////////////////////////////////////////////////// +// Helper class for encapsulation of the type for the parsed variable names +class declaration_type +{ +public: + enum vartype { + vartype_unknown = 0, // unknown variable type + vartype_int = 1, // 'int' + vartype_real = 2 // 'real' + }; + + declaration_type() : type(vartype_unknown) + { + } + template <typename ItT> + declaration_type(ItT const &first, ItT const &last) + { + init(string(first, last-first-1)); + } + declaration_type(declaration_type const &type_) : type(type_.type) + { + } + declaration_type(string const &type_) : type(vartype_unknown) + { + init(type_); + } + +// access to the variable type + operator vartype const &() const { return type; } + operator string () + { + switch(type) { + default: + case vartype_unknown: break; + case vartype_int: return string("int"); + case vartype_real: return string("real"); + } + return string ("unknown"); + } + + void swap(declaration_type &s) { std::swap(type, s.type); } + +protected: + void init (string const &type_) + { + if (type_ == "int") + type = vartype_int; + else if (type_ == "real") + type = vartype_real; + else + type = vartype_unknown; + } + +private: + vartype type; +}; + +/////////////////////////////////////////////////////////////////////////////// +// +// used closure type +// +/////////////////////////////////////////////////////////////////////////////// +struct var_decl_closure : BOOST_SPIRIT_CLASSIC_NS::closure<var_decl_closure, declaration_type> +{ + member1 val; +}; + +/////////////////////////////////////////////////////////////////////////////// +// +// symbols_with_data +// +// Helper class for inserting an item with data into a symbol table +// +/////////////////////////////////////////////////////////////////////////////// +template <typename T, typename InitT> +class symbols_with_data +{ +public: + typedef + symbol_inserter<T, BOOST_SPIRIT_CLASSIC_NS::impl::tst<T, char> > + symbol_inserter_t; + + symbols_with_data(symbol_inserter_t const &add_, InitT const &data_) : + add(add_), data(as_actor<InitT>::convert(data_)) + { + } + + template <typename IteratorT> + symbol_inserter_t const & + operator()(IteratorT const &first_, IteratorT const &last) const + { + IteratorT first = first_; + return add(first, last, data()); + } + +private: + symbol_inserter_t const &add; + typename as_actor<InitT>::type data; +}; + +template <typename T, typename CharT, typename InitT> +inline +symbols_with_data<T, InitT> +symbols_gen(symbol_inserter<T, BOOST_SPIRIT_CLASSIC_NS::impl::tst<T, CharT> > const &add_, + InitT const &data_) +{ + return symbols_with_data<T, InitT>(add_, data_); +} + +/////////////////////////////////////////////////////////////////////////////// +// The var_decl_list grammar parses variable declaration list + +struct var_decl_list : + public grammar<var_decl_list, var_decl_closure::context_t> +{ + template <typename ScannerT> + struct definition + { + definition(var_decl_list const &self) + { + // pass variable type returned from 'type' to list closure member 0 + decl = type[self.val = arg1] >> +space_p >> list(self.val); + + // m0 to access arg 0 of list --> passing variable type down to ident + list = ident(list.val) >> *(',' >> ident(list.val)); + + // store identifier and type into the symbol table + ident = (*alnum_p)[symbols_gen(symtab.add, ident.val)]; + + // the type of the decl is returned in type's closure member 0 + type = + str_p("int")[type.val = construct_<string>(arg1, arg2)] + | str_p("real")[type.val = construct_<string>(arg1, arg2)] + ; + + BOOST_SPIRIT_DEBUG_RULE(decl); + BOOST_SPIRIT_DEBUG_RULE(list); + BOOST_SPIRIT_DEBUG_RULE(ident); + BOOST_SPIRIT_DEBUG_RULE(type); + } + + rule<ScannerT> const& + start() const { return decl; } + + private: + typedef rule<ScannerT, var_decl_closure::context_t> rule_t; + rule_t type; + rule_t list; + rule_t ident; + symbols<declaration_type> symtab; + + rule<ScannerT> decl; // start rule + }; +}; + +/////////////////////////////////////////////////////////////////////////////// +// main entry point +int main() +{ +var_decl_list decl; +declaration_type type; +char const *pbegin = "int var1"; + + if (parse (pbegin, decl[assign(type)]).full) { + cout << endl + << "Parsed variable declarations successfully!" << endl + << "Detected type: " << declaration_type::vartype(type) + << " (" << string(type) << ")" + << endl; + } else { + cout << endl + << "Parsing the input stream failed!" + << endl; + } + return 0; +} + diff --git a/src/boost/libs/spirit/classic/example/intermediate/regex_convert.cpp b/src/boost/libs/spirit/classic/example/intermediate/regex_convert.cpp new file mode 100644 index 00000000..e167c2e3 --- /dev/null +++ b/src/boost/libs/spirit/classic/example/intermediate/regex_convert.cpp @@ -0,0 +1,177 @@ +/*============================================================================= + Copyright (c) 2002-2003 Martin Wille + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to 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) +=============================================================================*/ +/////////////////////////////////////////////////////////////////////////////// +// vim:ts=4:sw=4:et +// +// Demonstrate regular expression parsers for match based text conversion +// +// This sample requires an installed version of the boost regex library +// (http://www.boost.org) The sample was tested with boost V1.29.0 +// +// Note: - there is no error handling in this example +// - this program isn't particularly useful +// +// This example shows one way build a kind of filter program. +// It reads input from std::cin and uses a grammar and actions +// to print out a modified version of the input. +// +// [ Martin Wille, 10/18/2002 ] +// +/////////////////////////////////////////////////////////////////////////////// + +#include <string> +#include <iostream> +#include <streambuf> +#include <sstream> +#include <deque> +#include <iterator> + +#include <boost/function.hpp> +#include <boost/spirit/include/classic_core.hpp> + +/////////////////////////////////////////////////////////////////////////////// +// +// The following header must be included, if regular expression support is +// required for Spirit. +// +// The BOOST_SPIRIT_NO_REGEX_LIB PP constant should be defined, if you're using the +// Boost.Regex library from one translation unit only. Otherwise you have to +// link with the Boost.Regex library as defined in the related documentation +// (see. http://www.boost.org). +// +/////////////////////////////////////////////////////////////////////////////// +#define BOOST_SPIRIT_NO_REGEX_LIB +#include <boost/spirit/include/classic_regex.hpp> + +using namespace BOOST_SPIRIT_CLASSIC_NS; +using namespace std; + +namespace { + long triple(long val) + { + return 3*val; + } + /////////////////////////////////////////////////////////////////////////// + // + // actions + // + struct emit_constant + { + emit_constant(string const &text) + : msg(text) + {} + + template<typename Iterator> + void operator()(Iterator b, Iterator e) const + { + cout.rdbuf()->sputn(msg.data(), msg.size()); + } + + private: + + string msg; + }; + + void + copy_unmodified(char letter) + { + cout.rdbuf()->sputc(letter); + } + + struct emit_modified_subscript + { + emit_modified_subscript(boost::function<long (long)> const &f) + : modifier(f) + {} + + template<typename Iterator> + void operator()(Iterator b, Iterator e) const + { + string tmp(b+1,e-1); + long val = strtol(tmp.c_str(),0, 0); + ostringstream os; + os << modifier(val); + tmp = os.str(); + cout.rdbuf()->sputc('['); + cout.rdbuf()->sputn(tmp.c_str(), tmp.size()); + cout.rdbuf()->sputc(']'); + } + + private: + + boost::function<long (long)> modifier; + }; +} + +/////////////////////////////////////////////////////////////////////////////// +// The grammar 'conversion_grammar' serves as a working horse for match based +// text conversion. It does the following: +// +// - converts the word "class" into the word "struct" +// - multiplies any integer number enclosed in square brackets with 3 +// - any other input is simply copied to the output + +struct conversion_grammar + : grammar<conversion_grammar> +{ + template<class ScannerT> + struct definition + { + typedef ScannerT scanner_t; + + definition(conversion_grammar const &) + { + static const char expr[] = "\\[\\d+\\]"; + first = ( + ///////////////////////////////////////////////////////////// + // note that "fallback" is the last alternative here ! + top = *(class2struct || subscript || fallback), + ///////////////////////////////////////////////////////////// + // replace any occurrence of "class" by "struct" + class2struct = str_p("class") [emit_constant("struct")], + ///////////////////////////////////////////////////////////// + // if the input maches "[some_number]" + // "some_number" is multiplied by 3 before printing + subscript = regex_p(expr) [emit_modified_subscript(&triple)], + ///////////////////////////////////////////////////////////// + // if nothing else can be done with the input + // then it will be printed without modifications + fallback = anychar_p [©_unmodified] + ); + } + + rule<scanner_t> const & start() { return first; } + + private: + + subrule<0> top; + subrule<1> class2struct; + subrule<2> subscript; + subrule<3> fallback; + rule<scanner_t> first; + }; +}; + +int +main() +{ + // this would print "struct foo {}; foo bar[9];": + // parse("class foo {}; foo bar[3];", conversion_grammar()); + + // Note: the regular expression parser contained in the + // grammar requires a bidirectional iterator. Therefore, + // we cannot use sdt::istreambuf_iterator as one would + // do with other Spirit parsers. + istreambuf_iterator<char> input_iterator(cin); + std::deque<char> input(input_iterator, istreambuf_iterator<char>()); + + parse(input.begin(), input.end(), conversion_grammar()); + return 0; +} + diff --git a/src/boost/libs/spirit/classic/example/intermediate/simple_xml/actions.hpp b/src/boost/libs/spirit/classic/example/intermediate/simple_xml/actions.hpp new file mode 100644 index 00000000..285edf21 --- /dev/null +++ b/src/boost/libs/spirit/classic/example/intermediate/simple_xml/actions.hpp @@ -0,0 +1,68 @@ +// Copyright (c) 2005 Carl Barron. 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) + +#ifndef ACTIONS_H +#define ACTIONS_H +#include <boost/spirit/include/phoenix1.hpp> +#include <boost/variant.hpp> +#include "tag.hpp" + +struct push_child_impl +{ + template <class T,class A> + struct result {typedef void type;}; + + template <class T,class A> + void operator () (T &list, const A &value) const + { + typename tag::variant_type p(value); + list.push_back(p); + } +}; + +struct store_in_map_impl +{ + template <class T,class A> + struct result{typedef void type;}; + + template <class T,class A> + void operator () (T &map,const A &value)const + { + typedef typename T::value_type value_type; + map.insert(value_type(value)); + } +}; + +struct push_back_impl +{ + template <class T,class A> + struct result {typedef void type;}; + + template <class T,class A> + void operator () (T &list,const A &value)const + { + list.push_back(value); + } +}; + +struct store_tag_impl +{ + template <class T,class A,class B,class C> + struct result {typedef void type;}; + + template <class T,class A,class B,class C> + void operator ()(T &t,const A &a,const B &b,const C &c)const + { + t.id = a; + t.attributes = b; + t.children = c; + } +}; + + +typedef phoenix::function<push_back_impl> push_back_f; +typedef phoenix::function<store_in_map_impl>store_in_map_f; +typedef phoenix::function<push_child_impl> push_child_f; +typedef phoenix::function<store_tag_impl> store_tag_f; +#endif diff --git a/src/boost/libs/spirit/classic/example/intermediate/simple_xml/driver.cpp b/src/boost/libs/spirit/classic/example/intermediate/simple_xml/driver.cpp new file mode 100644 index 00000000..57ad6f20 --- /dev/null +++ b/src/boost/libs/spirit/classic/example/intermediate/simple_xml/driver.cpp @@ -0,0 +1,43 @@ +// Copyright (c) 2005 Carl Barron. 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 "xml_g.hpp" +#include <boost/spirit/include/classic_utility.hpp> +#include <iostream> + +namespace std +{ + std::ostream & operator << (std::ostream &os,std::pair<std::string,std::string> const &p) + { + return os << p.first << '=' << p.second; + } + + std::ostream & operator << (std::ostream &os,const tag &t) + { + return os << t.id; + } + +} + +int main() +{ + const char *test = + // "<A x=\"1\" y=\"2\"> test 1 </A>" + // "<B x=\"3\" y= \"4\" z = \"10\"> test 3 </B>" + // "<C><A></A><V><W></W></V></C>" + // "<D x=\"4\"/>" + "<E>xxx<F>yyy</F>zzz</E>" + ; + std::list<tag> tags; + xml_g g(tags); + + if(SP::parse(test,g,SP::comment_p("<---","--->")).full) + { + std::for_each(tags.begin(),tags.end(),walk_data()); + } + else + { + std::cout << "parse failed\n"; + } +} diff --git a/src/boost/libs/spirit/classic/example/intermediate/simple_xml/tag.cpp b/src/boost/libs/spirit/classic/example/intermediate/simple_xml/tag.cpp new file mode 100644 index 00000000..088f3a00 --- /dev/null +++ b/src/boost/libs/spirit/classic/example/intermediate/simple_xml/tag.cpp @@ -0,0 +1,46 @@ +// Copyright (c) 2005 Carl Barron. 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 "tag.hpp" +#include <iostream> +#include <algorithm> + +namespace +{ + struct print_pair + { + template <class P> + void operator () (const P &x) + { + std::cout << '\t' << x.first << ':' << x.second <<'\n'; + } + }; + +} + +void walk_data::operator () (const std::string &x) +{ + std::cout << "String:" << x <<'\n'; +} + +void walk_data::operator () (const tag &t) +{ + std::cout << "Tag:" << t.id << '\n'; + std::cout << "Attributes\n"; + + std::for_each + ( + t.attributes.begin(), + t.attributes.end(), + print_pair() + ); + std::cout << "Children:\n"; + std::for_each + ( + t.children.begin(), + t.children.end(), + boost::apply_visitor(*this) + ); + std::cout << "End of tag:" << t.id << '\n'; +} diff --git a/src/boost/libs/spirit/classic/example/intermediate/simple_xml/tag.hpp b/src/boost/libs/spirit/classic/example/intermediate/simple_xml/tag.hpp new file mode 100644 index 00000000..15f97593 --- /dev/null +++ b/src/boost/libs/spirit/classic/example/intermediate/simple_xml/tag.hpp @@ -0,0 +1,33 @@ +// Copyright (c) 2005 Carl Barron. 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) + +#ifndef SIMPLE_XML_TAG_H +#define SIMPLE_XML_TAG_H + +#include <boost/variant.hpp> +#include <list> +#include <map> +#include <string> + +struct tag +{ + std::string id; + std::map<std::string,std::string> attributes; + typedef boost::variant< + std::string, + boost::recursive_wrapper<tag> + > + variant_type; + std::list<variant_type> children; +}; + + +struct walk_data +{ + typedef void result_type; + void operator () (const std::string &x); + void operator () (const tag &t); +}; + +#endif diff --git a/src/boost/libs/spirit/classic/example/intermediate/simple_xml/xml_g.hpp b/src/boost/libs/spirit/classic/example/intermediate/simple_xml/xml_g.hpp new file mode 100644 index 00000000..fb0a4c61 --- /dev/null +++ b/src/boost/libs/spirit/classic/example/intermediate/simple_xml/xml_g.hpp @@ -0,0 +1,186 @@ +// Copyright (c) 2005 Carl Barron. 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) + +#ifndef XML_G_H +#define XML_G_H +#define BOOST_SPIRIT_DEBUG +#ifndef BOOST_SPIRIT_CLOSURE_LIMIT +#define BOOST_SPIRIT_CLOSURE_LIMIT 10 +#endif + +#ifndef PHOENIX_LIMIT +#define PHOENIX_LIMIT 10 +#endif + +#if BOOST_SPIRIT_CLOSURE_LIMIT < 6 +#undef BOOST_SPIRIT_CLOSURE_LIMIT +#define BOOST_SPIRIT_CLOSURE_LIMIT 6 +#endif + +#if PHOENIX_LIMIT < BOOST_SPIRIT_CLOSURE_LIMIT +#undef PHOENIX_LIMIT +#define PHOENIX_LIMIT BOOST_SPIRIT_CLOSURE_LIMIT +#endif + +#if 0 +#ifdef BOOST_SPIRIT_DEBUG_FLAGS +#undef BOOST_SPIRIT_DEBUG_FLAGS +#endif +#define BOOST_SPIRIT_DEBUG_FLAGS (BOOST_SPIRIT_DEBUG_FLAGS_MAX - BOOST_SPIRIT_DEBUG_FLAGS_CLOSURES) +#endif + +#include <boost/spirit/include/classic_core.hpp> +#include <boost/spirit/include/classic_attribute.hpp> +#include <boost/spirit/include/phoenix1.hpp> +#include "tag.hpp" +#include "actions.hpp" +#include <boost/variant.hpp> + +#include <string> +#include <utility> + +namespace SP = BOOST_SPIRIT_CLASSIC_NS; +using phoenix::arg1; +using phoenix::arg2; +using phoenix::construct_; +using phoenix::var; + +struct str_cls:SP::closure<str_cls,std::string> +{ member1 value;}; + +struct attrib_cls:SP::closure +< + attrib_cls, + std::pair<std::string,std::string>, + std::string, + std::string +> +{ + member1 value; + member2 first; + member3 second; +}; + +struct tagged_cls:SP::closure +< + tagged_cls, + tag, + std::string, + std::map<std::string,std::string>, + std::list<typename tag::variant_type> +> +{ + member1 value; + member2 ID; + member3 attribs; + member4 children; +}; + +struct xml_g:SP::grammar<xml_g> +{ + std::list<tag> &tags; + xml_g(std::list<tag> &a):tags(a){} + template <class Scan> + struct definition + { + definition(const xml_g &s) + { + white = +SP::space_p + ; + + tagged = (start_tag + >> *inner + >> end_tag + | simple_start_tag + ) + [store_tag(tagged.value,tagged.ID,tagged.attribs, + tagged.children)] + ; + + end_tag = SP::str_p("</") + >> SP::f_str_p(tagged.ID) + >> '>' + ; + + inner = (tagged + | str) [push_child(tagged.children,arg1)] + ; + + str = SP::lexeme_d[+(SP::anychar_p - '<')] + [str.value=construct_<std::string>(arg1,arg2)] + ; + + top = +tagged + [push_back(var(s.tags),arg1)] + ; + + starter = SP::ch_p('<') + >> SP::lexeme_d[+SP::alpha_p] + [tagged.ID = construct_<std::string>(arg1,arg2)] + >> *attrib + [store_in_map(tagged.attribs,arg1)] + >> !white + ; + start_tag = starter + >> '>' + ; + + simple_start_tag = starter + >> "/>" + ; + + attrib = white + >>SP::lexeme_d[+SP::alpha_p] + [attrib.first = construct_<std::string>(arg1,arg2)] + >> !white + >> '=' + >> !white + >> '"' + >> SP::lexeme_d[+(SP::anychar_p - '"')] + [attrib.second = construct_<std::string>(arg1,arg2)] + >> SP::ch_p('"') + [attrib.value = construct_ + < + std::pair + < + std::string, + std::string + > + >(attrib.first,attrib.second)] + ; + BOOST_SPIRIT_DEBUG_RULE(tagged); + BOOST_SPIRIT_DEBUG_RULE(end_tag); + BOOST_SPIRIT_DEBUG_RULE(inner); + BOOST_SPIRIT_DEBUG_RULE(str); + BOOST_SPIRIT_DEBUG_RULE(top); + BOOST_SPIRIT_DEBUG_RULE(start_tag); + BOOST_SPIRIT_DEBUG_RULE(attrib); + BOOST_SPIRIT_DEBUG_RULE(white); + BOOST_SPIRIT_DEBUG_RULE(starter); + BOOST_SPIRIT_DEBUG_RULE(simple_start_tag); + } + + // actions + push_back_f push_back; + push_child_f push_child; + store_in_map_f store_in_map; + store_tag_f store_tag; + // rules + SP::rule<Scan,tagged_cls::context_t> tagged; + SP::rule<Scan> end_tag; + SP::rule<Scan> inner; + SP::rule<Scan,str_cls::context_t> str; + SP::rule<Scan> top; + SP::rule<Scan> starter; + SP::rule<Scan> simple_start_tag; + SP::rule<Scan> start_tag; + SP::rule<Scan> white; + SP::rule<Scan,attrib_cls::context_t> attrib; + SP::rule<Scan> const &start() const + { return top;} + }; +}; + +#endif + |