如何在ANTLR4中正常使用字符串内的保留关键字
解决方案
问题根源
ANTLR词法分析器遵循先定义优先匹配的规则:你把IF等关键字规则写在了普通字符/字符串规则前面,所以遇到符合关键字特征的文本会优先识别为关键字Token,而非普通字符或字符串内容。另外你当前的词法规则存在两个明显缺陷:
- 仅定义了单引号包裹的字符串字面量规则,没有定义双引号包裹的字符串规则,单独的
DOUBLEQUOTESToken会导致双引号内部的内容被按普通规则拆分,自然会识别出关键字 - 把
LETTER定义为独立Token而非片段,每个字母会被单独拆分为Token,连续字母匹配时会优先命中提前定义的关键字规则
方案1:修复字符串规则(解决引号内关键字被识别的问题)
如果你需要让引号内的所有内容都作为普通字符串、不需要拆分,直接在词法规则中新增完整的双引号字符串规则即可,字符串规则天然不会和字母开头的关键字规则冲突,内部内容会被整体识别:
// 放在词法规则任意位置即可,建议放在顶部 STRING_LITERAL_DOUBLE : '"' ( '\\"' | ~'"' )* '"';
调整后所有被双引号/单引号包裹的内容都会被识别为完整的STRING_LITERAL/STRING_LITERAL_DOUBLE Token,内部不会拆分出任何关键字。
方案2:优雅处理非引号场景下关键字作为普通词使用
你不需要逐个把所有关键字加到word规则里,可以按下面两步调整:
第一步:优化词法规则
把LETTER改为片段规则,新增标识符规则放在所有关键字的后面:
// 把原来的LETTER规则改成fragment,不再作为独立Token输出 fragment LETTER: [A-Za-z\u00e4\u00c4\u00d6\u00f6\u00dc\u00fc\u00df]; // 所有关键字规则的最后面加标识符规则,非关键字的连续字母会被识别为IDENTIFIER IDENTIFIER: (LETTER | '_')+;
第二步:解析器层统一封装关键字规则
在解析器中定义一次keyword规则枚举所有关键字,之后所有需要用到普通词的位置直接引用即可,不需要重复列所有关键字:
// 只需要定义一次,后续新增关键字只更新此处即可 keyword: IF | ENDIF | ELSE | CASE | ENDCASE | BREAK | SWITCH | SUBSTRING; word: ( symbolCharacters | IDENTIFIER | keyword )+ ;
可选优化:软关键字实现
如果你的关键字仅在特定语法上下文下生效,其他位置都作为普通词,可以在词法规则中添加动作动态修改Token类型,不需要在解析器层做任何处理,示例:
// 关键字规则加动作,非关键字上下文时自动转为IDENTIFIER类型 IF: I F { if(!isInKeywordContext()) setType(IDENTIFIER); };
你只需要自己实现isInKeywordContext()方法判断当前位置是否需要识别为关键字即可。
内容的提问来源于stack exchange,提问作者kalaiselvan panneerselvam
相关产品推荐
相关产品推荐

