You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决Grammar Kit中自定义语言BNF的嵌套表达式解析问题?

解决IntelliJ自定义语言BNF的嵌套表达式优先级冲突问题

我在为IntelliJ插件编写自定义语言的BNF规则时,遇到了嵌套表达式的优先级冲突问题。自定义语言包含二元运算表达式和数组引用表达式,最初写的BNF规则如下:

{
  extends(".*_expr")=expr
  tokens=[
    id="regexp:[a-zA-Z_][a-zA-Z0-9_]*"
    number="regexp:[0-9]+"
  ]
}

expr ::=  binary_expr| array_ref_expr | const_expr

const_expr ::= number
binary_expr ::= expr '+' expr
array_ref_expr ::= id '[' expr ']'

解析a[1+1]时会报错:

']' expected, got '+'

调试后发现,数组引用表达式的优先级设置导致括号内无法识别二元运算;但如果交换优先级,又无法正确解析a[1]+1这类需要先算数组引用再算加法的表达式。调整优先级或结合性都无法同时适配两种场景。


解决方案:拆分表达式层级明确优先级

核心思路是通过分层定义表达式,让数组引用的优先级高于二元运算,同时允许括号内的表达式包含所有运算类型。修改后的BNF规则如下:

{
  extends(".*_expr")=expr
  tokens=[
    id="regexp:[a-zA-Z_][a-zA-Z0-9_]*"
    number="regexp:[0-9]+"
  ]
}

# 最顶层表达式,包含所有运算类型
expr ::= binary_expr | array_ref_expr | primary_expr

# 二元运算:优先级低于数组引用,右操作数限定为基础表达式
binary_expr ::= expr '+' primary_expr

# 数组引用:基于基础表达式定义,括号内支持任意表达式
array_ref_expr ::= primary_expr '[' expr ']'

# 基础表达式:最高优先级单元,包含常量、标识符、括号包裹的完整表达式
primary_expr ::= const_expr | id | '(' expr ')'

const_expr ::= number

规则说明:

  • primary_expr:作为最高优先级的基础单元,包含常量、标识符,以及用括号包裹的任意表达式——这保证了a[1+1]中括号内的1+1能被完整解析为合法表达式。
  • array_ref_expr:基于primary_expr定义,意味着数组引用只能作用于基础表达式(比如id或括号表达式),同时括号内可以是任意expr(包括二元运算),解决了嵌套运算的解析问题。
  • binary_expr:定义为expr '+' primary_expr,确保二元运算的优先级低于数组引用——解析a[1]+1时,会先处理a[1](属于primary_expr层级),再处理加法,符合运算顺序预期。

修改后两种场景的表达式都能被正确解析:

  • a[1+1]:括号内的1+1被完整识别为expr,外层数组引用正常解析;
  • a[1]+1:先解析a[1]作为加法左操作数,再处理右侧的1,运算顺序正确。

内容的提问来源于stack exchange,提问作者G. Seinfeld

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 11:03:27