Boost::Spirit 在尝试解析带引号的字符串文字时编译失败

Boost::Spirit fails to compile when trying to parse quoted string literal

本文关键字:字符串 文字 失败 编译 Spirit Boost      更新时间:2023-10-16

我正在尝试使用 Boost::Spirit 解析带有转义序列的带引号的字符串。不幸的是,似乎在语法定义中包含引号会导致大量(-ly 无用)编译时错误(正如人们对 Boost 所期望的那样)。省略引号可以让程序编译,但显然它不会按预期运行。这是代码(实际上是更大图景的一部分,但它演示了问题):

#include "boost/spirit/include/qi.hpp"
#include "boost/proto/deep_copy.hpp"
#include "boost/optional.hpp"
#include <string>
using boost::spirit::qi::char_;
using boost::spirit::qi::lexeme;
using boost::proto::deep_copy;

auto string_literal = deep_copy(
    lexeme[
            // char_('"')
            /* >> */ *((char_ - '"' - '') | (char_('') >> char_))
            // >> char_('"')
          ]);

template <class Iterator, class Grammar>
boost::optional<std::string> parse_string(Iterator first, Iterator last, Grammar&& gr)
{
    using boost::spirit::qi::space;
    using boost::spirit::qi::phrase_parse;
    std::string temp;
    bool success = phrase_parse(
        first,
        last,
        gr,
        space,
        temp
    );
    if (first == last && success)
        return temp;
    else return boost::none;
}

int main()
{
    std::string str;
    std::cout << "string_literal: ";
    getline(std::cin, str);
    auto presult = parse_string(str.begin(), str.end(), string_literal);
    if (presult) {
        std::cout << "parsed: " << *presult;
    } else
        std::cout << "failuren";
    return 0;
}

取消注释string_literal定义的注释部分会导致错误。在当前状态(带注释)下,代码将编译。我已经尝试了几件事,例如将引号移动到parse_string中,以及使用不太具体的定义(上面的定义是我能想到的最不具体的,仍然有用,正确的语法在 OCaml 语言手册中,但我想我可以单独验证转义序列),但没有任何效果。

我的 Boost 版本是 1.56.0,我的编译器是 MinGW-w64 g++ 4.9.1。任何帮助都非常感谢。

我花了一点时间才看到它。

问题在于 - 最终 - 事实上[1]

(qi::char_('') >> qi::char_) | (qi::char_ - '"')

合成为

boost::variant<
    boost::fusion::vector2<char, char>,
    char>

而不是,正如您可能期望的那样charstd::vector<char>.Spirit的属性兼容性规则近乎魔法,它们让你侥幸逃脱(这真是太漂亮了),但它也隐藏了你的意识问题。

只有当你进一步使规则复杂化时,才会抱怨它。

现在我可以看到两种可能的路由:要么你想返回去转义的字符串值(不带引号),你把它改成:[2]

    qi::lexeme [
            '"' >>
                *(('' >> qi::char_) | (qi::char_ - '"'))
            >> '"'
        ]

或者你想用引号捕获原始字符串,而你根本不关心公开的属性:

    qi::raw [
            '"' >>
                *(('' >> qi::char_) | (qi::char_ - '"'))
            >> '"'
        ]

后者使用从源迭代器对(qi::raw[])到std::string(绑定属性)的隐式属性转换。

现场观看完整内容:

住在科里鲁

#include <boost/spirit/include/qi.hpp>
#include <boost/proto/deep_copy.hpp>
#include <boost/optional.hpp>
#include <string>
namespace qi = boost::spirit::qi;
namespace {
    auto string_literal = boost::proto::deep_copy(
#if 1
        qi::lexeme [
                '"' >>
                    *(('' >> qi::char_) | (qi::char_ - '"'))
                >> '"'
            ]
#else
        qi::raw [
                '"' >>
                    *(('' >> qi::char_) | (qi::char_ - '"'))
                >> '"'
            ]
#endif
        );
}
template <class Iterator, class Grammar>
boost::optional<std::string> parse_string(Iterator first, Iterator last, Grammar&& gr)
{
    std::string temp;
    bool success = qi::phrase_parse(
        first,
        last,
        std::forward<Grammar>(gr),
        qi::space,
        temp
    );
    if (success && first == last)
        return temp;
    else return boost::none;
}

int main()
{
    std::string str;
    std::cout << "string_literal: ";
    getline(std::cin, str);
    auto presult = parse_string(str.begin(), str.end(), string_literal);
    if (presult) {
        std::cout << "parsed: '" << *presult << "'n";
    } else
        std::cout << "failuren";
    return 0;
}

[1] 通过重新排序分支略有简化

[2](请注意,''等效于通过表达式模板操作数的隐式转换qi::lit('')