grammars.qbk 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. [/
  2. / Copyright (c) 2008 Eric Niebler
  3. /
  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 Grammars and Nested Matches]
  8. [h2 Overview]
  9. One of the key benefits of representing regexes as C++ expressions is the ability to easily refer to other C++
  10. code and data from within the regex. This enables programming idioms that are not possible with other regular
  11. expression libraries. Of particular note is the ability for one regex to refer to another regex, allowing you
  12. to build grammars out of regular expressions. This section describes how to embed one regex in another by value
  13. and by reference, how regex objects behave when they refer to other regexes, and how to access the tree of results
  14. after a successful parse.
  15. [h2 Embedding a Regex by Value]
  16. The _basic_regex_ object has value semantics. When a regex object appears on the right-hand side in the definition
  17. of another regex, it is as if the regex were embedded by value; that is, a copy of the nested regex is stored by
  18. the enclosing regex. The inner regex is invoked by the outer regex during pattern matching. The inner regex
  19. participates fully in the match, back-tracking as needed to make the match succeed.
  20. Consider a text editor that has a regex-find feature with a whole-word option. You can implement this with
  21. xpressive as follows:
  22. find_dialog dlg;
  23. if( dialog_ok == dlg.do_modal() )
  24. {
  25. std::string pattern = dlg.get_text(); // the pattern the user entered
  26. bool whole_word = dlg.whole_word.is_checked(); // did the user select the whole-word option?
  27. sregex re = sregex::compile( pattern ); // try to compile the pattern
  28. if( whole_word )
  29. {
  30. // wrap the regex in begin-word / end-word assertions
  31. re = bow >> re >> eow;
  32. }
  33. // ... use re ...
  34. }
  35. Look closely at this line:
  36. // wrap the regex in begin-word / end-word assertions
  37. re = bow >> re >> eow;
  38. This line creates a new regex that embeds the old regex by value. Then, the new regex is assigned back to
  39. the original regex. Since a copy of the old regex was made on the right-hand side, this works as you might
  40. expect: the new regex has the behavior of the old regex wrapped in begin- and end-word assertions.
  41. [note Note that `re = bow >> re >> eow` does ['not] define a recursive regular expression, since regex
  42. objects embed by value by default. The next section shows how to define a recursive regular expression by
  43. embedding a regex by reference.]
  44. [h2 Embedding a Regex by Reference]
  45. If you want to be able to build recursive regular expressions and context-free grammars, embedding a regex
  46. by value is not enough. You need to be able to make your regular expressions self-referential. Most regular
  47. expression engines don't give you that power, but xpressive does.
  48. [tip The theoretical computer scientists out there will correctly point out that a self-referential
  49. regular expression is not "regular", so in the strict sense, xpressive isn't really a ['regular] expression engine
  50. at all. But as Larry Wall once said, "the term '''[regular expression]''' has grown with the capabilities of our
  51. pattern matching engines, so I'm not going to try to fight linguistic necessity here."]
  52. Consider the following code, which uses the `by_ref()` helper to define a recursive regular expression that
  53. matches balanced, nested parentheses:
  54. sregex parentheses;
  55. parentheses // A balanced set of parentheses ...
  56. = '(' // is an opening parenthesis ...
  57. >> // followed by ...
  58. *( // zero or more ...
  59. keep( +~(set='(',')') ) // of a bunch of things that are not parentheses ...
  60. | // or ...
  61. by_ref(parentheses) // a balanced set of parentheses
  62. ) // (ooh, recursion!) ...
  63. >> // followed by ...
  64. ')' // a closing parenthesis
  65. ;
  66. Matching balanced, nested tags is an important text processing task, and it is one that "classic" regular
  67. expressions cannot do. The `by_ref()` helper makes it possible. It allows one regex object to be embedded
  68. in another ['by reference]. Since the right-hand side holds `parentheses` by reference, assigning the right-hand
  69. side back to `parentheses` creates a cycle, which will execute recursively.
  70. [h2 Building a Grammar]
  71. Once we allow self-reference in our regular expressions, the genie is out of the bottle and all manner of
  72. fun things are possible. In particular, we can now build grammars out of regular expressions. Let's have
  73. a look at the text-book grammar example: the humble calculator.
  74. sregex group, factor, term, expression;
  75. group = '(' >> by_ref(expression) >> ')';
  76. factor = +_d | group;
  77. term = factor >> *(('*' >> factor) | ('/' >> factor));
  78. expression = term >> *(('+' >> term) | ('-' >> term));
  79. The regex `expression` defined above does something rather remarkable for a regular expression: it matches
  80. mathematical expressions. For example, if the input string were `"foo 9*(10+3) bar"`, this pattern would
  81. match `"9*(10+3)"`. It only matches well-formed mathematical expressions, where the parentheses are
  82. balanced and the infix operators have two arguments each. Don't try this with just any regular expression
  83. engine!
  84. Let's take a closer look at this regular expression grammar. Notice that it is cyclic: `expression` is
  85. implemented in terms of `term`, which is implemented in terms of `factor`, which is implemented in terms
  86. of `group`, which is implemented in terms of `expression`, closing the loop. In general, the way to define
  87. a cyclic grammar is to forward-declare the regex objects and embed by reference those regular expressions
  88. that have not yet been initialized. In the above grammar, there is only one place where we need to reference
  89. a regex object that has not yet been initialized: the definition of `group`. In that place, we use
  90. `by_ref()` to embed `expression` by reference. In all other places, it is sufficient to embed the other
  91. regex objects by value, since they have already been initialized and their values will not change.
  92. [tip [*Embed by value if possible]
  93. \n\n
  94. In general, prefer embedding regular expressions by value rather than by reference. It
  95. involves one less indirection, making your patterns match a little faster. Besides, value semantics
  96. are simpler and will make your grammars easier to reason about. Don't worry about the expense of "copying"
  97. a regex. Each regex object shares its implementation with all of its copies.]
  98. [h2 Dynamic Regex Grammars]
  99. Using _regex_compiler_, you can also build grammars out of dynamic regular expressions.
  100. You do that by creating named regexes, and referring to other regexes by name. Each
  101. _regex_compiler_ instance keeps a mapping from names to regexes that have been created
  102. with it.
  103. You can create a named dynamic regex by prefacing your regex with `"(?$name=)"`, where
  104. /name/ is the name of the regex. You can refer to a named regex from another regex with
  105. `"(?$name)"`. The named regex does not need to exist yet at the time it is referenced
  106. in another regex, but it must exist by the time you use the regex.
  107. Below is a code fragment that uses dynamic regex grammars to implement the calculator
  108. example from above.
  109. using namespace boost::xpressive;
  110. using namespace regex_constants;
  111. sregex expr;
  112. {
  113. sregex_compiler compiler;
  114. syntax_option_type x = ignore_white_space;
  115. compiler.compile("(? $group = ) \\( (? $expr ) \\) ", x);
  116. compiler.compile("(? $factor = ) \\d+ | (? $group ) ", x);
  117. compiler.compile("(? $term = ) (? $factor )"
  118. " ( \\* (? $factor ) | / (? $factor ) )* ", x);
  119. expr = compiler.compile("(? $expr = ) (? $term )"
  120. " ( \\+ (? $term ) | - (? $term ) )* ", x);
  121. }
  122. std::string str("foo 9*(10+3) bar");
  123. smatch what;
  124. if(regex_search(str, what, expr))
  125. {
  126. // This prints "9*(10+3)":
  127. std::cout << what[0] << std::endl;
  128. }
  129. As with static regex grammars, nested regex invocations create nested
  130. match results (see /Nested Results/ below). The result is a complete parse tree
  131. for string that matched. Unlike static regexes, dynamic regexes are always
  132. embedded by reference, not by value.
  133. [h2 Cyclic Patterns, Copying and Memory Management, Oh My!]
  134. The calculator examples above raises a number of very complicated memory-management issues. Each of the
  135. four regex objects refer to each other, some directly and some indirectly, some by value and some by
  136. reference. What if we were to return one of them from a function and let the others go out of scope?
  137. What becomes of the references? The answer is that the regex objects are internally reference counted,
  138. such that they keep their referenced regex objects alive as long as they need them. So passing a regex
  139. object by value is never a problem, even if it refers to other regex objects that have gone out of scope.
  140. Those of you who have dealt with reference counting are probably familiar with its Achilles Heel: cyclic
  141. references. If regex objects are reference counted, what happens to cycles like the one created in the
  142. calculator examples? Are they leaked? The answer is no, they are not leaked. The _basic_regex_ object has some tricky
  143. reference tracking code that ensures that even cyclic regex grammars are cleaned up when the last external
  144. reference goes away. So don't worry about it. Create cyclic grammars, pass your regex objects around and
  145. copy them all you want. It is fast and efficient and guaranteed not to leak or result in dangling references.
  146. [h2 Nested Regexes and Sub-Match Scoping]
  147. Nested regular expressions raise the issue of sub-match scoping. If both the inner and outer regex write
  148. to and read from the same sub-match vector, chaos would ensue. The inner regex would stomp on the
  149. sub-matches written by the outer regex. For example, what does this do?
  150. sregex inner = sregex::compile( "(.)\\1" );
  151. sregex outer = (s1= _) >> inner >> s1;
  152. The author probably didn't intend for the inner regex to overwrite the sub-match written by the outer
  153. regex. The problem is particularly acute when the inner regex is accepted from the user as input. The
  154. author has no way of knowing whether the inner regex will stomp the sub-match vector or not. This is
  155. clearly not acceptable.
  156. Instead, what actually happens is that each invocation of a nested regex gets its own scope. Sub-matches
  157. belong to that scope. That is, each nested regex invocation gets its own copy of the sub-match vector to
  158. play with, so there is no way for an inner regex to stomp on the sub-matches of an outer regex. So, for
  159. example, the regex `outer` defined above would match `"ABBA"`, as it should.
  160. [h2 Nested Results]
  161. If nested regexes have their own sub-matches, there should be a way to access them after a successful
  162. match. In fact, there is. After a _regex_match_ or _regex_search_, the _match_results_ struct behaves
  163. like the head of a tree of nested results. The _match_results_ class provides a `nested_results()`
  164. member function that returns an ordered sequence of _match_results_ structures, representing the
  165. results of the nested regexes. The order of the nested results is the same as the order in which
  166. the nested regex objects matched.
  167. Take as an example the regex for balanced, nested parentheses we saw earlier:
  168. sregex parentheses;
  169. parentheses = '(' >> *( keep( +~(set='(',')') ) | by_ref(parentheses) ) >> ')';
  170. smatch what;
  171. std::string str( "blah blah( a(b)c (c(e)f (g)h )i (j)6 )blah" );
  172. if( regex_search( str, what, parentheses ) )
  173. {
  174. // display the whole match
  175. std::cout << what[0] << '\n';
  176. // display the nested results
  177. std::for_each(
  178. what.nested_results().begin(),
  179. what.nested_results().end(),
  180. output_nested_results() );
  181. }
  182. This program displays the following:
  183. [pre
  184. ( a(b)c (c(e)f (g)h )i (j)6 )
  185. (b)
  186. (c(e)f (g)h )
  187. (e)
  188. (g)
  189. (j)
  190. ]
  191. Here you can see how the results are nested and that they are stored in the order in which they
  192. are found.
  193. [tip See the definition of [link boost_xpressive.user_s_guide.examples.display_a_tree_of_nested_results output_nested_results] in the
  194. [link boost_xpressive.user_s_guide.examples Examples] section.]
  195. [h2 Filtering Nested Results]
  196. Sometimes a regex will have several nested regex objects, and you want to know which result corresponds
  197. to which regex object. That's where `basic_regex<>::regex_id()` and `match_results<>::regex_id()`
  198. come in handy. When iterating over the nested results, you can compare the regex id from the results to
  199. the id of the regex object you're interested in.
  200. To make this a bit easier, xpressive provides a predicate to make it simple to iterate over just the
  201. results that correspond to a certain nested regex. It is called `regex_id_filter_predicate`, and it is
  202. intended to be used with _iterator_. You can use it as follows:
  203. sregex name = +alpha;
  204. sregex integer = +_d;
  205. sregex re = *( *_s >> ( name | integer ) );
  206. smatch what;
  207. std::string str( "marsha 123 jan 456 cindy 789" );
  208. if( regex_match( str, what, re ) )
  209. {
  210. smatch::nested_results_type::const_iterator begin = what.nested_results().begin();
  211. smatch::nested_results_type::const_iterator end = what.nested_results().end();
  212. // declare filter predicates to select just the names or the integers
  213. sregex_id_filter_predicate name_id( name.regex_id() );
  214. sregex_id_filter_predicate integer_id( integer.regex_id() );
  215. // iterate over only the results from the name regex
  216. std::for_each(
  217. boost::make_filter_iterator( name_id, begin, end ),
  218. boost::make_filter_iterator( name_id, end, end ),
  219. output_result
  220. );
  221. std::cout << '\n';
  222. // iterate over only the results from the integer regex
  223. std::for_each(
  224. boost::make_filter_iterator( integer_id, begin, end ),
  225. boost::make_filter_iterator( integer_id, end, end ),
  226. output_result
  227. );
  228. }
  229. where `output_results` is a simple function that takes a `smatch` and displays the full match.
  230. Notice how we use the `regex_id_filter_predicate` together with `basic_regex<>::regex_id()` and
  231. `boost::make_filter_iterator()` from the _iterator_ to select only those results
  232. corresponding to a particular nested regex. This program displays the following:
  233. [pre
  234. marsha
  235. jan
  236. cindy
  237. 123
  238. 456
  239. 789
  240. ]
  241. [endsect]