1

Boost.Spiritは初めてですが、ライブラリを使用して実装しようとしているミニインタープリターに関する質問があります。言語を解析するサブタスクとして、フォームの入力からファイルパスを抽出する必要があります。

"path = \"/path/to/file\""

そして、それを文字列(引用符なし)としてセマンティックアクションに渡します。

このタイプの入力を解析できるコードをいくつか作成しましたが、おそらくBoost.Spiritの経験が不足しているため、解析された文字列を渡すと期待どおりに機能しません。

誰か助けてもらえますか?

実際には、私の文法はもっと複雑ですが、問題を次のように切り分けました。

#include <string>
#include "boost/spirit/include/qi.hpp"
#include "boost/spirit/include/phoenix_core.hpp"
#include "boost/spirit/include/phoenix_operator.hpp"
namespace qi      = boost::spirit::qi;
namespace ascii   = boost::spirit::ascii;
namespace phoenix = boost::phoenix;

namespace parser {
    // Semantic action (note: in reality, this would use file_path_string in non-trivial way)
    void display_path(std::string file_path_string) {
        std::cout << "Detected file-path: " << file_path_string << std::endl;
    }

    // Grammar
    template <typename Iterator>
        struct path_command : qi::grammar<Iterator, ascii::space_type> {
            path_command() : path_command::base_type(path_specifier) {
                using qi::string;
                using qi::lit;

                path = +(qi::char_("/") >> *qi::char_("a-zA-Z_0-9"));
                quoted_path_string = lit('"') >> (path- lit('"')) >> lit('"');
                path_specifier = lit("path") >> qi::lit("=")
                                 >> quoted_path_string[&display_path];
            }

            qi::rule<Iterator, ascii::space_type> path_specifier;
            qi::rule<Iterator, std::string()> path, quoted_path_string;
        };
}

int main() {
    using ascii::space;
    typedef std::string::const_iterator iterator_type;
    typedef parser::path_command<iterator_type> path_command;

    bool parse_res;
    path_command command_instance;   // Instance of our Grammar
    iterator_type iter, end;

    std::string test_command1 = "path = \"/file1\"";
    std::string test_command2 = "path = \"/dirname1/dirname2/file2\"";

    // Testing example command 1
    iter      = test_command1.begin();
    end       = test_command1.end();
    parse_res = phrase_parse(iter, end, command_instance, space);
    std::cout << "Parse result for test 1: " << parse_res << std::endl;

    // Testing example command 2
    iter      = test_command2.begin();
    end       = test_command2.end();
    parse_res = phrase_parse(iter, end, command_instance, space);
    std::cout << "Parse result for test 2: " << parse_res << std::endl;

    return EXIT_SUCCESS;
}

出力は次のとおりです。

Detected file-path: /
Parse result for test 1: 1
Detected file-path: ///
Parse result for test 2: 1

しかし、私は取得したいと思います:

Detected file-path: /file1
Parse result for test 1: 1
Detected file-path: /dirname1/dirname2/file2
Parse result for test 2: 1
4

1 に答える 1

1

ほとんどすべてがパーサーで問題ありません。問題は、Spirit(Boost V1.46まで)のバグであり、このような場合に属性を正しく処理できません。これは最近SVNで修正され、Boost V1.47で利用できるようになります(このバージョンで変更されていないプログラムを実行してみましたが、すべて正常に動作します)。

今のところ、raw []ディレクティブを利用することでこの問題を回避できます(以下を参照)。

上記の「ほぼ」と言ったのは、a)持っているものを単純化できるため、b)qutoesの間にスキップパーサーが呼び出されないようにno_skip[]を使用する必要があるためです。

path = raw[+(qi::char_("/") >> *qi::char_("a-zA-Z_0-9"))];
quoted_path_string = no_skip['"' >> path >> '"'];
path_specifier = lit("path") >> qi::lit("=")
    >> quoted_path_string[&display_path];

パーサーはそもそも引用符を認識しない- lit('"')ため、この部分は省略できます。path

于 2011-03-02T13:34:07.327 に答える