3

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

(原始文件)

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

(sed的输出)

function add1 (int i) {
}

换句话说,我想删除函数体的实际内容。到目前为止,我无法让它工作。有什么建议么?

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

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

3 回答 3

4

在格式一致的文件上,您可以执行类似的操作

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 开头并{直接}在换行符之后以 a 结尾的块。

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

于 2012-09-23T09:50:06.977 回答
1

代替sed,您总是可以awk在每字符字段模式 ( FS="") 中使用:

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 子句仅输出最外面的大括号,以及不在大括号内的所有内容(即 when d == 0)。

可以扩展此awkscriptlet 以包含注释、字符串、字符常量(用于\047引用单引号,除非您使用 将脚本放入单独的文件中#!/usr/bin/awk -f),并处理或忽略预处理器宏。

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

如果你想使用成熟的 C 词法分析器,网上有很多免费的,但你必须使用更高级的语言,如 C 或 C++。如果您希望处理所有极端情况,它也需要合并一个 C/C++ 预处理器,但这些规则很容易(即使使用 awk)。

于 2012-09-23T11:19:24.253 回答
0

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

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

我不确定你为什么要这样做。特别是,struct可以并且有时确实是嵌套的。还有一些病态的情况——例如预处理器宏用大括号定义东西等。

更好的方法可能是对编译器内部进行操作(但是您必须处理来自#include-d 标头的内容)。您可以为此目的使用MELT(MELT 是一种用于扩展 GCC 的高级域特定语言,并且正在研究 GCC 内部)。

于 2012-09-23T09:59:26.057 回答