spirit/workbench/qi/keywords.cpp
2014-04-01 15:06:38 +08:00

554 lines
21 KiB
C++

/*=============================================================================
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;
}