ANTLR访问器访问节点时如何识别当前命中的产生式备选分支
方案1:直接使用ANTLR自带的备选分支索引
ANTLR生成的RedirectionContext上下文对象自带getAltNumber()方法,返回值就是当前命中的产生式备选分支的序号,序号从1开始,和你语法里写的备选分支顺序完全对应:
- 第1条
GREATER WORD对应返回值1 - 第2条
LESS WORD对应返回值2 - ...以此类推,最后一条
AND_GREATER_GREATER WORD对应返回值43
你直接在visitRedirection方法里用switch判断这个返回值即可,代码非常简洁,不需要写任何空值判断逻辑:
@Override public YourReturnType visitRedirection(BashParser.RedirectionContext ctx) { switch (ctx.getAltNumber()) { case 1: // 处理 GREATER WORD 分支 break; case 2: // 处理 LESS WORD 分支 break; // 其他分支按需补充 } // 你的通用逻辑 }
这个方法是最适配你需求的,不需要改语法,也不需要新增任何visit方法。
方案2:优化空值判断逻辑,分层匹配
如果你不想记备选分支序号,也可以把原来的组合判空逻辑分层,减少冗余判断:
- 第一步先判断前缀类型:是带
NUMBER、带REDIR_WORD还是无前缀 - 第二步再判断中间的运算符类型(
GREATER/LESS/GREATER_GREATER等) - 第三步判断后缀类型(
WORD/NUMBER/DASH等)
示例代码如下:
@Override public YourReturnType visitRedirection(BashParser.RedirectionContext ctx) { if (ctx.NUMBER() != null) { // 处理所有 NUMBER 开头的分支 if (ctx.GREATER() != null) { // 处理 NUMBER GREATER WORD } else if (ctx.GREATER_GREATER() != null) { // 处理 NUMBER GREATER_GREATER WORD } // 其他运算符分支 } else if (ctx.REDIR_WORD() != null) { // 处理所有 REDIR_WORD 开头的分支 } else { // 处理无前缀的分支 if (ctx.AND_GREATER() != null) { if (ctx.AND_GREATER_GREATER() != null) { // 处理 AND_GREATER_GREATER WORD } else { // 处理 AND_GREATER WORD } } // 其他运算符分支 } }
这种方式的好处是可读性更强,不需要对应语法里的分支顺序,修改语法新增分支时也不容易出错。
可选优化:给同类分支加分组标签
如果你还是想用标签的方式,也不需要给43个分支每个都加单独的标签,只需要给同类前缀的分支加同一个分组标签即可:
redirection : GREATER WORD # PlainRedir | LESS WORD # PlainRedir | NUMBER GREATER WORD # NumberPrefixedRedir | NUMBER LESS WORD # NumberPrefixedRedir | REDIR_WORD GREATER WORD # RedirWordPrefixedRedir | REDIR_WORD LESS WORD # RedirWordPrefixedRedir // 其他分支同理按前缀分组加标签 ;
这样你只需要实现3个visit方法,每个方法里只需要处理对应前缀的分支,判断逻辑会更简单。
内容的提问来源于stack exchange,提问作者Lor
相关产品推荐
相关产品推荐

