Last active
August 24, 2016 08:55
-
-
Save cppljevans/3d3bec54be8f3d0c4d8b94af84a6e529 to your computer and use it in GitHub Desktop.
spirit toy.cpp modified to show need for BOOST_SPIRIT_DEFINE
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//Purpose: | |
// Demonstrate the purpose BOOST_SPIRIT_DEFINE | |
// is to implement recursive rules. | |
//OriginalSource: | |
// https://github.com/boostorg/spirit/blob/develop/workbench/x3/toy/toy.cpp | |
//Modifications: | |
// Rm'ed use of context to implement recursiion and replaced with | |
// BOOST_SPIRIT_DEFINE | |
//=========================================================================== | |
#include <iostream> | |
#include <utility> | |
#include <cstring> | |
#include <boost/type_traits/is_same.hpp> | |
#include <boost/preprocessor/variadic/to_seq.hpp> | |
#include <boost/preprocessor/variadic/elem.hpp> | |
#include <boost/preprocessor/seq/for_each.hpp> | |
template <typename Derived> | |
struct parser | |
{ | |
Derived const& derived() const | |
{ | |
return *static_cast<Derived const*>(this); | |
} | |
}; | |
template <typename Char> | |
struct char_parser : parser<char_parser<Char>> | |
{ | |
char_parser(Char ch) : ch(ch) {} | |
template <typename Iterator, typename Context> | |
bool parse(Iterator& first, Iterator last, Context const& ctx) const | |
{ | |
if (first != last && *first == ch) | |
{ | |
++first; | |
return true; | |
} | |
return false; | |
} | |
Char ch; | |
}; | |
template <typename Char> | |
inline char_parser<Char> char_(Char ch) | |
{ | |
return char_parser<Char>(ch); | |
}; | |
template <typename Left, typename Right> | |
struct sequence_parser : parser<sequence_parser<Left, Right>> | |
{ | |
sequence_parser(Left left, Right right) | |
: left(left), right(right) {} | |
template <typename Iterator, typename Context> | |
bool parse(Iterator& first, Iterator last, Context const& ctx) const | |
{ | |
return left.parse(first, last, ctx) | |
&& right.parse(first, last, ctx); | |
} | |
Left left; | |
Right right; | |
}; | |
template <typename Left, typename Right> | |
inline sequence_parser<Left, Right> operator>>( | |
parser<Left> const& left, parser<Right> const& right) | |
{ | |
return sequence_parser<Left, Right>( | |
left.derived(), right.derived()); | |
} | |
template <typename Left, typename Right> | |
struct alternative_parser : parser<alternative_parser<Left, Right>> | |
{ | |
alternative_parser(Left left, Right right) | |
: left(left), right(right) {} | |
template <typename Iterator, typename Context> | |
bool parse(Iterator& first, Iterator last, Context const& ctx) const | |
{ | |
if (left.parse(first, last, ctx)) | |
return true; | |
return right.parse(first, last, ctx); | |
} | |
Left left; | |
Right right; | |
}; | |
template <typename Left, typename Right> | |
inline alternative_parser<Left, Right> operator|( | |
parser<Left> const& left, parser<Right> const& right) | |
{ | |
return alternative_parser<Left, Right>( | |
left.derived(), right.derived()); | |
} | |
struct empty_context | |
{ | |
}; | |
template <typename ID> | |
struct rule; | |
#define USE_ALWAYS_FALSE | |
#ifdef USE_ALWAYS_FALSE | |
/*! | |
* @brief | |
* Only used to avoid firing the static_assert in | |
* default parse_rule below when the | |
* specialized parse_rule is the one that would | |
* actually be called. | |
*/ | |
template <typename ID> | |
struct always_false | |
{ | |
static constexpr bool value=false; | |
}; | |
#endif | |
/*! | |
* @brief | |
* default parse_rule implementation | |
* copied from: | |
* https://github.com/boostorg/spirit/blob/develop/include/boost/spirit/home/x3/nonterminal/rule.hpp#L26 | |
* but modified to always static_assert. | |
*/ | |
template <typename ID, typename Iterator, typename Context> | |
bool parse_rule( | |
rule<ID> rule_ | |
, Iterator& first, Iterator const& last | |
, Context const& context) | |
{ | |
static_assert | |
#ifdef USE_ALWAYS_FALSE | |
( always_false<ID>::value | |
#else | |
( false | |
#endif | |
, "Undefined rule. Use BOOST_SPIRIT_DEFINE to define rule." | |
); | |
return false; | |
} | |
template <typename ID, typename RHS> | |
struct rule_definition : parser<rule_definition<ID, RHS>> | |
{ | |
typedef rule<ID> lhs_type; | |
rule_definition(RHS rhs) | |
: rhs(rhs) {} | |
template <typename Iterator, typename Context> | |
bool parse(Iterator& first, Iterator last, Context const& ctx) const | |
{ | |
return rhs.parse(first, last, ctx); | |
} | |
RHS rhs; | |
}; | |
template <typename ID> | |
struct rule : parser<rule<ID>> | |
{ | |
template <typename Derived> | |
rule_definition<ID, Derived> | |
operator=(parser<Derived> const& definition) const | |
{ | |
return rule_definition<ID, Derived>(definition.derived()); | |
} | |
template <typename Iterator, typename Context> | |
bool parse(Iterator& first, Iterator last, Context const& ctx) const | |
{ | |
return parse_rule(*this, first, last, ctx); | |
} | |
}; | |
template <typename Iterator, typename Derived> | |
inline bool parse(parser<Derived> const& p, Iterator& first, Iterator last) | |
{ | |
empty_context ctx; | |
return p.derived().parse(first, last, ctx); | |
} | |
/*! | |
\def BOOST_SPIRIT_DEFINE_(r, data, rule_def) | |
\a r is ignored. | |
\a data is ignored. | |
\a rule_def is an instance of rule_definition. | |
\purpose | |
Creates a parse_rule definition specialized for | |
decltype(rule_def)::lhs_type. This allows the | |
lhs_type::parse function, when it calls parse_rule, | |
to call the parse_rule specific to it. | |
*/ | |
#define BOOST_SPIRIT_DEFINE_(r, data, rule_def) \ | |
template <typename Iterator, typename Context> \ | |
inline bool parse_rule( \ | |
decltype(rule_def)::lhs_type rule_ \ | |
, Iterator& first, Iterator const& last \ | |
, Context const& context) \ | |
{ \ | |
auto const& def_ = (rule_def); \ | |
bool result=def_.parse(first, last, context); \ | |
return result; \ | |
} \ | |
/***/ | |
#define BOOST_SPIRIT_DEFINE(...) BOOST_PP_SEQ_FOR_EACH( \ | |
BOOST_SPIRIT_DEFINE_, _, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)) \ | |
/***/ | |
/////////////////////////////////////////////////////////////////////////////// | |
// test code | |
template <typename Parser> | |
bool test_parse(Parser const& p, char const* in) | |
{ | |
return parse(p, in, in + std::strlen(in)); | |
} | |
namespace x_definition | |
{ | |
struct x_id{}; | |
auto const x = rule<x_id>(); | |
#define USE_DEFINE | |
#ifdef USE_DEFINE | |
BOOST_SPIRIT_DEFINE( x = char_('x') | char_('a') >> x ); | |
auto const g = x; | |
#else | |
auto const g = ( x = char_('x') | char_('a') >> x ); | |
#endif | |
} | |
int main() | |
{ | |
{ // a non-recursive parser | |
auto abc = char_('a') >> char_('b') >> char_('c'); | |
std::cout << test_parse(abc, "abc") << std::endl; | |
std::cout << test_parse(abc, "abx") << std::endl; | |
std::cout << "==========================================" << std::endl; | |
} | |
{ // a recursive rule | |
using x_definition::g; | |
std::cout << test_parse(g, "x") << std::endl; | |
std::cout << test_parse(g, "ax") << std::endl; | |
std::cout << test_parse(g, "aaaaax") << std::endl; | |
std::cout << test_parse(g, "aaz") << std::endl; | |
std::cout << "==========================================" << std::endl; | |
} | |
return 0; | |
} | |
Slightly simplified code by using always_false in the default parse_rule.
Also provided macro, USE_ALWAYS_FALSE, so you can see it's purpose
by switching it on and off.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi Larry,
I really appreciate this and will study it.
Vince