如何解决将规则添加到 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 举报,一经查实,本站将立刻删除。