首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >将规则添加到Treesitter LR1语法会更改优先级

将规则添加到Treesitter LR1语法会更改优先级
EN

Stack Overflow用户
提问于 2021-04-17 20:21:47
回答 1查看 57关注 0票数 1

我正在尝试在Treesitter语法中获得正确的运算符优先级。Treesitter是一个LR1解析器生成器。

我有一个直截了当的艺术语法,部分看起来像这样:

代码语言:javascript
运行
复制
multiply_expression: $ => prec.left(2, seq(
    $._expression,
    '*',
    $._expression,
)),

addition_expression: $ => prec.left(1, seq(
    $._expression,
    '+',
    $._expression,
)),

这可以正常工作。multiply_expression确实比addition_expression有更高的优先权。

但是,当我添加中间规则时,优先级会发生变化:

代码语言:javascript
运行
复制
_partial_multi: $ => seq(
    $._expression,
    '*',
),

multiply_expression: $ => prec.left(2, seq(
    $._partial_multi,
    $._expression,
)),

我将$.expression, '*'迁移到了它自己的规则中。对我来说,这似乎是一个等价的语法,我希望不会有任何变化。但是,随着此更改,优先级不再正确。保持不变的addition_expression似乎比multiply_expression具有更高的优先级。

为什么引入额外的步骤会改变优先级?有没有这个问题的名称,或者我在哪里可以找到关于它的更多信息?在编写语法或解决优先级问题时,有没有需要遵循的规则或思考这个问题的方法?

EN

回答 1

Stack Overflow用户

发布于 2021-04-20 20:12:06

这里是你的完整语法,为了重现性:

代码语言:javascript
运行
复制
module.exports = grammar({
  name: 'github_example',

  conflicts: $ => [],

  rules: {
    source_file: $ => $._expression,

    _expression: $ => choice(
      $.number,
      $.multiply_expression,
      $.addition_expression
    ),

    number: $ => /\d+/,

    _partial_multi: $ => seq(
        $._expression,
        '*',
    ),

    multiply_expression: $ => prec.left(2, seq(
        $._partial_multi,
        $._expression,
    )),

    addition_expression: $ => prec.left(1, seq(
        $._expression,
        '+',
        $._expression,
    )),
  }
});

您可以通过向_partial_multi规则添加优先级并从multiply_expression规则中删除左关联优先级来解决此问题:

代码语言:javascript
运行
复制
   _partial_multi: $ => prec(2, seq(
        $._expression,
        '*',
    )),

    multiply_expression: $ => seq(
        $._partial_multi,
        $._expression,
    ),

你在这里所做的是将乘法定义为优先级为2的右结合运算符,这就是你在语法中定义左或右结合的方式,这些语法不会将其公开为基元。你可以通过编写如下代码来实现左关联乘法:

代码语言:javascript
运行
复制
    _partial_multi: $ => prec(2, seq(
        '*',
        $._expression,
    )),

    multiply_expression: $ => seq(
        $._expression,
        $._partial_multi,
    ),

您实际上偶然发现了一件非常有趣的事情,那就是您不需要显式的语言结构来定义语法中的优先级和结合性!它们只是让语法更容易读写的“语法糖”。有关如何通过分解规则来指定优先级和关联性的更多信息,请参见this page。您可以看到,完全通过语法构造指定优先级和结合性是令人困惑的,而且除非您仔细考虑,否则几乎会向后阅读您所期望的内容!正如您还发现的,混合使用这两种方法(通过语言结构和语法结构指定优先级和结合性)可能会导致混淆行为。最好是坚持其中之一。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67138113

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档