ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

c – Boost.Spirit.Qi:在分析时动态创建“差异”解析器

2019-09-29 09:05:34  阅读:207  来源: 互联网

标签:boost-spirit-qi c boost boost-spirit boost-phoenix


二元 – (减号)运算符可以创建“差异”解析器:

rule = qi::char_ - qi::lit("}}")

甚至复合差异:

rule = qi::char_ - qi::lit("}}") - qi::lit("]]")

但是如何在解析时生成差异解析器的整个结果呢?
我猜这可能是某种形式,如下所示:

phoenix::function<difference_parser_impl> difference_parser;
rule = qi::lazy(difference_parser(qi::char_, {"}}", "]]"}));

这里,{…,…,…}部分实际上是一个stl容器,但它不是重点;我能处理那个部分.

我找到了模板qi :: difference< Left,Right> – 但我找不到如何使用它.

解决方法:

在我看来,你不是在寻找一个动态的“差异”表达,而是一个动态的“变量替代(a | b | c ……)”表达式:

expr – a – b – c相当于expr – (a | b | c)

然后您可以使用以下任一方法轻松实现差异:

expr - orCombine(alternatives)

要么

!orCombine(alternatives) >> expr

现在,完成这项工作有许多粗糙的边缘,我将首先解释.幸运的是,有一种更简单的方法,使用qi :: symbols,我将在之后展示.

棘手的东西

如果你愿意,你可以按需“生成”替代的解析器表达式,并带有一些魔法.我在这个答案中展示了如何做到这一点:

> Generating Spirit parser expressions from a variadic list of alternative parser expressions

>它充满了陷阱(因为原型表达不适合复制)1
>它方便地使用variadics以避免中间存储(注意deepcopy_ to Ward of Undefined Behavior):

template<typename ...Expr>
void parse_one_of(Expr& ...expressions)
{
    auto parser = boost::fusion::fold(
                boost::tie(expressions...),
                qi::eps(false),
                deepcopy_(arg2 | arg1)
            );

看到你如何需要替代解析器的真正动态组合,我不知道如何在不增加复杂性和微妙错误机会的情况下如何适应您的需求(相信我,我已经尝试过).

所以,我建议尝试一下& “滥用”现有“动态”解析器的真正方法:

使用qi :: symbols简化

这个想法从着名的“Nabialek Trick”中丢失了.它使用qi :: symbols,因此具有出色的运行时性能特征2.

没有进一步的麻烦,这是一个如何使用它的例子,从字符串文字的向量开始:

template <typename It, typename Skipper = qi::space_type>
    struct parser : qi::grammar<It, std::string(), Skipper>
{
    parser() : parser::base_type(start)
    {
        static const std::vector<std::string> not_accepted { "}}", "]]" };

        using namespace qi;
        exclude = exclusions(not_accepted);
        start = *(char_ - exclude);

        BOOST_SPIRIT_DEBUG_NODE(start);
    }

  private:
    qi::rule<It, std::string(), Skipper> start;

    typedef qi::symbols<char, qi::unused_type> Exclude;
    Exclude exclude;

    template<typename Elements>
    Exclude exclusions(Elements const& elements) {
        Exclude result;

        for(auto& el : elements)
            result.add(el);

        return result;
    }
};

一个完整的工作样本是here: http://coliru.stacked-crooked.com/view?id=ddbb2549674bfed90e3c8df33b048574-7616891f9fd25da6391c2728423de797并打印

parse success
data: 123
trailing unparsed: ']] 4'

完整代码

备查:

#include <boost/spirit/include/qi.hpp>

namespace qi    = boost::spirit::qi;

template <typename It, typename Skipper = qi::space_type>
    struct parser : qi::grammar<It, std::string(), Skipper>
{
    parser() : parser::base_type(start)
    {
        static const std::vector<std::string> not_accepted { "}}", "]]" };

        using namespace qi;
        exclude = exclusions(not_accepted);
        start = *(char_ - exclude);

        BOOST_SPIRIT_DEBUG_NODE(start);
    }

  private:
    qi::rule<It, std::string(), Skipper> start;

    typedef qi::symbols<char, qi::unused_type> Exclude;
    Exclude exclude;

    template<typename Elements>
    Exclude exclusions(Elements const& elements) {
        Exclude result;

        for(auto& el : elements)
            result.add(el);

        return result;
    }
};

int main()
{
    const std::string input = "1 2 3]] 4";
    typedef std::string::const_iterator It;
    It f(begin(input)), l(end(input));

    parser<It> p;
    std::string data;

    bool ok = qi::phrase_parse(f,l,p,qi::space,data);
    if (ok)   
    {
        std::cout << "parse success\n";
        std::cout << "data: " << data << "\n";
    }
    else std::cerr << "parse failed: '" << std::string(f,l) << "'\n";

    if (f!=l) std::cerr << "trailing unparsed: '" << std::string(f,l) << "'\n";
}

1我相信即将推出的新版本Spirit(目前被称为实验版的“Spirit X3”)即将删除此问题

2它使用Tries查找匹配项

标签:boost-spirit-qi,c,boost,boost-spirit,boost-phoenix
来源: https://codeday.me/bug/20190929/1830899.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有