$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
Subject: [Boost-commit] svn:boost r69503 - in trunk/libs/spirit: optimization/qi repository/doc repository/doc/qi repository/example/qi repository/test repository/test/qi
From: joel_at_[hidden]
Date: 2011-03-02 19:32:53
Author: djowel
Date: 2011-03-02 19:32:48 EST (Wed, 02 Mar 2011)
New Revision: 69503
URL: http://svn.boost.org/trac/boost/changeset/69503
Log:
teejay's keyword directive
Added:
   trunk/libs/spirit/optimization/qi/keywords.cpp   (contents, props changed)
   trunk/libs/spirit/repository/doc/qi/kwd.qbk   (contents, props changed)
   trunk/libs/spirit/repository/example/qi/keywords.cpp   (contents, props changed)
   trunk/libs/spirit/repository/test/qi/keywords.cpp   (contents, props changed)
Text files modified: 
   trunk/libs/spirit/optimization/qi/Jamfile          |    11 +++++++++--                             
   trunk/libs/spirit/repository/doc/qi.qbk            |     3 ++-                                     
   trunk/libs/spirit/repository/doc/qi/directives.qbk |     1 +                                       
   trunk/libs/spirit/repository/example/qi/Jamfile    |     2 +-                                      
   trunk/libs/spirit/repository/test/Jamfile          |     3 ++-                                     
   5 files changed, 15 insertions(+), 5 deletions(-)
Modified: trunk/libs/spirit/optimization/qi/Jamfile
==============================================================================
--- trunk/libs/spirit/optimization/qi/Jamfile	(original)
+++ trunk/libs/spirit/optimization/qi/Jamfile	2011-03-02 19:32:48 EST (Wed, 02 Mar 2011)
@@ -5,9 +5,16 @@
 #   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)
 #==============================================================================
-project spirit-qi-benchmark ;
-
+project spirit-qi-benchmark 
+    : requirements
+        <include>.
+        <toolset>gcc:<cxxflags>-ftemplate-depth-300
+        <toolset>darwin:<cxxflags>-ftemplate-depth-300
+    :
+    :
+    ;
 # performance tests
 exe int_parser : int_parser.cpp ;
 exe real_parser : real_parser.cpp ;
 exe attr_vs_actions : attr_vs_actions.cpp ;
