我一直在读这篇由Ira D. Baxter等人撰写的题为Clone Detection using Abstract Syntax Trees的论文。我在下面转载的论文中有一段:
原则上,查找子树克隆 很简单:比较每个子树 每个其他子树都是平等的。在 练习,出现了几个问题: near-miss克隆检测,亚克隆 和规模。 ......
找到近乎未命中 克隆,完整子树上的哈希 失败正是因为好的哈希 功能包括的所有元素 树,因此用轻微的树木排序 差异分成不同的桶。我们 通过选择一个解决了这个问题 人为错误的哈希函数。必须对此功能进行表征 这样一种主要属性的方式 一个人想找到近乎无法克隆的人 保存完好。接近错过克隆 通常通过复制和粘贴创建 程序紧随其后 修改。这些修改 通常会产生微小的变化 与树相关的树的形状 复制了一段代码。因此,我们 争辩说这种近乎错过 克隆经常只有一些不同 小的子树。基于此 观察,哈希函数 忽略小的子树是一个 好的选择。 在实验中 在这里介绍,我们使用哈希 只忽略的函数 标识符名称(树中的叶子)。 因此,我们的散列函数会放置树 这是类似的模数标识符 进入相同的哈希箱 比较。
我正在尝试实现本文中讨论的技术,但我仍然试图理解这一段(不幸的是在论文的开头)。我理解段落的内容,但作者没有提到要选择的哈希函数或如何实际哈希AST。有人可以从实施的角度用一个简单的例子解释一下吗?
答案 0 :(得分:7)
作者自己应该回答的阴影。 StackOverflow不是很棒: - ?
哈希函数的关键在于您选择哪一个并不重要,只要它在大量存储桶中均匀分配输入值即可。您需要一个可以应用于整个树的哈希函数;通常的技术是以任何可能的方式序列化树(例如,通过有序树访问),然后将哈希函数应用于它产生的值流(树节点)。 (这个想法来自关于检测常见子表达式的编译器文献,这是原始CloneDR的灵感)。如果不清楚,您需要花费更多的精力来理解哈希函数如何应用于复杂的数据结构。维基百科hashing是一个很好的起点;如果这还不够,你需要找一本关于算法的书并进行研究。
您向哈希函数提供的内容取决于您。我在论文中提出的观点是,您可以计算忽略AST的标识符叶的散列函数,这将导致具有相同结构但不同标识符的树散列到同一个桶。因此,类似模数标识符的树很容易匹配,因为它们出现在同一个哈希桶中。
当然,只有匹配树模数标识符的整个克隆检测算法还有很多。您需要担心匹配参数化序列(这是本文中的重点),报告结果,当然,您需要一个高质量的语言解析器,无论您需要应用什么语言这个。
您可以看到许多不同语言的CloneDR结果。
答案 1 :(得分:2)
如果您知道两个AST是人眼的“克隆”,那么您也希望确保它们具有相同的哈希值。
例如,将每个标识符散列为常量,将每个字符串散列到另一个常量,以避免被变量重命名欺骗,而不是实际使用标识符名称作为散列的材料部分。
或者使用可交换哈希来表达可交换的表达式,即。确保a + b和b + a得到相同的哈希值。
涉及变量,整数,运算符和括号的算术表达式示例:
hash VariableName = 0x12345678
hash IntegerConstant = 0xff77ff77
hash x + y = (hash x) + (hash y)
hash (x) = (hash x) <<< 13
hash x * y = (hash x) xor (hash y)
等