antlr - ANTLR4 - 替换操作边界错误|如何使用 TokenStreamRewriter 从原始 AST 中重叠标记上的两个侦听器事件转换文本?
问题描述
您好 ANTLR 创建者/用户,
一些上下文 - 我正在使用 PlSql ANTLR4 解析器将一些查询从 oracle sql 转换为例如 spark sql。我有我的监听器类设置,它扩展了基础监听器。
问题示例 - 假设输入类似于 -
SELECT to_char(to_number(substr(ATTRIBUTE_VALUE,1,4))-3)||'0101') from xyz;
现在,我想替换 || 使用 CONCAT 和 to_char 使用 CAST 作为 STRING,因此最终查询看起来像 -
SELECT CONCAT(CAST(to_number(substr(ATTRIBUTE_VALUE,1,4))-3) as STRING),'0101') from xyz;
在我的侦听器类中,我重写了来自基本侦听器的两个函数来执行此操作 - 连接和 string_function。在这些中,我使用 tokenStreamRewriter 的替换来进行必要的转换。由于 tokenStreamRewriter 被懒惰地评估,我正在运行 ->
java.lang.IllegalArgumentException: replace op boundaries of
<ReplaceOp@[@38,228:234='to_char',<2193>,3:15]..[@53,276:276=')',
<2214>,3:63]:"CAST (to_number(substr(ATTRIBUTE_VALUE,1,4))-3 as STRING)">
overlap with previous <ReplaceOp@[@38,228:234='to_char',<2193>,3:15]..
[@56,279:284=''0101'',<2209>,3:66]:"CONCAT
(to_char(to_number(substr(ATTRIBUTE_VALUE,1,4))-3),'0101')">
显然,问题是我的两个侦听器函数试图替换/转换重叠边界上的文本。
ANTLR4 的领土重叠问题有什么解决办法吗?我敢肯定,人们可能一直都会遇到这样的事情。
我会很感激任何变通办法,即使是在这个时候肮脏的:)
我确实意识到 ANTLR4 不允许我们修改原始 AST,否则这会更容易解决。
谢谢!
解决方案
看一下 tokenstreamrewriter 的工作原理可以得出以下理解:
- 首先,构建所有修改操作的列表
- 然后,您调用 getText()
- 在这里,修改操作有所减少。例如,这个想法是将多个插入合并到一个缩减中。它的作用也是避免对同一数据进行多次替换(但我稍后会对此进行扩展)。
- 然后读取每个令牌,如果为所述令牌索引列出了修改,则 TokenStreamRewriter 执行操作,否则它只是弹出读取的令牌。
我们来看看修改操作是如何实现的:
- 对于插入,tokenstream rewriter 基本上只是在当前token索引处添加要添加的字符串,然后做一个index+1,有效地进入下一个token
- 对于替换,tokenstream rewriter 用新字符串替换一系列标记,并将新索引设置为该范围的末尾。
因此,对于 tokenstreamrewriter,重叠替换是不可能的,因为当您替换时,您会跳转到要替换的标记范围的末尾。特别是,如果您删除了重叠检查,则只会操作第一个替换,因为之后,令牌索引会超过其他替换。
基本上,这已经完成了,因为在使用重叠替换时无法轻松判断应该替换哪些标记。您将需要该符号识别和匹配。
因此,您要尝试执行以下操作(对于每个步骤,“*”之间的部分是修改的内容):
*SELECT to_char(to_number(substr(ATTRIBUTE_VALUE,1,4))-3)||'0101')* from xyz;
|
V
CONCAT (*to_char(to_number(substr(ATTRIBUTE_VALUE,1,4))-3)*,'0101') from xyz;
|
V
SELECT CONCAT(CAST(to_number(substr(ATTRIBUTE_VALUE,1,4))-3) as STRING),'0101') from xyz;
为了实现您的转型,您可以这样做替换:
- 'to_char' -> 'CONCAT(CAST'
- '||' -> '作为字符串),'
而且,通过在解析标记时使用一点智能,比如是否有“||” 在我的令牌中知道它是否是字符串,你会知道要替换什么。
问候
推荐阅读
- google-app-engine - 从服务帐户进行身份验证时访问 IAP 资源时出错 - 502 服务器错误
- intellij-idea - IntelliJ:无法为 Web 应用程序指定/创建应用服务器
- sql-server - Sqlcmd 使用 SQL Server 存储过程将数据导出到 csv
- rtmp - 如何在 RTMP 和 Video 上使用 YOLO 实时检测对象?
- conv-neural-network - 使用 YOLO3 进行对象检测
- javascript - 为什么 Mag Pagination 和 Mag Sort 不起作用
- azure - SSAS Invoke-ASCmd 创建或更新不创建数据库
- java - switch 语句未正确执行
- java - 移入列的算法:移动字母不起作用
- c# - 自定义 Slack 命令返回状态 200 并触发另一个作业