如何让ANTLR语法规则更模块化?解决互左递归问题
问题描述
我有如下表达式语法规则,所有逻辑都集中在expr规则中,运行正常:
grammar MyGrammar; expr : '(' expr ')' // BoolExressions -- cannot move these out or else get Left-Recursion | expr ('=' | '!=') expr | expr 'AND' expr | expr 'OR' expr | ATOM ; ATOM: [a-z]+ | [0-9]+; WHITESPACE: [ \t\r\n] -> skip;
现在想把布尔表达式相关逻辑拆分成独立的boolExpr规则,方便其他规则单独使用布尔表达式,但拆分后出现相互左递归错误:
grammar MyGrammar; expr : '(' expr ')' | boolExpr | ATOM ; boolExpr : expr ('=' | '!=') expr | expr 'AND' expr | expr 'OR' expr ; ATOM: [a-z]+ | [0-9]+; WHITESPACE: [ \t\r\n] -> skip; // error(119): The following sets of rules are // mutually left-recursive [expr, boolExpr]
需要找到合理的拆分方式,实现布尔表达式的独立分离。
解决方案
要解决相互左递归问题,核心是打破expr和boolExpr的循环引用,同时明确语法层级和运算优先级,重构后的语法如下:
grammar MyGrammar; // 顶层表达式:可直接使用布尔表达式或基础表达式 expr : boolExpr | primaryExpr ; // 独立的布尔表达式规则,仅处理布尔运算 boolExpr : primaryExpr ('=' | '!=') primaryExpr | boolExpr 'AND' primaryExpr | boolExpr 'OR' primaryExpr ; // 基础表达式单元:原子值和括号包裹的任意表达式 primaryExpr : ATOM | '(' expr ')' ; ATOM: [a-z]+ | [0-9]+; WHITESPACE: [ \t\r\n] -> skip;
关键说明
层级拆分:
primaryExpr作为最基础的表达式单元,包含原子值和括号嵌套的任意表达式(保证括号可以包裹布尔表达式或普通表达式)boolExpr仅处理布尔运算,通过左递归定义保证AND/OR的左结合性(符合常规运算逻辑),操作数使用primaryExpr避免和expr形成循环引用expr作为顶层入口,兼容布尔表达式和基础表达式,其他规则如果只需要布尔表达式,直接引用boolExpr即可
规避左递归:
原错误源于expr和boolExpr互相引用形成循环,现在让布尔表达式的操作数指向优先级更高的primaryExpr,彻底打破循环,同时ANTLR支持规则内部的左递归(如boolExpr 'AND' primaryExpr这种形式是合法的)语义兼容:
重构后的语法完全兼容原规则的所有合法输入,同时实现了布尔表达式的独立分离,满足"其他规则单独使用布尔表达式"的需求。
内容的提问来源于stack exchange,提问作者carl.hiass
相关产品推荐
相关产品推荐

