如何在ANTLR4中让表达式按左到右同等优先级求值?
解决ANTLR4中表达式左到右求值的规则修改方案
这个问题的核心是ANTLR4中运算符优先级与结合性的控制逻辑——默认情况下,如果二元运算符的右操作数是完整的expression(而非更基础的原子表达式),会导致解析器优先让右操作数组合成更高优先级的表达式,而非按左到右顺序结合。要实现AND、OR(以及其他二元运算符)优先级相同、左结合的效果,我们需要调整规则的层级结构:
为什么原规则会出现AND优先级更高的情况?
你的原规则中,AND和OR的右操作数都是expression:
expression : ... | left=expression op=AND right=expression #And | left=expression op=OR right=expression #Or ...
当解析a or a and a时,OR的右操作数a and a会被完整解析为一个合法的expression,最终得到a or (a and a)的结构,这本质是因为右操作数可以递归匹配包含更高优先级运算符的表达式。
修改方案:拆分规则层级,统一二元运算符优先级
我们需要把表达式拆分为**原子表达式(Primary)和二元表达式(Binary)**两个层级,让二元运算符的右操作数只能是原子表达式,从而强制所有二元运算符优先级相同、左结合。
方案1:合并二元运算符(简化标签)
如果不需要单独区分每个二元运算符的标签,可以把所有同优先级的二元运算符合并到一个分支:
expression : binaryExpr ; // 左递归规则,确保左结合,所有二元运算符优先级相同 binaryExpr : binaryExpr op=(AND|OR|XOR|IMPL|EQUIV|VAR) primaryExpr #BinaryOp | primaryExpr #Primary ; // 原子表达式:括号、一元否定、常量、变量 primaryExpr : L_BRACKET expression R_BRACKET #Parenthesis | op=NEG primaryExpr #Neg | VALUE #Value | VAR #Var ;
方案2:保留原标签(区分不同运算符)
如果需要保留#And、#Or等单独标签,可以将每个二元运算符作为独立分支,但确保它们的右操作数都是primaryExpr:
expression : binaryExpr ; binaryExpr : binaryExpr op=AND primaryExpr #And | binaryExpr op=OR primaryExpr #Or | binaryExpr op=XOR primaryExpr #Xor | binaryExpr op=IMPL primaryExpr #Impl | binaryExpr op=EQUIV primaryExpr #Equiv | binaryExpr op=VAR primaryExpr #Var | primaryExpr #Primary ; primaryExpr : L_BRACKET expression R_BRACKET #Parenthesis | op=NEG primaryExpr #Neg | VALUE #Value | VAR #Var ;
修改后的效果
调整后,表达式a or a and a and a and a会被解析为左结合的嵌套结构:((((a or a) and a) and a) and a),完全符合左到右顺序求值的需求。
内容的提问来源于stack exchange,提问作者John Smith




