其他分享
首页 > 其他分享> > c-在运行时合并规则并返回规则

c-在运行时合并规则并返回规则

作者:互联网

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

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

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

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

解决方法:

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

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

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

您的样品

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

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

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

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

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)一样使用它

一些鼓舞人心的例子

> Understanding the List Operator (%) in Boost.Spirit,显示即席as []工具:

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 = {};
}

> Avoid throwing expectation_failure when expectation parser fails动态组成符号查找:

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

> Dynamically switching symbol tables in x3是许多解析器工厂的非常完整的示例:

// (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:

// 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) ];
    }
}

用自动生成的语义动作编写成员式传播帮助程序的一种非常优雅的方法:

    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合成的强大功能.只有在您/ really /要求时,我才考虑在X3中重新创建qi :: lazy之类的东西

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

标签:boost-spirit-x3,c,c14,boost-spirit
来源: https://codeday.me/bug/20191011/1894931.html