将文件路径字符串传递给 Boost.Spirit 中的语义操作

发布于 2024-10-20 11:31:46 字数 2893 浏览 9 评论 0原文

我是 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

I am new to Boost.Spirit, and I have a question related to a mini-interpreter I am trying to implement using the library. As a sub-task of parsing my language, I need to extract a file-path from an input of the form:

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

and pass it as a string (without quotes) to a semantic action.

I wrote some code which can parse this type of input, but passing the parsed string does not work as expected, probably due to my lack of experience with Boost.Spirit.

Can anyone help?

In reality, my grammar is more complex, but I have isolated the problem to:

#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;
}

The output is:

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

but I would like to obtain:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

一抹微笑 2024-10-27 11:31:46

您的解析器几乎一切都很好。问题是 Spirit(直至 Boost V1.46)中的一个错误导致在这种情况下无法正确处理属性。这个问题最近已在 SVN 中得到修复,并将在 Boost V1.47 中提供(我尝试使用此版本运行未更改的程序,一切正常)。

目前,您可以使用 raw[] 指令来解决此问题(见下文)。

我在上面说“几乎”,因为你可以 a) 简化你所拥有的,b) 你应该使用 no_skip[] 来避免在 qutoes 之间调用跳过解析器。

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 解析器首先无法识别引号。

Almost everything is fine with your parser. The problem is a bug in Spirit (upto Boost V1.46) preventing the correct handling of the attribute in cases like this. This has been recently fixed in SVN and will be available in Boost V1.47 (I tried running your unchanged program with this version and everything works just fine).

For now, you can work around this problem by utilizing the raw[] directive (see below).

I said 'almost' above, because you can a) simplify what you have, b) you should use no_skip[] to avoid invoking the skip parser in between the qutoes.

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];

You can omit the - lit('"') part because your path parser does not recognize quotes in the first place.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文