summaryrefslogtreecommitdiffstats
blob: e9056894317e585e0b9bc0aea377f09aa89ac3cb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
/*=============================================================================
    Copyright (c) 1998-2003 Joel de Guzman
    http://spirit.sourceforge.net/

  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)
=============================================================================*/
#if !defined(BOOST_SPIRIT_RULE_HPP)
#define BOOST_SPIRIT_RULE_HPP

#include <boost/static_assert.hpp>

///////////////////////////////////////////////////////////////////////////////
//
//  Spirit predefined maximum number of simultaneously usable different
//  scanner types.
//
//  This limit defines the maximum number of of possible different scanner
//  types for which a specific rule<> may be used. If this isn't defined, a
//  rule<> may be used with one scanner type only (multiple scanner support
//  is disabled).
//
///////////////////////////////////////////////////////////////////////////////
#if !defined(BOOST_SPIRIT_RULE_SCANNERTYPE_LIMIT)
#  define BOOST_SPIRIT_RULE_SCANNERTYPE_LIMIT 1
#endif

//  Ensure a meaningful maximum number of simultaneously usable scanner types
BOOST_STATIC_ASSERT(BOOST_SPIRIT_RULE_SCANNERTYPE_LIMIT > 0);

#include <boost/scoped_ptr.hpp>
#include <boost/spirit/home/classic/namespace.hpp>
#include <boost/spirit/home/classic/core/non_terminal/impl/rule.ipp>

#if BOOST_SPIRIT_RULE_SCANNERTYPE_LIMIT > 1
#  include <boost/preprocessor/enum_params.hpp>
#endif

///////////////////////////////////////////////////////////////////////////////
namespace boost { namespace spirit {

BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN

#if BOOST_SPIRIT_RULE_SCANNERTYPE_LIMIT > 1

    ///////////////////////////////////////////////////////////////////////////
    //
    //  scanner_list (a fake scanner)
    //
    //      Typically, rules are tied to a specific scanner type and
    //      a particular rule cannot be used with anything else. Sometimes
    //      there's a need for rules that can accept more than one scanner
    //      type. The scanner_list<S0, ...SN> can be used as a template
    //      parameter to the rule class to specify up to the number of
    //      scanner types defined by the BOOST_SPIRIT_RULE_SCANNERTYPE_LIMIT
    //      constant. Example:
    //
    //          rule<scanner_list<ScannerT0, ScannerT1> > r;
    //
    //      *** This feature is available only to compilers that support
    //      partial template specialization. ***
    //
    ///////////////////////////////////////////////////////////////////////////
    template <
        BOOST_PP_ENUM_PARAMS(
            BOOST_SPIRIT_RULE_SCANNERTYPE_LIMIT,
            typename ScannerT
        )
    >
    struct scanner_list : scanner_base {};

#endif

    ///////////////////////////////////////////////////////////////////////////
    //
    //  rule class
    //
    //      The rule is a polymorphic parser that acts as a named place-
    //      holder capturing the behavior of an EBNF expression assigned to
    //      it.
    //
    //      The rule is a template class parameterized by:
    //
    //          1) scanner (scanner_t, see scanner.hpp),
    //          2) the rule's context (context_t, see parser_context.hpp)
    //          3) an arbitrary tag (tag_t, see parser_id.hpp) that allows
    //             a rule to be tagged for identification.
    //
    //      These template parameters may be specified in any order. The
    //      scanner will default to scanner<> when it is not specified.
    //      The context will default to parser_context when not specified.
    //      The tag will default to parser_address_tag when not specified.
    //
    //      The definition of the rule (its right hand side, RHS) held by
    //      the rule through a scoped_ptr. When a rule is seen in the RHS
    //      of an assignment or copy construction EBNF expression, the rule
    //      is held by the LHS rule by reference.
    //
    ///////////////////////////////////////////////////////////////////////////
    template <
        typename T0 = nil_t
      , typename T1 = nil_t
      , typename T2 = nil_t
    >
    class rule
        : public impl::rule_base<
            rule<T0, T1, T2>
          , rule<T0, T1, T2> const&
          , T0, T1, T2>
    {
    public:

        typedef rule<T0, T1, T2> self_t;
        typedef impl::rule_base<
            self_t
          , self_t const&
          , T0, T1, T2>
        base_t;

        typedef typename base_t::scanner_t scanner_t;
        typedef typename base_t::attr_t attr_t;
        typedef impl::abstract_parser<scanner_t, attr_t> abstract_parser_t;

        rule() : ptr() {}
        ~rule() {}

        rule(rule const& r)
        : ptr(new impl::concrete_parser<rule, scanner_t, attr_t>(r)) {}

        template <typename ParserT>
        rule(ParserT const& p)
        : ptr(new impl::concrete_parser<ParserT, scanner_t, attr_t>(p)) {}

        template <typename ParserT>
        rule& operator=(ParserT const& p)
        {
            ptr.reset(new impl::concrete_parser<ParserT, scanner_t, attr_t>(p));
            return *this;
        }

        rule& operator=(rule const& r)
        {
            ptr.reset(new impl::concrete_parser<rule, scanner_t, attr_t>(r));
            return *this;
        }

        rule<T0, T1, T2>
        copy() const
        {
            return rule<T0, T1, T2>(ptr.get() ? ptr->clone() : 0);
        }

    private:
        friend class impl::rule_base_access;

        abstract_parser_t*
        get() const
        {
            return ptr.get();
        }

        rule(abstract_parser_t* ptr_)
        : ptr(ptr_) {}

        rule(abstract_parser_t const* ptr_)
        : ptr(ptr_) {}

        scoped_ptr<abstract_parser_t> ptr;
    };

BOOST_SPIRIT_CLASSIC_NAMESPACE_END

}} // namespace BOOST_SPIRIT_CLASSIC_NS

#endif