2

Spirit ::Qi2.4を使用したパーサーの記述に問題があります。次の形式で解析する一連のキーと値のペアがあります<key name>=<value>

キー名[a-zA-Z0-9]の後には、キー名と記号=の間に空白を入れずに記号を付けることができます。キー名の前にも、常に少なくとも1つのスペースがあります。=

=は、 charおよびcodeブロックを含む式を除いて、ほとんどすべてのC式(スペースも可能)にすることができます{ }

キーと値のペアのシーケンスの最後に{記号があります。

この式のパーサーを書くのに苦労しています。キー名の前には常に少なくとも1つのスペースがあり、その後に=スペースがなく、スペースが含まれていないため、次のように定義しました。

  KeyName %= [+char_("a-zA-Z0-9_") >> lit("=")] ;

値はほとんど何でもかまいませんが、文字も含める=こともできない{ため、次のように定義しました。

  Value %=  +(char_ - char_("{=")) ;

値をキャッチするために、このような先読みを使用することを考えました。

ValueExpression 
    %= ( 
      Value  
      >> *space 
      >> &(KeyName | lit("{"))
    )
    ;

しかし、何らかの理由で機能しません(ValueExpression貪欲に看板に上がり=、そこから何をすべきか「わからない」ようです)。私はLLパーサーの知識が限られているので、ここで何が調理されているのかよくわかりません。この種のシーケンスに取り組むことができる他の方法はありますか?

シリーズの例は次のとおりです。

EXP1=FunctionCall(A, B, C) TEST="Example String" \
AnotherArg=__FILENAME__ - 'BlahBlah' EXP2= a+ b+* {

追加情報:これははるかに大きな文法の一部であるため、Spirit.Qiパーサー(「=」で分割してカスタム解析などを行うなど)以外の方法でこの問題を実際に解決することはできません。

編集:

ここで最小限の作業例を作成しました:http://ideone.com/kgYD8
(VS2012でブースト1.50でコンパイルされていますが、古いセットアップでも問題ありません)。

4

1 に答える 1

3

Spirit.Qiを使用したキーと値のペアのリストの解析の記事をご覧になることをお勧めします。

私はあなたのコードを大幅に簡素化しましたが、

  • 属性処理の追加
  • フェニックスのセマンティックアクションの削除
  • ルールのデバッグ

これは、これ以上苦労することなく、次のとおりです。

#define BOOST_SPIRIT_DEBUG

#include <boost/fusion/adapted.hpp>
#include <boost/spirit/include/qi.hpp>
#include <map>

namespace qi = boost::spirit::qi;
namespace fusion = boost::fusion;

typedef std::map<std::string, std::string> data_t;

template <typename It, typename Skipper>
struct grammar : qi::grammar<It, data_t(), Skipper>
{
    grammar() : grammar::base_type(Sequence)
    {
        using namespace qi;

        KeyName  = +char_("a-zA-Z0-9_") >> '=';
        Value    = qi::no_skip [+(~char_("={") - KeyName)];
        Sequence = +(KeyName > Value);

        BOOST_SPIRIT_DEBUG_NODE(KeyName);
        BOOST_SPIRIT_DEBUG_NODE(Value);
        BOOST_SPIRIT_DEBUG_NODE(Sequence);
    }
  private:
    qi::rule<It, data_t(), Skipper>      Sequence;
    qi::rule<It, std::string()>          KeyName; // no skipper, removes need for qi::lexeme
    qi::rule<It, std::string(), Skipper> Value;
};

template <typename Iterator>
data_t parse (Iterator begin, Iterator end)
{
    grammar<Iterator, qi::space_type> p;

    data_t data;

    if (qi::phrase_parse(begin, end, p, qi::space, data)) {
        std::cout << "parse ok\n";
        if (begin!=end) {
            std::cout << "remaining: " << std::string(begin,end) << '\n';
        }
    } else {
        std::cout << "failed: " << std::string(begin,end) << '\n';
    }

    return data;
}

int main ()
{
    std::string test(" ARG=Test still in first ARG ARG2=Zombie cat EXP2=FunctionCall(A, B C) {" );
    auto data = parse(test.begin(), test.end());

    for (auto& e : data)
        std::cout << e.first << "=" << e.second << '\n';
}

出力は次のようになります。

parse ok
remaining: {
ARG=Test still in first ARG 
ARG2=Zombie cat 
EXP2=FunctionCall(A, B C) 

'{'を最後の値の一部にしたい場合は、次の行を変更してください。

Value    = qi::no_skip [+(char_ - KeyName)];
于 2012-07-05T22:06:31.180 に答える