+exe keywords : keywords.cpp ;
Added: trunk/libs/spirit/optimization/qi/keywords.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/spirit/optimization/qi/keywords.cpp	2011-03-02 19:32:48 EST (Wed, 02 Mar 2011)
@@ -0,0 +1,553 @@
+/*=============================================================================
+    Copyright (c) 2001-2011 Joel de Guzman
+    Copyright (c) 2011 Thomas Bernard
+
+    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)
+=============================================================================*/
+
+#define FUSION_MAX_VECTOR_SIZE 50 
+#define BOOST_MPL_CFG_NO_PREPROCESSED_HEADERS 
+#define BOOST_MPL_LIMIT_LIST_SIZE 50 
+#define BOOST_MPL_LIMIT_VECTOR_SIZE 50
+
+#include "../measure.hpp"
+#include <boost/config/warning_disable.hpp>
+#include <boost/spirit/include/qi.hpp>
+#include <boost/spirit/include/phoenix_core.hpp>
+#include <boost/spirit/include/phoenix_operator.hpp>
+#include <boost/spirit/include/phoenix_object.hpp>
+#include <boost/spirit/include/phoenix_fusion.hpp>
+#include <boost/spirit/include/phoenix_container.hpp>
+#include <boost/fusion/include/adapt_struct.hpp>
+#include <boost/fusion/include/io.hpp>
+#include <boost/spirit/include/qi_permutation.hpp>
+#include <boost/spirit/home/qi/string/tst_map.hpp>
+#include <boost/spirit/repository/include/qi_kwd.hpp>
+#include <boost/spirit/repository/include/qi_keywords.hpp>
+#include <boost/optional.hpp>
+#include <boost/spirit/home/phoenix/core/argument.hpp>
+#include <boost/spirit/home/phoenix/bind/bind_member_variable.hpp>
+
+#include <iostream>
+#include <string>
+#include <complex>
+#include <vector>
+#include <iterator>
+#include <stdexcept>
+
+#include <boost/preprocessor/control/if.hpp>
+#include <boost/preprocessor/seq/for_each_i.hpp>
+#include <boost/preprocessor/seq/size.hpp>
+#include <boost/preprocessor/cat.hpp>
+#include <boost/preprocessor/stringize.hpp>
+
+#define KEYS_5
+
+#include "keywords.hpp"
+
+#define declOptions(r, data, i, elem) boost::optional<int> BOOST_PP_CAT(option,i);
+#define fusionOptions(r, data, i, elem) (boost::optional<int>, BOOST_PP_CAT(option,i))
+
+
+namespace client
+{
+        namespace qi = boost::spirit::qi;
+        namespace ascii = boost::spirit::ascii;
+
+        ///////////////////////////////////////////////////////////////////////////
+        //  Our parsedData struct
+        ///////////////////////////////////////////////////////////////////////////
+        //[tutorial_parsedData_struct
+        struct parsedDataOptions
+        {   
+                BOOST_PP_SEQ_FOR_EACH_I(declOptions,_,keys)
+        };
+        struct parsedData
+        {
+
+                std::string name;
+                parsedDataOptions options;        
+                void clear()
+                {
+                        name.clear();            
+                }
+        };
+
+        struct parsedData2
+        {
+                std::string name;
+                BOOST_PP_SEQ_FOR_EACH_I(declOptions,_,keys)
+
+                        void clear()
+                        {
+                                name.clear();            
+                        }
+        };
+}
+
+std::ostream &operator<<(std::ostream & os, client::parsedData &data)
+{
+        os << data.name <<std::endl;
+
+#define generateOutput1(r, d, i, elem) if( BOOST_PP_CAT(data.options.option, i) ) os<< BOOST_PP_STRINGIZE( BOOST_PP_CAT(option,i)) <<" "<< * BOOST_PP_CAT(data.options.option , i)<<std::endl;
+        BOOST_PP_SEQ_FOR_EACH_I(generateOutput1,_,keys)
+
+                os<<std::endl;
+
+        return os;
+}
+
+std::ostream &operator<<(std::ostream & os, client::parsedData2 &data)
+{
+        os << data.name <<std::endl;
+
+#define generateOutput2(r, d, i, elem) if(BOOST_PP_CAT(data.option, i)) os<< BOOST_PP_STRINGIZE( BOOST_PP_CAT(option,i)) <<" "<< * BOOST_PP_CAT(data.option,i)<<std::endl;
+        BOOST_PP_SEQ_FOR_EACH_I(generateOutput2,_,keys)
+
+                os<<std::endl;
+
+        return os;
+}
+
+
+
+BOOST_FUSION_ADAPT_STRUCT(
+                client::parsedDataOptions,
+                BOOST_PP_SEQ_FOR_EACH_I(fusionOptions,_,keys)
+                )
+
+BOOST_FUSION_ADAPT_STRUCT(
+                client::parsedData,
+                (std::string, name)
+                (client::parsedDataOptions, options)    
+                )
+
+BOOST_FUSION_ADAPT_STRUCT(
+                client::parsedData2,
+                (std::string, name)
+                BOOST_PP_SEQ_FOR_EACH_I(fusionOptions,_,keys)
+                )
+enum variation
+{
+        full,
+        no_assign,
+        assign
+};
+namespace client
+{
+
+
+        ///////////////////////////////////////////////////////////////////////////////
+        //  Our parsedData parser
+        ///////////////////////////////////////////////////////////////////////////////
+        //[tutorial_parsedData_parser
+        template <typename Iterator>
+                struct permutation_parser : qi::grammar<Iterator, parsedData(), ascii::space_type>
+        {
+                permutation_parser() : permutation_parser::base_type(start)
+                {
+                        using qi::int_;
+                        using qi::lit;
+                        using qi::double_;
+                        using qi::lexeme;
+                        using ascii::char_;
+                        using boost::phoenix::at_c;
+                        using boost::phoenix::assign;
+                        using qi::_r1;
+                        using qi::_1;
+                        using qi::_val;
+                        using qi::omit;
+                        using qi::repeat;
+
+
+                        quoted_string %= lexeme[+(char_-' ')];
+
+#define generateOptions1(r, data, i, elem) BOOST_PP_IF(i, ^(lit(elem) > int_) , (lit(elem) > int_))
+                        options = (BOOST_PP_SEQ_FOR_EACH_I(generateOptions1,_,keys));
+
+                        start %=
+                                quoted_string 
+                                >> options;                
+                        ;
+                        v_vals = repeat(1,2)[int_];
+                }
+
+                typedef parsedData parser_target_type;
+
+                qi::rule<Iterator, std::string(), ascii::space_type> quoted_string;
+                qi::rule<Iterator, parsedDataOptions(), ascii::space_type> options;
+                qi::rule<Iterator, std::vector<int>(), ascii::space_type> v_vals;
+
+                qi::rule<Iterator, parsedData(), ascii::space_type> start;
+        };
+
+        template <typename Iterator>
+                struct alternative_parser : qi::grammar<Iterator, parsedData2(), ascii::space_type>
+        {
+                alternative_parser() : alternative_parser::base_type(start)
+                {
+                        using qi::int_;
+                        using qi::lit;
+                        using qi::double_;
+                        using qi::lexeme;
+                        using ascii::char_;
+                        using boost::phoenix::at_c;                        
+                        using qi::_r1;
+                        using qi::_1;
+                        using qi::_val;
+
+                        quoted_string %= lexeme[+(char_-' ')];
+
+#define generateOptions2(r, data, i, elem) BOOST_PP_IF(i, |(lit(elem) > int_[at_c<i+1>(_r1)=_1]) , (lit(elem) > int_[at_c<i+1>(_r1)=_1]))
+                        options = (BOOST_PP_SEQ_FOR_EACH_I(generateOptions2,_,keys));
+
+                        start =
+                                quoted_string [at_c<0>(_val)=_1]
+                                >> *options(_val);                
+                        ;
+                }
+
+                typedef parsedData2 parser_target_type;
+
+                qi::rule<Iterator, std::string(), ascii::space_type> quoted_string;
+                qi::rule<Iterator, void(parsedData2 & ), ascii::space_type> options;
+                qi::rule<Iterator, parsedData2(), ascii::space_type> start;
+        };
+
+
+
+        template <typename Iterator,typename variation>
+                struct tst_parser : qi::grammar<Iterator, parsedData2(), ascii::space_type>
+        {
+                typedef variation variation_type;
+
+                tst_parser() : tst_parser::base_type(startalias)
+                {
+                        namespace phx = boost::phoenix;
+                        using qi::int_;
+                        using qi::lit;
+                        using qi::double_;
+                        using qi::lexeme;
+                        using ascii::char_;            
+                        using boost::phoenix::at_c;                        
+                        using qi::_r1;
+                        using qi::_1;
+                        using qi::_a;
+                        using qi::_val;
+                        using qi::locals;
+                        using qi::parameterized_nonterminal;
+
+                        startalias = start.alias();
+                        quoted_string %= lexeme[+(char_-' ')];
+
+#define generateRules(r, data, i, elem) BOOST_PP_CAT(rule,i) = int_[phx::at_c<i+1>(*phx::ref(currentObj))=_1];
+                        BOOST_PP_SEQ_FOR_EACH_I(generateRules,_,keys)
+
+#define generateOptions3(r, data, i, elem) (elem,& BOOST_PP_CAT(rule,i))
+
+
+                                options.add BOOST_PP_SEQ_FOR_EACH_I(generateOptions3,_,keys);
+                        switch(variation_type::value)
+                        {
+                                case full:
+                                        {
+                                                start =
+                                                        quoted_string [at_c<0>(_val)=_1][phx::ref(currentObj)=&_val]
+                                                        >> *( options [_a=_1] >> lazy(*_a));
+                                                ;
+                                                break;
+                                        }
+                                case no_assign:
+                                        {
+                                                start =
+                                                        quoted_string [at_c<0>(_val)=_1][phx::ref(currentObj)=&_val]
+                                                        >> *( options >> int_);
+                                                ;
+                                                break;
+                                        }
+                                case assign:
+                                        {
+                                                start =
+                                                        quoted_string [at_c<0>(_val)=_1][phx::ref(currentObj)=&_val]
+                                                        >> *( options [_a=_1] >> int_);
+                                                ;
+                                                break;
+                                        }
+                        }
+
+
+                }
+
+                parsedData2 *currentObj;
+
+                typedef parsedData2 parser_target_type;
+
+                qi::rule<Iterator, std::string(), ascii::space_type> quoted_string;
+                typedef qi::rule<Iterator, ascii::space_type> optionsRule;
+#define declareRules(r, data, i, elem) optionsRule BOOST_PP_CAT(rule,i);
+
+                BOOST_PP_SEQ_FOR_EACH_I(declareRules,_,keys)
+
+                        qi::symbols<char,optionsRule* > options;
+                qi::rule<Iterator, parsedData2(), ascii::space_type> startalias;
+                qi::rule<Iterator, parsedData2(), qi::locals<optionsRule*>, ascii::space_type> start;
+        };
+
+
+
+        template <typename Iterator,typename variation>
+                struct tst_map_parser : qi::grammar<Iterator, parsedData2(), ascii::space_type>
+        {
+                typedef variation variation_type;
+                tst_map_parser() : tst_map_parser::base_type(startalias)
+                {
+                        namespace phx = boost::phoenix;
+                        using qi::int_;
+                        using qi::lit;
+                        using qi::double_;
+                        using qi::lexeme;
+                        using ascii::char_;            
+                        using boost::phoenix::at_c;                        
+                        using qi::_r1;
+                        using qi::_1;
+                        using qi::_a;
+                        using qi::_val;
+                        using qi::locals;
+                        using qi::parameterized_nonterminal;
+
+                        startalias = start.alias();
+                        quoted_string %= lexeme[+(char_-' ')];
+
+#define generateRules3(r, data, i, elem) BOOST_PP_CAT(rule,i) = int_[phx::at_c<i+1>(*phx::ref(currentObj))=_1];
+                        BOOST_PP_SEQ_FOR_EACH_I(generateRules3,_,keys)
+
+#define generateOptions3(r, data, i, elem) (elem,& BOOST_PP_CAT(rule,i))
+
+
+                                options.add BOOST_PP_SEQ_FOR_EACH_I(generateOptions3,_,keys);
+
+                        switch(variation_type::value)
+                        {
+                                case full:
+                                        {
+                                                start =
+                                                        quoted_string [at_c<0>(_val)=_1][phx::ref(currentObj)=&_val]
+                                                        >> *( options [_a=_1] >> lazy(*_a));
+                                                ;
+                                                break;
+                                        }
+                                case no_assign:
+                                        {
+                                                start =
+                                                        quoted_string [at_c<0>(_val)=_1][phx::ref(currentObj)=&_val]
+                                                        >> *( options >> int_);
+                                                ;
+                                                break;
+                                        }
+                                case assign:
+                                        {
+                                                start =
+                                                        quoted_string [at_c<0>(_val)=_1][phx::ref(currentObj)=&_val]
+                                                        >> *( options [_a=_1] >> int_);
+                                                ;
+                                                break;
+                                        }
+                        }
+                }
+
+                parsedData2 *currentObj;
+
+                typedef parsedData2 parser_target_type;
+
+                qi::rule<Iterator, std::string(), ascii::space_type> quoted_string;
+                typedef qi::rule<Iterator, ascii::space_type> optionsRule;
+#define declareRules(r, data, i, elem) optionsRule BOOST_PP_CAT(rule,i);
+
+                BOOST_PP_SEQ_FOR_EACH_I(declareRules,_,keys)
+
+                        qi::symbols<char,optionsRule*, boost::spirit::qi::tst_map<char,optionsRule*> > options;
+                qi::rule<Iterator, parsedData2(), ascii::space_type> startalias;
+                qi::rule<Iterator, parsedData2(), qi::locals<optionsRule*>, ascii::space_type> start;
+        };
+
+
+        template <typename Iterator>
+                struct kwd_parser : qi::grammar<Iterator, parsedData(), ascii::space_type>
+        {
+                kwd_parser() : kwd_parser::base_type(start)
+                {
+                        using qi::int_;
+                        using qi::lit;
+                        using qi::double_;
+                        using qi::lexeme;
+                        using ascii::char_;
+                        using qi::_r1;
+                        using qi::_1;
+                        using qi::_val;
+                        using boost::spirit::repository::qi::kwd;
+
+                        quoted_string %= lexeme[+(char_-' ')];
+
+#define generateOptions4(r, data, i, elem) BOOST_PP_IF(i, / kwd( elem )[ int_ ] , kwd(  elem )[ int_ ] )
+                        options = (BOOST_PP_SEQ_FOR_EACH_I(generateOptions4,_,keys));
+
+                        start %=
+                                quoted_string 
+                                >> options;                
+                        ;
+                }
+
+                typedef parsedData parser_target_type;
+
+                qi::rule<Iterator, std::string(), ascii::space_type> quoted_string;
+                qi::rule<Iterator, parsedDataOptions(), ascii::space_type> options;
+                qi::rule<Iterator, boost::fusion::vector<boost::optional<int>,boost::optional<int> > () , ascii::space_type> v_vals;
+
+                qi::rule<Iterator, parsedData(), ascii::space_type> start;
+        };
+
+}
+
+
+template <typename parserType>
+        struct timeParser : test::base{
+                timeParser(const std::string & str) : str(str)
+                {
+                }
+                parserType &get_parser(){
+                        static parserType parser;
+                        return parser;
+                }    
+
+                std::string str;
+
+                void benchmark()    
+                {
+
+                        using boost::spirit::ascii::space;
+                        bool r = false;
+                        std::string::const_iterator end = str.end();
+                        std::string::const_iterator iter = str.begin();
+
+
+                        typename parserType::parser_target_type data;
+                        r = phrase_parse(iter, end, get_parser(), space, data);
+
+                        if (r && iter == end)
+                        {
+                                this->val += data.name.size();
+                        }
+                        else
+                        {
+                                throw std::runtime_error("Parsing failed");
+                        }
+                }
+
+        };
+
+
+
+
+typedef std::string::const_iterator iterator_type;
+typedef client::permutation_parser<iterator_type> permutation_parser;
+typedef client::kwd_parser<iterator_type> kwd_parser;
+typedef client::alternative_parser<iterator_type> alternative_parser;
+typedef client::tst_map_parser<iterator_type, boost::mpl::int_<full> > tst_map_parser;
+
+struct permutation_timer_fwd : timeParser<permutation_parser>
+{
+        permutation_timer_fwd() : timeParser<permutation_parser>(fwd) {}
+};
+
+struct permutation_timer_back : timeParser<permutation_parser>
+{
+        permutation_timer_back() : timeParser<permutation_parser>(back) {}
+};
+
+struct alternative_timer_fwd : timeParser<alternative_parser>
+{
+        alternative_timer_fwd() : timeParser<alternative_parser>(fwd) {}
+};
+
+struct alternative_timer_back : timeParser<alternative_parser>
+{
+        alternative_timer_back() : timeParser<alternative_parser>(back) {}
+};
+
+struct tst_timer_fwd_full : timeParser< client::tst_parser<iterator_type, boost::mpl::int_<full> > >
+{
+        tst_timer_fwd_full() : timeParser< client::tst_parser<iterator_type, boost::mpl::int_<full> > >(fwd) {}
+};
+
+struct tst_timer_fwd_no_assign : timeParser< client::tst_parser<iterator_type, boost::mpl::int_<no_assign> > >
+{
+        tst_timer_fwd_no_assign() : timeParser< client::tst_parser<iterator_type,boost::mpl::int_<no_assign> > >(fwd) {}
+};
+
+struct tst_timer_fwd_assign : timeParser< client::tst_parser<iterator_type,boost::mpl::int_<assign> > >
+{
+        tst_timer_fwd_assign() : timeParser< client::tst_parser<iterator_type,boost::mpl::int_<assign> > >(fwd) {}
+};
+
+
+
+struct tst_timer_back : timeParser< client::tst_parser<iterator_type,boost::mpl::int_<full> > >
+{
+        tst_timer_back() : timeParser< client::tst_parser<iterator_type,boost::mpl::int_<full> > >(back) {}
+};
+
+struct tst_map_timer_fwd : timeParser<tst_map_parser>
+{
+        tst_map_timer_fwd() : timeParser<tst_map_parser>(fwd) {}
+};
+
+struct tst_map_timer_back : timeParser<tst_map_parser>
+{
+        tst_map_timer_back() : timeParser<tst_map_parser>(back) {}
+};
+
+struct kwd_timer_fwd : timeParser<kwd_parser>
+{
+        kwd_timer_fwd() : timeParser<kwd_parser>(fwd) {}
+};
+
+struct kwd_timer_back : timeParser<kwd_parser>
+{
+        kwd_timer_back() : timeParser<kwd_parser>(back) {}
+};
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////
+//  Main program
+////////////////////////////////////////////////////////////////////////////
+        int
+main()
+{
+
+        BOOST_SPIRIT_TEST_BENCHMARK(
+                        10000000000,     // This is the maximum repetitions to execute
+                        (permutation_timer_fwd)
+                        (permutation_timer_back)
+                        (alternative_timer_fwd)
+                        (alternative_timer_back)
+                        (tst_timer_fwd_full)
+                        (tst_timer_fwd_no_assign)
+                        (tst_timer_fwd_assign)
+                        (tst_timer_back)
+                        (tst_map_timer_fwd)
+                        (tst_map_timer_back)
+                        (kwd_timer_fwd)
+                        (kwd_timer_back)
+                        )
+
+                // This is ultimately responsible for preventing all the test code
+                // from being optimized away.  Change this to return 0 and you
+                // unplug the whole test's life support system.
+                return test::live_code != 0;
+}
+
+
Modified: trunk/libs/spirit/repository/doc/qi.qbk
==============================================================================
--- trunk/libs/spirit/repository/doc/qi.qbk	(original)
+++ trunk/libs/spirit/repository/doc/qi.qbk	2011-03-02 19:32:48 EST (Wed, 02 Mar 2011)
@@ -11,7 +11,8 @@
 [include        qi/primitive_parsers.qbk]
 [include        qi/directives.qbk]
 [include        qi/nonterminals.qbk]
