C 如何使用grep查找所有内部循环?
我有一个巨大的C项目,有许多C文件。我必须找到所有的内部循环。我确信项目中没有任何O(n³)块,因此只能找到O(n²)-互补块(一个循环中的一个循环)C 如何使用grep查找所有内部循环?,c,regex,grep,code-analysis,C,Regex,Grep,Code Analysis,我有一个巨大的C项目,有许多C文件。我必须找到所有的内部循环。我确信项目中没有任何O(n³)块,因此只能找到O(n²)-互补块(一个循环中的一个循环) 是否可以使用grep查找所有内部循环?如果是,我可以使用什么正则表达式来查找所有类型的内部循环,如{for,for},{while,for},{for,while},{do,while},等等?如果没有,是否有任何简单的unix方式方法(可能是多个grep或一种awk)?正则表达式适用于正则语言,您所描述的内容似乎与上下文无关,我很确定不能使用正
是否可以使用grep查找所有内部循环?如果是,我可以使用什么正则表达式来查找所有类型的内部循环,如{for,for},{while,for},{for,while},{do,while},等等?如果没有,是否有任何简单的unix方式方法(可能是多个grep或一种awk)?正则表达式适用于正则语言,您所描述的内容似乎与上下文无关,我很确定不能使用正则表达式来完成。请参见类似问题的答案。您应该寻找其他类型的自动机,如脚本语言(python或其他语言)。如果没有C解析器,您最多只能得到一个启发式解决方案 如果您可以依赖代码中始终遵循的某些规则(例如,no
goto
,通过递归没有循环,…),则可以使用regexp扫描预处理的C代码。当然,grep还不够复杂,但只要使用几行Perl或类似的代码就可以了
但是技术上更好、更可靠的方法是使用真正的C解析器 对于特定的编译器扩展,这是一个很好的例子。最新的GCC编译器(即GCC的4.6版)可以通过插件(痛苦地用C编码)或扩展进行扩展;MELT是一种高级领域特定语言,用于编写GCC扩展,而且MELT比C更易于使用 然而,我承认,编写GCC扩展并不完全是一件小事:您必须部分了解GCC是如何工作的,以及它的主要内部表示(Gimple、Tree等)是什么。在扩展GCC时,基本上您可以添加自己的编译器过程,它可以做任何您想做的事情(包括检测嵌套循环)。编写GCC扩展通常需要一周以上的工作。(最难的部分是理解GCC是如何工作的) 在GCC框架内工作(通过C中的插件或MELT中的扩展)的最大优点是,您的扩展与编译器使用相同的数据
回到寻找嵌套循环的问题,不要认为它只是纯句法(这就是为什么代码> GRP不能工作)。在GCC编译器中,在某种内部表示级别上,由
for
,或while
,或do
,甚至使用goto
-s实现的循环仍然被视为循环,对于GCC来说,这些东西可以嵌套(GCC知道嵌套!)。C中有三种循环:
- “结构化语法”(while,for,…) [注意GCC,它可以使用(stmt;exp)语法在表达式中隐藏语句循环!]
- 使用“转到”的即席循环;它们与结构化语法交互
- 递归
pattern block_for_loop(t:expression,l:expression,i:expression, s: statements): statement
" for(\t,\l\,\i) { \s } ";
pattern statement_for_loop(t:expression,l:expression,i:expression, s: statement): statement
" for(\t,\l\,\i) \s ";
pattern block_while_loop(c:expression, s: statements): statement
" while(\c) { \s } ";
pattern statement_while_loop(c:expression): statement
" for(\c) \s ";
...
并将其分组:
pattern_set syntactic_loops
{ block_for_loop,
statement_for_loop,
block_while_loop,
block_statement_loop,
...
}
给定模式集,DMS可以扫描语法树并找到与任何集合成员的匹配项,而无需编码任何特定的树爬行机制,也无需知道树结构的大量细节。(对于一个真正的C解析器来说,AST中有很多节点类型!)用这种方法查找嵌套循环非常简单:从上到下扫描树中的循环(使用模式集);任何命中必须是顶级循环。扫描找到的循环AST节点的子树(当您知道外部循环的树在哪里时很容易)以查找其他循环;任何点击都必须是嵌套循环;如有必要,递归以拾取具有任意嵌套的循环。这也适用于带有语句的GCC循环。树节点上印有精确的文件/行/列信息,因此很容易生成位置报告
对于使用goto(什么,您的代码没有?)构建的特殊循环,您需要能够生成实际控制流图的东西,然后将该图构造成嵌套的控制流区域。这里的要点是一个while循环,它包含一个无条件的gotopublic void do(){
for(...){
somethingElse();
}
}
... Insert other code...
public void somethingElse(){
for(.....){
print(....);
}
}