You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在ANTLR中通过自定义函数动态捕获令牌结束位置?

可行,以下是实现示例

在ANTLR中完全可以实现这种根据方言动态解析原生表达式的需求,核心是利用词法分析器的模式(Mode)结合自定义规则/动作,根据匹配到的方言类型,动态判断原生表达式内容的结束位置(即正确的闭合))。

1. 语法定义(Native.g4)

grammar Native;

// 解析器规则
root: '=' expr ('+' expr)* EOF;
expr: NUMBER | NATIVE_EXPR;

// 词法规则:匹配完整的@dialect(...)结构
NATIVE_EXPR: '@' (POSTGRES | MYSQL);

// 匹配postgres方言前缀,切换到专属词法模式
POSTGRES: 'postgres' '(' -> pushMode(POSTGRES_MODE);

// 匹配mysql方言前缀,切换到专属词法模式
MYSQL: 'mysql' '(' -> pushMode(MYSQL_MODE);

NUMBER: [0-9]+;
WS: [ \t\r\n]+ -> skip;

// Postgres专属模式:处理内部内容,直到未被转义的')'
mode POSTGRES_MODE;
POSTGRES_CONTENT: (ESC_APOSTROPHE | ~[)])+; // 匹配转义单引号或非')'字符
POSTGRES_END: ')' -> popMode; // 匹配闭合括号,退出当前模式
fragment ESC_APOSTROPHE: '\'\''; // Postgres中用两个单引号转义单引号

// MySQL专属模式:处理内部内容,支持含')'的反引号标识符
mode MYSQL_MODE;
MYSQL_QUOTED_ID: '`' (ESC_BACKTICK | ~[`])* '`'; // 反引号包裹的标识符,内部允许含')'
MYSQL_CONTENT: ~[)`]+; // 匹配非')'非反引号的普通内容
MYSQL_END: ')' -> popMode; // 匹配闭合括号,退出当前模式
fragment ESC_BACKTICK: '``'; // MySQL中用两个反引号转义反引号

2. 扩展复杂逻辑(如注释处理)

如果需要处理示例中的PostgreSQL注释(--comment),可以在对应模式的规则中直接添加动作:

mode POSTGRES_MODE;
POSTGRES_CONTENT: (ESC_APOSTROPHE | ~[-)])+;
POSTGRES_COMMENT: '-' '-' ~[\r\n]* -> skip; // 跳过单行注释
POSTGRES_END: ')' -> popMode;
fragment ESC_APOSTROPHE: '\'\'';

3. 测试效果

针对你的示例输入:

= @postgres(')'''--comment) + 2
= 3 + @mysql(`my ide)ntifier`) + 4

解析后:

  • @postgres(')'''--comment)会被完整识别为一个NATIVE_EXPR令牌,内部的转义单引号和注释会被正确处理,直到最后的)才结束。
  • @mysql(my ide)ntifier)中的my ide)ntifier因被反引号包裹,不会提前触发闭合,只会在末尾的)处结束识别。

核心原理

  • 模式切换:通过pushMode和popMode进入/退出方言专属的词法分析上下文,避免与全局规则冲突。
  • 方言适配规则:针对不同方言的转义、标识符规则定义专属片段,确保不会误判闭合括号。
  • 灵活扩展:可在规则中嵌入目标语言(如JavaScript)的动作代码,实现更复杂的自定义字符消费逻辑。

内容的提问来源于stack exchange,提问作者David542

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 05:28:31