【问题标题】:Recursive x3 parser with results passing around递归 x3 解析器,结果传递
【发布时间】:2017-05-23 09:55:14
【问题描述】:

(1) 假设我们要解析一个由{} 包围的简单递归块。

{
    Some text.
    {
        {
            Some more text.
        }
        Some Text again.
        {}
    }
}

这个递归解析器非常简单。

x3::rule<struct idBlock1> const ruleBlock1{"Block1"};
auto const ruleBlock1_def =
    x3::lit('{') >>
    *(
        ruleBlock1 |
        (x3::char_ - x3::lit('}'))
    ) >>
    x3::lit('}');

BOOST_SPIRIT_DEFINE(ruleBlock1)

(2) 然后块变得更加复杂。它也可以被[]包围。

{
    Some text.
    [
        {
            Some more text.
        }
        Some Text again.
        []
    ]
}

我们需要在某个地方存储我们有什么样的左括号。由于 x3 没有局部变量,我们可以使用属性 (x3::_val) 来代替。

x3::rule<struct idBlock2, char> const ruleBlock2{"Block2"};
auto const ruleBlock2_def = x3::rule<struct _, char>{} =
    (
        x3::lit('{')[([](auto& ctx){x3::_val(ctx)='}';})] |
        x3::lit('[')[([](auto& ctx){x3::_val(ctx)=']';})]
    ) >>
    *(
        ruleBlock2 |
        (
            x3::char_ - 
            (
                x3::eps[([](auto& ctx){x3::_pass(ctx)='}'==x3::_val(ctx);})] >> x3::lit('}') |
                x3::eps[([](auto& ctx){x3::_pass(ctx)=']'==x3::_val(ctx);})] >> x3::lit(']')
            )
        )
    ) >>
    (
        x3::eps[([](auto& ctx){x3::_pass(ctx)='}'==x3::_val(ctx);})] >> x3::lit('}') |
        x3::eps[([](auto& ctx){x3::_pass(ctx)=']'==x3::_val(ctx);})] >> x3::lit(']')
    );

BOOST_SPIRIT_DEFINE(ruleBlock2)

(3) 块内容(被包围的部分),我们称之为参数,可能比这个例子复杂得多。所以我们决定为它创建一个规则。在这种情况下,此属性解决方案不起作用。幸运的是,我们还有 x3::with 指令。我们可以将左括号(或期望的右括号)保存在堆栈引用中,并将其传递到下一级。

struct SBlockEndTag {};
x3::rule<struct idBlockEnd> const ruleBlockEnd{"BlockEnd"};
x3::rule<struct idArg> const ruleArg{"Arg"};
x3::rule<struct idBlock3> const ruleBlock3{"Block3"};
auto const ruleBlockEnd_def =
    x3::eps[([](auto& ctx){
        assert(!x3::get<SBlockEndTag>(ctx).get().empty());
        x3::_pass(ctx)='}'==x3::get<SBlockEndTag>(ctx).get().top();
    })] >> 
    x3::lit('}') 
    |
    x3::eps[([](auto& ctx){
        assert(!x3::get<SBlockEndTag>(ctx).get().empty());
        x3::_pass(ctx)=']'==x3::get<SBlockEndTag>(ctx).get().top();
    })] >>
    x3::lit(']');
auto const ruleArg_def =
    *(
        ruleBlock3 |
        (x3::char_ - ruleBlockEnd)
    );
auto const ruleBlock3_def =
    (
        x3::lit('{')[([](auto& ctx){x3::get<SBlockEndTag>(ctx).get().push('}');})] |
        x3::lit('[')[([](auto& ctx){x3::get<SBlockEndTag>(ctx).get().push(']');})]
    ) >>
    ruleArg >>
    ruleBlockEnd[([](auto& ctx){
        assert(!x3::get<SBlockEndTag>(ctx).get().empty());
        x3::get<SBlockEndTag>(ctx).get().pop();
    })];

BOOST_SPIRIT_DEFINE(ruleBlockEnd, ruleArg, ruleBlock3)

代码位于Coliru

问题:这就是我们为这类问题编写递归 x3 解析器的方式吗?有了灵气的本地属性和继承属性,解决起来似乎就简单多了。谢谢。

【问题讨论】:

    标签: c++ recursion boost boost-spirit boost-spirit-x3


    【解决方案1】:

    您可以使用x3::with&lt;&gt;

    但是,我只想写这个:

    auto const block_def =
        '{' >> *( block  | (char_ - '}')) >> '}'
      | '[' >> *( block  | (char_ - ']')) >> ']';
    

    演示

    Live On Coliru

    #include <boost/spirit/home/x3.hpp>
    #include <iostream>
    
    namespace Parser {
        using namespace boost::spirit::x3;
    
        rule<struct idBlock1> const block {"Block"};
        auto const block_def =
            '{' >> *( block  | (char_ - '}')) >> '}'
          | '[' >> *( block  | (char_ - ']')) >> ']';
    
        BOOST_SPIRIT_DEFINE(block)
    }
    
    int main() {
        std::string const input = R"({
        Some text.
        [
            {
                Some more text.
            }
            Some Text again.
            []
        ]
    })";
    
        std::cout << "Parsed: " << std::boolalpha << parse(input.begin(), input.end(), Parser::block) << "\n";
    }
    

    打印:

    Parsed: true
    

    但是 - 代码重复!

    如果你坚持概括:

    auto dyna_block = [](auto open, auto close) {
        return open >> *(block | (char_ - close)) >> close;
    };
    
    auto const block_def =
        dyna_block('{', '}')
      | dyna_block('[', ']');
    

    【讨论】:

    • 增加了对反密码复制旅的抢先响应:)
    猜你喜欢
    • 1970-01-01
    • 2017-02-18
    • 1970-01-01
    • 2012-08-11
    • 2014-04-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-05
    相关资源
    最近更新 更多