Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r55304 - in trunk/libs/spirit/repository: doc/html doc/qi example/qi test test/qi
From: hartmut.kaiser_at_[hidden]
Date: 2009-07-30 21:12:33


Author: hkaiser
Date: 2009-07-30 19:05:02 EDT (Thu, 30 Jul 2009)
New Revision: 55304
URL: http://svn.boost.org/trac/boost/changeset/55304

Log:
Spirit: repository doc update, added example and test for qi::confix
Added:
   trunk/libs/spirit/repository/doc/qi/confix.qbk (contents, props changed)
   trunk/libs/spirit/repository/example/qi/confix.cpp (contents, props changed)
   trunk/libs/spirit/repository/test/qi/confix.cpp (contents, props changed)
Text files modified:
   trunk/libs/spirit/repository/doc/html/index.html | 24 ++++++++++++++----------
   trunk/libs/spirit/repository/doc/qi/compound_parsers.qbk | 2 +-
   trunk/libs/spirit/repository/doc/qi/directives.qbk | 3 ++-
   trunk/libs/spirit/repository/doc/qi/distinct.qbk | 2 +-
   trunk/libs/spirit/repository/doc/qi/flush_multi_pass.qbk | 2 +-
   trunk/libs/spirit/repository/doc/qi/primitive_parsers.qbk | 2 +-
   trunk/libs/spirit/repository/test/CMakeLists.txt | 1 +
   trunk/libs/spirit/repository/test/Jamfile | 1 +
   8 files changed, 22 insertions(+), 15 deletions(-)

Modified: trunk/libs/spirit/repository/doc/html/index.html
==============================================================================
--- trunk/libs/spirit/repository/doc/html/index.html (original)
+++ trunk/libs/spirit/repository/doc/html/index.html 2009-07-30 19:05:02 EDT (Thu, 30 Jul 2009)
@@ -34,7 +34,7 @@
 <div><p class="copyright">Copyright © 2001-2009 Joel
       de Guzman, Hartmut Kaiser</p></div>
 <div><div class="legalnotice" title="Legal Notice">
-<a name="id1026275"></a><p>
+<a name="id1015171"></a><p>
         Distributed under the Boost Software License, Version 1.0. (See accompanying
         file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
       </p>
@@ -48,14 +48,18 @@
 <dt><span class="section">Preface</span></dt>
 <dt><span class="section">Qi Components</span></dt>
 <dd><dl>
-<dt><span class="section"><a href="spirit_repository/qi_components/qi_parser_primitives.html">Qi
- Parser Primitives</a></span></dt>
-<dd><dl><dt><span class="section"><a href="spirit_repository/qi_components/qi_parser_primitives/qi_flush_multi_pass_parser.html">Qi
- flush_multi_pass parser</a></span></dt></dl></dd>
-<dt><span class="section"><a href="spirit_repository/qi_components/qi_parser_directives.html">Qi
- Parser Directives</a></span></dt>
-<dd><dl><dt><span class="section"><a href="spirit_repository/qi_components/qi_parser_directives/qi_distinct_parser.html">Qi
- Distinct Parser</a></span></dt></dl></dd>
+<dt><span class="section"><a href="spirit_repository/qi_components/primitive.html"> Qi Parser
+ Primitives</a></span></dt>
+<dd><dl><dt><span class="section"><a href="spirit_repository/qi_components/primitive/flush_multi_pass.html">
+ Qi flush_multi_pass parser</a></span></dt></dl></dd>
+<dt><span class="section"><a href="spirit_repository/qi_components/directives.html"> Qi Parser
+ Directives</a></span></dt>
+<dd><dl>
+<dt><span class="section"><a href="spirit_repository/qi_components/directives/confix.html">
+ Qi Confix Parser Directive</a></span></dt>
+<dt><span class="section"><a href="spirit_repository/qi_components/directives/distinct.html">
+ Qi Distinct Parser Directive</a></span></dt>
+</dl></dd>
 </dl></dd>
 <dt><span class="section">Karma Components</span></dt>
 <dd><dl>
@@ -68,7 +72,7 @@
 </div>
 </div>
 <table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
-<td align="left"><p><small>Last revised: July 27, 2009 at 18:43:05 GMT</small></p></td>
+<td align="left"><p><small>Last revised: July 30, 2009 at 22:57:50 GMT</small></p></td>
 <td align="right"><div class="copyright-footer"></div></td>
 </tr></table>
 <hr>

Modified: trunk/libs/spirit/repository/doc/qi/compound_parsers.qbk
==============================================================================
--- trunk/libs/spirit/repository/doc/qi/compound_parsers.qbk (original)
+++ trunk/libs/spirit/repository/doc/qi/compound_parsers.qbk 2009-07-30 19:05:02 EDT (Thu, 30 Jul 2009)
@@ -6,5 +6,5 @@
     file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 ===============================================================================/]
 