-[/include        qi/compound_parsers.qbk]
+[include        qi/operators.qbk]
+[/include       qi/compound_parsers.qbk]
 
 [endsect] [/ Qi]
 
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	2011-03-02 19:32:48 EST (Wed, 02 Mar 2011)
@@ -9,4 +9,5 @@
 [section:directives Qi Parser Directives]
 [include        confix.qbk]
 [include        distinct.qbk]
+[include        kwd.qbk]
 [endsect]
Added: trunk/libs/spirit/repository/doc/qi/kwd.qbk
==============================================================================
--- (empty file)
+++ trunk/libs/spirit/repository/doc/qi/kwd.qbk	2011-03-02 19:32:48 EST (Wed, 02 Mar 2011)
@@ -0,0 +1,95 @@
+[/==============================================================================
+    Copyright (C) 2001-2011 Joel de Guzman
+    Copyright (C) 2001-2011 Hartmut Kaiser
+    Copyright (C) 2011 Thomas Bernard
+
+    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:kwd Qi Keyword Parser Directive ]
+
+[heading Description]
+
+The `kwd[]` and `ikwd[]` provide a powerful and flexible mechanism for parsing keyword
+based input. It works in conjuction with the / operator to create an effective
+keyword parsing loop. The keyword parsing loop doesn't require the 
+keywords to appear in a defined order in the input but also provides the possibility
+to check how many times a keyword appears in the input.
+
+The kwd directive will parse the keywords respecting case sensitivity whereas the ikwd
+direcive is case insensitive. You can mix the kwd and ikwd directives inside a set of 
+keywords, but be aware that this has a small overhead. It should be prefered not to 
+mix the kwd and ikwd directives.
+
+The kwd directive is very similar to the repeat directive in that it enables to enforce
+keyword occurence constraints but also provides very interesting speed improvement
+over the pure EBNF syntax or the Nabialek-Trick. 
+
+[heading Header]
+
+    // forwards to <boost/spirit/repository/home/qi/directive/kwd.hpp>
+    #include <boost/spirit/repository/include/qi_kwd.hpp>
+
+[heading Synopsis]
+
+[table
+    [[Expression]               [Semantics]]
+    [[`kwd(keyword)[subject]`]              [Parse ( `"keyword"` > `subject`) zero or more times.]]
+    [[`kwd(keyword,n)[subject]`]           [Parse ( `"keyword"` > `subject`) exactly `n` times.]]
+    [[`kwd(keyword,min, max)[subject]`]    [Parse ( `"keyword"` > `subject`) at least `min` times and at most `max` times.]]
+    [[`kwd(keyword,min, inf)[subject]`]    [Parse ( `"keyword"` > `subject`) at least `min` or more. ]]
+]
+
+For non case sensitive keywords use the ikwd directive.
+
+[heading Parameters]
+
+[table
+    [[Parameter]            [Description]]
+    [[`keyword`]             [The parser for the opening (the prefix).]]    
+    [[`subject`]            [The parser for the input sequence following the keyword part.]]
+    [[`n`]            [Int representing the exact number of times the keyword must be repeated.]]
+    [[`min`]            [Int representing the minimum number of times the keyword must be repeated.]]
+    [[`max`]            [Int representing the maximum number of times the keyword must be repeated.]]
+]
+
+All three parameters can be arbitrarily complex parsers themselves.
+
+
+[heading Attributes]
+
+[table
+    [[Expression]             [Attribute]]
+    [[`kwd(k1)[a]`]
+[``a: A --> kwd(k1)[a]: optional<A> or vector<A>
+a: Unused --> kwd(k1)[a]: Unused``]]
+    [[`kwd(k1,n)[a]`]
+[``a: A --> kwd(k1,n)[a]: optional<A> or vector<A>
+a: Unused --> kwd(k1,n)[a]: Unused``]]
+    [[`kwd(k1,min, max)[a]`]
+[``a: A --> kwd(k1,min, max)[a]: optional<A> or vector<A>
+a: Unused --> kwd(k1,min, max)[a]: Unused``]]
+    [[`kwd(k1,min, inf)[a]`]
+[``a: A --> kwd(k1,min, inf)[a]: optional<A> or vector<A>
+a: Unused --> kwd(k1,min, inf)[a]: Unused``]]
+]
+
+[heading Complexity]
+
+[:The overall complexity is defined by the complexity of its subject
+parser. The complexity of the keyword list construct `kwd` itself is O(N), where N is the number
+of repetitions executed.
+
+The complexity of the keyword list itself determined by the complexity of the internal TST contents :
+
+O(log n+k)
+
+Where k is the length of the string to be searched in a TST with n strings.
+]
+
+[heading Example]
+
+Please refer to keyword_list.
+
+[endsect]
Modified: trunk/libs/spirit/repository/example/qi/Jamfile
==============================================================================
--- trunk/libs/spirit/repository/example/qi/Jamfile	(original)
+++ trunk/libs/spirit/repository/example/qi/Jamfile	2011-03-02 19:32:48 EST (Wed, 02 Mar 2011)
@@ -18,4 +18,4 @@
 exe calc1_sr : calc1_sr.cpp ;
 exe mini_xml2_sr : mini_xml2_sr.cpp ;
 exe advance : advance.cpp ;
