ANTLR 4.6语义谓词如何访问层级语法符号以解决语法歧义
解决ANTLR 4.6中语义谓词适配层级ID的问题
针对你遇到的层级ID(hier_id : ID ('.' ID)*)无法用原有的istype()方法判断类型的问题,我给你两种可行的解决方案,都能避免破坏语法可读性或编译错误:
方案一:通过前瞻Token构建完整层级名称(推荐,不修改核心语法结构)
原问题的核心是getCurrentToken()只能获取单个Token,无法拿到hier_id的完整字符串。我们可以修改语义谓词的判断逻辑,通过前瞻多个Token拼接出完整的层级名称后再判断是否属于类型集合。
修改后的完整语法代码如下:
// predicates/PredCppStat.g4 @parser::members { Set<String> types = new HashSet<String>() {{ add("T"); add("A.B"); // 示例层级类型 add("X.Y.Z"); }}; // 前瞻拼接完整的hier_id字符串,判断是否为类型 boolean isHierIdType() { StringBuilder sb = new StringBuilder(); int lookaheadOffset = 0; // 先检查第一个Token是否是ID(hier_id的起始) Token firstToken = _input.LA(1 + lookaheadOffset); if (firstToken.getType() != ID) { return false; } sb.append(firstToken.getText()); lookaheadOffset++; // 循环匹配后续的 "." + ID 组合 while (true) { Token dotToken = _input.LA(1 + lookaheadOffset); // 检查下一个Token是否是 ".",且再下一个是ID if (dotToken.getType() != '.' || _input.LA(1 + lookaheadOffset + 1) != ID) { break; } // 拼接 "." 和后续的ID sb.append('.').append(_input.LA(1 + lookaheadOffset + 1).getText()); lookaheadOffset += 2; // 跳过 "." 和 ID 两个Token } return types.contains(sb.toString()); } } stat: decl ';' {System.out.println("decl "+$decl.text);} | expr ';' {System.out.println("expr "+$expr.text);} ; decl: ID ID | {isHierIdType()}? hier_id '(' ID ')' ; expr: INT | ID | {!isHierIdType()}? hier_id '(' expr ')' ; hier_id : ID ('.' ID)* ; ID : [a-zA-Z]+ ; INT : [0-9]+ ; WS : [ \t\r\n]+ -> skip ;
方案优势:
- 完全保留原有语法结构,不会破坏可读性
- 不需要新增规则,仅通过修改谓词逻辑解决问题
- 兼容ANTLR 4.6的特性,无编译错误
方案二:新增中间规则后置语义谓词(更直观,语法结构更清晰)
如果你觉得前瞻逻辑稍显复杂,也可以通过新增两个中间规则,把语义谓词放在hier_id匹配完成后,直接访问$hier_id.text来判断类型:
修改后的核心规则部分如下:
@parser::members { Set<String> types = new HashSet<String>() {{ add("T"); add("A.B"); }}; } stat: decl ';' {System.out.println("decl "+$decl.text);} | expr ';' {System.out.println("expr "+$expr.text);} ; // 用中间规则封装类型判断 decl: ID ID | typed_hier_id '(' ID ')' ; expr: INT | ID | untyped_hier_id '(' expr ')' ; // 匹配层级ID且属于类型集合 typed_hier_id: hier_id {types.contains($hier_id.text)}? ; // 匹配层级ID且不属于类型集合 untyped_hier_id: hier_id {!types.contains($hier_id.text)}? ; hier_id : ID ('.' ID)* ; // 其余词法规则不变...
方案优势:
- 逻辑直观,谓词直接基于已匹配的
hier_id文本判断 - 语法结构模块化,可读性更强
- 无前瞻逻辑,代码更简洁
注意:
你之前尝试这种方案时报编译错误,大概率是谓词的位置写错了——语义谓词作为规则的后置条件时,需要写成{...}?放在规则末尾,而不是前置。上面的写法是符合ANTLR 4.6语法规范的,不会出现编译问题。
内容的提问来源于stack exchange,提问作者Riaz
相关产品推荐
相关产品推荐