-[section Qi Compound Parsers]
+[section:compound Qi Compound Parsers]
 [endsect]

Added: trunk/libs/spirit/repository/doc/qi/confix.qbk
==============================================================================
--- (empty file)
+++ trunk/libs/spirit/repository/doc/qi/confix.qbk 2009-07-30 19:05:02 EDT (Thu, 30 Jul 2009)
@@ -0,0 +1,136 @@
+[/==============================================================================
+ Copyright (C) 2001-2009 Hartmut Kaiser
+ Copyright (C) 2001-2009 Joel de Guzman
+ Copyright (C) 2009 Chris Hoeppler
+
+ Distributed under the Boost Software License, Version 1.0. (See accompanying
+ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+===============================================================================/]
+
+[section:confix Qi Confix Parser Directive]
+
+[heading Description]
+
+The __qi__ `confix` directive is a unary parser component allowing to embed a
+parser (the subject) inside an opening (the prefix) and a closing (the suffix):
+
+ confix(prefix, suffix)[subject]
+
+This results in a parser that is equivalent to the sequence
+
+ omit[prefix] >> subject >> omit[suffix]
+
+A simple example is a parser for non-nested comments which can now be written
+as:
+
+ confix("/*", "*/")[*(char_ - "*/")] // C style comment
+ confix("//", eol)[*(char_ - eol)] // C++ style comment
+
+Using the `confix` directive instead of the explicit sequence has the advantage
+of being able to encapsulate the prefix and the suffix into a separate construct.
+The following code snippet illustrates the idea:
+
+ namespace spirit = boost::spirit;
+ namespace repo = boost::spirit::repository;
+
+ // Define a metafunction allowing to compute the type
+ // of the confix() construct
+ template <typename Prefix, typename Suffix = Prefix>
+ struct confix_spec
+ {
+ typedef typename spirit::result_of::terminal<
+ repo::tag::confix(Prefix, Suffix)
+ >::type type;
+ };
+
+ confix_spec<std::string>::type const c_comment = repo::confix("/*", "*/");
+ confix_spec<std::string>::type const cpp_comment = repo::confix("//", "\n");
+
+Now, the comment parsers can be written as
+
+ c_comment[*(char_ - "*/")] // C style comment
+ cpp_comment[*(char_ - eol)] // C++ style comment
+
+[note While the `confix_p(prefix, subject, suffix)` parser in __classic__
+ was equivalent to the sequence `prefix >> (subject - suffix) >> suffix,
+ the __qi__ `confix` directive will not perform this refactoring any more.
+ This simplifies the code and makes things more explicit.]
+
+[heading Header]
+
+ #include <boost/spirit/repository/include/qi_confix.hpp>
+
+[heading Synopsis]
+
+ confix(prefix, suffix)[subject]
+
+[heading Parameters]
+
+[table
+ [[Parameter] [Description]]
+ [[`prefix`] [The parser for the opening (the prefix).]]
+ [[`suffix`] [The parser for the ending (the suffix).]]
+ [[`subject`] [The parser for the input sequence between the
+ `prefix` and `suffix` parts.]]
+]
+
+All three parameters can be arbitrarily complex parsers themselves.
+
+[heading Attribute]
+
+The `confix` directive exposes the attribute type of its subject as its own
+attribute type. If the `subject` does not expose any attribute (the type is
+`unused_type`), then the `confix` does not expose any attribute either.
+
+ a: A, p: P, s: S: --> confix(p, s)[a]: A
+
+[note This notation is used all over the Spirit documentation and reads as:
+ Given, `a`, `p`, and `s` are parsers, and `A`, `P`, and `S` are the types
+ of their attributes, then the type of the attribute exposed by
+ `confix(p, s)[a]` will be `A`.]
+
+[heading Example]
+
+The following example shows simple use cases of the `confix` directive. We will
+illustrate its usage by generating parsers for different comment styles and
+for some simple tagged data (for the full example code see
+[@../../example/qi/confix.cpp confix.cpp])
+
+[import ../example/qi/confix.cpp]
+
+[heading Prerequisites]
+
+In addition to the main header file needed to include the core components
+implemented in __qi__ we add the header file needed for the new `confix`
+directive.
+
+[qi_confix_includes]
+
+In order to make the examples below more readable we import a number of
+elements into the current namespace:
+
+[qi_confix_using]
+
+[heading Parsing Different Comment Styles]
+
+We will show how to parse different comment styles. First we will parse
+a C++ comment:
+
+[qi_confix_cpp_comment]
+
+This function will obviously parse input such as "`// This is a comment \n `".
+Similarily parsing a 'C'-style comment proves to be straightforward:
+
+[qi_confix_c_comment]
+
+which again will be able to parse e.g. "`/* This is a comment */ `".
+
+[heading Parsing Tagged Data]
+
+Generating a parser that extracts the body from the HTML snippet "`<b>The Body</b>`"
+is not very hard, either:
+
+[qi_confix_tagged_data]
+
+
+[endsect]

Modified: trunk/libs/spirit/repository/doc/qi/directives.qbk
==============================================================================
--- trunk/libs/spirit/repository/doc/qi/directives.qbk (original)
+++ trunk/libs/spirit/repository/doc/qi/directives.qbk 2009-07-30 19:05:02 EDT (Thu, 30 Jul 2009)
@@ -6,6 +6,7 @@
     file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 ===============================================================================/]
 
-[section Qi Parser Directives]
+[section:directives Qi Parser Directives]
+[include confix.qbk]
 [include distinct.qbk]
 [endsect]

Modified: trunk/libs/spirit/repository/doc/qi/distinct.qbk
==============================================================================
--- trunk/libs/spirit/repository/doc/qi/distinct.qbk (original)
+++ trunk/libs/spirit/repository/doc/qi/distinct.qbk 2009-07-30 19:05:02 EDT (Thu, 30 Jul 2009)
@@ -6,7 +6,7 @@
     file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 ===============================================================================/]
 
