]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | [/============================================================================== |
2 | Copyright (C) 2001-2011 Hartmut Kaiser | |
3 | Copyright (C) 2001-2011 Joel de Guzman | |
4 | Copyright (C) 2009 Chris Hoeppler | |
5 | ||
6 | Distributed under the Boost Software License, Version 1.0. (See accompanying | |
7 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
8 | ===============================================================================/] | |
9 | ||
10 | [section:confix Qi Confix Parser Directive] | |
11 | ||
12 | [heading Description] | |
13 | ||
14 | The __qi__ `confix` directive is a unary parser component allowing to embed a | |
15 | parser (the subject) inside an opening (the prefix) and a closing (the suffix): | |
16 | ||
17 | confix(prefix, suffix)[subject] | |
18 | ||
19 | This results in a parser that is equivalent to the sequence | |
20 | ||
21 | omit[prefix] >> subject >> omit[suffix] | |
22 | ||
23 | A simple example is a parser for non-nested comments which can now be written | |
24 | as: | |
25 | ||
26 | confix("/*", "*/")[*(char_ - "*/")] // C style comment | |
27 | confix("//", eol)[*(char_ - eol)] // C++ style comment | |
28 | ||
29 | Using the `confix` directive instead of the explicit sequence has the advantage | |
30 | of being able to encapsulate the prefix and the suffix into a separate construct. | |
31 | The following code snippet illustrates the idea: | |
32 | ||
33 | namespace spirit = boost::spirit; | |
34 | namespace repo = boost::spirit::repository; | |
35 | ||
36 | // Define a metafunction allowing to compute the type | |
37 | // of the confix() construct | |
38 | template <typename Prefix, typename Suffix = Prefix> | |
39 | struct confix_spec | |
40 | { | |
41 | typedef typename spirit::result_of::terminal< | |
42 | repo::tag::confix(Prefix, Suffix) | |
43 | >::type type; | |
44 | }; | |
45 | ||
46 | confix_spec<std::string>::type const c_comment = repo::confix("/*", "*/"); | |
47 | confix_spec<std::string>::type const cpp_comment = repo::confix("//", "\n"); | |
48 | ||
49 | Now, the comment parsers can be written as | |
50 | ||
51 | c_comment[*(char_ - "*/")] // C style comment | |
52 | cpp_comment[*(char_ - eol)] // C++ style comment | |
53 | ||
54 | [note While the `confix_p(prefix, subject, suffix)` parser in __classic__ | |
55 | was equivalent to the sequence `prefix >> *(subject - suffix) >> suffix, | |
56 | the __qi__ `confix` directive will not perform this refactoring any more. | |
57 | This simplifies the code and makes things more explicit.] | |
58 | ||
59 | [heading Header] | |
60 | ||
61 | // forwards to <boost/spirit/repository/home/qi/directive/confix.hpp> | |
62 | #include <boost/spirit/repository/include/qi_confix.hpp> | |
63 | ||
64 | [heading Synopsis] | |
65 | ||
66 | confix(prefix, suffix)[subject] | |
67 | ||
68 | [heading Parameters] | |
69 | ||
70 | [table | |
71 | [[Parameter] [Description]] | |
72 | [[`prefix`] [The parser for the opening (the prefix).]] | |
73 | [[`suffix`] [The parser for the ending (the suffix).]] | |
74 | [[`subject`] [The parser for the input sequence between the | |
75 | `prefix` and `suffix` parts.]] | |
76 | ] | |
77 | ||
78 | All three parameters can be arbitrarily complex parsers themselves. | |
79 | ||
80 | [heading Attribute] | |
81 | ||
82 | The `confix` directive exposes the attribute type of its subject as its own | |
83 | attribute type. If the `subject` does not expose any attribute (the type is | |
84 | `unused_type`), then the `confix` does not expose any attribute either. | |
85 | ||
86 | a: A, p: P, s: S: --> confix(p, s)[a]: A | |
87 | ||
88 | [note This notation is used all over the Spirit documentation and reads as: | |
89 | Given, `a`, `p`, and `s` are parsers, and `A`, `P`, and `S` are the types | |
90 | of their attributes, then the type of the attribute exposed by | |
91 | `confix(p, s)[a]` will be `A`.] | |
92 | ||
93 | [heading Example] | |
94 | ||
95 | The following example shows simple use cases of the `confix` directive. We will | |
96 | illustrate its usage by generating parsers for different comment styles and | |
97 | for some simple tagged data (for the full example code see | |
98 | [@../../example/qi/confix.cpp confix.cpp]) | |
99 | ||
100 | [import ../example/qi/confix.cpp] | |
101 | ||
102 | [heading Prerequisites] | |
103 | ||
104 | In addition to the main header file needed to include the core components | |
105 | implemented in __qi__ we add the header file needed for the new `confix` | |
106 | directive. | |
107 | ||
108 | [qi_confix_includes] | |
109 | ||
110 | In order to make the examples below more readable we import a number of | |
111 | elements into the current namespace: | |
112 | ||
113 | [qi_confix_using] | |
114 | ||
115 | [heading Parsing Different Comment Styles] | |
116 | ||
117 | We will show how to parse different comment styles. First we will parse | |
118 | a C++ comment: | |
119 | ||
120 | [qi_confix_cpp_comment] | |
121 | ||
122 | This function will obviously parse input such as "`// This is a comment \n `". | |
123 | Similarily parsing a 'C'-style comment proves to be straightforward: | |
124 | ||
125 | [qi_confix_c_comment] | |
126 | ||
127 | which again will be able to parse e.g. "`/* This is a comment */ `". | |
128 | ||
129 | [heading Parsing Tagged Data] | |
130 | ||
131 | Generating a parser that extracts the body from the HTML snippet "`<b>The Body</b>`" | |
132 | is not very hard, either: | |
133 | ||
134 | [qi_confix_tagged_data] | |
135 | ||
136 | ||
137 | [endsect] |