使用sed删除C / C ++文件中的函数体

我正在试图从一个源文件中创build一个具有所有函数/枚举/结构/ etc名称的文件。 为此,我正在尝试使用sed来完成这样的事情:

(原始文件)

 function add1 (int i) { return i+1; } 

(sed的输出)

 function add1 (int i) { } 

换句话说,我想删除函数正文的实际内容。 我到目前为止还没有得到它的工作。 有什么build议么?

编辑 :我尝试了这样的事情,没有成功(现在我试图只在函数的身体空白行):

 sed '/{/,/}/ s/.*//' 

Solutions Collecting From Web of "使用sed删除C / C ++文件中的函数体"

而不是sed ,你总是可以在每字符字段模式( FS="" )中使用awk

 awk 'BEGIN { RS = "\n" ; FS = "" ; d = 0 ; } { for (i=1; i<=NF; i++) if ($i == "{") { d++ ; if (d == 1) printf "{\n" } else if ($i == "}") { d-- ; if (d == 0) printf "}" } else if (d == 0) printf "%s", $i ; if (d == 0) printf "\n" }' INPUT-FILE(s)... 

以上将跳过任何成对花括号的内容,即函数和结构体,数组初始化等,并将结果输出到标准输出。 您可以指定一个或多个文件。 (如果你没有指定任何文件,它会期望来自标准输入的输入。)

就像现在一样,它会在引号或注释中混淆大括号。 这可以用相同的方法解决,但是它确实变得很复杂。 这只是一个黑客让你大部分的方式。

我添加了分号( ; ),以便您可以将所有内容填充到上面的代码片段中。

脚本的逻辑非常简单。 它使用空字段分隔符( FS ),以便输入中的每个字符都是它们自己的字段。 BEGIN规则在处理任何输入之前运行一次,并设置它。 对于开发人员信息,我也初始化d = 0尽管awk不是必需的,因为它假定未初始化的变量为空或零。 它将跟踪每个输入字符的当前支撑深度。

每个记录将执行第二个括号表达式。 由于我设置了RS = "\n" ,每行都是一个单独的表达式。 因此,它将在每个输入行执行一次。 由于FS = "" ,该行上的每个字符将是一个单独的字段。 记录中有NF字段: $1$2 ,.., $(NF-1)$NF 。 三部分if子句只是输出最外面的大括号,而不是大括号内的所有内容(即当d == 0 )。

可以扩展这个awk scriptlet来包含注释,字符串,字符常量(使用\047来引用单引号,除非你用#!/usr/bin/awk -f把脚本放入单独的文件中),处理或忽略预处理器宏。

它确实有些复杂,最终你会得到几百行的awk脚本,但是它应该是相当可靠和相当快的。 这是可能的原因是因为在这种情况下C中的标记化规则很容易遵循; 我个人会在所有其他使用情况下使用全面的C词法分析器(词法分析器或扫描仪)。 也可能是为了这个。

如果你想使用一个成熟的C词法分析器,网络上可以自由地使用它们,但是你必须使用像C或C ++这样的更高级的语言。 如果你想处理所有的角落案例,它也需要加入一个C / C ++预处理器,但是这些规则很容易(即使使用awk)。

在一致格式的文件上,你可以做类似的事情

 sed '/{$/ {:r;/\n}/!{N;br}; s/\n.*\n/\n/}' 

立即读取函数体并删除大括号之间的所有内容:

 $ echo 'function add1 (int i) { if (i == 1) {return i+1;} }' | sed '/{$/ {:r;/\n}/!{N;br}; s/\n.*\n/\n/}' function add1 (int i) { } 

该命令仅适用于直接在换行符之后以{直接在前,以a结尾}块。

:r;/\n}/!{N;br}部分:r定义了一个名为r标签 ,其中另一行从输入( N )附加到模式空间,然后执行流程开始再次( br )。 它只发生在\n}遇到。 所以当我们离开这个“循环”的时候,我们在模式空间中有了整个函数体,然后我们使用s命令。

我会首先建议确保您的C源文件正确缩进。 你可以使用indent -gnu

那么你可以使用一些sed技巧。 使用适当缩进的代码,您只需要关心大括号(打开或关闭)作为其行的第一个字符。

我不确定你为什么要这样做。 特别是, struct可以是,有时甚至是嵌套的。 还有病理性的情况 – 例如用大括号定义的东西的预处理宏等等。

一个更好的方法可能是在编译器内部进行操作(但是你必须处理来自#include -d头文件的东西)。 你可以使用MELT来达到这个目的(MELT是扩展GCC的高层领域特定语言,并且正在GCC内部工作)。