Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:52:23

0001 /*=============================================================================
0002     Copyright (c) 2001-2011 Joel de Guzman
0003     Copyright (c) 2001-2011 Hartmut Kaiser
0004     Copyright (c)      2011 Thomas Heller
0005 
0006     Distributed under the Boost Software License, Version 1.0. (See accompanying
0007     file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0008 ==============================================================================*/
0009 #if !defined(BOOST_SPIRIT_TERMINAL_NOVEMBER_04_2008_0906AM)
0010 #define BOOST_SPIRIT_TERMINAL_NOVEMBER_04_2008_0906AM
0011 
0012 #if defined(_MSC_VER)
0013 #pragma once
0014 #endif
0015 
0016 #include <boost/config.hpp>
0017 #include <boost/spirit/home/support/meta_compiler.hpp>
0018 #include <boost/spirit/home/support/detail/make_vector.hpp>
0019 #include <boost/spirit/home/support/unused.hpp>
0020 #include <boost/spirit/home/support/detail/is_spirit_tag.hpp>
0021 #include <boost/spirit/home/support/terminal_expression.hpp>
0022 #include <boost/phoenix/core/as_actor.hpp>
0023 #include <boost/phoenix/core/is_actor.hpp>
0024 #include <boost/phoenix/core/terminal_fwd.hpp>
0025 #include <boost/phoenix/core/value.hpp> // includes as_actor specialization
0026 #include <boost/phoenix/function/function.hpp>
0027 #include <boost/preprocessor/tuple/elem.hpp>
0028 #include <boost/proto/extends.hpp>
0029 #include <boost/proto/traits.hpp>
0030 
0031 namespace boost { namespace spirit
0032 {
0033     template <typename Terminal, typename Args>
0034     struct terminal_ex
0035     {
0036         typedef Terminal terminal_type;
0037         typedef Args args_type;
0038 
0039         terminal_ex(Args const& args_)
0040           : args(args_) {}
0041         terminal_ex(Args const& args_, Terminal const& term_)
0042           : args(args_), term(term_) {}
0043 
0044         Args args;  // Args is guaranteed to be a fusion::vectorN so you
0045                     // can use that template for detection and specialization
0046         Terminal term;
0047     };
0048 
0049     template <typename Terminal, typename Actor, int Arity>
0050     struct lazy_terminal
0051     {
0052         typedef Terminal terminal_type;
0053         typedef Actor actor_type;
0054         static int const arity = Arity;
0055 
0056         lazy_terminal(Actor const& actor_)
0057           : actor(actor_) {}
0058         lazy_terminal(Actor const& actor_, Terminal const& term_)
0059           : actor(actor_), term(term_) {}
0060 
0061         Actor actor;
0062         Terminal term;
0063     };
0064 
0065     template <typename Domain, typename Terminal, int Arity, typename Enable = void>
0066     struct use_lazy_terminal : mpl::false_ {};
0067 
0068     template <typename Domain, typename Terminal, int Arity, typename Enable = void>
0069     struct use_lazy_directive : mpl::false_ {};
0070 
0071     template <typename Terminal>
0072     struct terminal;
0073 
0074     template <typename Domain, typename Terminal>
0075     struct use_terminal<Domain, terminal<Terminal> >
0076         : use_terminal<Domain, Terminal> {};
0077 
0078     template <typename Domain, typename Terminal, int Arity, typename Actor>
0079     struct use_terminal<Domain, lazy_terminal<Terminal, Actor, Arity> >
0080         : use_lazy_terminal<Domain, Terminal, Arity> {};
0081 
0082     template <typename Domain, typename Terminal, int Arity, typename Actor>
0083     struct use_directive<Domain, lazy_terminal<Terminal, Actor, Arity> >
0084         : use_lazy_directive<Domain, Terminal, Arity> {};
0085 
0086     template <
0087         typename F
0088       , typename A0 = unused_type
0089       , typename A1 = unused_type
0090       , typename A2 = unused_type
0091       , typename Unused = unused_type
0092     >
0093     struct make_lazy;
0094 
0095     template <typename F, typename A0>
0096     struct make_lazy<F, A0>
0097     {
0098         typedef typename
0099             proto::terminal<
0100                 lazy_terminal<
0101                     typename F::terminal_type
0102                   , typename phoenix::detail::expression::function_eval<F, A0>::type
0103                   , 1 // arity
0104                 >
0105             >::type
0106         result_type;
0107         typedef result_type type;
0108 
0109         result_type
0110         operator()(F f, A0 const& _0_) const
0111         {
0112             typedef typename result_type::proto_child0 child_type;
0113             return result_type::make(child_type(
0114                 phoenix::detail::expression::function_eval<F, A0>::make(f, _0_)
0115               , f.proto_base().child0
0116             ));
0117         }
0118     };
0119 
0120     template <typename F, typename A0, typename A1>
0121     struct make_lazy<F, A0, A1>
0122     {
0123         typedef typename
0124             proto::terminal<
0125                lazy_terminal<
0126                     typename F::terminal_type
0127                   , typename phoenix::detail::expression::function_eval<F, A0, A1>::type
0128                   , 2 // arity
0129                 >
0130             >::type
0131         result_type;
0132         typedef result_type type;
0133 
0134         result_type
0135         operator()(F f, A0 const& _0_, A1 const& _1_) const
0136         {
0137             typedef typename result_type::proto_child0 child_type;
0138             return result_type::make(child_type(
0139                 phoenix::detail::expression::function_eval<F, A0, A1>::make(f, _0_, _1_)
0140               , f.proto_base().child0
0141             ));
0142         }
0143     };
0144 
0145     template <typename F, typename A0, typename A1, typename A2>
0146     struct make_lazy<F, A0, A1, A2>
0147     {
0148         typedef typename
0149             proto::terminal<
0150                lazy_terminal<
0151                     typename F::terminal_type
0152                   , typename phoenix::detail::expression::function_eval<F, A0, A1, A2>::type
0153                   , 3 // arity
0154                 >
0155             >::type
0156         result_type;
0157         typedef result_type type;
0158 
0159         result_type
0160         operator()(F f, A0 const& _0_, A1 const& _1_, A2 const& _2_) const
0161         {
0162             typedef typename result_type::proto_child0 child_type;
0163             return result_type::make(child_type(
0164                 phoenix::detail::expression::function_eval<F, A0, A1, A2>::make(f, _0_, _1_, _2_)
0165               , f.proto_base().child0
0166             ));
0167         }
0168     };
0169 
0170     namespace detail
0171     {
0172         // Helper struct for SFINAE purposes
0173         template <bool C> struct bool_;
0174 
0175         template <>
0176         struct bool_<true> : mpl::bool_<true>
0177         { 
0178             typedef bool_<true>* is_true; 
0179         };
0180 
0181         template <>
0182         struct bool_<false> : mpl::bool_<false>
0183         { 
0184             typedef bool_<false>* is_false; 
0185         };
0186 
0187         // Metafunction to detect if at least one arg is a Phoenix actor
0188         template <
0189             typename A0
0190           , typename A1 = unused_type
0191           , typename A2 = unused_type
0192         >
0193         struct contains_actor
0194             : bool_<
0195                   phoenix::is_actor<A0>::value
0196                || phoenix::is_actor<A1>::value
0197                || phoenix::is_actor<A2>::value
0198               >
0199         {};
0200 
0201         // to_lazy_arg: convert a terminal arg type to the type make_lazy needs
0202         template <typename A>
0203         struct to_lazy_arg
0204           : phoenix::as_actor<A> // wrap A in a Phoenix actor if not already one
0205         {};
0206 
0207         template <typename A>
0208         struct to_lazy_arg<const A>
0209           : to_lazy_arg<A>
0210         {};
0211         
0212         template <typename A>
0213         struct to_lazy_arg<A &>
0214           : to_lazy_arg<A>
0215         {};
0216 
0217         template <>
0218         struct to_lazy_arg<unused_type>
0219         {
0220             // unused arg: make_lazy wants unused_type
0221             typedef unused_type type;
0222         };
0223 
0224         // to_nonlazy_arg: convert a terminal arg type to the type make_vector needs
0225         template <typename A>
0226         struct to_nonlazy_arg
0227         {
0228             // identity
0229             typedef A type;
0230         };
0231 
0232         template <typename A>
0233         struct to_nonlazy_arg<const A>
0234           : to_nonlazy_arg<A>
0235         {};
0236 
0237         template <typename A>
0238         struct to_nonlazy_arg<A &>
0239           : to_nonlazy_arg<A>
0240         {};
0241 
0242         // incomplete type: should not be appeared unused_type in nonlazy arg.
0243         template <>
0244         struct to_nonlazy_arg<unused_type>;
0245     }
0246 
0247     template <typename Terminal>
0248     struct terminal
0249       : proto::extends<
0250             typename proto::terminal<Terminal>::type
0251           , terminal<Terminal>
0252         >
0253     {
0254         typedef terminal<Terminal> this_type;
0255         typedef Terminal terminal_type;
0256 
0257         typedef proto::extends<
0258             typename proto::terminal<Terminal>::type
0259           , terminal<Terminal>
0260         > base_type;
0261 
0262         terminal() {}
0263 
0264         terminal(Terminal const& t)
0265           : base_type(proto::terminal<Terminal>::type::make(t)) 
0266         {}
0267 
0268 #if defined(BOOST_MSVC)
0269 #pragma warning(push)
0270 // warning C4348: 'boost::spirit::terminal<...>::result_helper': redefinition of default parameter: parameter 3, 4
0271 #pragma warning(disable: 4348)
0272 #endif
0273 
0274         template <
0275             bool Lazy
0276           , typename A0
0277           , typename A1 = unused_type
0278           , typename A2 = unused_type
0279         >
0280         struct result_helper;
0281 
0282 #if defined(BOOST_MSVC)
0283 #pragma warning(pop)
0284 #endif
0285 
0286         template <
0287             typename A0
0288         >
0289         struct result_helper<false, A0>
0290         {
0291             typedef typename
0292                 proto::terminal<
0293                     terminal_ex<
0294                         Terminal
0295                       , typename detail::result_of::make_vector<
0296                             typename detail::to_nonlazy_arg<A0>::type>::type>
0297                 >::type
0298             type;
0299         };
0300 
0301         template <
0302             typename A0
0303           , typename A1
0304         >
0305         struct result_helper<false, A0, A1>
0306         {
0307             typedef typename
0308                 proto::terminal<
0309                     terminal_ex<
0310                         Terminal
0311                       , typename detail::result_of::make_vector<
0312                             typename detail::to_nonlazy_arg<A0>::type
0313                           , typename detail::to_nonlazy_arg<A1>::type>::type>
0314                 >::type
0315             type;
0316         };
0317 
0318         template <
0319             typename A0
0320           , typename A1
0321           , typename A2
0322         >
0323         struct result_helper<false, A0, A1, A2>
0324         {
0325             typedef typename
0326                 proto::terminal<
0327                     terminal_ex<
0328                         Terminal
0329                       , typename detail::result_of::make_vector<
0330                             typename detail::to_nonlazy_arg<A0>::type
0331                           , typename detail::to_nonlazy_arg<A1>::type
0332                           , typename detail::to_nonlazy_arg<A2>::type>::type>
0333                 >::type
0334             type;
0335         };
0336 
0337         template <
0338             typename A0
0339           , typename A1
0340           , typename A2
0341         >
0342         struct result_helper<true, A0, A1, A2>
0343         {
0344             typedef typename
0345                 make_lazy<this_type
0346                   , typename detail::to_lazy_arg<A0>::type
0347                   , typename detail::to_lazy_arg<A1>::type
0348                   , typename detail::to_lazy_arg<A2>::type>::type
0349             type;
0350         };
0351 
0352         // FIXME: we need to change this to conform to the result_of protocol
0353         template <
0354             typename A0
0355           , typename A1 = unused_type
0356           , typename A2 = unused_type      // Support up to 3 args
0357         >
0358         struct result
0359         {
0360             typedef typename
0361                 result_helper<
0362                     detail::contains_actor<A0, A1, A2>::value
0363                   , A0, A1, A2
0364                 >::type
0365             type;
0366         };
0367 
0368         template <typename This, typename A0>
0369         struct result<This(A0)>
0370         {
0371             typedef typename
0372                 result_helper<
0373                     detail::contains_actor<A0, unused_type, unused_type>::value
0374                   , A0, unused_type, unused_type
0375                 >::type
0376             type;
0377         };
0378 
0379         template <typename This, typename A0, typename A1>
0380         struct result<This(A0, A1)>
0381         {
0382             typedef typename
0383                 result_helper<
0384                     detail::contains_actor<A0, A1, unused_type>::value
0385                   , A0, A1, unused_type
0386                 >::type
0387             type;
0388         };
0389 
0390 
0391         template <typename This, typename A0, typename A1, typename A2>
0392         struct result<This(A0, A1, A2)>
0393         {
0394             typedef typename
0395                 result_helper<
0396                      detail::contains_actor<A0, A1, A2>::value
0397                    , A0, A1, A2
0398                  >::type
0399                  type;
0400         };
0401 
0402         // Note: in the following overloads, SFINAE cannot
0403         // be done on return type because of gcc bug #24915:
0404         //   http://gcc.gnu.org/bugzilla/show_bug.cgi?id=24915
0405         // Hence an additional, fake argument is used for SFINAE,
0406         // using a type which can never be a real argument type.
0407 
0408         // Non-lazy overloads. Only enabled when all
0409         // args are immediates (no Phoenix actor).
0410 
0411         template <typename A0>
0412         typename result<A0>::type
0413         operator()(A0 const& _0_
0414           , typename detail::contains_actor<A0>::is_false = 0) const
0415         {
0416             typedef typename result<A0>::type result_type;
0417             typedef typename result_type::proto_child0 child_type;
0418             return result_type::make(
0419                 child_type(
0420                     detail::make_vector(_0_)
0421                   , this->proto_base().child0)
0422             );
0423         }
0424 
0425         template <typename A0, typename A1>
0426         typename result<A0, A1>::type
0427         operator()(A0 const& _0_, A1 const& _1_
0428           , typename detail::contains_actor<A0, A1>::is_false = 0) const
0429         {
0430             typedef typename result<A0, A1>::type result_type;
0431             typedef typename result_type::proto_child0 child_type;
0432             return result_type::make(
0433                 child_type(
0434                     detail::make_vector(_0_, _1_)
0435                   , this->proto_base().child0)
0436             );
0437         }
0438 
0439         template <typename A0, typename A1, typename A2>
0440         typename result<A0, A1, A2>::type
0441         operator()(A0 const& _0_, A1 const& _1_, A2 const& _2_
0442           , typename detail::contains_actor<A0, A1, A2>::is_false = 0) const
0443         {
0444             typedef typename result<A0, A1, A2>::type result_type;
0445             typedef typename result_type::proto_child0 child_type;
0446             return result_type::make(
0447                 child_type(
0448                     detail::make_vector(_0_, _1_, _2_)
0449                   , this->proto_base().child0)
0450             );
0451         }
0452 
0453         // Lazy overloads. Enabled when at
0454         // least one arg is a Phoenix actor.
0455         template <typename A0>
0456         typename result<A0>::type
0457         operator()(A0 const& _0_
0458           , typename detail::contains_actor<A0>::is_true = 0) const
0459         {
0460             return make_lazy<this_type
0461               , typename phoenix::as_actor<A0>::type>()(*this
0462               , phoenix::as_actor<A0>::convert(_0_));
0463         }
0464 
0465         template <typename A0, typename A1>
0466         typename result<A0, A1>::type
0467         operator()(A0 const& _0_, A1 const& _1_
0468           , typename detail::contains_actor<A0, A1>::is_true = 0) const
0469         {
0470             return make_lazy<this_type
0471               , typename phoenix::as_actor<A0>::type
0472               , typename phoenix::as_actor<A1>::type>()(*this
0473               , phoenix::as_actor<A0>::convert(_0_)
0474               , phoenix::as_actor<A1>::convert(_1_));
0475         }
0476 
0477         template <typename A0, typename A1, typename A2>
0478         typename result<A0, A1, A2>::type
0479         operator()(A0 const& _0_, A1 const& _1_, A2 const& _2_
0480           , typename detail::contains_actor<A0, A1, A2>::is_true = 0) const
0481         {
0482             return make_lazy<this_type
0483               , typename phoenix::as_actor<A0>::type
0484               , typename phoenix::as_actor<A1>::type
0485               , typename phoenix::as_actor<A2>::type>()(*this
0486               , phoenix::as_actor<A0>::convert(_0_)
0487               , phoenix::as_actor<A1>::convert(_1_)
0488               , phoenix::as_actor<A2>::convert(_2_));
0489         }
0490     };
0491 
0492     ///////////////////////////////////////////////////////////////////////////
0493     namespace result_of
0494     {
0495         // Calculate the type of the compound terminal if generated by one of
0496         // the spirit::terminal::operator() overloads above
0497 
0498         // The terminal type itself is passed through without modification
0499         template <typename Tag>
0500         struct terminal
0501         {
0502             typedef spirit::terminal<Tag> type;
0503         };
0504 
0505         template <typename Tag, typename A0>
0506         struct terminal<Tag(A0)>
0507         {
0508             typedef typename spirit::terminal<Tag>::
0509                 template result<A0>::type type;
0510         };
0511 
0512         template <typename Tag, typename A0, typename A1>
0513         struct terminal<Tag(A0, A1)>
0514         {
0515             typedef typename spirit::terminal<Tag>::
0516                 template result<A0, A1>::type type;
0517         };
0518 
0519         template <typename Tag, typename A0, typename A1, typename A2>
0520         struct terminal<Tag(A0, A1, A2)>
0521         {
0522             typedef typename spirit::terminal<Tag>::
0523                 template result<A0, A1, A2>::type type;
0524         };
0525     }
0526 
0527     ///////////////////////////////////////////////////////////////////////////
0528     // support for stateful tag types
0529     namespace tag
0530     {
0531         template <
0532             typename Data, typename Tag
0533           , typename DataTag1 = unused_type, typename DataTag2 = unused_type>
0534         struct stateful_tag
0535         {
0536             BOOST_SPIRIT_IS_TAG()
0537 
0538             typedef Data data_type;
0539 
0540             stateful_tag() {}
0541             stateful_tag(data_type const& data) : data_(data) {}
0542 
0543             data_type data_;
0544         };
0545     }
0546 
0547     template <
0548         typename Data, typename Tag
0549       , typename DataTag1 = unused_type, typename DataTag2 = unused_type>
0550     struct stateful_tag_type
0551       : spirit::terminal<tag::stateful_tag<Data, Tag, DataTag1, DataTag2> >
0552     {
0553         typedef tag::stateful_tag<Data, Tag, DataTag1, DataTag2> tag_type;
0554 
0555         stateful_tag_type() {}
0556         stateful_tag_type(Data const& data)
0557           : spirit::terminal<tag_type>(data) 
0558         {}
0559     };
0560 
0561     namespace detail
0562     {
0563         // extract expression if this is a Tag
0564         template <typename StatefulTag>
0565         struct get_stateful_data
0566         {
0567             typedef typename StatefulTag::data_type data_type;
0568 
0569             // is invoked if given tag is != Tag
0570             template <typename Tag_>
0571             static data_type call(Tag_) { return data_type(); }
0572 
0573             // this is invoked if given tag is same as'Tag'
0574             static data_type const& call(StatefulTag const& t) { return t.data_; }
0575         };
0576     }
0577 
0578 }}
0579 
0580 namespace boost { namespace phoenix
0581 {
0582     template <typename Tag>
0583     struct is_custom_terminal<Tag, typename Tag::is_spirit_tag>
0584       : mpl::true_
0585     {};
0586 
0587     template <typename Tag>
0588     struct custom_terminal<Tag, typename Tag::is_spirit_tag>
0589     {
0590 #ifndef BOOST_PHOENIX_NO_SPECIALIZE_CUSTOM_TERMINAL
0591         typedef void _is_default_custom_terminal; // fix for #7730
0592 #endif
0593 
0594         typedef spirit::terminal<Tag> result_type;
0595 
0596         template <typename Context>
0597         result_type operator()(Tag const & t, Context const &)
0598         {
0599             return spirit::terminal<Tag>(t);
0600         }
0601     };
0602 }}
0603 
0604 // Define a spirit terminal. This macro may be placed in any namespace.
0605 // Common placeholders are placed in the main boost::spirit namespace
0606 // (see common_terminals.hpp)
0607 
0608 #define BOOST_SPIRIT_TERMINAL_X(x, y) ((x, y)) BOOST_SPIRIT_TERMINAL_Y
0609 #define BOOST_SPIRIT_TERMINAL_Y(x, y) ((x, y)) BOOST_SPIRIT_TERMINAL_X
0610 #define BOOST_SPIRIT_TERMINAL_X0
0611 #define BOOST_SPIRIT_TERMINAL_Y0
0612 
0613 #ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS
0614 
0615 #define BOOST_SPIRIT_TERMINAL_NAME(name, type_name)                             \
0616     namespace tag { struct name { BOOST_SPIRIT_IS_TAG() }; }                    \
0617     typedef boost::proto::terminal<tag::name>::type type_name;                  \
0618     type_name const name = {{}};                                                \
0619     inline void BOOST_PP_CAT(silence_unused_warnings_, name)() { (void) name; } \
0620     /***/
0621 
0622 #else
0623 
0624 #define BOOST_SPIRIT_TERMINAL_NAME(name, type_name)                             \
0625     namespace tag { struct name { BOOST_SPIRIT_IS_TAG() }; }                    \
0626     typedef boost::proto::terminal<tag::name>::type type_name;                  \
0627     /***/
0628 
0629 #endif
0630 
0631 #define BOOST_SPIRIT_TERMINAL(name)                                             \
0632     BOOST_SPIRIT_TERMINAL_NAME(name, name ## _type)                             \
0633     /***/
0634 
0635 #define BOOST_SPIRIT_DEFINE_TERMINALS_NAME_A(r, _, names)                       \
0636     BOOST_SPIRIT_TERMINAL_NAME(                                                 \
0637         BOOST_PP_TUPLE_ELEM(2, 0, names),                                       \
0638         BOOST_PP_TUPLE_ELEM(2, 1, names)                                        \
0639     )                                                                           \
0640     /***/
0641 
0642 #define BOOST_SPIRIT_DEFINE_TERMINALS_NAME(seq)                                 \
0643     BOOST_PP_SEQ_FOR_EACH(BOOST_SPIRIT_DEFINE_TERMINALS_NAME_A, _,              \
0644         BOOST_PP_CAT(BOOST_SPIRIT_TERMINAL_X seq, 0))                           \
0645     /***/
0646 
0647 // Define a spirit extended terminal. This macro may be placed in any namespace.
0648 // Common placeholders are placed in the main boost::spirit namespace
0649 // (see common_terminals.hpp)
0650 
0651 #ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS
0652 
0653 #define BOOST_SPIRIT_TERMINAL_NAME_EX(name, type_name)                          \
0654     namespace tag { struct name { BOOST_SPIRIT_IS_TAG() }; }                    \
0655     typedef boost::spirit::terminal<tag::name> type_name;                       \
0656     type_name const name = type_name();                                         \
0657     inline void BOOST_PP_CAT(silence_unused_warnings_, name)() { (void) name; } \
0658     /***/
0659 
0660 #else
0661 
0662 #define BOOST_SPIRIT_TERMINAL_NAME_EX(name, type_name)                          \
0663     namespace tag { struct name { BOOST_SPIRIT_IS_TAG() }; }                    \
0664     typedef boost::spirit::terminal<tag::name> type_name;                       \
0665     /***/
0666 
0667 #endif
0668 
0669 #define BOOST_SPIRIT_TERMINAL_EX(name)                                          \
0670     BOOST_SPIRIT_TERMINAL_NAME_EX(name, name ## _type)                          \
0671     /***/
0672 
0673 #define BOOST_SPIRIT_DEFINE_TERMINALS_NAME_EX_A(r, _, names)                    \
0674     BOOST_SPIRIT_TERMINAL_NAME_EX(                                              \
0675         BOOST_PP_TUPLE_ELEM(2, 0, names),                                       \
0676         BOOST_PP_TUPLE_ELEM(2, 1, names)                                        \
0677     )                                                                           \
0678     /***/
0679 
0680 #define BOOST_SPIRIT_DEFINE_TERMINALS_NAME_EX(seq)                              \
0681     BOOST_PP_SEQ_FOR_EACH(BOOST_SPIRIT_DEFINE_TERMINALS_NAME_EX_A, _,           \
0682         BOOST_PP_CAT(BOOST_SPIRIT_TERMINAL_X seq, 0))                           \
0683     /***/
0684 
0685 #endif
0686 
0687