我正在编写一个程序,我需要解析 JavaScript 源文件、提取一些事实并插入/替换部分代码。给定以下代码,我需要做的各种事情的简化描述是:
foo(['a', 'b', 'c']);
提取'a', 'b', 并将'c'代码重写为:
foo('bar', [0, 1, 2]);
我正在使用 ANTLR 来满足我的解析需求,生成 C# 3 代码。其他人已经贡献了 JavaScript 语法。源代码的解析正在工作。
我遇到的问题是弄清楚如何真正正确地分析和修改源文件。我在实际解决问题时尝试采用的每种方法都将我带入了死胡同。我不禁认为我没有按预期使用该工具,或者在处理 AST 时我只是一个新手。
我的第一种方法是使用 a 解析TokenRewriteStream并实现EnterRule_*我感兴趣的规则的部分方法。虽然这似乎使修改令牌流变得非常容易,但我的分析没有足够的上下文信息。似乎我只能访问一个扁平的令牌流,这并不能告诉我关于整个代码结构的足够信息。例如,要检测foo函数是否被调用,仅仅查看第一个标记是行不通的,因为它也会错误地匹配:
a.b.foo();
为了让我能够进行更复杂的代码分析,我的第二种方法是使用重写规则修改语法以生成更多的树。现在,第一个示例代码块生成:
程序
呼叫表达
标识符('foo')
参数列表
数组字面量
字符串文字('a')
字符串文字('b')
字符串文字('c')
这对于分析代码非常有用。但是,现在我无法轻松地重写代码。当然,我可以修改树结构来表示我想要的代码,但我不能用它来输出源代码。我曾希望与每个节点关联的标记至少能给我足够的信息,让我知道我需要在原始文本中的哪个位置进行修改,但我得到的只是标记索引或行/列号。要使用行号和列号,我将不得不对源代码进行一次尴尬的第二次遍历。
我怀疑我在理解如何正确使用 ANTLR 来做我需要的事情时遗漏了一些东西。我有没有更合适的方法来解决这个问题?