regex_convert.cpp 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. /*=============================================================================
  2. Copyright (c) 2002-2003 Martin Wille
  3. http://spirit.sourceforge.net/
  4. Use, modification and distribution is subject to the Boost Software
  5. License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  6. http://www.boost.org/LICENSE_1_0.txt)
  7. =============================================================================*/
  8. ///////////////////////////////////////////////////////////////////////////////
  9. // vim:ts=4:sw=4:et
  10. //
  11. // Demonstrate regular expression parsers for match based text conversion
  12. //
  13. // This sample requires an installed version of the boost regex library
  14. // (http://www.boost.org) The sample was tested with boost V1.29.0
  15. //
  16. // Note: - there is no error handling in this example
  17. // - this program isn't particularly useful
  18. //
  19. // This example shows one way build a kind of filter program.
  20. // It reads input from std::cin and uses a grammar and actions
  21. // to print out a modified version of the input.
  22. //
  23. // [ Martin Wille, 10/18/2002 ]
  24. //
  25. ///////////////////////////////////////////////////////////////////////////////
  26. #include <string>
  27. #include <iostream>
  28. #include <streambuf>
  29. #include <sstream>
  30. #include <deque>
  31. #include <iterator>
  32. #include <boost/function.hpp>
  33. #include <boost/spirit/include/classic_core.hpp>
  34. ///////////////////////////////////////////////////////////////////////////////
  35. //
  36. // The following header must be included, if regular expression support is
  37. // required for Spirit.
  38. //
  39. // The BOOST_SPIRIT_NO_REGEX_LIB PP constant should be defined, if you're using the
  40. // Boost.Regex library from one translation unit only. Otherwise you have to
  41. // link with the Boost.Regex library as defined in the related documentation
  42. // (see. http://www.boost.org).
  43. //
  44. ///////////////////////////////////////////////////////////////////////////////
  45. #define BOOST_SPIRIT_NO_REGEX_LIB
  46. #include <boost/spirit/include/classic_regex.hpp>
  47. using namespace BOOST_SPIRIT_CLASSIC_NS;
  48. using namespace std;
  49. namespace {
  50. long triple(long val)
  51. {
  52. return 3*val;
  53. }
  54. ///////////////////////////////////////////////////////////////////////////
  55. //
  56. // actions
  57. //
  58. struct emit_constant
  59. {
  60. emit_constant(string const &text)
  61. : msg(text)
  62. {}
  63. template<typename Iterator>
  64. void operator()(Iterator b, Iterator e) const
  65. {
  66. cout.rdbuf()->sputn(msg.data(), msg.size());
  67. }
  68. private:
  69. string msg;
  70. };
  71. void
  72. copy_unmodified(char letter)
  73. {
  74. cout.rdbuf()->sputc(letter);
  75. }
  76. struct emit_modified_subscript
  77. {
  78. emit_modified_subscript(boost::function<long (long)> const &f)
  79. : modifier(f)
  80. {}
  81. template<typename Iterator>
  82. void operator()(Iterator b, Iterator e) const
  83. {
  84. string tmp(b+1,e-1);
  85. long val = strtol(tmp.c_str(),0, 0);
  86. ostringstream os;
  87. os << modifier(val);
  88. tmp = os.str();
  89. cout.rdbuf()->sputc('[');
  90. cout.rdbuf()->sputn(tmp.c_str(), tmp.size());
  91. cout.rdbuf()->sputc(']');
  92. }
  93. private:
  94. boost::function<long (long)> modifier;
  95. };
  96. }
  97. ///////////////////////////////////////////////////////////////////////////////
  98. // The grammar 'conversion_grammar' serves as a working horse for match based
  99. // text conversion. It does the following:
  100. //
  101. // - converts the word "class" into the word "struct"
  102. // - multiplies any integer number enclosed in square brackets with 3
  103. // - any other input is simply copied to the output
  104. struct conversion_grammar
  105. : grammar<conversion_grammar>
  106. {
  107. template<class ScannerT>
  108. struct definition
  109. {
  110. typedef ScannerT scanner_t;
  111. definition(conversion_grammar const &)
  112. {
  113. static const char expr[] = "\\[\\d+\\]";
  114. first = (
  115. /////////////////////////////////////////////////////////////
  116. // note that "fallback" is the last alternative here !
  117. top = *(class2struct || subscript || fallback),
  118. /////////////////////////////////////////////////////////////
  119. // replace any occurrence of "class" by "struct"
  120. class2struct = str_p("class") [emit_constant("struct")],
  121. /////////////////////////////////////////////////////////////
  122. // if the input maches "[some_number]"
  123. // "some_number" is multiplied by 3 before printing
  124. subscript = regex_p(expr) [emit_modified_subscript(&triple)],
  125. /////////////////////////////////////////////////////////////
  126. // if nothing else can be done with the input
  127. // then it will be printed without modifications
  128. fallback = anychar_p [&copy_unmodified]
  129. );
  130. }
  131. rule<scanner_t> const & start() { return first; }
  132. private:
  133. subrule<0> top;
  134. subrule<1> class2struct;
  135. subrule<2> subscript;
  136. subrule<3> fallback;
  137. rule<scanner_t> first;
  138. };
  139. };
  140. int
  141. main()
  142. {
  143. // this would print "struct foo {}; foo bar[9];":
  144. // parse("class foo {}; foo bar[3];", conversion_grammar());
  145. // Note: the regular expression parser contained in the
  146. // grammar requires a bidirectional iterator. Therefore,
  147. // we cannot use sdt::istreambuf_iterator as one would
  148. // do with other Spirit parsers.
  149. istreambuf_iterator<char> input_iterator(cin);
  150. std::deque<char> input(input_iterator, istreambuf_iterator<char>());
  151. parse(input.begin(), input.end(), conversion_grammar());
  152. return 0;
  153. }