Gre*_*con 11 c c++ regex git parsing
我试图从存储在git存储库中的多年历史中构建一个"热图",其中粒度单位是单独的函数.函数应该变得更热,因为它们更频繁地更改次数,并且更改非空行更多.
首先,我检查了输出
git log --patch -M --find-renames --find-copies-harder --function-context -- *.c
Run Code Online (Sandbox Code Playgroud)
我看过使用Hackage中的Language.C,但它似乎想要一个完整的翻译单元扩展标题和所有 - 而不是能够处理源片段.
该--function-context
选项是自1.7.8版以来的新选项.v1.7.9.4中的实现基础是一个正则表达式:
PATTERNS("cpp",
/* Jump targets or access declarations */
"!^[ \t]*[A-Za-z_][A-Za-z_0-9]*:.*$\n"
/* C/++ functions/methods at top level */
"^([A-Za-z_][A-Za-z_0-9]*([ \t*]+[A-Za-z_][A-Za-z_0-9]*([ \t]*::[ \t]*[^[:space:]]+)?){1,}[ \t]*\\([^;]*)$\n"
/* compound type at top level */
"^((struct|class|enum)[^;]*)$",
/* -- */
"[a-zA-Z_][a-zA-Z0-9_]*"
"|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lL]?"
"|[-+*/<>%&^|=!]=|--|\\+\\+|<<=?|>>=?|&&|\\|\\||::|->"),
Run Code Online (Sandbox Code Playgroud)
这似乎可以很好地识别边界,但并不总是将函数作为差异块的第一行,例如,#include
顶部的指令或包含多个函数定义的块.告诉diff为每个更改的函数发出单独的数据库的选项非常有用.
这不是安全关键,所以我可以忍受一些失误.这是否意味着我可能有Zawinski的"两个问题"?
我意识到这个建议有点离题,但它可能有助于澄清需求并对其进行排序。这适用于 C 或 C++ ...
使用编译器生成二进制块,而不是尝试查找作为函数的文本块并比较它们。具体来说,对于更改集中的每个 C/C++ 源文件,将其编译为对象。然后使用目标代码作为比较的基础。
这对您来说可能不可行,但 IIRC gcc 上有一个编译选项,以便每个函数都编译为生成的目标代码文件中的“独立块”。链接器可以将每个“块”拉入程序中。(现在已经很晚了,所以如果你对这个想法感兴趣的话,我会在早上查一下。)
因此,假设我们可以做到这一点,您将拥有由二进制代码块定义的许多函数,因此一个简单的“热度”比较是“任何函数的版本之间的代码长或多短?”
我还认为使用 objdump 重构函数的汇编器可能是实用的。我可能会在这个阶段使用一些正则表达式来修剪寄存器名称,以便寄存器分配的更改不会导致太多误报(更改)。
我什至可能尝试对函数体中的汇编指令进行排序,并对它们进行比较以获得两个函数实现之间“删除”与“添加”的模式。这将给出一种变化的度量,它几乎独立于布局,甚至在某种程度上独立于某些源的顺序。
因此,看看同一函数的两个替代实现(即来自不同的更改集)是否是相同的指令可能会很有趣:-)
这种方法也应该适用于 C++,因为所有名称都已被适当地修改,这应该保证比较相同的函数。
因此,正则表达式可能会非常简单:-)
假设所有这些都很简单,那么这种方法可能无法给您带来什么?
旁注:这个基本策略适用于任何以机器代码为目标的语言,以及 VM 指令集,如 Java VM 字节码、.NET CLR 代码等。