Last active
September 1, 2020 08:44
-
-
Save cppljevans/06bd7b854bc244a0d85095fafdcd37f0 to your computer and use it in GitHub Desktop.
prototype_simplified_spirit_x3_rule
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: | |
// Simplify rule, rule_definition, parse_rule, BOOST_SPIRIT_DEFINE. | |
//References: | |
// [inline] | |
// https://isocpp.org/wiki/faq/inline-functions#where-to-put-inline-keyword | |
// https://stackoverflow.com/questions/3992980/c-inline-member-function-in-cpp-file | |
//=========================================================================== | |
#include "toy_rule_parse_rule.hpp" | |
/////////////////////////////////////////////////////////////////////////////// | |
// test code | |
using iterator_type=char const*; | |
#include <cstring> | |
template <typename Parser> | |
bool test_parse(Parser const& p, iterator_type first) | |
{ | |
iterator_type const last=first + strlen(first); | |
bool result=p.derived().parse(first, last); | |
return result; | |
} | |
namespace ns_toy | |
{ //based on grammar expressions in [toy] | |
using namespace toy_x3; | |
struct x_id{}; | |
struct x_attr{}; | |
auto const x = rule<x_id,x_attr>("x_rule"); | |
#define USE_ONE_RULE 0 | |
#if USE_ONE_RULE | |
auto const x_def = x = char_('x') | char_('a') >> x; | |
#else | |
struct ax_id{}; | |
struct ax_attr{}; | |
auto const ax = rule<ax_id,ax_attr>("ax_rule"); | |
auto const x_def = x = char_('x') | ax; | |
#endif | |
auto const start = x; | |
} | |
using namespace ns_toy; | |
#if USE_ONE_RULE | |
BOOST_SPIRIT_DEFINE( x_def ); | |
#else | |
#define USE_PARSE_RULE_INSTANTIATE 1 | |
#if USE_PARSE_RULE_INSTANTIATE | |
BOOST_SPIRIT_DEFINE( (ax = char_('a') >> x) ) | |
BOOST_SPIRIT_DEFINE_AND_INSTANTIATE( x_def, iterator_type ) | |
#else | |
BOOST_SPIRIT_DEFINE( (ax = char_('a') >> x) , x_def ); | |
#endif | |
#endif | |
#define PRINT_MACRO(macro) std::cout<<#macro "=" <<macro<<"\n"; | |
int main() | |
{ | |
PRINT_MACRO(USE_ONE_RULE) | |
{ | |
using ns_toy::start; | |
std::cout<<"***recursive rule ns_toy::start\n"; | |
std::cout << test_parse(start, "x") << std::endl; | |
std::cout << test_parse(start, "ax") << std::endl; | |
std::cout << test_parse(start, "aaaaax") << std::endl; | |
std::cout << test_parse(start, "aaz") << std::endl;//should fail | |
std::cout << "==========================================" << std::endl; | |
} | |
return 0; | |
} | |
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
#ifndef TOY_RULE_PARSE_RULE_HPP_INCLUDED | |
#define TOY_RULE_PARSE_RULE_HPP_INCLUDED | |
#include <string> | |
#include <iostream> | |
namespace toy_x3 | |
{ | |
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 | |
> | |
bool parse | |
( Iterator& first | |
, Iterator last | |
) const | |
{ | |
bool result=false; | |
if (first != last && *first == ch) | |
{ | |
++first; | |
result=true; | |
} | |
return result; | |
} | |
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 | |
> | |
bool parse | |
( Iterator& first | |
, Iterator last | |
) const | |
{ | |
return left.parse | |
( first | |
, last | |
) | |
&& right.parse | |
( first | |
, last | |
); | |
} | |
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 | |
> | |
bool parse | |
( Iterator& first | |
, Iterator last | |
) const | |
{ | |
if ( left.parse | |
( first | |
, last | |
) | |
) | |
return true; | |
return right.parse | |
( first | |
, last | |
); | |
} | |
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()); | |
} | |
template <typename ID, typename Attribute=std::string> | |
struct rule : parser<rule<ID,Attribute>> | |
{ | |
using attribute_type=Attribute; | |
using name_type=char const*; | |
rule(name_type name="unknown") | |
: name(name) {} | |
private: | |
template<typename RHS> | |
struct rule_definition | |
{ | |
using rule_type=rule;//allows BOOST_SPIRIT_DEF_ to work. | |
rule_definition(RHS rhs): rhs(rhs){} | |
RHS rhs;//definition of enclosing rule. | |
template <typename Iterator> | |
bool | |
parse_definition | |
( Iterator& first | |
, Iterator last | |
, attribute_type& attr | |
, typename rule_type::name_type name | |
)const | |
{ | |
//In actual implementation, this would call same function as | |
//the current x3::rule_definition::parse member function, i.e. | |
// detail::rule_parser<attribute_type, ID> | |
// ::call_rule_definition(...) | |
std::cout<<"rule::rule_definition::"<<__func__<<":name="<<name<<";\n"; | |
return rhs.parse(first,last); | |
} | |
}; | |
public: | |
template <typename Derived> | |
rule_definition<Derived> | |
operator=(parser<Derived> const& definition) const | |
{ | |
return rule_definition<Derived>(definition.derived()); | |
} | |
template <typename Iterator> | |
bool | |
parse(Iterator& first, Iterator last) const | |
{ | |
attribute_type attr_; | |
//In actual implementation, this would have another | |
//arg, 'Attribute attr' and the code here would | |
//perform the same traits::transform_attribute on 'attr' | |
//as the current x3::rule::parse function does to get 'attr_'. | |
bool result=parse_rule(first, last, attr_); | |
return result; | |
} | |
private: | |
name_type name; | |
template <typename Iterator> | |
bool | |
parse_rule | |
( Iterator& first | |
, Iterator last | |
, attribute_type& attr | |
)const | |
/**@brief | |
* The definition of this function should be | |
* generated by the BOOST_SPIRIT_DEFINE_ macro. | |
*/ | |
; | |
}; | |
} | |
#include <boost/preprocessor/variadic/to_seq.hpp> | |
#include <boost/preprocessor/seq/for_each.hpp> | |
/*! | |
\def BOOST_SPIRIT_DEFINE_(r, data, rule_def) | |
\a r is ignored. | |
\a data is ignored. | |
\a rule_def is an instance of rule<...>::rule_definition. | |
\purpose | |
defines body of rule<ID,Attribute>::parse_rule. | |
*/ | |
#define BOOST_SPIRIT_DEFINE_(r, data, rule_def) \ | |
template <> \ | |
template <typename Iterator> inline \ | |
bool std::decay_t<decltype(rule_def)>::rule_type \ | |
::parse_rule \ | |
( Iterator& first \ | |
, Iterator last \ | |
, std::decay_t<decltype(rule_def)>::rule_type::attribute_type& attr \ | |
)const \ | |
{ \ | |
auto const def_ = rule_def; \ | |
return def_.parse_definition(first, last, attr, name); \ | |
} \ | |
/***/ | |
#define BOOST_SPIRIT_DEFINE(...) BOOST_PP_SEQ_FOR_EACH( \ | |
BOOST_SPIRIT_DEFINE_, _, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)) \ | |
/***/ | |
#define BOOST_SPIRIT_INSTANTIATE(rule_def,IterInstance) \ | |
template \ | |
bool std::decay_t<decltype(rule_def)>::rule_type \ | |
::parse_rule<IterInstance> \ | |
( IterInstance& first \ | |
, IterInstance last \ | |
, std::decay_t<decltype(rule_def)>::rule_type::attribute_type& attr \ | |
)const; \ | |
/***/ | |
#define BOOST_SPIRIT_DEFINE_AND_INSTANTIATE(rule_def,IterInstance) \ | |
BOOST_SPIRIT_DEFINE_(_,_,rule_def) \ | |
BOOST_SPIRIT_INSTANTIATE(rule_def,IterInstance) \ | |
/***/ | |
#endif//TOY_RULE_PARSE_RULE_HPP_INCLUDED |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
The above .cpp file compiles with clang10; however, with g++-7, it doesn't. Instead, it gives error:
toy_rule_parse_rule.hpp:201:12: error: ‘std::decay_t<decltype (ns_toy::ax = operator>>()(toy_x3::char_('a'), ns_toy::x))>::rule_type’ is not a type
bool std::decay_t<decltype(rule_def)>::rule_type
^
However, that may be because -std=c++17 used instead of -std=c++20.