Skip to content

Instantly share code, notes, and snippets.

@cppljevans
Created March 6, 2020 12:19

Revisions

  1. cppljevans created this gist Mar 6, 2020.
    133 changes: 133 additions & 0 deletions sehe-coliru-stackoverflow-answer.cpp
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,133 @@
    //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";
    }
    }