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
|
[/==============================================================================
Copyright (C) 2001-2011 Hartmut Kaiser
Copyright (C) 2001-2011 Joel de Guzman
Copyright (C) 2009 Chris Hoeppler
Distributed under 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)
===============================================================================/]
[section:confix Qi Confix Parser Directive]
[heading Description]
The __qi__ `confix` directive is a unary parser component allowing to embed a
parser (the subject) inside an opening (the prefix) and a closing (the suffix):
confix(prefix, suffix)[subject]
This results in a parser that is equivalent to the sequence
omit[prefix] >> subject >> omit[suffix]
A simple example is a parser for non-nested comments which can now be written
as:
confix("/*", "*/")[*(char_ - "*/")] // C style comment
confix("//", eol)[*(char_ - eol)] // C++ style comment
Using the `confix` directive instead of the explicit sequence has the advantage
of being able to encapsulate the prefix and the suffix into a separate construct.
The following code snippet illustrates the idea:
namespace spirit = boost::spirit;
namespace repo = boost::spirit::repository;
// Define a metafunction allowing to compute the type
// of the confix() construct
template <typename Prefix, typename Suffix = Prefix>
struct confix_spec
{
typedef typename spirit::result_of::terminal<
repo::tag::confix(Prefix, Suffix)
>::type type;
};
confix_spec<std::string>::type const c_comment = repo::confix("/*", "*/");
confix_spec<std::string>::type const cpp_comment = repo::confix("//", "\n");
Now, the comment parsers can be written as
c_comment[*(char_ - "*/")] // C style comment
cpp_comment[*(char_ - eol)] // C++ style comment
[note While the `confix_p(prefix, subject, suffix)` parser in __classic__
was equivalent to the sequence `prefix >> *(subject - suffix) >> suffix,
the __qi__ `confix` directive will not perform this refactoring any more.
This simplifies the code and makes things more explicit.]
[heading Header]
// forwards to <boost/spirit/repository/home/qi/directive/confix.hpp>
#include <boost/spirit/repository/include/qi_confix.hpp>
[heading Synopsis]
confix(prefix, suffix)[subject]
[heading Parameters]
[table
[[Parameter] [Description]]
[[`prefix`] [The parser for the opening (the prefix).]]
[[`suffix`] [The parser for the ending (the suffix).]]
[[`subject`] [The parser for the input sequence between the
`prefix` and `suffix` parts.]]
]
All three parameters can be arbitrarily complex parsers themselves.
[heading Attribute]
The `confix` directive exposes the attribute type of its subject as its own
attribute type. If the `subject` does not expose any attribute (the type is
`unused_type`), then the `confix` does not expose any attribute either.
a: A, p: P, s: S: --> confix(p, s)[a]: A
[note This notation is used all over the Spirit documentation and reads as:
Given, `a`, `p`, and `s` are parsers, and `A`, `P`, and `S` are the types
of their attributes, then the type of the attribute exposed by
`confix(p, s)[a]` will be `A`.]
[heading Example]
The following example shows simple use cases of the `confix` directive. We will
illustrate its usage by generating parsers for different comment styles and
for some simple tagged data (for the full example code see
[@../../example/qi/confix.cpp confix.cpp])
[import ../../example/qi/confix.cpp]
[heading Prerequisites]
In addition to the main header file needed to include the core components
implemented in __qi__ we add the header file needed for the new `confix`
directive.
[qi_confix_includes]
In order to make the examples below more readable we import a number of
elements into the current namespace:
[qi_confix_using]
[heading Parsing Different Comment Styles]
We will show how to parse different comment styles. First we will parse
a C++ comment:
[qi_confix_cpp_comment]
This function will obviously parse input such as "`// This is a comment \n `".
Similarily parsing a 'C'-style comment proves to be straightforward:
[qi_confix_c_comment]
which again will be able to parse e.g. "`/* This is a comment */ `".
[heading Parsing Tagged Data]
Generating a parser that extracts the body from the HTML snippet "`<b>The Body</b>`"
is not very hard, either:
[qi_confix_tagged_data]
[endsect]
|