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