|
Boost-Commit : |
From: joel_at_[hidden]
Date: 2008-07-10 10:45:16
Author: djowel
Date: 2008-07-10 10:45:15 EDT (Thu, 10 Jul 2008)
New Revision: 47290
URL: http://svn.boost.org/trac/boost/changeset/47290
Log:
tutorials
Added:
branches/release/libs/spirit/doc/qi_and_karma/actions.qbk (contents, props changed)
branches/release/libs/spirit/doc/qi_and_karma/num_list2.qbk (contents, props changed)
branches/release/libs/spirit/doc/qi_and_karma/num_list3.qbk (contents, props changed)
branches/release/libs/spirit/doc/qi_and_karma/num_list4.qbk (contents, props changed)
Text files modified:
branches/release/libs/spirit/doc/qi_and_karma.qbk | 4 ++
branches/release/libs/spirit/doc/qi_and_karma/sum_tutorial.qbk | 55 +++++++++++++++++++++++++++++++++++++++
branches/release/libs/spirit/doc/qi_and_karma/tutorial_intro.qbk | 8 +++++
branches/release/libs/spirit/doc/qi_and_karma/warming_up.qbk | 2 +
branches/release/libs/spirit/doc/spirit2.qbk | 6 ++-
branches/release/libs/spirit/example/qi/actions.cpp | 52 ++++++++++++++++++++++++++++++-------
branches/release/libs/spirit/example/qi/num_list2.cpp | 2 +
branches/release/libs/spirit/example/qi/num_list3.cpp | 2 +
branches/release/libs/spirit/example/qi/num_list4.cpp | 2 +
branches/release/libs/spirit/example/qi/sum.cpp | 5 ++
10 files changed, 124 insertions(+), 14 deletions(-)
Modified: branches/release/libs/spirit/doc/qi_and_karma.qbk
==============================================================================
--- branches/release/libs/spirit/doc/qi_and_karma.qbk (original)
+++ branches/release/libs/spirit/doc/qi_and_karma.qbk 2008-07-10 10:45:15 EDT (Thu, 10 Jul 2008)
@@ -11,7 +11,11 @@
[section Tutorials]
[include qi_and_karma/tutorial_intro.qbk]
[include qi_and_karma/warming_up.qbk]
+[include qi_and_karma/actions.qbk]
[include qi_and_karma/sum_tutorial.qbk]
+[include qi_and_karma/num_list2.qbk]
+[include qi_and_karma/num_list3.qbk]
+[include qi_and_karma/num_list4.qbk]
[endsect]
[section Abstracts]
Added: branches/release/libs/spirit/doc/qi_and_karma/actions.qbk
==============================================================================
--- (empty file)
+++ branches/release/libs/spirit/doc/qi_and_karma/actions.qbk 2008-07-10 10:45:15 EDT (Thu, 10 Jul 2008)
@@ -0,0 +1,98 @@
+[/==============================================================================
+ Copyright (C) 2001-2008 Joel de Guzman
+ Copyright (C) 2001-2008 Hartmut Kaiser
+
+ 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 Semantic Actions]
+
+Our parser above is really nothing but a recognizer. It answers the question
+"did the input match our grammar?", but it does not do anything other than that.
+It does not extract any information from what was parsed. For example, whenever
+we parse a real number, we wish to store the parsed number after a successful
+match.
+
+Enter Semantic actions. Semantic actions may be attached to any point in the
+grammar specification. These actions are C++ functions or function objects that
+are called whenever a part of the parser successfully recognizes a portion of
+the input. Say you have a parser `P`, and a C++ function `F`, you can make the
+parser call `F` whenever it matches an input by attaching `F`:
+
+ P[F]
+
+The expression above links `F` to the parser, `P`.
+
+The function/function object signature depends on the type of the parser to
+which it is attached. The parser `double_` passes the parsed number. Thus, if we
+were to attach a function `F` to `double_`, we need `F` to be declared as:
+
+ void F(double n);
+
+There are actually 2 more arguments being passed (the parser context and a
+reference to a boolean 'hit' parameter). We don't need these, for now, but we'll
+see more on these other arguments later. Spirit.Qi allows us to bind a single
+argument function, like above. The other arguments are simply ignored.
+
+Presented are various ways to attach semantic actions:
+
+* Using plain function pointer
+* Using simple function object
+* Using __boost_bind__ with a plain function
+* Using __boost_bind__ with a member function
+* Using __boost_lambda__
+
+[import ../../example/qi/actions.cpp]
+
+Given:
+
+[tutorial_semantic_action_functions]
+
+Take note that with function objects, we need to have an `operator()` with 3
+arguments. Since we don't care about the other two, we can use `unused_type` for
+these. We'll see more of `unused_type` elsewhere. Get used to it. `unused_type`
+is a Spirit supplied support class.
+
+All examples parse inputs of the form:
+
+ "{number}"
+
+The first example shows how to attach a plain function:
+
+[tutorial_attach_actions1]
+
+The next example shows how to attach a simple function object:
+
+[tutorial_attach_actions2]
+
+We can use __boost_bind__ to 'bind' member functions:
+
+[tutorial_attach_actions4]
+
+Likewise, we can also use __boost_bind__ to 'bind' plain functions:
+
+[tutorial_attach_actions3]
+
+Yep, we can also use __boost_lambda__:
+
+[tutorial_attach_actions5]
+
+There are more ways to bind semantic action functions, but the examples above
+are the most common. Attaching semantic actions is the first hurdle one has
+to tackle when getting started with parsing with Spirit. Familiarize yourself
+with this task and get intimate with the tools behind it such as __boost_bind__
+and __boost_lambda__.
+
+The examples above can be found here: [@../../example/qi/actions.cpp]
+
+[heading Phoenix]
+
+__phoenix__, a companion library bundled with Spirit, is specifically suited
+for binding semantic actions. It is like __boost_lambda__ in steroids, with
+special custom features that make it easy to integrate semantic actions with
+Spirit. If your requirements go beyond simple to moderate parsing, I suggest you
+use this library. Examples presented henceforth shall be using the library
+exclusively
+
+[endsect]
Added: branches/release/libs/spirit/doc/qi_and_karma/num_list2.qbk
==============================================================================
--- (empty file)
+++ branches/release/libs/spirit/doc/qi_and_karma/num_list2.qbk 2008-07-10 10:45:15 EDT (Thu, 10 Jul 2008)
@@ -0,0 +1,30 @@
+[/==============================================================================
+ Copyright (C) 2001-2008 Joel de Guzman
+ Copyright (C) 2001-2008 Hartmut Kaiser
+
+ 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 Number List - stuffing numbers into a std::vector]
+
+This sample demontrates a parser for a comma separated list of numbers. The
+numbers are inserted in a vector using phoenix.
+
+[import ../../example/qi/num_list2.cpp]
+
+[tutorial_numlist2]
+
+The full cpp file for this example can be found here: [@../../example/qi/num_list2.cpp]
+
+This, again, is the same parser as before. This time, instead of summing up the
+numbers, we stuff them in a `std::vector`. `push_back` is supplied by
+__phoenix__. The expression:
+
+ push_back(ref(v), _1)
+
+appends the parsed number. Like before, `_1` is a __phoenix__ placeholder for
+the parsed result attribute. Also, like before, `ref(v)` tells __phoenix__ that
+`v`, the `std::vector`, is a mutable reference.
+
+[endsect]
Added: branches/release/libs/spirit/doc/qi_and_karma/num_list3.qbk
==============================================================================
--- (empty file)
+++ branches/release/libs/spirit/doc/qi_and_karma/num_list3.qbk 2008-07-10 10:45:15 EDT (Thu, 10 Jul 2008)
@@ -0,0 +1,33 @@
+[/==============================================================================
+ Copyright (C) 2001-2008 Joel de Guzman
+ Copyright (C) 2001-2008 Hartmut Kaiser
+
+ 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 Number List Redux - list syntax]
+
+
+So far, we've been using the syntax:
+
+ double_ >> *(',' >> double_)
+
+to parse a comma-delimited list of numbers. Such lists are common in parsing and
+Spirit provides a simpler shortcut for them. The expression above can be
+simplified to:
+
+ double_ % ','
+
+read as: a list of doubles separated by `','`.
+
+
+This sample, again a variation of our previous example, demonstrates just that:
+
+[import ../../example/qi/num_list3.cpp]
+
+[tutorial_numlist3]
+
+The full cpp file for this example can be found here: [@../../example/qi/num_list3.cpp]
+
+[endsect]
Added: branches/release/libs/spirit/doc/qi_and_karma/num_list4.qbk
==============================================================================
--- (empty file)
+++ branches/release/libs/spirit/doc/qi_and_karma/num_list4.qbk 2008-07-10 10:45:15 EDT (Thu, 10 Jul 2008)
@@ -0,0 +1,50 @@
+[/==============================================================================
+ Copyright (C) 2001-2008 Joel de Guzman
+ Copyright (C) 2001-2008 Hartmut Kaiser
+
+ 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 Number List Attribute - one more, with style]
+
+You've seen that the `double_` parser has a `double` attribute. All parsers have
+an attribute, even complex parsers, those that are composed from primitives
+using operators, like the list parser, also have an attribute. It so happens that
+the the attribute of a list parser:
+
+ p % d
+
+is a `std::vector` of the attribute of `p`. So, for our parser:
+
+
+ double_ % ','
+
+we'll have an attribute of:
+
+ std::vector<double>
+
+
+So, what does this give us? Well, we can simply pass in a `std::vector<double>`
+to our number list parser and it will happily churn out our result in our
+vector. For that to happen, we'll use a variation of the `phrase_parse` with
+an additional argument: the parser's attribute:
+
+# An iterator pointing to the start of the input
+# An iterator pointing to one past the end of the input
+# The parser object
+# The parser's attribute
+# Another parser called the skip parser
+
+So, our parser now is further simplified to:
+
+[import ../../example/qi/num_list4.cpp]
+
+[tutorial_numlist4]
+
+The full cpp file for this example can be found here: [@../../example/qi/num_list4.cpp]
+
+[*Hey, no more actions!!!] Now we're entering the realm of attribute grammars.
+Cool eh?
+
+[endsect]
Modified: branches/release/libs/spirit/doc/qi_and_karma/sum_tutorial.qbk
==============================================================================
--- branches/release/libs/spirit/doc/qi_and_karma/sum_tutorial.qbk (original)
+++ branches/release/libs/spirit/doc/qi_and_karma/sum_tutorial.qbk 2008-07-10 10:45:15 EDT (Thu, 10 Jul 2008)
@@ -8,9 +8,62 @@
[section Sum - adding numbers]
-
+Here's a parser that sums a comma-separated list of numbers. This time, we're
+using __phoenix__ to do the semantic actions.
[import ../../example/qi/sum.cpp]
+
+Ok we've glossed over some details in our previous examples. First, our
+includes:
+
+[tutorial_adder_includes]
+
+Then some using directives:
+
+[tutorial_adder_using]
+
+[table
+ [[Namespace] [Description]]
+ [[boost::phoenix] [All of phoenix]]
+ [[boost::spirit] [All of spirit]]
+ [[boost::spirit::qi] [All of spirit.qi]]
+ [[boost::spirit::ascii] [ASCII version of `char_` and all char related parsers. Other
+ encodings are also provided (e.g. also an ISO8859.1)]]
+ [[boost::spirit::arg_names] [Special phoenix placeholders for spirit]]
+]
+
+[note If you feel uneasy with using whole namespaces, feel free to qualify your
+code, use namespace aliases, etc. For the purpose of this tutorial, we will be
+presenting unqualified names for both Spirit and __phoenix__. No worries, we
+will always present the full working code, so you won't get lost. In fact, all
+examples in this tutorial have a corresponding cpp file that QuickBook (the
+documentation tool we are using) imports in here as code snippets.]
+
+Now the actual parser:
+
[tutorial_adder]
+The full cpp file for this example can be found here: [@../../example/qi/actions.cpp]
+
+This is almost like our original numbers list example. We're incrementally
+building on top of our examples. This time though, we'll be adding the
+smarts. There's an accumulator (`double& n) that adds the numbers parsed.
+On a successful parse, this number is the sum of all the parsed numbers.
+
+The first `double_` parser attaches this action:
+
+ ref(n) = _1
+
+This assigns the parsed result (actually, the attribute of `double_`) to `n`.
+`ref(n)` tells __phoenix__ that `n` is a mutable reference. `_1` is a
+__phoenix__ placeholder for the parsed result attribute.
+
+The second `double_` parser attaches this action:
+
+ ref(n) += _1
+
+So, subsequent numbers add into `n`.
+
+That wasn't too bad, was it :-) ?
+
[endsect]
Modified: branches/release/libs/spirit/doc/qi_and_karma/tutorial_intro.qbk
==============================================================================
--- branches/release/libs/spirit/doc/qi_and_karma/tutorial_intro.qbk (original)
+++ branches/release/libs/spirit/doc/qi_and_karma/tutorial_intro.qbk 2008-07-10 10:45:15 EDT (Thu, 10 Jul 2008)
@@ -31,4 +31,12 @@
size? -very tight -essentially comparable to hand written recursive descent
code.
+Our tutorials will walk you through the simplest Spirit examples, incrementally
+building on top of the earlier examples as we expose more and more features and
+techniques. We will try to be as gentle as possible with the learning curve.
+We will present the tutorials in a cookbook style approach. This style of
+presentation is based on our BoostCon '07 and BoostCon '08 slides.
+
+Have fun!
+
[endsect] [/ Quickstart]
Modified: branches/release/libs/spirit/doc/qi_and_karma/warming_up.qbk
==============================================================================
--- branches/release/libs/spirit/doc/qi_and_karma/warming_up.qbk (original)
+++ branches/release/libs/spirit/doc/qi_and_karma/warming_up.qbk 2008-07-10 10:45:15 EDT (Thu, 10 Jul 2008)
@@ -112,6 +112,8 @@
by the iterator type. By doing so, it can take in data coming from any STL
conforming sequence as long as the iterators conform to a forward iterator.
+You can find the full cpp file here: [@../../example/qi/num_list1.cpp]
+
[note `char` and `wchar_t` operands
The careful reader may notice that the parser expression has `','` instead of
Modified: branches/release/libs/spirit/doc/spirit2.qbk
==============================================================================
--- branches/release/libs/spirit/doc/spirit2.qbk (original)
+++ branches/release/libs/spirit/doc/spirit2.qbk 2008-07-10 10:45:15 EDT (Thu, 10 Jul 2008)
@@ -24,8 +24,8 @@
[/ Some links ]
[def __spirit__ [@http://spirit.sourceforge.net Spirit]]
-[def __phoenix__ [@http://boost.org/libs/spirit/phoenix/index.html Phoenix]]
-[def __phoenix2__ [@http://spirit.sourceforge.net/dl_more/phoenix_v2/libs/spirit/phoenix/doc/html/index.html Phoenix2]]
+[def __phoenix__ [@../../phoenix/doc/html/index.html Phoenix]]
+[def __phoenix2__ [@../../phoenix/doc/html/index.html Phoenix2]]
[def __fusion__ [@http://spirit.sourceforge.net/dl_more/fusion_v2/libs/fusion/doc/html/index.html Fusion]]
[def __mpl__ [@http://www.boost.org/libs/mpl/index.html MPL]]
[def __boost_tuples__ [@http://www.boost.org/libs/tuple/index.html Boost.Tuples]]
@@ -51,6 +51,8 @@
[def __boost_variant__ [@http://www.boost.org/doc/html/variant.html `boost::variant<>`]]
[def __boost_iterator_range__ [@http://www.boost.org/libs/range/doc/utility_class.html#iter_range `boost::iterator_range<>`]]
+[def __boost_bind__ [@http://www.boost.org/libs/bind/index.html Boost.Bind]]
+[def __boost_lambda__ [@http://www.boost.org/libs/lambda/index.html Boost.Lambda]]
[def __classic__ /Spirit.Classic/]
Modified: branches/release/libs/spirit/example/qi/actions.cpp
==============================================================================
--- branches/release/libs/spirit/example/qi/actions.cpp (original)
+++ branches/release/libs/spirit/example/qi/actions.cpp 2008-07-10 10:45:15 EDT (Thu, 10 Jul 2008)
@@ -15,16 +15,29 @@
// Presented are various ways to attach semantic actions
// * Using plain function pointer
// * Using simple function object
-// * Using boost.bind
+// * Using boost.bind with a plain function
+// * Using boost.bind with a member function
// * Using boost.lambda
using namespace boost::spirit;
+//[tutorial_semantic_action_functions
+// A plain function
void write(int const& i)
{
std::cout << i << std::endl;
}
+// A member function
+struct writer
+{
+ void print(int const& i) const
+ {
+ std::cout << i << std::endl;
+ }
+};
+
+// A function object
struct write_action
{
void operator()(int const& i, unused_type, unused_type) const
@@ -32,32 +45,51 @@
std::cout << i << std::endl;
}
};
+//]
int main()
{
{ // example using plain function
- char const *s1 = "{42}", *e1 = s1 + std::strlen(s1);
- qi::parse(s1, e1, '{' >> int_[&write] >> '}');
+ char const *first = "{42}", *last = first + std::strlen(first);
+ //[tutorial_attach_actions1
+ qi::parse(first, last, '{' >> int_[&write] >> '}');
+ //]
}
{ // example using simple function object
- char const *s1 = "{43}", *e1 = s1 + std::strlen(s1);
- qi::parse(s1, e1, '{' >> int_[write_action()] >> '}');
+ char const *first = "{43}", *last = first + std::strlen(first);
+ //[tutorial_attach_actions2
+ qi::parse(first, last, '{' >> int_[write_action()] >> '}');
+ //]
+ }
+
+ { // example using boost.bind with a plain function
+
+ char const *first = "{44}", *last = first + std::strlen(first);
+ //[tutorial_attach_actions3
+ qi::parse(first, last, '{' >> int_[boost::bind(&write, _1)] >> '}');
+ //]
}
- { // example using boost.bind
+ { // example using boost.bind with a member function
- char const *s1 = "{44}", *e1 = s1 + std::strlen(s1);
- qi::parse(s1, e1, '{' >> int_[boost::bind(&write, _1)] >> '}');
+ char const *first = "{44}", *last = first + std::strlen(first);
+ //[tutorial_attach_actions4
+ writer w;
+ qi::parse(first, last, '{' >> int_[boost::bind(&writer::print, &w, _1)] >> '}');
+ //]
}
{ // example using boost.lambda
namespace lambda = boost::lambda;
- char const *s1 = "{45}", *e1 = s1 + std::strlen(s1);
- qi::parse(s1, e1, '{' >> int_[std::cout << lambda::_1 << '\n'] >> '}');
+ char const *first = "{45}", *last = first + std::strlen(first);
+ using lambda::_1;
+ //[tutorial_attach_actions5
+ qi::parse(first, last, '{' >> int_[std::cout << _1 << '\n'] >> '}');
+ //]
}
return 0;
Modified: branches/release/libs/spirit/example/qi/num_list2.cpp
==============================================================================
--- branches/release/libs/spirit/example/qi/num_list2.cpp (original)
+++ branches/release/libs/spirit/example/qi/num_list2.cpp 2008-07-10 10:45:15 EDT (Thu, 10 Jul 2008)
@@ -33,6 +33,7 @@
///////////////////////////////////////////////////////////////////////////////
// Our number list compiler
///////////////////////////////////////////////////////////////////////////////
+//[tutorial_numlist2
template <typename Iterator>
bool parse_numbers(Iterator first, Iterator last, std::vector<double>& v)
{
@@ -52,6 +53,7 @@
return false;
return r;
}
+//]
////////////////////////////////////////////////////////////////////////////
// Main program
Modified: branches/release/libs/spirit/example/qi/num_list3.cpp
==============================================================================
--- branches/release/libs/spirit/example/qi/num_list3.cpp (original)
+++ branches/release/libs/spirit/example/qi/num_list3.cpp 2008-07-10 10:45:15 EDT (Thu, 10 Jul 2008)
@@ -33,6 +33,7 @@
///////////////////////////////////////////////////////////////////////////////
// Our number list compiler
///////////////////////////////////////////////////////////////////////////////
+//[tutorial_numlist3
template <typename Iterator>
bool parse_numbers(Iterator first, Iterator last, std::vector<double>& v)
{
@@ -51,6 +52,7 @@
return false;
return r;
}
+//]
////////////////////////////////////////////////////////////////////////////
// Main program
Modified: branches/release/libs/spirit/example/qi/num_list4.cpp
==============================================================================
--- branches/release/libs/spirit/example/qi/num_list4.cpp (original)
+++ branches/release/libs/spirit/example/qi/num_list4.cpp 2008-07-10 10:45:15 EDT (Thu, 10 Jul 2008)
@@ -33,6 +33,7 @@
///////////////////////////////////////////////////////////////////////////////
// Our number list compiler
///////////////////////////////////////////////////////////////////////////////
+//[tutorial_numlist4
template <typename Iterator>
bool parse_numbers(Iterator first, Iterator last, std::vector<double>& v)
{
@@ -51,6 +52,7 @@
return false;
return r;
}
+//]
////////////////////////////////////////////////////////////////////////////
// Main program
Modified: branches/release/libs/spirit/example/qi/sum.cpp
==============================================================================
--- branches/release/libs/spirit/example/qi/sum.cpp (original)
+++ branches/release/libs/spirit/example/qi/sum.cpp 2008-07-10 10:45:15 EDT (Thu, 10 Jul 2008)
@@ -14,18 +14,21 @@
///////////////////////////////////////////////////////////////////////////////
#include <boost/config/warning_disable.hpp>
+//[tutorial_adder_includes
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
-
#include <iostream>
#include <string>
+//]
+//[tutorial_adder_using
using namespace boost::phoenix;
using namespace boost::spirit;
using namespace boost::spirit::qi;
using namespace boost::spirit::ascii;
using namespace boost::spirit::arg_names;
+//]
///////////////////////////////////////////////////////////////////////////////
// Our adder
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