3

混合変数($(name))と変数と値のペア($(name:value))で構成される単純な文法があります。私は手作業でコーディングされた再帰下降パーサーを持っていますが、それをスピリットを学ぶための演習として使用することに興味があります。これは、最終的にはより複雑な文法に必要になります(/すぐに)。

とにかく、私が使用している可能なフォームのセット(完全な文法から簡略化)は次のとおりです。

$(variable)     // Uses simple look-up, recursion and inline replace
$(name:value)   // Inserts a new variable into the local lookup table

私の現在のルールは次のようになります。

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

template <typename Iterator>
bool parse_vars(Iterator first, Iterator last, dictionary & vars, std::string & output)
{
    using qi::phrase_parse;
    using qi::_1;
    using ascii::char_;
    using ascii::string;
    using ascii::space;
    using phoenix::insert;

    dictionary statevars;

    typedef qi::rule<Iterator, std::string()> string_rule;
    typedef qi::rule<Iterator, std::pair<std::string, std::string>()> pair_rule;

    string_rule state = string >> ':' >> string; // Error 3
    pair_rule variable = 
    (
        char_('$') >> '(' >> 
        (
            state[insert(phoenix::ref(statevars), _1)] |
            string[output += vars[_1]] // Error 1, will eventually need to recurse
        ) >> ')'
    ); // Error 2

    bool result = phrase_parse
    (
        first, last, 
        (
            variable % ','
        ), 
        space
    );

    return r;
}

はっきりしていなければ、Spiritがどのように機能するのかわかりません。ドキュメントには実際の説明以外のすべてが含まれているので、これは例をまとめて約1時間です。

私が特に質問する部分char_('$')変数ルールの先頭ですが、これを削除するとシフト演算子エラーが発生します(コンパイラー'$' >> '('は右シフトとして解釈します)。

コンパイルすると、状態ルール、特にペアの作成、およびルックアップに関連するエラーが発生します。

  1. エラーC2679:バイナリ'[':タイプ'const boost :: spirit :: _ 1_type'の右側のオペランドをとる演算子が見つかりません(または受け入れ可能な変換がありません)
  2. エラーC2512:'boost :: spirit :: qi :: rule :: rule':適切なデフォルトコンストラクターが利用できません

ルックアップ(vars[_1])を単純に変更すると、次のようになり+=ます。

3。エラーC2665:'boost :: spirit :: char_class :: classify :: is':15個のオーバーロードのいずれもすべての引数タイプを変換できませんでした

_1エラー1は、プレースホルダーのタイプ(属性?)に関連しているようですが、これは文字列である必要があり、出力文字列への印刷または連結に使用されます。2は1によって引き起こされたノイズのようです。

テンプレートエラーのスタックを掘り下げるエラー3は、状態ルールをペアに変換できないことに関連しているようです。これは、この例のルールの1つとほぼ完全に一致するため、奇妙に思えます。

両方の入力フォームを適切に処理するように変数ルールを変更するにはどうすればよいですか?

4

2 に答える 2

2

注意すべきいくつかのこと:

  1. 適応するstd::pairには(マップで使用できるように)、(少なくとも)含める必要があります

    #include <boost/fusion/adapted/std_pair.hpp>
    
  2. シンボルテーブルを作成しようとしているようです。あなたはそのために使うことができqi::symbolsます

  3. 出力生成と構文解析を混在させないでください。問題が過度に複雑になります。

上記のすべてを「修正」したわけではありませんが(コンテキストが不足しているため)、それらから生じる他の質問については喜んでお手伝いします。

これは、OPにかなり近いままの修正コードバージョンです。編集は今もそれをテストしました、以下の出力:

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

namespace qi    = boost::spirit::qi;
namespace phx   = boost::phoenix;

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

template <typename Iterator, typename Skipper = qi::space_type>
    struct parser : qi::grammar<Iterator, Skipper>
{
    parser(dictionary& statevars, std::string& output) : parser::base_type(start)
    {
        using namespace qi;
        using phx::insert; 

        with_initializer = +~char_(":)") >> ':' >> *~char_(")");

        simple           = +~char_(")");

        variable         = 
            "$(" >> (
                   with_initializer  [ insert(phx::ref(statevars), qi::_1) ] 
                 | simple            [ phx::ref(output) += phx::ref(statevars)[_1] ]
             ) >> ')';

        start = variable % ',';

        BOOST_SPIRIT_DEBUG_NODE(start);
        BOOST_SPIRIT_DEBUG_NODE(variable);
        BOOST_SPIRIT_DEBUG_NODE(simple);
        BOOST_SPIRIT_DEBUG_NODE(with_initializer);
    }

  private:
    qi::rule<Iterator, std::pair<std::string, std::string>(), Skipper> with_initializer;
    qi::rule<Iterator, std::string(), Skipper> simple;
    qi::rule<Iterator, Skipper> variable;
    qi::rule<Iterator, Skipper> start;
};

template <typename Iterator>
bool parse_vars(Iterator &first, Iterator last, dictionary & vars, std::string & output)
{
    parser<Iterator> p(vars, output);
    return qi::phrase_parse(first, last, p, qi::space);
}

int main()
{
    const std::string input = "$(name:default),$(var),$(name)";
    std::string::const_iterator f(input.begin());
    std::string::const_iterator l(input.end());

    std::string output;
    dictionary table;

    if (!parse_vars(f,l,table,output))
        std::cerr << "oops\n";
    if (f!=l)
        std::cerr << "Unparsed: '" << std::string(f,l) << "'\n";
    std::cout << "Output:   '" << output << "'\n";
}

出力:

Output:   'default'
于 2012-02-05T13:26:18.450 に答える
-2

char_('$')が必要です。そうでない場合、>>は両側で' char'になります。オーバーロードされた演算子>>を取得するには、少なくとも1つのスピリットタイプが必要です。

また、フェニックスの_1を使用する必要がある場合もあります。

http://boost-spirit.com/home/articles/qi-example/parsing-a-list-of-key-value-pairs-using-spirit-qi/もご覧ください。

于 2012-02-04T11:36:32.960 に答える