123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383 |
- /*=============================================================================
- Copyright (c) 2003 Giovanni Bajo
- 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_ast.hpp>
- #include <boost/spirit/include/classic_tree_to_xml.hpp>
- #include <boost/preprocessor/arithmetic/inc.hpp>
- #include <boost/preprocessor/punctuation/comma_if.hpp>
- #include <boost/preprocessor/repetition.hpp>
- #include <boost/preprocessor/arithmetic/sub.hpp>
- #include <boost/mpl/list.hpp>
- #include <boost/mpl/apply.hpp>
- #include <boost/mpl/remove.hpp>
- #include <boost/mpl/size.hpp>
- #include <boost/mpl/for_each.hpp>
- #include <map>
- #include <string>
- #include <fstream>
- #include <boost/detail/lightweight_test.hpp>
- #include "impl/string_length.hpp"
- #define DEBUG_DUMP_TREES (1)
- //////////////////////////////////////////////////////////////////////////////
- // rule_id helper
- // http://sf.net/tracker/index.php?func=detail&aid=715483&group_id=28447&atid=393389)
- namespace boost { namespace spirit {
- template <
- typename ScannerT,
- unsigned long ID = 0,
- typename ContextT = parser_context<> >
- class rule_id
- : public rule<ScannerT, ContextT, parser_tag<ID> >
- {
- typedef rule<ScannerT, ContextT, parser_tag<ID> > base_t;
- public:
- // Forward ctors and operator=.
- rule_id()
- {}
- template <typename T>
- rule_id(const T& a)
- : base_t(a) {}
- template <typename T>
- rule_id& operator=(const T& a)
- { base_t::operator=(a); return *this; }
- };
- }}
- //////////////////////////////////////////////////////////////////////////////
- // Framework setup
- namespace mpl = boost::mpl;
- using namespace BOOST_SPIRIT_CLASSIC_NS;
- using namespace std;
- enum RULE_ID
- {
- ID_A = 1,
- ID_B,
- ID_C,
- ID_ROOT
- };
- map<parser_id, string> rule_names;
- //////////////////////////////////////////////////////////////////////////////
- // Generic tree manipulation tools
- template <typename TreeT>
- RULE_ID id(TreeT& t)
- { return (RULE_ID)t.value.id().to_long(); }
- template <typename TreeT>
- TreeT& child(TreeT& t, unsigned n)
- {
- return t.children[n];
- }
- template <typename TreeT>
- size_t num_children(const TreeT& t)
- { return t.children.size(); }
- template <typename TreeT>
- typename TreeT::parse_node_t::iterator_t ValueBeginIterator(TreeT& t)
- { return t.value.begin(); }
- template <typename TreeT>
- typename TreeT::parse_node_t::iterator_t ValueEndIterator(TreeT& t)
- { return t.value.end(); }
- template <typename TreeT>
- bool equal(TreeT& a, TreeT& b)
- {
- if (id(a) != id(b))
- return false;
- if (num_children(a) != num_children(b))
- return false;
- unsigned n = num_children(a);
- for (unsigned i=0;i<n;i++)
- if (!equal(child(a, i), child(b, i)))
- return false;
- return true;
- }
- template <typename TreeT>
- void dump(ostream& o, TreeT& t, int level = 0)
- {
- string name;
- string value;
- map<parser_id, string>::iterator iter =
- rule_names.find(id(t));
- if (iter == rule_names.end())
- name = "noname";
- else
- name = iter->second;
- value.assign(ValueBeginIterator(t), ValueEndIterator(t));
- for (int i=0;i<level;i++)
- o << " ";
- o << name << ": " << value << endl;
-
- unsigned n = num_children(t);
- for (unsigned c=0;c<n;c++)
- dump(o, child(t, c), level+1);
- }
- //////////////////////////////////////////////////////////////////////////////
- // Tree folding
- namespace test_impl {
- template <typename ParmT>
- struct fold_node
- {
- // assign a subtree
- void operator()(ParmT& t, ParmT ch) const
- { t = ch; }
- // wrong specialization
- template <typename TreeT>
- void operator()(TreeT& t, ParmT p) const
- { typedef typename TreeT::this_should_never_be_compiled type; }
- };
- template <>
- struct fold_node<nil_t>
- {
- template <typename TreeT>
- void operator()(TreeT& t, nil_t) const
- { typedef typename TreeT::this_should_never_be_compiled type; }
- };
- template <>
- struct fold_node<RULE_ID>
- {
- template <typename TreeT>
- void operator()(TreeT& t, RULE_ID id) const
- { t.value.id(id); }
- };
- template <typename ParmT>
- struct fold_child
- {
- template <typename TreeT>
- void operator()(TreeT& t, ParmT p, unsigned n) const
- { fold_node<ParmT>()(t.children[n], p); }
- };
- template <>
- struct fold_child<nil_t>
- {
- template <typename TreeT>
- void operator()(TreeT& t, nil_t, unsigned n) const
- {}
- };
- }
- template <typename TreeT,
- typename T, typename T1, typename T2, typename T3, typename T4,
- typename T5, typename T6, typename T7, typename T8>
- TreeT fold(T p, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7, T8 p8)
- {
- // Prepare a list with all the template types
- typedef mpl::list<T1,T2,T3,T4,T5,T6,T7,T8> full_list_t;
- // Remove the ones equal to nil_t: they are the default parameters
- // unspecified from the user
- typedef typename mpl::remove<full_list_t, nil_t>::type parm_list_t;
- // Get the size of the list = number of parameters specified by the user
- typedef typename mpl::size<parm_list_t>::type parm_list_size_t;
- enum { NUM_CHILDREN = parm_list_size_t::value };
- TreeT t;
- // Generate the root of the tree (specialized for the first parameter)
- test_impl::fold_node<T>()(t, p);
- // Make room for the children
- if (NUM_CHILDREN > 0)
- t.children.resize(NUM_CHILDREN);
- // For each children, call the GenerateChild function, which is specialized
- // on the different types
- test_impl::fold_child<T1>()(t, p1, 0);
- test_impl::fold_child<T2>()(t, p2, 1);
- test_impl::fold_child<T3>()(t, p3, 2);
- test_impl::fold_child<T4>()(t, p4, 3);
- test_impl::fold_child<T5>()(t, p5, 4);
- test_impl::fold_child<T6>()(t, p6, 5);
- test_impl::fold_child<T7>()(t, p7, 6);
- test_impl::fold_child<T8>()(t, p8, 7);
- return t;
- }
- // Define fold() wrapper for 1->7 parameters: they just call the 8 parameter
- // version passing nil_t for the other arguments
- #define PUT_EMPTY(Z, N, _) nil_t()
- #define DEFINE_FOLD(Z, N, _) \
- template <typename TreeT, typename T BOOST_PP_COMMA_IF(N) \
- BOOST_PP_ENUM_PARAMS(N, typename T) > \
- TreeT fold(T p BOOST_PP_COMMA_IF(N) BOOST_PP_ENUM_BINARY_PARAMS(N, T, p)) \
- { \
- return fold<TreeT>(p \
- BOOST_PP_COMMA_IF(N) BOOST_PP_ENUM_PARAMS(N, p) \
- BOOST_PP_COMMA_IF(BOOST_PP_SUB(8,N)) \
- BOOST_PP_ENUM(BOOST_PP_SUB(8,N), PUT_EMPTY, _)); \
- }
- BOOST_PP_REPEAT(7, DEFINE_FOLD, _)
- #undef PUT_EMPTY
- #undef DEFINE_FOLD
- //////////////////////////////////////////////////////////////////////////////
- // test_banal: simple tree construction
- struct test_banal : public grammar<test_banal>
- {
- template <class T>
- struct definition
- {
- rule_id<T, ID_ROOT> root;
- rule_id<T, ID_A> a;
- rule_id<T, ID_B> b;
- rule_id<T, ID_C> c;
- definition(const test_banal&)
- {
- root = a >> c;
- a = b;
- b = chlit<>('b');
- c = chlit<>('c');
- }
- const rule_id<T, ID_ROOT>& start()
- { return root; }
- };
- const char* pattern(void)
- {
- return "bc";
- }
- template <typename TreeT>
- TreeT expected_tree(void)
- {
- return fold<TreeT>(
- ID_ROOT, fold<TreeT>(
- ID_A,
- ID_B),
- ID_C);
- }
- };
- //////////////////////////////////////////////////////////////////////////////
- // All the tests
- typedef mpl::list
- <
- test_banal
- > tests_t;
- //////////////////////////////////////////////////////////////////////////////
- // run_test - code to run a test
- struct run_test
- {
- template <typename TestT>
- void operator()(TestT gram)
- {
- typedef const char* iterator_t;
- typedef node_val_data_factory<nil_t> factory_t;
- typedef typename
- factory_t
- ::BOOST_NESTED_TEMPLATE factory<iterator_t>
- ::node_t node_t;
- typedef tree_node<node_t> tree_t;
- iterator_t text_begin = gram.pattern();
- iterator_t text_end = text_begin + test_impl::string_length(text_begin);
- tree_parse_info<iterator_t, factory_t> info =
- ast_parse(text_begin, text_end, gram);
- BOOST_TEST(info.full);
- tree_t expected = gram.template expected_tree<tree_t>();
- #if DEBUG_DUMP_TREES
- dump(cout, info.trees[0]);
- dump(cout, expected);
- #endif
- BOOST_TEST(equal(info.trees[0], expected));
- }
- };
- //////////////////////////////////////////////////////////////////////////////
- // main() stuff
- #ifdef BOOST_NO_EXCEPTIONS
- namespace boost
- {
- void throw_exception(std::exception const & )
- {
- std::cerr << "Exception caught" << std::endl;
- BOOST_TEST(0);
- }
- }
- #endif
- void init(void)
- {
- rule_names[ID_ROOT] = "ID_ROOT";
- rule_names[ID_A] = "ID_A";
- rule_names[ID_B] = "ID_B";
- rule_names[ID_C] = "ID_C";
- }
- int main()
- {
- init();
- mpl::for_each<tests_t, mpl::_> (run_test());
- return boost::report_errors();
- }
|