1 /*=============================================================================
2     Copyright (c) 2002 2004 2006 Joel de Guzman
3     Copyright (c) 2004 Eric Niebler
4     Copyright (c) 2010 Daniel James
5     http://spirit.sourceforge.net/
6 
7     Use, modification and distribution is subject to the Boost Software
8     License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
9     http://www.boost.org/LICENSE_1_0.txt)
10 =============================================================================*/
11 #if !defined(BOOST_SPIRIT_QUICKBOOK_GRAMMARS_IMPL_HPP)
12 #define BOOST_SPIRIT_QUICKBOOK_GRAMMARS_IMPL_HPP
13 
14 #include "grammar.hpp"
15 #include "cleanup.hpp"
16 #include "values.hpp"
17 #include <boost/spirit/include/classic_symbols.hpp>
18 
19 namespace quickbook
20 {
21     namespace cl = boost::spirit::classic;
22 
23     // Information about a square bracket element (e.g. [* word]).
24     //
25     // TODO: The naming is a bit confused as element is also sometimes used for
26     // syntactic/implicit elements (such as lists and horizontal rules). Maybe
27     // should use entity as a more general name instead of element. Or it might
28     // be better to use 'tag' for square bracket elements, although that is
29     // currently used for the type of entities.
30     struct element_info
31     {
32         // Types of elements.
33         //
34         // Used to determine:
35         //
36         //  - where they can be used.
37         //  - whether they end a paragraph
38         //  - how following newlines are interpreted by the grammar.
39         //  - and possibly other things.....
40         enum type_enum {
41             // Used when there's no element.
42             nothing = 0,
43 
44             // A section tag. These can't be nested.
45             section_block = 1,
46 
47             // Block elements that can be used in conditional phrases and lists,
48             // but not nested. (TODO: not a good name).
49             conditional_or_block = 2,
50 
51             // Block elements that can be nested in other elements.
52             nested_block = 4,
53 
54             // Phrase elements.
55             phrase = 8,
56 
57             // Depending on the context this can be a block or phrase.
58             //
59             // Currently this is only used for elements that don't actually
60             // generate output (e.g. anchors, source mode tags). The main
61             // reason is so that lists can be preceeded by the element, e.g.
62             //
63             // [#anchor]
64             // * list item.
65             //
66             // If the anchor was considered to be a phrase element, then the
67             // list wouldn't be recognised.
68             maybe_block = 16
69         };
70 
71         // Masks to determine which context elements can be used in (in_*), and
72         // whether they are consided to be a block element (is_*).
73         enum context {
74             // At the top level we allow everything.
75             in_top_level = phrase | maybe_block | nested_block |
76                 conditional_or_block | section_block,
77 
78             // In conditional phrases and list blocks we everything but section
79             // elements.
80             in_conditional = phrase | maybe_block | nested_block |
81                 conditional_or_block,
82             in_list_block = phrase | maybe_block | nested_block |
83                 conditional_or_block,
84 
85             // In nested blocks we allow a more limited range of elements.
86             in_nested_block = phrase | maybe_block | nested_block,
87 
88             // In a phrase we only allow phrase elements, ('maybe_block'
89             // elements are treated as phrase elements in this context)
90             in_phrase = phrase | maybe_block,
91 
92             // At the start of a block these are all block elements.
93             is_contextual_block = maybe_block | nested_block |
94                 conditional_or_block | section_block,
95 
96             // These are all block elements in all other contexts.
97             is_block = nested_block | conditional_or_block | section_block,
98         };
99 
element_infoquickbook::element_info100         element_info()
101             : type(nothing), rule(), tag(0) {}
102 
element_infoquickbook::element_info103         element_info(
104                 type_enum t,
105                 cl::rule<scanner>* r,
106                 value::tag_type tag = value::default_tag,
107                 unsigned int v = 0)
108             : type(t), rule(r), tag(tag), qbk_version(v) {}
109 
110         type_enum type;
111         cl::rule<scanner>* rule;
112         value::tag_type tag;
113         unsigned int qbk_version;
114     };
115 
116     struct quickbook_grammar::impl
117     {
118         quickbook::state& state;
119         cleanup cleanup_;
120 
121         // Main Grammar
122         cl::rule<scanner> block_start;
123         cl::rule<scanner> phrase_start;
124         cl::rule<scanner> nested_phrase;
125         cl::rule<scanner> inline_phrase;
126         cl::rule<scanner> paragraph_phrase;
127         cl::rule<scanner> extended_phrase;
128         cl::rule<scanner> table_title_phrase;
129         cl::rule<scanner> inside_preformatted;
130         cl::rule<scanner> inside_paragraph;
131         cl::rule<scanner> command_line;
132         cl::rule<scanner> attribute_template_body;
133         cl::rule<scanner> attribute_value_1_7;
134         cl::rule<scanner> escape;
135         cl::rule<scanner> raw_escape;
136         cl::rule<scanner> skip_entity;
137 
138         // Miscellaneous stuff
139         cl::rule<scanner> hard_space;
140         cl::rule<scanner> space;
141         cl::rule<scanner> blank;
142         cl::rule<scanner> eol;
143         cl::rule<scanner> phrase_end;
144         cl::rule<scanner> comment;
145         cl::rule<scanner> line_comment;
146         cl::rule<scanner> macro_identifier;
147 
148         // Element Symbols
149         cl::symbols<element_info> elements;
150 
151         // Source mode
152         cl::symbols<source_mode_type> source_modes;
153 
154         // Doc Info
155         cl::rule<scanner> doc_info_details;
156 
157         impl(quickbook::state&);
158 
159     private:
160 
161         void init_main();
162         void init_block_elements();
163         void init_phrase_elements();
164         void init_doc_info();
165     };
166 }
167 
168 #endif // BOOST_SPIRIT_QUICKBOOK_GRAMMARS_HPP
169