• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 [&copy_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