-[section Qi Distinct Parser]
+[section:distinct Qi Distinct Parser Directive]
 
 [heading Description]
 

Modified: trunk/libs/spirit/repository/doc/qi/flush_multi_pass.qbk
==============================================================================
--- trunk/libs/spirit/repository/doc/qi/flush_multi_pass.qbk (original)
+++ trunk/libs/spirit/repository/doc/qi/flush_multi_pass.qbk 2009-07-30 19:05:02 EDT (Thu, 30 Jul 2009)
@@ -6,7 +6,7 @@
     file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 ===============================================================================/]
 
-[section Qi flush_multi_pass parser]
+[section:flush_multi_pass Qi flush_multi_pass parser]
 
 [heading Description]
 

Modified: trunk/libs/spirit/repository/doc/qi/primitive_parsers.qbk
==============================================================================
--- trunk/libs/spirit/repository/doc/qi/primitive_parsers.qbk (original)
+++ trunk/libs/spirit/repository/doc/qi/primitive_parsers.qbk 2009-07-30 19:05:02 EDT (Thu, 30 Jul 2009)
@@ -6,6 +6,6 @@
     file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 ===============================================================================/]
 
-[section Qi Parser Primitives]
+[section:primitive Qi Parser Primitives]
 [include flush_multi_pass.qbk]
 [endsect]

