你想要的是一个庞大的代码更改引擎。
ANTLR 不会成功;AST 是必要的,但还不够。请参阅我关于解析后的生活的文章。如果 Eclipse 包对名称和类型解析提供一些支持,Eclipse 的“AST”可能会更好;否则你将永远无法弄清楚如何替换每个“doSomething”(可能是重载的或本地的),除非你愿意全部替换它们(你可能不能这样做,因为有些符号是指 Java库元素)。
我们的DMS 软件再造工具包可用于完成您的任务。DMS 可以将 Java 解析为 AST(包括注释捕获),以任意方式遍历 AST,分析/更改 AST,并将修改后的 AST 导出为有效源代码(包括注释)。
基本上,您想枚举所有注释、字符串和标识符声明,将它们导出到外部“数据库”以映射(手动?通过谷歌翻译?)到等价物。在每种情况下,您不仅要注意感兴趣的项目,还要注意其精确位置(源文件、行、甚至列),因为在原始文本中拼写相同的项目在修改后的文本中可能需要不同的拼写。
如果你有 AST,那么枚举字符串非常容易;只需爬取树并查找包含字符串文字的树节点。(ANTLR 和 Eclipse 也确实可以做到这一点)。
如果您拥有的解析器捕获了评论,那么评论的枚举也很简单。DMS 可以。我不太确定是 ANTLR 的 Java 语法还是 Eclipse AST 引擎;我怀疑他们都有能力。
声明(类、方法、字段、局部变量)的枚举相对简单;有更多的情况需要担心(例如,匿名类包含对基类的扩展)。您可以编写一个过程来遍历 AST 并匹配树结构,但这是 DMS 开始发挥作用的地方:您可以编写看起来像您想要匹配的源代码的表面语法模式。例如:
pattern local_for_loop_index(i: IDENTIFIER, t: type, e: expression, e2: expression, e3:expression): for_loop_header
= "for (\t \i = \e,\e2,\e3)"
将匹配本地 for 循环变量的声明,并返回 IDENTIFIER、类型和各种表达式的子树;您只想捕获标识符(及其位置,可以通过从 DMS 在每个树节点上标记的源位置信息中获取 if 轻松完成)。您可能需要 10-20 个这样的模式来涵盖所有不同类型标识符的情况。
捕获步骤完成,需要将所有捕获的实体翻译成您的目标语言。我把它留给你;剩下的就是把翻译后的实体放回去。
关键是精确的源位置。行号在实践中不够好;您可能在同一行中有多个翻译的实体,在最坏的情况下,一些具有不同的范围(例如嵌套 for 循环)。注释、字符串和声明的替换过程很简单;重新扫描树中与任何已识别位置匹配的节点,并用其翻译替换在那里找到的实体。(您可以使用 DMS 和 ANTLR 执行此操作。我认为 Eclipse ADT 需要您生成“补丁”,但我想这会起作用。)。
有趣的部分在于替换标识符uses。为此,您需要知道两件事:
- 对于标识符的任何使用,声明的用途是什么;如果您知道这一点,则可以将其替换为声明的新名称;DMS 提供完整的名称和类型解析以及使用列表,使这变得非常简单,并且
- 重命名的标识符是否在与原始标识符不同的范围内相互影响?一般来说,这更难做到。但是,对于 Java 语言,我们有一个“阴影”检查,因此您至少可以在重命名后确定您有问题。(甚至还有一个重命名程序可以用来解决这种阴影冲突
修补树后,您只需使用 DMS 的内置漂亮打印机将修补的树重写为源文件。我认为 Eclipse AST 可以写出它的树和补丁。我不确定 ANTLR 是否提供了从 AST 重新生成源代码的任何工具,尽管有人可能已经为 Java 语法编写了一个工具。由于所有挑剔的细节,这比听起来更难做到。YMMV。
鉴于您的目标,我有点惊讶您不希望包含“class foo { ... }”的源文件“foo.java”重命名为.java。这不仅需要将转换后的树写入翻译后的文件名(非常容易),甚至可能需要重建目录树(DMS 也提供了用于进行目录构建和文件复制的工具)。
如果您想为多种语言执行此操作,则需要为每种语言运行一次该过程。如果您只想为字符串执行此操作(经典的国际化案例),您可以通过调用具有唯一资源 ID 的资源访问来替换每个字符串(需要更改,并非所有字符串都需要更改);运行时表将保存各种字符串。