/*============================================================================= 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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 > { typedef rule > base_t; public: // Forward ctors and operator=. rule_id() {} template rule_id(const T& a) : base_t(a) {} template 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 rule_names; ////////////////////////////////////////////////////////////////////////////// // Generic tree manipulation tools template RULE_ID id(TreeT& t) { return (RULE_ID)t.value.id().to_long(); } template TreeT& child(TreeT& t, unsigned n) { return t.children[n]; } template size_t num_children(const TreeT& t) { return t.children.size(); } template typename TreeT::parse_node_t::iterator_t ValueBeginIterator(TreeT& t) { return t.value.begin(); } template typename TreeT::parse_node_t::iterator_t ValueEndIterator(TreeT& t) { return t.value.end(); } template 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 void dump(ostream& o, TreeT& t, int level = 0) { string name; string value; map::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 struct fold_node { // assign a subtree void operator()(ParmT& t, ParmT ch) const { t = ch; } // wrong specialization template void operator()(TreeT& t, ParmT p) const { typedef typename TreeT::this_should_never_be_compiled type; } }; template <> struct fold_node { template void operator()(TreeT& t, nil_t) const { typedef typename TreeT::this_should_never_be_compiled type; } }; template <> struct fold_node { template void operator()(TreeT& t, RULE_ID id) const { t.value.id(id); } }; template struct fold_child { template void operator()(TreeT& t, ParmT p, unsigned n) const { fold_node()(t.children[n], p); } }; template <> struct fold_child { template void operator()(TreeT& t, nil_t, unsigned n) const {} }; } template 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 full_list_t; // Remove the ones equal to nil_t: they are the default parameters // unspecified from the user typedef typename mpl::remove::type parm_list_t; // Get the size of the list = number of parameters specified by the user typedef typename mpl::size::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, 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()(t, p1, 0); test_impl::fold_child()(t, p2, 1); test_impl::fold_child()(t, p3, 2); test_impl::fold_child()(t, p4, 3); test_impl::fold_child()(t, p5, 4); test_impl::fold_child()(t, p6, 5); test_impl::fold_child()(t, p7, 6); test_impl::fold_child()(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 \ TreeT fold(T p BOOST_PP_COMMA_IF(N) BOOST_PP_ENUM_BINARY_PARAMS(N, T, p)) \ { \ return fold(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 { template struct definition { rule_id root; rule_id a; rule_id b; rule_id c; definition(const test_banal&) { root = a >> c; a = b; b = chlit<>('b'); c = chlit<>('c'); } const rule_id& start() { return root; } }; const char* pattern(void) { return "bc"; } template TreeT expected_tree(void) { return fold( ID_ROOT, fold( 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 void operator()(TestT gram) { typedef const char* iterator_t; typedef node_val_data_factory factory_t; typedef typename factory_t ::BOOST_NESTED_TEMPLATE factory ::node_t node_t; typedef tree_node tree_t; iterator_t text_begin = gram.pattern(); iterator_t text_end = text_begin + test_impl::string_length(text_begin); tree_parse_info info = ast_parse(text_begin, text_end, gram); BOOST_TEST(info.full); tree_t expected = gram.template expected_tree(); #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 (run_test()); return boost::report_errors(); }