【问题标题】:Boost Spirit x3: parse delimited stringBoost Spirit x3:解析分隔字符串
【发布时间】:2019-08-09 07:49:10
【问题描述】:

我正在用 Spirit X3 编写另一个无聊的计算器解析器,但遇到了一个问题:我定义了 2 个字面量,“cos”和“cosh”,每个字面值后面都应该跟一个数字。我写的规则是:

const std::string COS_TAG = "cos";
const std::string COSH_TAG = "cosh";
const auto cos = (COS_TAG > value)[math::cos_solver{}];
const auto cosh = (COSH_TAG > value)[math::cosh_solver{}];

(我知道语义操作不是首选方式,但我很懒)。 现在,解析“cosh 3.5”时的问题是:

expectation failure: expecting value here "cosh 3.5"
----------------------------------------------^-----

看起来解析器很急切并使用第一个标签而不检查另一个标签。我已经通过使用这样的差异运算符使其工作:

const std::string COS_TAG = "cos";
const std::string COSH_TAG = "cosh";
const auto cos = ((x3::lit(COS_TAG) - COSH_TAG) > value)[math::cos_solver{}];
const auto cosh = (COSH_TAG > value)[math::cosh_solver{}];

有更好的方法吗?

【问题讨论】:

    标签: boost boost-spirit eager


    【解决方案1】:

    所以,不是分隔字符串,而是检查标记边界。

    Qi 存储库为此提供了distinct,我想我可能曾经在 X3 代码库中看过它。会找的。​​p>

    不管现在/旧版本/你的理解,这里有一些方法来实现它:

    • 重新排序分支,如果你在cos 之前匹配cosh,你会因为贪婪而得到你想要的行为

    • 对您的标识符做出更一般的断言:

      auto kw = [](auto p) {
           return x3::lexeme [ x3::as_parser(p) >> !x3::char_("a-zA-Z0-9_") ];
      };
      

      现在您可以使用kw(COSH) 代替lit(COSH),并确保它不会匹配coshida

    【讨论】:

    • 谢谢,我将采用第二种方法(这是我实现的,但以一种更优雅的方式),我不喜欢在使用声明性语法时考虑评估顺序。
    • 是的,没有人这样做,这就是为什么 PEG 不是最流行的解析器生成器范例
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-28
    • 2023-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多