Re: X3: Using dynamic Repetition Parser Directives

Seth <[email protected]>
Newsgroups gmane.comp.parsers.spirit.general
Message-ID <[email protected]>
On 31-01-16 20:33, Mike Gresens wrote:
> Was just the original code from
>
> https://stackoverflow.com/questions/33624149/boost-spirit-x3-cannot-compile-repeat-directive-with-variable-factor/33627991#33627991
>
> replacing std::vector<int> by std::string and x3::int_ by x3::char_
>
> Would like to provide you buildable code, but currently this code seems to
> be completely broken:
>
> #include <boost/spirit/home/x3.hpp>
> #include <boost/spirit/home/x3/binary.hpp>
> #include <string>
> #include <memory>
> #include <iostream>
>
> namespace x3 = boost::spirit::x3;
>
> namespace hessian {
>
> typedef std::string string_t;
>
> namespace parser {
> namespace detail {
>
> //string ::= s b1 b0 <utf8-data> string
> //       ::= S b1 b0 <utf8-data>
> //       ::= [x00-x1f] <utf8-data>
>
> // NOTE: The length means number of UTF16 characters but the content is
> given in UTF8 characters!
>
> struct length_tag;
> const auto length_action = [](auto& ctx)
> {
> 	*x3::get<length_tag>(ctx) = x3::_attr(ctx);
> };
> const auto more_action = [](auto &ctx)
> {
> 	x3::_pass(ctx) = *x3::get<length_tag>(ctx) >  x3::_val(ctx).size();
> };
> const auto done_action = [](auto &ctx)
> {
> 	x3::_pass(ctx) = *x3::get<length_tag>(ctx) == x3::_val(ctx).size();
> };
> const auto push_action = [](auto &ctx)
> {
> 	x3::_val(ctx).push_back(x3::_attr(ctx));
> };
>
> const x3::rule<class string_rule, string_t> string_rule("string");
> const x3::rule<class string1_rule, string_t> string1_rule;
> const x3::rule<class string2_rule, string_t> string2_rule;
>
> const auto length_rule = x3::omit[x3::big_word [length_action] ];
> const auto content_rule = x3::lexeme[ *(x3::eps [more_action] >> x3::char_
> [push_action]) >> x3::eps [done_action] ];
>
> const auto string_rule_def =
> x3::with<length_tag>(std::make_shared<std::size_t>())[string1_rule |
> string2_rule];
> const auto string1_rule_def = x3::lit('S') >> length_rule >> content_rule;
> const auto string2_rule_def = x3::lit('s') >> length_rule >> content_rule >>
> string_rule;
>
> BOOST_SPIRIT_DEFINE(string_rule, string1_rule, string2_rule);
>
> }
>
> using detail::string_rule;
>
> }
> }
>
> void test_string()
> {
> 	const std::string text("s\x00\x07hello, S\x00\x05world"s);
> 	try
> 	{
> 	hessian::string_t attr;
> 	std::cout << x3::parse(text.begin(), text.end(), x3::eps >
> hessian::parser::string_rule, attr) << std::endl;
> 	std::cout << attr << std::endl;
> 	}
> 	catch (const x3::expectation_failure<std::string::const_iterator>&
> exception)
> 	{
> 		std::cout << exception.what() << " " << exception.which() << " " <<
> std::string(exception.where(), text.end()) << std::endl;
> 	}
> }
>
> Error is always: fatal error: template instantiation depth exceeds maximum
> of 2048
>
Here's my take on things:

With debug: http://coliru.stacked-crooked.com/a/40b87b1c08e92806
Without debug: http://coliru.stacked-crooked.com/a/420ba52e76dfeeff

That said, I think you're far better off writing a custom parser here.

    #include <iostream>
    #include <boost/spirit/home/x3.hpp>
    #include <boost/spirit/home/x3/binary.hpp>
    #include <string>
    #include <memory>

    namespace x3 = boost::spirit::x3;

    namespace hessian {

    typedef std::string string_t;

    namespace parser {
    namespace detail {

        // string ::= s b1 b0 <utf8-data> string
        //       ::= S b1 b0 <utf8-data>
        //       ::= [x00-x1f] <utf8-data>

        // NOTE: The length means number of UTF16 characters but the
    content is given in UTF8 characters!

        struct length_tag;
        struct state { size_t expected, actual; };

        const auto length_action = [](auto &ctx) {
            state& s = x3::get<length_tag>(ctx);
            s = { x3::_attr(ctx), 0 };
        };
        const auto more_action = [](auto &ctx) {
            state& s = x3::get<length_tag>(ctx);
            x3::_pass(ctx) = (s.expected >  s.actual);
        };
        const auto done_action = [](auto &ctx) {
            state& s = x3::get<length_tag>(ctx);
            x3::_pass(ctx) = (s.expected == s.actual);
        };
        const auto push_action = [](auto &ctx) { // FIXME handle UTF8
            state& s = x3::get<length_tag>(ctx);
            x3::_val(ctx).push_back(x3::_attr(ctx));
            s.actual += 1;
        };

        const auto length  = x3::omit[x3::big_word[length_action]];
        const auto content = x3::lexeme[*(x3::eps[more_action] >>
    x3::char_[push_action]) >> x3::eps[done_action]];

        template <typename T> struct mutable_wrapper {
            T mutable value;
            operator T&() const { return value; }
        };

        const auto string_s = 's' >> length >> content;
        const auto string_S = 'S' >> x3::eps >> length >> content;
        const auto string
            = x3::rule<struct string_class, std::string> { "string" }
            = x3::with<length_tag>(mutable_wrapper<state>{})[*string_s
    >> string_S];
    }

    auto const& rule = detail::string;
    }
    }

    #include <iomanip>

    std::string as_hex(std::string const& what) {
        std::ostringstream oss;
        oss << std::hex << std::setfill('0');
        for (uint8_t ch : what) {
            if (std::isprint(ch)) oss << ch;
            else                  oss << "\\x" << std::setw(2) << int{ch};
        }

        return oss.str();
    }

    void test_string() {
        const std::string text("s\x00\x07hello, S\x00\x05world", 18);
        try {
            hessian::string_t attr;
            auto f = text.begin(), l = text.end();
            bool ok = x3::parse(f, l, x3::eps > hessian::parser::rule,
    attr);

            if (ok)
                std::cout << "Parsed: '" << as_hex(attr) << "'\n";
            else
                std::cout << "Failed\n";

            if(f!=l)
                std::cout << "Remaining: '" << as_hex({f,l}) << "'\n";

        } catch (const
    x3::expectation_failure<std::string::const_iterator> &exception) {
            std::cout << exception.what() << " " << exception.which() <<
    " " << std::string(exception.where(), text.end())
                      << std::endl;
        }
    }

    int main()
    {
        test_string();
    }

------------------------------------------------------------------------------
Site24x7 APM Insight: Get Deep Visibility into Application Performance
APM + Mobile APM + RUM: Monitor 3 App instances at just $35/Month
Monitor end-to-end web transactions and take corrective actions now
Troubleshoot faster and improve end-user experience. Signup Now!
http://pubads.g.doubleclick.net/gampad/clk?id=267308311&iu=/4140

_______________________________________________
Spirit-general mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/spirit-general
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.