summaryrefslogtreecommitdiff
path: root/tools/quickbook/src/grammar_impl.hpp
blob: 8d37d351f19719d4368243dafd22785d0eea0601 (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
/*=============================================================================
    Copyright (c) 2002 2004 2006 Joel de Guzman
    Copyright (c) 2004 Eric Niebler
    Copyright (c) 2010 Daniel James
    http://spirit.sourceforge.net/

    Use, modification and distribution is subject to 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_QUICKBOOK_GRAMMARS_IMPL_HPP)
#define BOOST_SPIRIT_QUICKBOOK_GRAMMARS_IMPL_HPP

#include "grammar.hpp"
#include "cleanup.hpp"
#include "values.hpp"
#include <boost/spirit/include/classic_symbols.hpp>

namespace quickbook
{
    namespace cl = boost::spirit::classic;

    // Information about a square bracket element (e.g. [* word]).
    //
    // TODO: The naming is a bit confused as element is also sometimes used for
    // syntactic/implicit elements (such as lists and horizontal rules). Maybe
    // should use entity as a more general name instead of element. Or it might
    // be better to use 'tag' for square bracket elements, although that is
    // currently used for the type of entities.
    struct element_info
    {
        // Types of elements.
        //
        // Used to determine:
        //
        //  - where they can be used.
        //  - whether they end a paragraph
        //  - how following newlines are interpreted by the grammar.
        //  - and possibly other things.....
        enum type_enum {
            // Used when there's no element.
            nothing = 0,

            // A section tag. These can't be nested.
            section_block = 1,

            // Block elements that can be used in conditional phrases and lists,
            // but not nested. (TODO: not a good name).
            conditional_or_block = 2,

            // Block elements that can be nested in other elements.            
            nested_block = 4,
            
            // Phrase elements.
            phrase = 8,

            // Depending on the context this can be a block or phrase.
            //
            // Currently this is only used for elements that don't actually
            // generate output (e.g. anchors, source mode tags). The main
            // reason is so that lists can be preceeded by the element, e.g.
            //
            // [#anchor]
            // * list item.
            //
            // If the anchor was considered to be a phrase element, then the
            // list wouldn't be recognised.
            maybe_block = 16
        };

        // Masks to determine which context elements can be used in (in_*), and
        // whether they are consided to be a block element (is_*).
        enum context {
            // At the top level we allow everything.
            in_top_level = phrase | maybe_block | nested_block |
                conditional_or_block | section_block,

            // In conditional phrases and list blocks we everything but section
            // elements.
            in_conditional = phrase | maybe_block | nested_block |
                conditional_or_block,
            in_list_block = phrase | maybe_block | nested_block |
                conditional_or_block,

            // In nested blocks we allow a more limited range of elements.
            in_nested_block = phrase | maybe_block | nested_block,

            // In a phrase we only allow phrase elements, ('maybe_block'
            // elements are treated as phrase elements in this context)
            in_phrase = phrase | maybe_block,

            // At the start of a block these are all block elements.
            is_contextual_block = maybe_block | nested_block |
                conditional_or_block | section_block,

            // These are all block elements in all other contexts.
            is_block = nested_block | conditional_or_block | section_block,
        };

        element_info()
            : type(nothing), rule(), tag(0) {}

        element_info(
                type_enum t,
                cl::rule<scanner>* r,
                value::tag_type tag = value::default_tag,
                unsigned int v = 0)
            : type(t), rule(r), tag(tag), qbk_version(v) {}

        type_enum type;
        cl::rule<scanner>* rule;
        value::tag_type tag;
        unsigned int qbk_version;
    };

    struct quickbook_grammar::impl
    {
        quickbook::state& state;
        cleanup cleanup_;

        // Main Grammar
        cl::rule<scanner> block_start;
        cl::rule<scanner> phrase_start;
        cl::rule<scanner> nested_phrase;
        cl::rule<scanner> inline_phrase;
        cl::rule<scanner> paragraph_phrase;
        cl::rule<scanner> extended_phrase;
        cl::rule<scanner> table_title_phrase;
        cl::rule<scanner> inside_preformatted;
        cl::rule<scanner> inside_paragraph;
        cl::rule<scanner> command_line;
        cl::rule<scanner> attribute_template_body;
        cl::rule<scanner> attribute_value_1_7;
        cl::rule<scanner> escape;
        cl::rule<scanner> raw_escape;
        cl::rule<scanner> skip_entity;

        // Miscellaneous stuff
        cl::rule<scanner> hard_space;
        cl::rule<scanner> space;
        cl::rule<scanner> blank;
        cl::rule<scanner> eol;
        cl::rule<scanner> phrase_end;
        cl::rule<scanner> comment;
        cl::rule<scanner> line_comment;
        cl::rule<scanner> macro_identifier;

        // Element Symbols       
        cl::symbols<element_info> elements;

        // Source mode
        cl::symbols<source_mode_type> source_modes;
        
        // Doc Info
        cl::rule<scanner> doc_info_details;
        
        impl(quickbook::state&);

    private:

        void init_main();
        void init_block_elements();
        void init_phrase_elements();
        void init_doc_info();
    };
}

#endif // BOOST_SPIRIT_QUICKBOOK_GRAMMARS_HPP