Added: trunk/libs/spirit/repository/example/qi/confix.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/spirit/repository/example/qi/confix.cpp 2009-07-30 19:05:02 EDT (Thu, 30 Jul 2009)
@@ -0,0 +1,113 @@
+// Copyright (c) 2009 Chris Hoeppler
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+// The purpose of this example is to demonstrate different use cases for the
+// confix directive.
+
+#include <iostream>
+#include <string>
+#include <vector>
+
+//[qi_confix_includes
+#include <boost/spirit/include/qi.hpp>
+#include <boost/spirit/repository/include/qi_confix.hpp>
+//]
+
+namespace client {
+//[qi_confix_using
+ using boost::spirit::eol;
+ using boost::spirit::lexeme;
+ using boost::spirit::ascii::alnum;
+ using boost::spirit::ascii::char_;
+ using boost::spirit::ascii::space;
+ using boost::spirit::qi::parse;
+ using boost::spirit::qi::phrase_parse;
+ using boost::spirit::repository::confix;
+//]
+
+//[qi_confix_cpp_comment
+ template <typename Iterator>
+ bool parse_cpp_comment(Iterator first, Iterator last, std::string& attr)
+ {
+ bool r = parse(first, last,
+ confix("//", eol)[*(char_ - eol)], // grammar
+ attr); // attribute
+
+ if (!r || first != last) // fail if we did not get a full match
+ return false;
+ return r;
+ }
+//]
+
+//[qi_confix_c_comment
+ template <typename Iterator>
+ bool parse_c_comment(Iterator first, Iterator last, std::string& attr)
+ {
+ bool r = parse(first, last,
+ confix("/*", "*/")[*(char_ - "*/")], // grammar
+ attr); // attribute
+
+ if (!r || first != last) // fail if we did not get a full match
+ return false;
+ return r;
+ }
+//]
+
+//[qi_confix_tagged_data
+ template <typename Iterator>
+ bool parse_tagged(Iterator first, Iterator last, std::string& attr)
+ {
+ bool r = phrase_parse(first, last,
+ confix("<b>", "</b>")[lexeme[*(char_ - '<')]], // grammar
+ space, // skip
+ attr); // attribute
+
+ if (!r || first != last) // fail if we did not get a full match
+ return false;
+ return r;
+ }
+//]
+}
+
+
+int main()
+{
+ // C++ comment
+ std::string comment("// This is a comment\n");
+ std::string attr;
+ bool r = client::parse_cpp_comment(comment.begin(), comment.end(), attr);
+
+ std::cout << "Parsing a C++ comment";
+ if (r && attr == " This is a comment")
+ std::cout << " succeeded." << std::endl;
+ else
+ std::cout << " failed" << std::endl;
+
+ // C comment
+ comment = "/* This is another comment */";
+ attr.clear();
+ r = client::parse_c_comment(comment.begin(), comment.end(), attr);
+
+ std::cout << "Parsing a C comment";
+ if (r && attr == " This is another comment ")
+ std::cout << " succeeded." << std::endl;
+ else
+ std::cout << " failed" << std::endl;
+
+ // Tagged data
+ std::string data = "<b> This is the body. </b>";
+ attr.clear();
+
+ r = client::parse_tagged(data.begin(), data.end(), attr);
+
+ std::cout << "Parsing tagged data";
+ if (r && attr == "This is the body. ")
+ std::cout << " succeeded." << std::endl;
+ else
+ std::cout << " failed" << std::endl;
+
+ return 0;
+}
+

Modified: trunk/libs/spirit/repository/test/CMakeLists.txt
==============================================================================
--- trunk/libs/spirit/repository/test/CMakeLists.txt (original)
+++ trunk/libs/spirit/repository/test/CMakeLists.txt 2009-07-30 19:05:02 EDT (Thu, 30 Jul 2009)
@@ -19,6 +19,7 @@
 ENDIF(CMAKE_COMPILER_IS_GNUCC)
 
 # run Qi repository tests
+boost_test_run(qi_repo_confix qi/confix.cpp COMPILE_FLAGS ${test_compile_flags})
 boost_test_run(qi_repo_distinct qi/distinct.cpp COMPILE_FLAGS ${test_compile_flags})
 
 # run Karma repository tests

Modified: trunk/libs/spirit/repository/test/Jamfile
==============================================================================
--- trunk/libs/spirit/repository/test/Jamfile (original)
+++ trunk/libs/spirit/repository/test/Jamfile 2009-07-30 19:05:02 EDT (Thu, 30 Jul 2009)
@@ -22,6 +22,7 @@
     test-suite spirit_v2_repository :
 
     # run Qi repository tests
+ [ run qi/confix.cpp : : : : qi_repo_confix ]
     [ run qi/distinct.cpp : : : : qi_repo_distinct ]
 
     # run Karma repository tests

