attributes.qbk 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. [/==============================================================================
  2. Copyright (C) 2001-2011 Hartmut Kaiser
  3. Copyright (C) 2001-2011 Joel de Guzman
  4. Distributed under the Boost Software License, Version 1.0. (See accompanying
  5. file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. ===============================================================================/]
  7. [section:attributes Attributes]
  8. [/////////////////////////////////////////////////////////////////////////////]
  9. [section:primitive_attributes Attributes of Primitive Components]
  10. Parsers and generators in __spirit__ are fully attributed. __qi__ parsers always
  11. /expose/ an attribute specific to their type. This is called /synthesized
  12. attribute/ as it is returned from a successful match representing the matched
  13. input sequence. For instance, numeric parsers, such as `int_` or `double_`,
  14. return the `int` or `double` value converted from the matched input sequence.
  15. Other primitive parser components have other intuitive attribute types, such as
  16. for instance `int_` which has `int`, or `ascii::char_` which has `char`. For
  17. primitive parsers apply the normal C++ convertibility rules: you can use any
  18. C++ type to receive the parsed value as long as the attribute type of the
  19. parser is convertible to the type provided. The following example shows how a
  20. synthesized parser attribute (the `int` value) is extracted by calling the
  21. API function `qi::parse`:
  22. int value = 0;
  23. std::string str("123");
  24. std::string::iterator strbegin = str.begin();
  25. qi::parse(strbegin, str.end(), int_, value); // value == 123
  26. The attribute type of a generator defines what data types this generator is
  27. able to consume in order to produce its output. __karma__ generators always
  28. /expect/ an attribute specific to their type. This is called /consumed
  29. attribute/ and is expected to be passed to the generator. The consumed
  30. attribute is most of the time the value the generator is designed to emit
  31. output for. For primitive generators the normal C++ convertibility rules apply.
  32. Any data type convertible to the attribute type of a primitive generator can be
  33. used to provide the data to generate. We present a similar example as above,
  34. this time the consumed attribute of the `int_` generator (the `int` value)
  35. is passed to the API function `karma::generate`:
  36. int value = 123;
  37. std::string str;
  38. std::back_insert_iterator<std::string> out(str);
  39. karma::generate(out, int_, value); // str == "123"
  40. Other primitive generator components have other intuitive attribute types, very
  41. similar to the corresponding parser components. For instance, the
  42. `ascii::char_` generator has `char` as consumed attribute. For a full list of
  43. available parser and generator primitives and their attribute types please see
  44. the sections __sec_qi_primitive__ and __sec_karma_primitive__.
  45. [endsect]
  46. [/////////////////////////////////////////////////////////////////////////////]
  47. [section:compound_attributes Attributes of Compound Components]
  48. __qi__ and __karma__ implement well defined attribute type propagation rules
  49. for all compound parsers and generators, such as sequences, alternatives,
  50. Kleene star, etc. The main attribute propagation rule for a sequences is for
  51. instance:
  52. [table
  53. [[Library] [Sequence attribute propagation rule]]
  54. [[Qi] [`a: A, b: B --> (a >> b): tuple<A, B>`]]
  55. [[Karma] [`a: A, b: B --> (a << b): tuple<A, B>`]]
  56. ]
  57. which reads as:
  58. [:Given `a` and `b` are parsers (generators), and `A` is the attribute type of
  59. `a`, and `B` is the attribute type of `b`, then the attribute type of
  60. `a >> b` (`a << b`) will be `tuple<A, B>`.]
  61. [note The notation `tuple<A, B>` is used as a placeholder expression for any
  62. fusion sequence holding the types A and B, such as
  63. `boost::fusion::tuple<A, B>` or `std::pair<A, B>` (for more information
  64. see __fusion__).]
  65. As you can see, in order for a type to be compatible with the attribute type
  66. of a compound expression it has to
  67. * either be convertible to the attribute type,
  68. * or it has to expose certain functionalities, i.e. it needs to conform to a
  69. concept compatible with the component.
  70. Each compound component implements its own set of attribute propagation rules.
  71. For a full list of how the different compound generators consume attributes
  72. see the sections __sec_qi_compound__ and __sec_karma_compound__.
  73. [heading The Attribute of Sequence Parsers and Generators]
  74. Sequences require an attribute type to expose the concept of a fusion sequence,
  75. where all elements of that fusion sequence have to be compatible with the
  76. corresponding element of the component sequence. For example, the expression:
  77. [table
  78. [[Library] [Sequence expression]]
  79. [[Qi] [`double_ >> double_`]]
  80. [[Karma] [`double_ << double_`]]
  81. ]
  82. is compatible with any fusion sequence holding two types, where both types have
  83. to be compatible with `double`. The first element of the fusion sequence has to
  84. be compatible with the attribute of the first `double_`, and the second element
  85. of the fusion sequence has to be compatible with the attribute of the second
  86. `double_`. If we assume to have an instance of a `std::pair<double, double>`,
  87. we can directly use the expressions above to do both, parse input to fill the
  88. attribute:
  89. // the following parses "1.0 2.0" into a pair of double
  90. std::string input("1.0 2.0");
  91. std::string::iterator strbegin = input.begin();
  92. std::pair<double, double> p;
  93. qi::phrase_parse(strbegin, input.end(),
  94. qi::double_ >> qi::double_, // parser grammar
  95. qi::space, // delimiter grammar
  96. p); // attribute to fill while parsing
  97. and generate output for it:
  98. // the following generates: "1.0 2.0" from the pair filled above
  99. std::string str;
  100. std::back_insert_iterator<std::string> out(str);
  101. karma::generate_delimited(out,
  102. karma::double_ << karma::double_, // generator grammar (format description)
  103. karma::space, // delimiter grammar
  104. p); // data to use as the attribute
  105. (where the `karma::space` generator is used as the delimiter, allowing to
  106. automatically skip/insert delimiting spaces in between all primitives).
  107. [tip *For sequences only:* __qi__ and __karma__ expose a set of API functions
  108. usable mainly with sequences. Very much like the functions of the `scanf`
  109. and `printf` families these functions allow to pass the attributes for
  110. each of the elements of the sequence separately. Using the corresponding
  111. overload of /Qi's/ parse or /Karma's/ `generate()` the expression above
  112. could be rewritten as:
  113. ``
  114. double d1 = 0.0, d2 = 0.0;
  115. qi::phrase_parse(begin, end, qi::double_ >> qi::double_, qi::space, d1, d2);
  116. karma::generate_delimited(out, karma::double_ << karma::double_, karma::space, d1, d2);
  117. ``
  118. where the first attribute is used for the first `double_`, and
  119. the second attribute is used for the second `double_`.
  120. ]
  121. [heading The Attribute of Alternative Parsers and Generators]
  122. Alternative parsers and generators are all about - well - alternatives. In
  123. order to store possibly different result (attribute) types from the different
  124. alternatives we use the data type __boost_variant__. The main attribute
  125. propagation rule of these components is:
  126. a: A, b: B --> (a | b): variant<A, B>
  127. Alternatives have a second very important attribute propagation rule:
  128. a: A, b: A --> (a | b): A
  129. often allowing to simplify things significantly. If all sub expressions of
  130. an alternative expose the same attribute type, the overall alternative
  131. will expose exactly the same attribute type as well.
  132. [endsect]
  133. [/////////////////////////////////////////////////////////////////////////////]
  134. [section:more_compound_attributes More About Attributes of Compound Components]
  135. While parsing input or generating output it is often desirable to combine some
  136. constant elements with variable parts. For instance, let us look at the example
  137. of parsing or formatting a complex number, which is written as `(real, imag)`,
  138. where `real` and `imag ` are the variables representing the real and imaginary
  139. parts of our complex number. This can be achieved by writing:
  140. [table
  141. [[Library] [Sequence expression]]
  142. [[Qi] [`'(' >> double_ >> ", " >> double_ >> ')'`]]
  143. [[Karma] [`'(' << double_ << ", " << double_ << ')'`]]
  144. ]
  145. Fortunately, literals (such as `'('` and `", "`) do /not/ expose any attribute
  146. (well actually, they do expose the special type `unused_type`, but in this
  147. context `unused_type` is interpreted as if the component does not expose any
  148. attribute at all). It is very important to understand that the literals don't
  149. consume any of the elements of a fusion sequence passed to this component
  150. sequence. As said, they just don't expose any attribute and don't produce
  151. (consume) any data. The following example shows this:
  152. // the following parses "(1.0, 2.0)" into a pair of double
  153. std::string input("(1.0, 2.0)");
  154. std::string::iterator strbegin = input.begin();
  155. std::pair<double, double> p;
  156. qi::parse(strbegin, input.end(),
  157. '(' >> qi::double_ >> ", " >> qi::double_ >> ')', // parser grammar
  158. p); // attribute to fill while parsing
  159. and here is the equivalent __karma__ code snippet:
  160. // the following generates: (1.0, 2.0)
  161. std::string str;
  162. std::back_insert_iterator<std::string> out(str);
  163. generate(out,
  164. '(' << karma::double_ << ", " << karma::double_ << ')', // generator grammar (format description)
  165. p); // data to use as the attribute
  166. where the first element of the pair passed in as the data to generate is still
  167. associated with the first `double_`, and the second element is associated with
  168. the second `double_` generator.
  169. This behavior should be familiar as it conforms to the way other input and
  170. output formatting libraries such as `scanf`, `printf` or `boost::format` are
  171. handling their variable parts. In this context you can think about __qi__'s
  172. and __karma__'s primitive components (such as the `double_` above) as of being
  173. type safe placeholders for the attribute values.
  174. [tip Similarly to the tip provided above, this example could be rewritten
  175. using /Spirit's/ multi-attribute API function:
  176. ``
  177. double d1 = 0.0, d2 = 0.0;
  178. qi::parse(begin, end, '(' >> qi::double_ >> ", " >> qi::double_ >> ')', d1, d2);
  179. karma::generate(out, '(' << karma::double_ << ", " << karma::double_ << ')', d1, d2);
  180. ``
  181. which provides a clear and comfortable syntax, more similar to the
  182. placeholder based syntax as exposed by `printf` or `boost::format`.
  183. ]
  184. Let's take a look at this from a more formal perspective. The sequence attribute
  185. propagation rules define a special behavior if generators exposing `unused_type`
  186. as their attribute are involved (see __sec_karma_compound__):
  187. [table
  188. [[Library] [Sequence attribute propagation rule]]
  189. [[Qi] [`a: A, b: Unused --> (a >> b): A`]]
  190. [[Karma] [`a: A, b: Unused --> (a << b): A`]]
  191. ]
  192. which reads as:
  193. [:Given `a` and `b` are parsers (generators), and `A` is the attribute type of
  194. `a`, and `unused_type` is the attribute type of `b`, then the attribute type
  195. of `a >> b` (`a << b`) will be `A` as well. This rule applies regardless of
  196. the position the element exposing the `unused_type` is at.]
  197. This rule is the key to the understanding of the attribute handling in
  198. sequences as soon as literals are involved. It is as if elements with
  199. `unused_type` attributes 'disappeared' during attribute propagation. Notably,
  200. this is not only true for sequences but for any compound components. For
  201. instance, for alternative components the corresponding rule is:
  202. a: A, b: Unused --> (a | b): A
  203. again, allowing to simplify the overall attribute type of an expression.
  204. [endsect]
  205. [/////////////////////////////////////////////////////////////////////////////]
  206. [section:nonterminal_attributes Attributes of Rules and Grammars]
  207. Nonterminals are well known from parsers where they are used as the main means
  208. of constructing more complex parsers out of simpler ones. The nonterminals in
  209. the parser world are very similar to functions in an imperative programming
  210. language. They can be used to encapsulate parser expressions for a particular
  211. input sequence. After being defined, the nonterminals can be used as 'normal'
  212. parsers in more complex expressions whenever the encapsulated input needs to be
  213. recognized. Parser nonterminals in __qi__ may accept /parameters/ (inherited
  214. attributes) and usually return a value (the synthesized attribute).
  215. Both, the types of the inherited and the synthesized attributes have to be
  216. explicitly specified while defining the particular `grammar` or the `rule`
  217. (the Spirit __repo__ additionally has `subrules` which conform to a similar
  218. interface). As an example, the following code declares a __qi__ `rule`
  219. exposing an `int` as its synthesized attribute, while expecting a single
  220. `double` as its inherited attribute (see the section about the __qi__ __rule__
  221. for more information):
  222. qi::rule<Iterator, int(double)> r;
  223. In the world of generators, nonterminals are just as useful as in the parser
  224. world. Generator nonterminals encapsulate a format description for a particular
  225. data type, and, whenever we need to emit output for this data type, the
  226. corresponding nonterminal is invoked in a similar way as the predefined
  227. __karma__ generator primitives. The __karma__ [karma_nonterminal nonterminals]
  228. are very similar to the __qi__ nonterminals. Generator nonterminals may accept
  229. /parameters/ as well, and we call those inherited attributes too. The main
  230. difference is that they do not expose a synthesized attribute (as parsers do),
  231. but they require a special /consumed attribute/. Usually the consumed attribute
  232. is the value the generator creates its output from. Even if the consumed
  233. attribute is not 'returned' from the generator we chose to use the same
  234. function style declaration syntax as used in __qi__. The example below declares
  235. a __karma__ `rule` consuming a `double` while not expecting any additional
  236. inherited attributes.
  237. karma::rule<OutputIterator, double()> r;
  238. The inherited attributes of nonterminal parsers and generators are normally
  239. passed to the component during its invocation. These are the /parameters/ the
  240. parser or generator may accept and they can be used to parameterize the
  241. component depending on the context they are invoked from.
  242. [/
  243. * attribute propagation
  244. * explicit and operator%=
  245. ]
  246. [endsect]
  247. [endsect] [/ Attributes]