tree_tests.cpp

来自「Boost provides free peer-reviewed portab」· C++ 代码 · 共 384 行

CPP
384
字号
/*=============================================================================    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 setupnamespace 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 toolstemplate <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 foldingnamespace 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 constructionstruct 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 teststypedef mpl::list<    test_banal> tests_t;//////////////////////////////////////////////////////////////////////////////// run_test - code to run a teststruct 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_EXCEPTIONSnamespace boost{    void throw_exception(std::exception const & )    {        std::cerr << "Exception caught" << std::endl;        BOOST_TEST(0);    }}#endifvoid 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();}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?