在运行时合并规则并返回规则 [英] Combining rules at runtime and returning rules

查看:49
本文介绍了在运行时合并规则并返回规则的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试编写一些在Spirit-X3之上构建的复杂解析器,所以我需要了解一些事情:

I am trying to write some complex parser made on top of Spirit-X3, so I need to know some things:

♦如何在运行时合并规则. (有纳比亚力克的把戏)

♦ How to combine rules at runtime. (with Nabialek's trick)

♦返回这样的规则是否可以:

♦ Is it ok to return rules like this:

x3::rule<char> SomeFunction(std::string &str)
{
    x3::rule<char> foo;
    auto bar = baz;
    BOOST_SPIRIT_DEFINE(foo, bar);
    return foo;
}

PS:SomeFunction不会有固定的收益,所以我不能只使用x3 :: sequence

PS: SomeFunction won't have a fixed return, so I can't use just a x3::sequence

推荐答案

是的,x3使编写规则变得容易得多.

Yes, x3 makes it a lot easier to compose rules.

主要是因为解析器表达式在分配给变量时不倾向于保留对临时变量的引用,就像它们在Qi¹时代一样.

Mainly because parser expressions don't have the tendency to keep references to temporaries when assigned to variables, like they used to in the age of Qi¹.

局限性:在X3中声明具有外部链接的解析器要复杂得多...复杂,需要与您显示的BOOST_SPIRIT_{DECLARE,DEFINE}宏一起跳舞.

Limitation: declaring parsers with external linkage is a lot more ... complicated in X3, requiring the dance with the macros that you show BOOST_SPIRIT_{DECLARE,DEFINE}.

那将不会成功,因为该宏应在命名空间范围内使用.好消息是您可能不需要它,因为除非您要递归地处理规则,否则无需将规则与定义分开声明.

That won't fly because the macro is meant to be used at namespace scope. The good news is you may not need it, because there is no need to declare the rule separately from the definition unless you are dealing with recursively required rules.

顺便说一句,x3::rule<char>可能是一个错误. char是该声明中的标记类型,但这不是一个好的标记类型.如果您想使用 attribute 类型,则该类型必须是第二个模板参数.

As an aside x3::rule<char> is likely a mistake. char is a tag type in that declaration, and that's not a good tag type. If you wanted an attribute type instead, that needs to be the second template argument.

auto SomeFunction(std::string &str)
{
    return x3::rule<struct _tag, std::string> {"dynamic"}
        = '[' >> x3::lit(str) >> ']';
}

事实上,我经常在报关处制造小工厂:

In fact I very frequently make little factories at my declaration site:

template <typename Attr>
auto compose = [](auto p1, auto p2) {
     return rule<struct _, Attr> {"compose"}
         = nocase [ 
               lexeme [ "property:" << as_parser(p1) ]
               >> '='
               lexeme [ "value:" << as_parser(p2) ]
           ];                  
};

这有点做作,但是应该给您一些想法.像compose<int>("number", x3::int_)compose<std::string>("name", +x3::graph)

That's a bit contrived but should give you ideas. Use it like compose<int>("number", x3::int_) or compose<std::string>("name", +x3::graph)

namespace {
    template <typename T>
    struct as_type {
        template <typename Expr>
            auto operator[](Expr&& expr) const {
                return x3::rule<struct _, T>{"as"} = x3::as_parser(std::forward<Expr>(expr));
            }
    };

    template <typename T> static const as_type<T> as = {};
}

  • 避免在期望解析器中引发Expectation_failure失败,它会动态组成符号查找:

  • Avoid throwing expectation_failure when expectation parser fails which dynamically composes a symbols lookup:

    x3::symbols<char> const keyword = []{
        x3::symbols<char> kw;
        kw += "for","begin","end","function","while","break","switch";
        return kw;
    }();
    

  • 在x3中动态切换符号表这是一个具有很多解析器工厂的非常完整示例:

  • Dynamically switching symbol tables in x3 which is a very complete example with many parser factories:

    // (case insensitive) keyword handling
    static auto kw        = [](auto p) { return x3::lexeme[p >> !(x3::graph - x3::char_("/=,()"))]; };
    static auto ikw       = [](auto p) { return x3::no_case [kw(p)]; };
    static auto qualifier = [](auto p) { return x3::lexeme['/' >> ikw(p)]; };
    

    甚至显示了如何为您自己的类型覆盖as_spirit_parser:

    And even shows how to override as_spirit_parser for your own types:

    // Options and CiOptions
    namespace util {
        template <typename Tag>
        auto as_spirit_parser(Options<Tag> const& o, bool to_lower = false) {
            x3::symbols<typename Options<Tag>::type> p;
            int n = 0;
            for (std::string el : o._options) {
                if (to_lower) boost::to_lower(el);
                p.add(el, n++);
            }
            return kw(p);
        }
    
        template <typename Tag>
        auto as_spirit_parser(IcOptions<Tag> const& o) {
            return x3::no_case [ as_spirit_parser(o, true) ];
        }
    }
    

    使用自动生成的语义动作来编写成员级传播助手的一种非常优雅的方法:

    And pretty elegant way to write member-wise propagation helpers with auto-generated semantic actions:

        auto set = [](auto member, auto p) {
            auto propagate = [member](auto& ctx) {
                traits::move_to(_attr(ctx), _val(ctx).*(member));
            };
            return as_parser(p)[propagate];
        };
    
        using T = ast::ShowSymbolsCommand;;
        return qualifier("all")  >> set(&T::all, attr(true))
             | qualifier("full") >> set(&T::full, attr(true))
             | qualifier("out")  >> set(&T::out, '=' >> Filespec)
             | qualifier("type") >> set(&T::types, '=' >> SymbolTypes)
             | set(&T::wildcard, Wildcard);
    

  • 我强烈建议您仔细阅读这些示例,以了解X3合成的强大功能.仅当您/确实/需要时,我才考虑在X3中重新创建类似qi::lazy的内容

    I strongly suggest you per-use these examples to get a sense of just how powerful X3 composing is. Only when you /really/ require it would I consider recreating something like qi::lazy in X3

    ¹或实际上任何基于Proto的东西,例如Phoenix

    ¹ or in fact anything Proto-based, like Phoenix too

    这篇关于在运行时合并规则并返回规则的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