1 /*=============================================================================
2 Copyright (c) 2001-2003 Hartmut Kaiser
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 //
11 // This example shows:
12 // 1. Parsing of different comment styles
13 // parsing C/C++-style comment
14 // parsing C++-style comment
15 // parsing PASCAL-style comment
16 // 2. Parsing tagged data with the help of the confix_parser
17 // 3. Parsing tagged data with the help of the confix_parser but the semantic
18 // action is directly attached to the body sequence parser
19 //
20 ///////////////////////////////////////////////////////////////////////////////
21
22 #include <string>
23 #include <iostream>
24 #include <cassert>
25
26 #include <boost/spirit/include/classic_core.hpp>
27 #include <boost/spirit/include/classic_confix.hpp>
28 #include <boost/spirit/include/classic_chset.hpp>
29
30
31 ///////////////////////////////////////////////////////////////////////////////
32 // used namespaces
33 using namespace std;
34 using namespace BOOST_SPIRIT_CLASSIC_NS;
35
36 ///////////////////////////////////////////////////////////////////////////////
37 // actor called after successfully matching a single character
38 class actor_string
39 {
40 public:
actor_string(std::string & rstr)41 actor_string(std::string &rstr) :
42 matched(rstr)
43 {
44 }
45
operator ()(const char * pbegin,const char * pend) const46 void operator() (const char *pbegin, const char *pend) const
47 {
48 matched += std::string(pbegin, pend-pbegin);
49 }
50
51 private:
52 std::string &matched;
53 };
54
55 ///////////////////////////////////////////////////////////////////////////////
56 // actor called after successfully matching a C++-comment
actor_cpp(const char * pfirst,const char * plast)57 void actor_cpp (const char *pfirst, const char *plast)
58 {
59 cout << "Parsing C++-comment" <<endl;
60 cout << "Matched (" << plast-pfirst << ") characters: ";
61 cout << "\"" << std::string(pfirst, plast) << "\"" << endl;
62 }
63
64 ///////////////////////////////////////////////////////////////////////////////
65 // main entry point
main()66 int main ()
67 {
68
69 ///////////////////////////////////////////////////////////////////////////////
70 //
71 // 1. Parsing different comment styles
72 // parsing C/C++-style comments (non-nested!)
73 //
74 ///////////////////////////////////////////////////////////////////////////////
75
76 char const* pCComment = "/* This is a /* nested */ C-comment */";
77
78 rule<> cpp_comment;
79
80 cpp_comment =
81 comment_p("/*", "*/") // rule for C-comments
82 | comment_p("//") // rule for C++ comments
83 ;
84
85 std::string comment_c;
86 parse_info<> result;
87
88 result = parse (pCComment, cpp_comment[actor_string(comment_c)]);
89 if (result.hit)
90 {
91 cout << "Parsed C-comment successfully!" << endl;
92 cout << "Matched (" << (int)comment_c.size() << ") characters: ";
93 cout << "\"" << comment_c << "\"" << endl;
94 }
95 else
96 {
97 cout << "Failed to parse C/C++-comment!" << endl;
98 }
99 cout << endl;
100
101 // parsing C++-style comment
102 char const* pCPPComment = "// This is a C++-comment\n";
103 std::string comment_cpp;
104
105 result = parse (pCPPComment, cpp_comment[&actor_cpp]);
106 if (result.hit)
107 cout << "Parsed C++-comment successfully!" << endl;
108 else
109 cout << "Failed to parse C++-comment!" << endl;
110
111 cout << endl;
112
113
114 // parsing PASCAL-style comment (nested!)
115 char const* pPComment = "{ This is a (* nested *) PASCAL-comment }";
116
117 rule<> pascal_comment;
118
119 pascal_comment = // in PASCAL we have two comment styles
120 comment_nest_p('{', '}') // both may be nested
121 | comment_nest_p("(*", "*)")
122 ;
123
124 std::string comment_pascal;
125
126 result = parse (pPComment, pascal_comment[actor_string(comment_pascal)]);
127 if (result.hit)
128 {
129 cout << "Parsed PASCAL-comment successfully!" << endl;
130 cout << "Matched (" << (int)comment_pascal.size() << ") characters: ";
131 cout << "\"" << comment_pascal << "\"" << endl;
132 }
133 else
134 {
135 cout << "Failed to parse PASCAL-comment!" << endl;
136 }
137 cout << endl;
138
139 ///////////////////////////////////////////////////////////////////////////////
140 //
141 // 2. Parsing tagged data with the help of the confix parser
142 //
143 ///////////////////////////////////////////////////////////////////////////////
144
145 std::string body;
146 rule<> open_tag, html_tag, close_tag, body_text;
147
148 open_tag =
149 str_p("<b>")
150 ;
151
152 body_text =
153 anychar_p
154 ;
155
156 close_tag =
157 str_p("</b>")
158 ;
159
160 html_tag =
161 confix_p (open_tag, (*body_text)[actor_string(body)], close_tag)
162 ;
163
164 char const* pTag = "<b>Body text</b>";
165
166 result = parse (pTag, html_tag);
167 if (result.hit)
168 {
169 cout << "Parsed HTML snippet \"<b>Body text</b>\" successfully "
170 "(with re-attached actor)!" << endl;
171 cout << "Found body (" << (int)body.size() << " characters): ";
172 cout << "\"" << body << "\"" << endl;
173 }
174 else
175 {
176 cout << "Failed to parse HTML snippet (with re-attached actor)!"
177 << endl;
178 }
179 cout << endl;
180
181 ///////////////////////////////////////////////////////////////////////////////
182 //
183 // 3. Parsing tagged data with the help of the confix_parser but the
184 // semantic action is directly attached to the body sequence parser
185 // (see comment in confix.hpp) and out of the usage of the 'direct()'
186 // construction function no automatic refactoring takes place.
187 //
188 // As you can see, for successful parsing it is required to refactor the
189 // confix parser by hand. To see, how it fails, you can try the following:
190 //
191 // html_tag_direct =
192 // confix_p.direct(
193 // str_p("<b>"),
194 // (*body_text)[actor_string(bodydirect)],
195 // str_p("</b>")
196 // )
197 // ;
198 //
199 // Here the *body_text parser eats up all the input up to the end of the
200 // input sequence.
201 //
202 ///////////////////////////////////////////////////////////////////////////////
203
204 rule<> html_tag_direct;
205 std::string bodydirect;
206
207 html_tag_direct =
208 confix_p.direct(
209 str_p("<b>"),
210 (*(body_text - str_p("</b>")))[actor_string(bodydirect)],
211 str_p("</b>")
212 )
213 ;
214
215 char const* pTagDirect = "<b>Body text</b>";
216
217 result = parse (pTagDirect, html_tag_direct);
218 if (result.hit)
219 {
220 cout << "Parsed HTML snippet \"<b>Body text</b>\" successfully "
221 "(with direct actor)!" << endl;
222 cout << "Found body (" << (int)bodydirect.size() << " characters): ";
223 cout << "\"" << bodydirect << "\"" << endl;
224 }
225 else
226 {
227 cout << "Failed to parse HTML snippet (with direct actor)!" << endl;
228 }
229 cout << endl;
230
231 return 0;
232 }
233