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