1

我正在阅读Boost X3 快速入门教程并注意到这条线

eps是一个特殊的精神解析器,它不消耗任何输入但总是成功的。我们使用它来初始化规则的综合属性,在其他任何事情之前为零。[...] 使用eps这种方式有利于进行前后初始化。

现在我不禁想知道是否eps_that_might_fail可以对解析输入的一部分进行某种语义/后分析,这可能会失败,以便在语法中进行某种检查的局部性。

是否存在可能失败eps,使用此构造进行额外的输入验证是否是个好主意?

我试图传达的一个可怕的例子:

int_ >> eps_might_fail[is_prime]

如果我没记错的话,这只会解析素数,并允许完整的解析器在它期望素数的地方失败。

4

1 回答 1

4

语义动作就是为此而设计的。

灵气

最自然的例子是

 qi::int_ [ qi::_pass = is_prime(qi::_1) ]

确保%=在存在语义动作的情况下使用规则分配,因为没有它,语义动作会禁用自动属性传播。

显然,您也可以更冗长,并写

 qi::int_ >> qi::eps(is_prime(qi::_val))

正如你所看到的,引用的文档有点不完整:eps已经可以接受一个参数,在这种情况下是惰性actor is_prime(qi::_val),它决定了它是成功还是失败。

精神X3

在 Spirit X3 中,同样的机制也适用,只是 X3 没有与 Phoenix 集成。这意味着两件事:

  • 从好的方面来说,我们可以只使用核心语言特征 (lambdas) 来进行语义操作,从而使学习曲线不那么陡峭
  • 不利的一面是,没有一个只有一个参数的版本x3::eps需要一个懒惰的演员

这是一个带有 X3 的演示程序:

Live On Coliru

#include <boost/spirit/home/x3.hpp>

namespace parser {
    using namespace boost::spirit::x3;

    auto is_ltua = [](auto& ctx) {
        _pass(ctx) = 0 == (_attr(ctx) % 42); 
    };

    auto start = int_ [ is_ltua ];

}

#include <iostream>

int main() {
    for (std::string const txt : { "43", "42", "84", "85" }) {
        int data;
        if (parse(txt.begin(), txt.end(), parser::start, data))
            std::cout << "Parsed " << data << "\n";
        else
            std::cout << "Parse failed (" << txt << ")\n";
    }
}

印刷

Parse failed (43)
Parsed 42
Parsed 84
Parse failed (85)
于 2016-07-11T09:23:12.053 回答