-
+exe keywords : keywords.cpp ;
Added: trunk/libs/spirit/repository/example/qi/keywords.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/spirit/repository/example/qi/keywords.cpp	2011-03-02 19:32:48 EST (Wed, 02 Mar 2011)
@@ -0,0 +1,214 @@
+/*=============================================================================
+    Copyright (c) 2001-2011 Joel de Guzman
+    http://spirit.sourceforge.net/
+
+    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)
+=============================================================================*/
+//[reference_includes
+#include <boost/spirit/include/qi.hpp>
+#include <boost/spirit/include/phoenix_core.hpp>
+#include <boost/spirit/include/phoenix_operator.hpp>
+#include <boost/fusion/include/adapt_struct.hpp>
+#include <boost/spirit/repository/include/qi_kwd.hpp>
+#include <boost/spirit/repository/include/qi_keywords.hpp>
+#include <iostream>
+#include <string>
+#include <cstdlib>
+#include <iterator>
+//]
+
+//[reference_test
+template <typename P>
+void test_parser(
+    char const* input, P const& p, bool full_match = true)
+{
+    using boost::spirit::qi::parse;
+
+    char const* f(input);
+    char const* l(f + strlen(f));
+    if (parse(f, l, p) && (!full_match || (f == l)))
+        std::cout << "ok" << std::endl;
+    else
+        std::cout << "fail" << std::endl;
+}
+
+template <typename P>
+void test_phrase_parser(
+    char const* input, P const& p, bool full_match = true)
+{
+    using boost::spirit::qi::phrase_parse;
+    using boost::spirit::qi::ascii::space;
+    
+    char const* f(input);
+    char const* l(f + strlen(f));
+    if (phrase_parse(f, l, p, space) && (!full_match || (f == l)))
+        std::cout << "ok" << std::endl;
+    else
+        std::cout << "fail" << std::endl;
+}
+//]
+
+//[reference_test_attr
+template <typename P, typename T>
+void test_parser_attr(
+    char const* input, P const& p, T& attr, bool full_match = true)
+{
+    using boost::spirit::qi::parse;
+
+    char const* f(input);
+    char const* l(f + strlen(f));
+    if (parse(f, l, p, attr) && (!full_match || (f == l)))
+        std::cout << "ok" << std::endl;
+    else
+        std::cout << "fail" << std::endl;
+}
+
+template <typename P, typename T>
+void test_phrase_parser_attr(
+    char const* input, P const& p, T& attr, bool full_match = true)
+{
+    using boost::spirit::qi::phrase_parse;
+    using boost::spirit::qi::ascii::space;
+
+    char const* f(input);
+    char const* l(f + strlen(f));
+    if (phrase_parse(f, l, p, space, attr) && (!full_match || (f == l)))
+        std::cout << "ok" << std::endl;
+    else
+        std::cout << "fail" << std::endl;
+}
+//]
+
+
+
+//[reference_keyword_list_test_data_structure
+// Data structure definitions to test the kwd directive
+// and the keywords list operator
+
+struct person {
+    std::string name;
+    int age;
+    double size;
+    std::vector<std::string> favorite_colors;
+   
+};
+
+std::ostream &operator<<(std::ostream &os, const person &p)
+{
+    os<<"Person : "<<p.name<<", "<<p.age<<", "<<p.size<<std::endl;
+    std::copy(p.favorite_colors.begin(),p.favorite_colors.end(),std::ostream_iterator<std::string>(os,"\n"));
+    return os;
+} 
+
+BOOST_FUSION_ADAPT_STRUCT( person,
+    (std::string, name)
+    (int, age)
+    (double, size)
+    (std::vector<std::string>, favorite_colors)
+)
+//]
+
+int
+main()
+{
+    
+     // keyword_list
+    {
+        //[reference_using_declarations_keyword_list
+        using boost::spirit::repository::qi::kwd;
+        using boost::spirit::qi::inf;
+        using boost::spirit::ascii::space_type; 
+        using boost::spirit::ascii::char_;
+        using boost::spirit::qi::double_;
+        using boost::spirit::qi::int_;
+        using boost::spirit::qi::rule;
+        //]
+       
+        //[reference_keyword_list_rule_declarations
+        rule<const char *, std::string(), space_type> parse_string;
+        rule<const char *, person(), space_type> no_constraint_person_rule, constraint_person_rule; 
+        
+         parse_string   %= '"'> *(char_-'"') > '"';
+        //]
+        
+        //[reference_keyword_list_no_constraint_rule
+        no_constraint_person_rule %= 
+            kwd("name")['=' > parse_string ] 
+          / kwd("age")   ['=' > int_] 
+          / kwd("size")   ['=' > double_ > 'm']
+          ;
+        //]
+        
+
+        //[reference_keyword_list
+        //`Parsing a keyword list:
+        // Let's declare a small list of people for which we want to collect information.
+        person John,Mary,Mike,Hellen,Johny;
+        test_phrase_parser_attr(
+                        "name = \"John\" \n age = 10 \n size = 1.69m "
+                        ,no_constraint_person_rule 
+                        ,John);  // full in orginal order
+        std::cout<<John;
+
+        test_phrase_parser_attr(
+                        "age = 10 \n size = 1.69m \n name = \"Mary\""
+                        ,no_constraint_person_rule 
+                        ,Mary);  // keyword oder doesn't matter
+        std::cout<<Mary;
+
+        test_phrase_parser_attr(
+                         "size = 1.69m \n name = \"Mike\" \n age = 10 "
+                        ,no_constraint_person_rule
+                        ,Mike);  // still the same result
+        
+        std::cout<<Mike;
+        
+         /*`The code above will print:[teletype]
+        
+                Person : John, 10, 1.69
+                Person : Mary, 10, 1.69
+                Person : Mike, 10, 1.69
+         */
+        //]
+
+        //[reference_keyword_list_constraint_rule
+        /*`The parser definition below uses the kwd directive occurence constraint variants to 
+            make sure that the name and age keyword occur only once and allows the favorite color 
+            entry to appear 0 or more times. */
+        constraint_person_rule %=
+            kwd("name",1)                 ['=' > parse_string ]
+          / kwd("age"   ,1)                 ['=' > int_]
+          / kwd("size"   ,1)                 ['=' > double_ > 'm']
+          / kwd("favorite color",0,inf) [ '=' > parse_string ]
+          ;
+        //]
+         
+        //[reference_keyword_list_constraints
+      
+        // Here all the give constraint are resepected : parsing will succeed.
+        test_phrase_parser_attr(
+            "name = \"Hellen\" \n age = 10 \n size = 1.80m \n favorite color = \"blue\" \n favorite color = \"green\" "
+            ,constraint_person_rule 
+            ,Hellen);   
+        std::cout<<Hellen;
+        
+       // Parsing this string will fail because the age and size minimum occurence requirements aren't met.
+       test_phrase_parser_attr(
+            "name = \"Johny\"  \n favorite color = \"blue\" \n favorite color = \"green\" "
+            ,constraint_person_rule
+            ,Johny );
+        
+        /*`Parsing the first string will succeed but fail for the second string as the 
+        occurence constraints aren't met. This code should print:[teletype]
+        
+        Person : Hellen, 10, 1.8
+        blue
+        green
+        */
+        //]
+    }
+    
+        
+    return 0;
+}
Modified: trunk/libs/spirit/repository/test/Jamfile
==============================================================================
--- trunk/libs/spirit/repository/test/Jamfile	(original)
+++ trunk/libs/spirit/repository/test/Jamfile	2011-03-02 19:32:48 EST (Wed, 02 Mar 2011)
@@ -9,7 +9,7 @@
 project spirit_v2_repository/test
     : requirements
         <include>.