Added: trunk/libs/spirit/repository/test/qi/confix.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/spirit/repository/test/qi/confix.cpp 2009-07-30 19:05:02 EDT (Thu, 30 Jul 2009)
@@ -0,0 +1,147 @@
+/*=============================================================================
+ Copyright (c) 2009 Chris Hoeppler
+
+ Distributed under the Boost Software License, Version 1.0. (See accompanying
+ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+=============================================================================*/
+#include <boost/detail/lightweight_test.hpp>
+
+#include <boost/spirit/include/qi_action.hpp>
+#include <boost/spirit/include/qi_auxiliary.hpp>
+#include <boost/spirit/include/qi_char.hpp>
+#include <boost/spirit/include/qi_directive.hpp>
+#include <boost/spirit/include/qi_nonterminal.hpp>
+#include <boost/spirit/include/qi_numeric.hpp>
+#include <boost/spirit/include/qi_operator.hpp>
+#include <boost/spirit/include/qi_string.hpp>
+#include <boost/spirit/include/phoenix_bind.hpp>
+#include <boost/spirit/include/phoenix_core.hpp>
+#include <boost/spirit/include/phoenix_object.hpp>
+#include <boost/spirit/include/phoenix_operator.hpp>
+
+#include <boost/spirit/repository/home/qi/confix.hpp>
+
+#include <string>
+#include "test.hpp"
+
+namespace comment {
+ namespace spirit = boost::spirit;
+ namespace repo = boost::spirit::repository;
+
+ // Define a metafunction allowing to compute the type
+ // of the confix() construct
+ template <typename Prefix, typename Suffix = Prefix>
+ struct confix_spec_traits
+ {
+ typedef typename spirit::result_of::terminal<
+ repo::tag::confix(Prefix, Suffix)
+ >::type type;
+ };
+
+ template <typename Prefix, typename Suffix>
+ inline typename confix_spec_traits<Prefix, Suffix>::type
+ confix_spec(Prefix const& prefix, Suffix const& suffix)
+ {
+ return repo::confix(prefix, suffix);
+ }
+
+ inline confix_spec_traits<std::string>::type
+ confix_spec(const char* prefix, const char* suffix)
+ {
+ return repo::confix(std::string(prefix), std::string(suffix));
+ }
+ confix_spec_traits<std::string>::type const c_comment = confix_spec("/*", "*/");
+ confix_spec_traits<std::string>::type const cpp_comment = confix_spec("//", "\n");
+}
+
+int main()
+{
+ using spirit_test::test_attr;
+ using spirit_test::test;
+
+ using namespace boost::spirit::ascii;
+ using namespace boost::spirit::qi::labels;
+ using boost::spirit::qi::locals;
+ using boost::spirit::qi::rule;
+ using boost::spirit::qi::debug;
+
+ namespace phx = boost::phoenix;
+ namespace repo = boost::spirit::repository;
+
+ { // basic tests
+
+ rule<char const*> start;
+
+ start = repo::confix('a', 'c')['b'];
+ BOOST_TEST(test("abc", start));
+
+ start = repo::confix('a', 'c')['b'] | "abd";
+ BOOST_TEST(test("abd", start));
+
+ start = repo::confix("/*", "*/")[*(alpha - "*/")];
+ BOOST_TEST(test("/*aaaabababaaabbb*/", start));
+
+ start = repo::confix(char_('/') >> '*', '*' >> char_('/'))[*alpha - "*/"];
+ BOOST_TEST(test("/*aaaabababaaabba*/", start));
+
+ start = comment::c_comment[*(alpha - "*/")];
+ BOOST_TEST(test("/*aaaabababaaabbb*/", start));
+
+ // ignore the skipper!
+ BOOST_TEST(!test("/* aaaabababaaabba*/", start, space));
+ }
+
+ { // basic tests w/ skipper
+
+ rule<char const*, space_type> start;
+
+ start = repo::confix('a', 'c')['b'];
+ BOOST_TEST(test(" a b c ", start, space));
+
+ start = repo::confix(char_('/') >> '*', '*' >> char_('/'))[*alpha - "*/"];
+ BOOST_TEST(test(" / *a b a b a b a a a b b b * / ", start, space));
+ }
+
+ { // context tests
+ char ch;
+ rule<char const*, char()> a;
+ a = repo::confix("/*", "*/")[alpha][_val = _1];
+
+ BOOST_TEST(test("/*x*/", a[phx::ref(ch) = _1]));
+ BOOST_TEST(ch == 'x');
+
+ a %= repo::confix("/*", "*/")[alpha];
+ BOOST_TEST(test_attr("/*z*/", a, ch)); // attribute is given.
+ BOOST_TEST(ch == 'z');
+ }
+
+ { // rules test
+ rule<char const*> a, b, c, start;
+
+ a = 'a';
+ b = 'b';
+ c = 'c';
+
+ a.name("a");
+ b.name("b");
+ c.name("c");
+ start.name("start");
+
+ debug(a);
+ debug(b);
+ debug(c);
+ debug(start);
+
+ start = repo::confix(a, c)[b];
+ BOOST_TEST(test("abc", start));
+ }
+
+ { // modifiers test
+ rule<char const*> start;
+ start = no_case[repo::confix("_A_", "_Z_")["heLLo"]];
+ BOOST_TEST(test("_a_hello_z_", start));
+ }
+
+ return boost::report_errors();
+}
+


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk