• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/spirit/include/classic_chset.hpp>
13 #include <boost/spirit/include/classic_core.hpp>
14 #include <boost/spirit/include/classic_loops.hpp>
15 #include <boost/spirit/include/classic_numerics.hpp>
16 #include <boost/spirit/include/classic_symbols.hpp>
17 #include <boost/spirit/include/phoenix1_operators.hpp>
18 #include <boost/spirit/include/phoenix1_primitives.hpp>
19 #include "actions.hpp"
20 #include "doc_info_tags.hpp"
21 #include "for.hpp"
22 #include "grammar_impl.hpp"
23 #include "phrase_tags.hpp"
24 #include "state.hpp"
25 
26 namespace quickbook
27 {
28     namespace cl = boost::spirit::classic;
29 
30     struct attribute_info
31     {
attribute_infoquickbook::attribute_info32         attribute_info(value::tag_type t, cl::rule<scanner>* r)
33             : tag(t), rule(r)
34         {
35         }
36 
37         value::tag_type tag;
38         cl::rule<scanner>* rule;
39     };
40 
41     struct doc_info_grammar_local
42     {
43         struct assign_attribute_type
44         {
assign_attribute_typequickbook::doc_info_grammar_local::assign_attribute_type45             assign_attribute_type(doc_info_grammar_local& l_) : l(l_) {}
46 
operator ()quickbook::doc_info_grammar_local::assign_attribute_type47             void operator()(value::tag_type& t) const
48             {
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         {
fallback_attribute_typequickbook::doc_info_grammar_local::fallback_attribute_type58             fallback_attribute_type(doc_info_grammar_local& l_) : l(l_) {}
59 
operator ()quickbook::doc_info_grammar_local::fallback_attribute_type60             void operator()(parse_iterator, parse_iterator) const
61             {
62                 l.attribute_rule = l.doc_fallback;
63                 l.attribute_tag = value::default_tag;
64             }
65 
66             doc_info_grammar_local& l;
67         };
68 
69         cl::rule<scanner> doc_info_block, doc_attribute, doc_info_attribute,
70             doc_info_escaped_attributes, doc_title, doc_simple, doc_phrase,
71             doc_fallback, doc_authors, doc_author, doc_copyright,
72             doc_copyright_holder, doc_source_mode, doc_biblioid,
73             doc_compatibility_mode, quickbook_version, macro, char_;
74         cl::uint_parser<int, 10, 4, 4> doc_copyright_year;
75         cl::symbols<> doc_types;
76         cl::symbols<value::tag_type> doc_info_attributes;
77         cl::symbols<value::tag_type> doc_attributes;
78         std::map<value::tag_type, cl::rule<scanner>*> attribute_rules;
79         value::tag_type attribute_tag;
80         cl::rule<scanner> attribute_rule;
81         assign_attribute_type assign_attribute;
82         fallback_attribute_type fallback_attribute;
83 
doc_info_grammar_localquickbook::doc_info_grammar_local84         doc_info_grammar_local()
85             : assign_attribute(*this), fallback_attribute(*this)
86         {
87         }
88 
89         bool source_mode_unset;
90     };
91 
init_doc_info()92     void quickbook_grammar::impl::init_doc_info()
93     {
94         doc_info_grammar_local& local =
95             cleanup_.add(new doc_info_grammar_local);
96 
97         typedef cl::uint_parser<int, 10, 1, 2> uint2_t;
98 
99         local.doc_types = "book", "article", "library", "chapter", "part",
100         "appendix", "preface", "qandadiv", "qandaset", "reference", "set";
101 
102         QUICKBOOK_FOR (value::tag_type t, doc_attributes::tags()) {
103             local.doc_attributes.add(doc_attributes::name(t), t);
104             local.doc_info_attributes.add(doc_attributes::name(t), t);
105         }
106 
107         QUICKBOOK_FOR (value::tag_type t, doc_info_attributes::tags()) {
108             local.doc_info_attributes.add(doc_info_attributes::name(t), t);
109         }
110 
111         // Actions
112         error_action error(state);
113         plain_char_action plain_char(state);
114         do_macro_action do_macro(state);
115         scoped_parser<to_value_scoped_action> to_value(state);
116         member_action_value<quickbook::state, source_mode_type>
117             change_source_mode(state, &state::change_source_mode);
118         member_action_fixed_value<quickbook::state, source_mode_type>
119             default_source_mode(
120                 state, &state::change_source_mode, source_mode_tags::cpp);
121 
122         // clang-format off
123 
124         doc_info_details =
125                 cl::eps_p                   [ph::var(local.source_mode_unset) = true]
126             >>  *(  space
127                 >>  local.doc_attribute
128                 )
129             >>  !(  space
130                 >>  local.doc_info_block
131                 )
132             >>  *eol
133             ;
134 
135         local.doc_info_block =
136                 '['
137             >>  space
138             >>  (local.doc_types >> cl::eps_p)
139                                             [state.values.entry(ph::arg1, ph::arg2, doc_info_tags::type)]
140             >>  hard_space
141             >>  to_value(doc_info_tags::title)
142                 [  *(   ~cl::eps_p(blank >> (cl::ch_p('[') | ']' | cl::eol_p))
143                     >>  local.char_
144                     )
145                     // Include 'blank' here so that it will be included in
146                     // id generation.
147                     >> blank
148                 ]
149             >>  space
150             >>  !(qbk_ver(106u) >> cl::eps_p(ph::var(local.source_mode_unset))
151                                             [default_source_mode]
152                 )
153             >>  (   *(  (  local.doc_info_attribute
154                         |  local.doc_info_escaped_attributes
155                         )
156                         >>  space
157                     )
158                 )                           [state.values.sort()]
159             >>  (   ']'
160                 >>  (eol | cl::end_p)
161                 |   cl::eps_p               [error]
162                 )
163             ;
164 
165         local.doc_attribute =
166                 '['
167             >>  space
168             >>  local.doc_attributes        [local.assign_attribute]
169             >>  hard_space
170             >>  state.values.list(ph::var(local.attribute_tag))
171                 [   cl::eps_p               [state.values.entry(ph::arg1, ph::arg2, doc_info_tags::before_docinfo)]
172                 >>  local.attribute_rule
173                 ]
174             >>  space
175             >>  ']'
176             ;
177 
178         local.doc_info_attribute =
179                 '['
180             >>  space
181             >>  (   local.doc_info_attributes
182                                             [local.assign_attribute]
183                 |   (+(cl::alnum_p | '_' | '-'))
184                                             [local.fallback_attribute]
185                                             [error("Unrecognized document attribute: '%s'.")]
186                 )
187             >>  hard_space
188             >>  state.values.list(ph::var(local.attribute_tag))
189                 [local.attribute_rule]
190             >>  space
191             >>  ']'
192             ;
193 
194         local.doc_fallback = to_value() [
195             *(~cl::eps_p(']') >> local.char_)
196         ];
197 
198         local.doc_info_escaped_attributes =
199                 ("'''" >> !eol)
200             >>  (*(cl::anychar_p - "'''"))      [state.values.entry(ph::arg1, ph::arg2, doc_info_tags::escaped_attribute)]
201             >>  (   cl::str_p("'''")
202                 |   cl::eps_p                   [error("Unclosed boostbook escape.")]
203                 )
204                 ;
205 
206         // Document Attributes
207 
208         local.quickbook_version =
209                 cl::uint_p                  [state.values.entry(ph::arg1)]
210             >>  '.'
211             >>  uint2_t()                   [state.values.entry(ph::arg1)]
212             ;
213 
214         local.attribute_rules[doc_attributes::qbk_version] = &local.quickbook_version;
215 
216         local.doc_compatibility_mode =
217                 cl::uint_p                  [state.values.entry(ph::arg1)]
218             >>  '.'
219             >>  uint2_t()                   [state.values.entry(ph::arg1)]
220             ;
221 
222         local.attribute_rules[doc_attributes::compatibility_mode] = &local.doc_compatibility_mode;
223 
224         local.doc_source_mode = source_modes
225                                             [change_source_mode]
226                                             [ph::var(local.source_mode_unset) = false]
227             ;
228 
229         local.attribute_rules[doc_attributes::source_mode] = &local.doc_source_mode;
230 
231         // Document Info Attributes
232 
233         local.doc_simple = to_value() [*(~cl::eps_p(']') >> local.char_)];
234         local.attribute_rules[doc_info_attributes::version] = &local.doc_simple;
235         local.attribute_rules[doc_info_attributes::id] = &local.doc_simple;
236         local.attribute_rules[doc_info_attributes::dirname] = &local.doc_simple;
237         local.attribute_rules[doc_info_attributes::category] = &local.doc_simple;
238         local.attribute_rules[doc_info_attributes::last_revision] = &local.doc_simple;
239         local.attribute_rules[doc_info_attributes::lang] = &local.doc_simple;
240         local.attribute_rules[doc_info_attributes::xmlbase] = &local.doc_simple;
241 
242         local.doc_copyright_holder
243             =   *(  ~cl::eps_p
244                     (   ']'
245                     |   ',' >> space >> local.doc_copyright_year
246                     )
247                 >>  local.char_
248                 );
249 
250         local.doc_copyright =
251             *(  +(  local.doc_copyright_year
252                                             [state.values.entry(ph::arg1, doc_info_tags::copyright_year)]
253                 >>  space
254                 >>  !(  '-'
255                     >>  space
256                     >>  local.doc_copyright_year
257                                             [state.values.entry(ph::arg1, doc_info_tags::copyright_year_end)]
258                     >>  space
259                     )
260                 >>  !cl::ch_p(',')
261                 >>  space
262                 )
263             >>  to_value(doc_info_tags::copyright_name) [ local.doc_copyright_holder ]
264             >>  !cl::ch_p(',')
265             >>  space
266             )
267             ;
268 
269         local.attribute_rules[doc_info_attributes::copyright] = &local.doc_copyright;
270 
271         local.doc_phrase = to_value() [ nested_phrase ];
272         local.attribute_rules[doc_info_attributes::purpose] = &local.doc_phrase;
273         local.attribute_rules[doc_info_attributes::license] = &local.doc_phrase;
274 
275         local.doc_author =
276                 '['
277             >>   space
278             >>  to_value(doc_info_tags::author_surname)
279                 [*(~cl::eps_p(',') >> local.char_)]
280             >>  ',' >> space
281             >>  to_value(doc_info_tags::author_first)
282                 [*(~cl::eps_p(']') >> local.char_)]
283             >>  ']'
284             ;
285 
286         local.doc_authors =
287             *(  local.doc_author
288             >>  space
289             >>  !(cl::ch_p(',') >> space)
290             )
291             ;
292 
293         local.attribute_rules[doc_info_attributes::authors] = &local.doc_authors;
294 
295         local.doc_biblioid =
296                 (+cl::alnum_p)              [state.values.entry(ph::arg1, ph::arg2, doc_info_tags::biblioid_class)]
297             >>  hard_space
298             >>  to_value(doc_info_tags::biblioid_value)
299                 [+(~cl::eps_p(']') >> local.char_)]
300             ;
301 
302         local.attribute_rules[doc_info_attributes::biblioid] = &local.doc_biblioid;
303 
304         local.char_ =
305                 escape
306             |   local.macro
307             |   cl::anychar_p[plain_char];
308             ;
309 
310         local.macro =
311             cl::eps_p
312             (   (   state.macro
313                 >>  ~cl::eps_p(cl::alpha_p | '_')
314                                                 // must not be followed by alpha or underscore
315                 )
316                 &   macro_identifier            // must be a valid macro for the current version
317             )
318             >>  state.macro                     [do_macro]
319             ;
320 
321         // clang-format on
322     }
323 }
324