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