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

Posted

技术标签:

【中文标题】将文件路径字符串传递给 Boost.Spirit 中的语义操作【英文标题】:Passing file-path string to semantic action in Boost.Spirit 【发布时间】:2011-03-02 12:39:56 【问题描述】:

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

【问题讨论】:

【参考方案1】:

您的解析器几乎一切正常。问题是 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 解析器首先无法识别引号。

【讨论】:

以上是关于将文件路径字符串传递给 Boost.Spirit 中的语义操作的主要内容,如果未能解决你的问题,请参考以下文章

为啥 nvcc 无法使用 boost::spirit 编译 CUDA 文件?

使用 boost::spirit 解析任意精度整数

Boost.Spirit 的单元测试

boost::spirit 解析器的编译错误

Boost Spirit解析字符串以前缀开头

Boost Spirit 语法检测登录失败