微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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

如何解决将规则添加到 Treesitter LR1 语法更改优先级

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

我有一个简单的算术语法,部分如下所示:

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

这可以正常工作。 multiply_expression 确实比 addition_expression 获得更高的优先级。

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

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

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

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

解决方法

这是您的完整语法,为了可重复:

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,'+',}
});

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

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

您在这里所做的是使乘法成为优先级为 2 的右结合运算符。这就是您如何在不将其公开为原语的文法中定义左结合或右结合。您可以通过如下编写使乘法左结合:

    _partial_multi: $ => prec(2,seq(
        '*',multiply_expression: $ => seq(
        $._expression,$._partial_multi,

您实际上偶然发现了一些非常有趣的事情,那就是您不需要明确的语言结构来定义语法中的优先级和结合性!它们只是使语法更易于阅读和编写的“语法糖”。有关如何通过分解规则指定优先级和关联性的详细信息,请参阅 this page。您可以看到,纯粹通过语法结构来指定优先级和结合性是令人困惑的,并且除非您仔细考虑,否则几乎与您的期望相反!正如您还发现的,混合这两种方法(通过语言结构语法结构指定优先级和结合性)会导致混淆行为。最好坚持其中之一。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。