Skip to content

Instantly share code, notes, and snippets.

@cppljevans
Last active September 1, 2020 08:44
Show Gist options
  • Save cppljevans/06bd7b854bc244a0d85095fafdcd37f0 to your computer and use it in GitHub Desktop.
Save cppljevans/06bd7b854bc244a0d85095fafdcd37f0 to your computer and use it in GitHub Desktop.
prototype_simplified_spirit_x3_rule
//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;
}
#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
@cppljevans
Copy link
Author

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment