ANTLR4 - 替换op边界错误|如何使用TokenStreamRewriter从原始AST中重叠标记上的两个侦听器事件转换文本?

时间:2018-05-22 22:48:46

标签: antlr antlr4

Hello 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,否则这将更容易解决。

谢谢!

2 个答案:

答案 0 :(得分:0)

研究tokenstreamrewriter的工作方式会导致以下理解:

  • 首先,构建所有修改操作的列表
  • 然后,您调用getText()
  • 这里,减少了修改操作。例如,该想法是将多个插入片段合并成一个缩略词。它的作用还在于避免对同一数据进行多次替换(但是稍后我将对此进行扩展)。
  • 然后读取每个令牌,如果该令牌索引列出了修改,则TokenStreamRewriter进行操作,否则将弹出读取的令牌。

让我们看看如何实现修改操作:

  • 对于插入,tokenstream重写器基本上只添加要在当前令牌索引处添加的字符串,然后执行index + 1,有效地转到下一个令牌
  • 对于替换,tokenstream重写器用新字符串替换一系列令牌,并将新索引设置为该范围的末尾。

因此,对于tokenstreamrewriter,不可能进行重叠替换,因为当您进行替换时,您将跳到要替换的令牌范围的末尾。特别是,在删除重叠检查的情况下,将仅操作第一个替换,因为之后,令牌索引超过了另一个替换。

基本上,这样做是因为在使用重叠替换时,无法轻松分辨应该替换哪些令牌。您需要进行符号识别和匹配。

因此,您要尝试执行的操作如下(对于每个步骤,“ *”之间的部分都将被修改):

<button>
</button>

要实现转换,您可以替换:

  • 'to_char'->'CONCAT(CAST'
  • '||' ->“作为STRING),”

并且,通过在解析令牌时使用一些智能,就像有一个'||'用我的令牌知道它是否为字符串,您将知道要替换什么。

致谢

答案 1 :(得分:0)

我在基于ANTLR的多个项目中解决该问题的方法是:我将ANTLR解析树转换为使用Kolasu编写的AST,AST是我们在Strumenta开发的开源库。

Kolasu具有各种各样的实用程序来处理和变异AST。对于所有不重要的项目,我最终都会在AST上进行转换。

Kolasu