Skip to content

Instantly share code, notes, and snippets.

@cppljevans
Created March 6, 2020 12:19
Show Gist options
  • Save cppljevans/86770e37767b38f3aa0cceaea06f4407 to your computer and use it in GitHub Desktop.
Save cppljevans/86770e37767b38f3aa0cceaea06f4407 to your computer and use it in GitHub Desktop.
skipper in recursive context leads to infinite template instantiation
//OriginalCode:
// http://coliru.stacked-crooked.com/a/d149f05af81bf0cf
//WhichWasAnswerTo:
// https://stackoverflow.com/questions/45899090/recursive-rule-in-spirit-x3/45900983
//DownloadedOn:
// 2020-03-06.0512CST
//Modifications:
// WHAT:
// * added macro, USE_TOP_LEVEL_SKIPPER
// * depending on defined(USE_TOP_LEVEL_SKIPPER)
// used skipper top level or at lower level
// WHY:
// to see if https://github.com/boostorg/spirit/pull/237 solves problem
// mentioned in the stackoverflow question.
//Conclusion:
// #if defined(USE_TOP_LEVEL_SKIPPER)
// runs OK
// #else
// fails at compile time with:
/*
/usr/include/boost/spirit/home/x3/support/traits/attribute_of.hpp:35:51: fatal error: recursive template instantiation exceeded
maximum depth of 200
typename Component::attribute_type>::type>
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
*/
//=============
//#define USE_TOP_LEVEL_SKIPPER
//#define BOOST_SPIRIT_X3_DEBUG
#include <iostream>
#include <boost/fusion/adapted.hpp>
#include <boost/spirit/home/x3.hpp>
#include <string>
#include <vector>
#include <variant>
struct value: std::variant<int,float,std::vector<value>>
{
using base_type = std::variant<int,float,std::vector<value>>;
using base_type::variant;
friend std::ostream& operator<<(std::ostream& os, base_type const& v) {
struct {
std::ostream& operator()(float const& f) const { return _os << "float:" << f; }
std::ostream& operator()(int const& i) const { return _os << "int:" << i; }
std::ostream& operator()(std::vector<value> const& v) const {
_os << "tuple: [";
for (auto& el : v) _os << el << ",";
return _os << ']';
}
std::ostream& _os;
} vis { os };
return std::visit(vis, v);
}
};
namespace parser {
namespace x3 = boost::spirit::x3;
x3::rule<struct value_class, value> const value_ = "value";
x3::rule<struct o_tuple_class, std::vector<value> > o_tuple_ = "tuple";
x3::real_parser<float, x3::strict_real_policies<float> > float_;
const auto o_tuple__def
= "tuple" >> x3::lit(':') >>
#ifndef USE_TOP_LEVEL_SKIPPER
x3::skip(x3::space) [
#endif
("[" >> value_ % "," >> "]")
#ifndef USE_TOP_LEVEL_SKIPPER
]
#endif
;
const auto value__def
= "float" >> (':' >> float_)
| "int" >> (':' >> x3::int_)
| o_tuple_
;
BOOST_SPIRIT_DEFINE(value_, o_tuple_)
const auto entry_point =
#ifdef USE_TOP_LEVEL_SKIPPER
x3::skip(x3::space) [ value_ ]
#else
value_
#endif
;
}
int main()
{
for (std::string const str : {
"",
"float: 3.14",
"int: 3.14",
"tuple: [float: 3.14,int: 3]",
// the following _should_ have compiled with the original skip() configuration:
"tuple: [ float: 3.14,\tint: 3 ]",
// the following would not have parsed with the original skip() configuration:
"float:3.14",
"int:3.14",
"tuple:[float: 3.14,int: 3]",
"tuple:[float:3.14,int:3]",
"tuple: [ float:3.14,\tint:3 ]",
// one final show case for good measure
R"(
tuple: [
int : 4,
float: 7e9,
tuple: [float: -inf],
int: 42
])"
}) {
std::cout << "============ '" << str << "'\n";
//using boost::spirit::x3::parse;
auto first = str.begin(), last = str.end();
value val;
if (parse(first, last, parser::entry_point, val))
std::cout << "Parsed '" << val << "'\n";
else
std::cout << "Parse failed\n";
if (first != last)
std::cout << "Remaining input: '" << std::string(first, last) << "'\n";
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment