2

(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 パーサーを作成する方法ですか? スピリット Qi のローカルと継承された属性を使用すると、解決策ははるかに簡単に見えます。ありがとう。

4

1 に答える 1