Imported Upstream version 1.49.0
[platform/upstream/boost.git] / tools / quickbook / src / doc_info_grammar.cpp
1 /*=============================================================================
2     Copyright (c) 2002 2004 2006 Joel de Guzman
3     Copyright (c) 2004 Eric Niebler
4     http://spirit.sourceforge.net/
5
6     Use, modification and distribution is subject to the Boost Software
7     License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
8     http://www.boost.org/LICENSE_1_0.txt)
9 =============================================================================*/
10
11 #include <map>
12 #include <boost/foreach.hpp>
13 #include <boost/spirit/include/classic_core.hpp>
14 #include <boost/spirit/include/classic_actor.hpp>
15 #include <boost/spirit/include/classic_loops.hpp>
16 #include <boost/spirit/include/classic_symbols.hpp>
17 #include <boost/spirit/include/classic_chset.hpp>
18 #include <boost/spirit/include/classic_numerics.hpp>
19 #include <boost/spirit/include/phoenix1_primitives.hpp>
20 #include <boost/spirit/include/phoenix1_operators.hpp>
21 #include "grammar_impl.hpp"
22 #include "actions_class.hpp"
23 #include "doc_info_tags.hpp"
24 #include "phrase_tags.hpp"
25
26 namespace quickbook
27 {
28     namespace cl = boost::spirit::classic;
29
30     struct attribute_info
31     {
32         attribute_info(value::tag_type t, cl::rule<scanner>* r)
33             : tag(t), rule(r)
34         {}
35
36         value::tag_type tag;
37         cl::rule<scanner>* rule;
38     };
39
40     struct doc_info_grammar_local
41     {
42         struct assign_attribute_type
43         {
44             assign_attribute_type(doc_info_grammar_local& l)
45                 : l(l)
46             {}
47
48             void operator()(value::tag_type& t) const {
49                 l.attribute_rule = *l.attribute_rules[t];
50                 l.attribute_tag = t;
51             }
52             
53             doc_info_grammar_local& l;
54         };
55         
56         struct fallback_attribute_type
57         {
58             fallback_attribute_type(doc_info_grammar_local& l)
59                 : l(l)
60             {}
61
62             void operator()(parse_iterator, parse_iterator) const {
63                 l.attribute_rule = l.doc_fallback;
64                 l.attribute_tag = value::default_tag;
65             }
66             
67             doc_info_grammar_local& l;
68         };
69
70         cl::rule<scanner>
71                         doc_info_block, doc_attribute, doc_info_attribute,
72                         doc_title, doc_simple, doc_phrase, doc_fallback,
73                         doc_authors, doc_author,
74                         doc_copyright, doc_copyright_holder,
75                         doc_source_mode, doc_biblioid, doc_compatibility_mode,
76                         quickbook_version, char_;
77         cl::uint_parser<int, 10, 4, 4> doc_copyright_year;
78         cl::symbols<> doc_types;
79         cl::symbols<value::tag_type> doc_info_attributes;
80         cl::symbols<value::tag_type> doc_attributes;
81         std::map<value::tag_type, cl::rule<scanner>* > attribute_rules;
82         value::tag_type attribute_tag;
83         cl::rule<scanner> attribute_rule;
84         assign_attribute_type assign_attribute;
85         fallback_attribute_type fallback_attribute;
86
87         doc_info_grammar_local()
88             : assign_attribute(*this)
89             , fallback_attribute(*this)
90         {}
91
92         bool source_mode_unset;
93     };
94
95     void quickbook_grammar::impl::init_doc_info()
96     {
97         doc_info_grammar_local& local = cleanup_.add(
98             new doc_info_grammar_local);
99
100         typedef cl::uint_parser<int, 10, 1, 2>  uint2_t;
101
102         local.doc_types =
103             "book", "article", "library", "chapter", "part"
104           , "appendix", "preface", "qandadiv", "qandaset"
105           , "reference", "set"
106         ;
107
108         BOOST_FOREACH(value::tag_type t, doc_attributes::tags()) {
109             local.doc_attributes.add(doc_attributes::name(t), t);
110             local.doc_info_attributes.add(doc_attributes::name(t), t);
111         }
112
113         BOOST_FOREACH(value::tag_type t, doc_info_attributes::tags()) {
114             local.doc_info_attributes.add(doc_info_attributes::name(t), t);
115         }
116         
117         doc_info_details =
118                 space                       [ph::var(local.source_mode_unset) = true]
119             >>  *(  local.doc_attribute
120                 >>  space
121                 )
122             >>  !local.doc_info_block
123             ;
124
125         local.doc_info_block =
126                 '['
127             >>  space
128             >>  (local.doc_types >> cl::eps_p)
129                                             [actions.values.entry(ph::arg1, ph::arg2, doc_info_tags::type)]
130             >>  hard_space
131             >>  actions.to_value(doc_info_tags::title)
132                 [  *(   ~cl::eps_p(blank >> (cl::ch_p('[') | ']' | cl::eol_p))
133                     >>  local.char_
134                     )
135                     // Include 'blank' here so that it will be included in
136                     // id generation.
137                     >> blank
138                 ]
139             >>  space
140             >>  !(qbk_since(106u) >> cl::eps_p(ph::var(local.source_mode_unset))
141                                             [cl::assign_a(actions.source_mode, "c++")]
142                 )
143             >>  (*(  local.doc_info_attribute
144                 >>  space
145                 ))                          [actions.values.sort()]
146             >>  (   ']'
147                 >>  (+eol | cl::end_p)
148                 |   cl::eps_p               [actions.error]
149                 )
150             ;
151
152         local.doc_attribute =
153                 '['
154             >>  space
155             >>  local.doc_attributes        [local.assign_attribute]
156             >>  hard_space
157             >>  actions.values.list(ph::var(local.attribute_tag))
158                 [   cl::eps_p               [actions.values.entry(ph::arg1, ph::arg2, doc_info_tags::before_docinfo)]
159                 >>  local.attribute_rule
160                 ]
161             >>  space
162             >>  ']'
163             ;
164
165         local.doc_info_attribute =
166                 '['
167             >>  space
168             >>  (   local.doc_info_attributes
169                                             [local.assign_attribute]
170                 |   (+(cl::alnum_p | '_' | '-'))
171                                             [local.fallback_attribute]
172                                             [actions.error("Unrecognized document attribute: '%s'.")]
173                 )
174             >>  hard_space
175             >>  actions.values.list(ph::var(local.attribute_tag))
176                 [local.attribute_rule]
177             >>  space
178             >>  ']'
179             ;
180
181         local.doc_fallback = actions.to_value() [
182             *(~cl::eps_p(']') >> local.char_)
183         ];
184
185         // Document Attributes
186
187         local.quickbook_version =
188                 cl::uint_p                  [actions.values.entry(ph::arg1)]
189             >>  '.' 
190             >>  uint2_t()                   [actions.values.entry(ph::arg1)]
191             ;
192
193         local.attribute_rules[doc_attributes::qbk_version] = &local.quickbook_version;
194
195         local.doc_compatibility_mode =
196                 cl::uint_p                  [actions.values.entry(ph::arg1)]
197             >>  '.'
198             >>  uint2_t()                   [actions.values.entry(ph::arg1)]
199             ;
200
201         local.attribute_rules[doc_attributes::compatibility_mode] = &local.doc_compatibility_mode;
202
203         local.doc_source_mode =
204                 (
205                    cl::str_p("c++")
206                 |  "python"
207                 |  "teletype"
208                 )                           [cl::assign_a(actions.source_mode)]
209                                             [ph::var(local.source_mode_unset) = false]
210             ;
211
212         local.attribute_rules[doc_attributes::source_mode] = &local.doc_source_mode;
213
214         // Document Info Attributes
215
216         local.doc_simple = actions.to_value() [*(~cl::eps_p(']') >> local.char_)];
217         local.attribute_rules[doc_info_attributes::version] = &local.doc_simple;
218         local.attribute_rules[doc_info_attributes::id] = &local.doc_simple;
219         local.attribute_rules[doc_info_attributes::dirname] = &local.doc_simple;
220         local.attribute_rules[doc_info_attributes::category] = &local.doc_simple;
221         local.attribute_rules[doc_info_attributes::last_revision] = &local.doc_simple;
222         local.attribute_rules[doc_info_attributes::lang] = &local.doc_simple;
223         local.attribute_rules[doc_info_attributes::xmlbase] = &local.doc_simple;
224
225         local.doc_copyright_holder
226             =   *(  ~cl::eps_p
227                     (   ']'
228                     |   ',' >> space >> local.doc_copyright_year
229                     )
230                 >>  local.char_
231                 );
232
233         local.doc_copyright =
234             *(  +(  local.doc_copyright_year
235                                             [actions.values.entry(ph::arg1, doc_info_tags::copyright_year)]
236                 >>  space
237                 >>  !(  '-'
238                     >>  space
239                     >>  local.doc_copyright_year
240                                             [actions.values.entry(ph::arg1, doc_info_tags::copyright_year_end)]
241                     >>  space
242                     )
243                 >>  !cl::ch_p(',')
244                 >>  space
245                 )
246             >>  actions.to_value(doc_info_tags::copyright_name) [ local.doc_copyright_holder ]
247             >>  !cl::ch_p(',')
248             >>  space
249             )
250             ;
251
252         local.attribute_rules[doc_info_attributes::copyright] = &local.doc_copyright;
253
254         local.doc_phrase = actions.to_value() [ nested_phrase ];
255         local.attribute_rules[doc_info_attributes::purpose] = &local.doc_phrase;
256         local.attribute_rules[doc_info_attributes::license] = &local.doc_phrase;
257
258         local.doc_author =
259                 '['
260             >>   space
261             >>  actions.to_value(doc_info_tags::author_surname)
262                 [*(~cl::eps_p(',') >> local.char_)]
263             >>  ',' >> space
264             >>  actions.to_value(doc_info_tags::author_first)
265                 [*(~cl::eps_p(']') >> local.char_)]
266             >>  ']'
267             ;
268
269         local.doc_authors =
270             *(  local.doc_author
271             >>  space
272             >>  !(cl::ch_p(',') >> space)
273             )
274             ;
275
276         local.attribute_rules[doc_info_attributes::authors] = &local.doc_authors;
277
278         local.doc_biblioid =
279                 (+cl::alnum_p)              [actions.values.entry(ph::arg1, ph::arg2, doc_info_tags::biblioid_class)]
280             >>  hard_space
281             >>  actions.to_value(doc_info_tags::biblioid_value)
282                 [+(~cl::eps_p(']') >> local.char_)]
283             ;
284
285         local.attribute_rules[doc_info_attributes::biblioid] = &local.doc_biblioid;
286
287         local.char_ = escape | cl::anychar_p[actions.plain_char];
288     }
289 }