如何利用ANTLR Lexical Modes基于上下文区分同一词法标记?
如何根据上下文对同一词法标记做不同处理?
我想确认是否可以根据上下文对同一词法标记进行不同处理,文档提到可使用Lexical Modes实现此功能,想了解该方案是否适用。
示例SQL语句
select 1.2, 1.2e, .2, 1.e, tbl, tbl.select
开头的SELECT是保留关键字,但.后的SELECT属于路径表达式,应被识别为identifier。期望忽略数字逻辑的前提下,第一个select被识别为select标记,第二个被识别为IDENTIFIER。
当前ANTLR示例语法
grammar DBParser; options { caseInsensitive=true; } statement:select_statement EOF; select_statement : SELECT expr (COMMA expr)* ; expr : NUMBER | IDENTIFIER ; COMMA: ','; // 1. 优先匹配数字(为简化问题做了格式简化) NUMBER: [0-9]* '.' [0-9]* 'e'?; // 2. 保留关键字部分 SELECT: 'SELECT'; // 3. 非保留关键字则作为标识符匹配 IDENTIFIER: [A-Z_] [A-Z_0-9]*; WHITESPACE: [ \t\r\n] -> skip;
当前解析处理.后的select时出现问题,能否在词法阶段设置规则来正确解析?
更新:更复杂的场景示例
select ([{'select': 1}])[0].select;
点访问可能出现在括号表达式、数组访问、函数调用等场景之后。
解决方案:使用词法模式(Lexical Modes)实现上下文切换
ANTLR的词法模式(Lexical Modes)完全适配这类上下文相关的词法识别需求,核心思路是根据解析进度切换词法规则的生效集合:
定义双词法模式
- 默认模式:保留关键字(如
SELECT)优先匹配 AFTER_DOT模式:不识别保留关键字,所有符合标识符规则的文本统一识别为IDENTIFIER
- 默认模式:保留关键字(如
在语法中触发模式切换
- 解析到
.时,切换到AFTER_DOT模式 - 完成
.后标识符的识别后,切回默认模式
- 解析到
修改后的语法示例:
grammar DBParser; options { caseInsensitive=true; } // 默认模式下的语法规则 statement: select_statement EOF; select_statement : SELECT expr (COMMA expr)* ; expr : NUMBER | IDENTIFIER | expr '.' IDENTIFIER // 处理点访问,触发词法模式切换 | '(' expr ')' // 支持括号表达式 | expr '[' expr ']' // 支持数组访问 ; // 默认模式下的词法规则 COMMA: ','; NUMBER: [0-9]* '.' [0-9]* 'e'?; SELECT: 'SELECT'; IDENTIFIER: [A-Z_] [A-Z_0-9]*; DOT: '.' -> pushMode(AFTER_DOT); // 遇到点时切换到AFTER_DOT模式 WHITESPACE: [ \t\r\n] -> skip; // AFTER_DOT模式:此模式下仅识别标识符和空白符 mode AFTER_DOT; AFTER_DOT_IDENTIFIER: [A-Z_] [A-Z_0-9]* -> type(IDENTIFIER), popMode; AFTER_DOT_WHITESPACE: [ \t\r\n] -> skip;
关键说明
- 当解析到
DOT(.)时,通过pushMode(AFTER_DOT)切换词法模式,后续文本仅匹配该模式下的规则 AFTER_DOT_IDENTIFIER将文本标记为IDENTIFIER类型,同时通过popMode切回默认模式,不影响后续正常解析- 针对括号、数组访问后的点访问场景,
expr规则的递归定义已经覆盖,只要解析到.就会触发模式切换,无需额外适配
此外,也可使用语义谓词实现上下文判断,但词法模式的实现更清晰、性能更优,适合这类明确的上下文切换场景。
内容的提问来源于stack exchange,提问作者samuelbrody1249
相关产品推荐
相关产品推荐