-        <toolset>gcc:<cxxflags>-ftemplate-depth-300
+        <toolset>gcc:<cxxflags>-ftemplate-depth-300 <linkflags>-lrt
         <toolset>darwin:<cxxflags>-ftemplate-depth-300
     :
     :
@@ -26,6 +26,7 @@
     [ run qi/confix.cpp                     : : : : qi_repo_confix ]
     [ run qi/distinct.cpp                   : : : : qi_repo_distinct ]
     [ run qi/subrule.cpp                    : : : : qi_repo_subrule ]
+    [ run qi/keywords.cpp                   : : : : qi_repo_keywords ]
 
     # run Karma repository tests
     [ run karma/confix.cpp                  : : : : karma_repo_confix ]
Added: trunk/libs/spirit/repository/test/qi/keywords.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/spirit/repository/test/qi/keywords.cpp	2011-03-02 19:32:48 EST (Wed, 02 Mar 2011)
@@ -0,0 +1,154 @@
+/*=============================================================================
+    Copyright (c) 2001-2011 Joel de Guzman
+    Copyright (c) 2011 Thomas Bernard
+
+    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 <string>
+#include <vector>
+
+#include <boost/detail/lightweight_test.hpp>
+#include <boost/utility/enable_if.hpp>
+
+#include <boost/spirit/include/qi_operator.hpp>
+#include <boost/spirit/include/qi_char.hpp>
+#include <boost/spirit/include/qi_string.hpp>
+#include <boost/spirit/include/qi_numeric.hpp>
+#include <boost/spirit/include/qi_directive.hpp>
+#include <boost/spirit/include/qi_action.hpp>
+#include <boost/spirit/include/support_argument.hpp>
+#include <boost/spirit/include/phoenix_core.hpp>
+#include <boost/spirit/include/phoenix_operator.hpp>
+#include <boost/spirit/include/phoenix_container.hpp>
+#include <boost/spirit/repository/include/qi_kwd.hpp>
+#include <boost/spirit/repository/include/qi_keywords.hpp>
+
+#include <string>
+#include <iostream>
+#include "test.hpp"
+
+struct x_attr
+{
+    
+};
+
+namespace boost { namespace spirit { namespace traits 
+{
+    
+    
+    template <>
+    struct container_value<x_attr>
+    {
+        typedef char type; // value type of container
+    };
+
+    
+    template <>
+    struct push_back_container<x_attr, char>
+    {
+        static bool call(x_attr& /*c*/, char /*val*/)
+        {
+            // push back value type into container
+            return true;
+        }
+    };
+}}} 
+
+int
+main()
+{
+    using spirit_test::test_attr;
+    using spirit_test::test;
+    using namespace boost::spirit;
+    using namespace boost::spirit::ascii;
+    using boost::spirit::repository::kwd;
+    using boost::spirit::repository::ikwd;
+    using boost::spirit::qi::inf;
+    using boost::spirit::qi::omit;
+    using boost::spirit::qi::int_;
+    using boost::spirit::qi::lit;
+    using boost::spirit::qi::_1;
+    using boost::spirit::qi::lexeme;
+
+    {
+    
+        // no constraints
+        boost::fusion::vector<char,char,int> data;
+        BOOST_TEST( test_attr("c=1 a=a", kwd("a")[ '=' > char_] / kwd("b")[ '=' > char_] / kwd("c")['=' > int_], data, space)); 
+        BOOST_TEST( test("a=a c=1", kwd("a")[ '=' > char_] / kwd("b")[ '=' > char_] / kwd("c")['=' > int_], space)); 
+
+        // Exact
+        BOOST_TEST(test("a=a b=b c=1", kwd("a",1)[ '=' > char_] / kwd("b")[ '=' > char_] / kwd("c")['=' > int_], space)); 
+        BOOST_TEST(test("a=a b=c b=e c=1", kwd("a",1)[ '=' > char_] / kwd("b",2)[ '=' > char_] / kwd("c")['=' > int_], space)); 
+        BOOST_TEST(!test("b=c b=e c=1", kwd("a",1)[ '=' > char_] / kwd("b",2)[ '=' > char_] / kwd("c")['=' > int_], space)); 
+        
+        // Min - Max 
+        BOOST_TEST(test("a=f b=c b=e c=1", kwd("a",1,2)[ '=' > char_] / kwd("b",0,2)[ '=' > char_] / kwd("c",1,2)['=' > int_], space)); 
+        BOOST_TEST(!test("b=c b=e c=1", kwd("a",1,2)[ '=' > char_] / kwd("b",0,1)[ '=' > char_] / kwd("c",1,2)['=' > int_], space)); 
+        BOOST_TEST(test("a=g a=f b=c b=e c=1", kwd("a",1,2)[ '=' > char_] / kwd("b",0,2)[ '=' > char_] / kwd("c",1,2)['=' > int_], space)); 
+        BOOST_TEST(!test("a=f a=e b=c b=e a=p c=1", kwd("a",1,2)[ '=' > char_] / kwd("b",0,1)[ '=' > char_] / kwd("c",1,2)['=' > int_], space)); 
+
+        // Min - inf
+        BOOST_TEST(test("a=f b=c b=e c=1", kwd("a",1,inf)[ '=' > char_] / kwd("b",0,inf)[ '=' > char_] / kwd("c",1,inf)['=' > int_], space )); 
+        BOOST_TEST(!test("b=c b=e c=1", kwd("a",1,inf)[ '=' > char_] / kwd("b",0,inf)[ '=' > char_] / kwd("c",1,inf)['=' > int_], space )); 
+        BOOST_TEST(test("a=f a=f a=g b=c b=e c=1 a=e", kwd("a",1,inf)[ '=' > char_] / kwd("b",0,inf)[ '=' > char_] / kwd("c",1,inf)['=' > int_], space )); 
+    }
+
+    {   // Single keyword, empty string
+        BOOST_TEST(test(" ", kwd("aad")[char_],space));        
+        BOOST_TEST(test("aad E ", kwd("aad")[char_],space));        
+        //BOOST_TEST(test("AaD E ", ikwd("aad")[char_],space));        
+        
+    }
+    
+    {
+        // Vector container
+        boost::fusion::vector<std::vector<int>,std::vector<int>,std::vector<int> > data;
+        BOOST_TEST(test_attr(" a=1 b=2 b=5 c=3",kwd("a")[ '=' > int_] / kwd("b")[ '=' > int_] / kwd("c")['=' > int_] , data, space) 
+                    && (boost::fusion::at_c<0>(data).size()==1) 
+                    && (boost::fusion::at_c<0>(data)[0]==1)
+    
+                    &&(boost::fusion::at_c<1>(data).size()==2)
+                    &&(boost::fusion::at_c<1>(data)[0]==2)
+                    &&(boost::fusion::at_c<1>(data)[1]==5)
+    
+                    &&(boost::fusion::at_c<2>(data).size()==1)
+                    &&(boost::fusion::at_c<2>(data)[0]==3)
+            );
+    }
+
+    {
+        // no_case test
+        BOOST_TEST( test("B=a c=1 a=E", no_case[kwd("a")[ "=E" ] / kwd("b")[ '=' > char_] / kwd("c")['=' > int_]], space)); 
+        BOOST_TEST( test("B=a c=1 a=e", no_case[kwd("a")[ "=E" ] / kwd("b")[ '=' > char_] / kwd("c")['=' > int_]], space)); 
+        BOOST_TEST( !test("B=a c=1 A=E", no_case[kwd("a")[ '=' > char_]] / kwd("b")[ '=' > char_] / kwd("c")['=' > int_], space)); 
+        BOOST_TEST( test("b=a c=1 A=E", no_case[kwd("a")[ '=' > char_]] / kwd("b")[ '=' > char_] / kwd("c")['=' > int_], space)); 
+        BOOST_TEST( !test("A=a c=1 a=E", kwd("a")[ '=' > char_] / kwd("b")[ '=' > char_] / kwd("c")['=' > int_], space)); 
+        BOOST_TEST( test("A=a c=1 a=E", ikwd("a")[ '=' > char_] / kwd("b")[ '=' > char_] / kwd("c")['=' > int_], space)); 
+        BOOST_TEST( !test("A=a C=1 a=E", ikwd("a")[ '=' > char_] / kwd("b")[ '=' > char_] / kwd("c")['=' > int_], space)); 
+    }
+    
+    {
+        // iterator restoration
+        BOOST_TEST( test("a=a c=1 ba=d", (kwd("a")[ '=' > char_] / kwd("b")[ '=' > int_] / kwd("c")['=' > int_] ) | lit("ba=") > char_, space)); 
+        BOOST_TEST( test("A=a c=1 ba=d", (ikwd("a")[ '=' > char_] / kwd("b")[ '=' > int_] / kwd("c")['=' > int_] ) | lit("ba=") > char_, space)); 
+    }
+
+    { // actions
+        namespace phx = boost::phoenix;
+
+        std::vector<int> v;
+        BOOST_TEST(test("b=2 c=4", kwd("b")['=' > int_][phx::ref(v)=_1] / kwd("c")[ '=' > int_ ],space) && 
+            v[0] == 2 );
+    }
+
+    { // attribute customization
+        
+        x_attr x;
+//        test_attr("a = b c = d", kwd("a")['=' > char_] / kwd("c")['=' > char_], x);
+    }
+
+    return boost::report_errors();
+}
+