【问题标题】:How to extract a single function from a source file如何从源文件中提取单个函数
【发布时间】:2010-11-11 18:12:19
【问题描述】:

我正在进行一项关于extremely long and complicated functions in the Linux kernel 的小型学术研究。我试图弄清楚是否有充分的理由编写 600 或 800 行长的函数。

为此,我想找到一个可以从 .c 文件中提取函数的工具,这样我就可以对该函数进行一些自动化测试。

例如,如果我在文件 connect.c 中有函数 cifs_parse_mount_options(),我正在寻找一个大致如下的解决方案:

extract /fs/cifs/connect.c cifs_parse_mount_options

并返回函数的 523 行代码(!),从左大括号到右大括号。

当然,任何操纵现有软件包(如 gcc)的方式来做到这一点也是最有帮助的。

谢谢,

乌迪

编辑:Regex to pull out C function prototype declarations? 的答案让我确信,通过正则表达式匹配函数声明绝非易事。

【问题讨论】:

    标签: c regex text-processing code-metrics mcc


    【解决方案1】:

    如果您发现难以提取函数名称:

    1> 使用 ctags(一个程序)提取函数名称。 ctags -x --c-kinds=fp path_to_file。 2> 一旦你得到函数名,编写一个简单的 perl 脚本,通过传递函数的脚本名来提取函数的内容,如上所述。

    【讨论】:

    • 谢谢,正是我需要的 :-)
    【解决方案2】:

    缩进 -kr code -o code.out

    awk -f split.awk code.out

    你必须适应一点 split.awk 这有点特定于我的代码和重构需求(例如,你有 so struct 不是 typedefs

    而且我相信你可以制作一个更好的脚本 :-)

    --
    BEGIN   { line=0; FS="";
        out=ARGV[ARGC-1]  ".out";
        var=ARGV[ARGC-1]  ".var";
        ext=ARGV[ARGC-1]  ".ext";
        def=ARGV[ARGC-1]  ".def";
        inc=ARGV[ARGC-1]  ".inc";
        typ=ARGV[ARGC-1]  ".typ";
        system ( rm " " -f " " out " " var " " ext " " def " " inc " " typ );
        }
    /^[     ]*\/\/.*/   { print "comment :" $0 "\n"; print $0 >> out ; next ;}
    /^#define.*/        { print "define :" $0 ; print $0 >>def ; next;}
    /^#include.*/       { print "define :" $0 ; print $0 >>inc ; next;}
    /^typedef.*{$/      { print "typedef var :" $0 "\n"; decl="typedef";print $0 >> typ;infile="typ";next;}
    /^extern.*$/        { print "extern :" $0 "\n"; print $0 >> ext;infile="ext";next;}
    /^[^    }].*{$/     { print "init var :" $0 "\n";decl="var";print $0 >> var; infile="vars";
                    print $0;
                    fout=gensub("^([^    \\*])*[    ]*([a-zA-A0-9_]*)\\[.*","\\2","g") ".vars";
                         print "var decl : " $0 "in file " fout;
                         print $0 >fout;
                    next;
                            }
    /^[^    }].*)$/     { print "func  :" $0 "\n";decl="func"; infile="func";
                    print $0;
                    fout=gensub("^.*[    \\*]([a-zA-A0-9_]*)[   ]*\\(.*","\\1","g") ".func";
                         print "function : " $0 "in file " fout;
                         print $0 >fout;
                    next;
                }
    /^}[    ]*$/        { print "end of " decl ":" $0 "\n"; 
                    if(infile=="typ") {
                        print $0 >> typ;
                    }else if (infile=="ext"){
                        print $0 >> ext;
                    }else if (infile=="var") {
                        print $0 >> var;
                    }else if ((infile=="func")||(infile=="vars")) {
                        print $0 >> fout; 
                        fflush (fout);
                        close (fout);
                    }else if (infile=="def") {
                        print $0 >> def;
                    }else if (infile=="inc"){
                        print $0 >> inc;
                    }else print $0 >> out;
                    next;
                }
    /^[a-zA-Z_]/        { print "extern :" $0 "\n"; print $0 >> var;infile="var";next;}
                { print "other :" $0 "\n" ; 
                    if(infile=="typ") {
                        print $0 >> typ;
                    }else if (infile=="ext"){
                        print $0 >> ext;
                    }else if (infile=="var") {
                        print $0 >> var;
                    }else if ((infile=="func")||(infile=="vars")){
                        print $0 >> fout;
                    }else if (infile=="def") {
                        print $0 >> def;
                    }else if (infile=="inc"){
                        print $0 >> inc;
                    }else print $0 >> out;
                   next;
                   }
    

    【讨论】:

      【解决方案3】:

      您为什么不编写一个小的 PERL/PHP/Python 脚本,甚至是一个小的 C++、Java 或 C# 程序来做到这一点?

      我不知道有什么工具可以做到这一点,但编写代码来解析文本文件并从 C++ 代码文件中提取函数体不应超过 20 行代码。唯一的困难部分将定位函数的开头,这应该是使用 RegEx 的相对简单的任务。之后,您只需要遍历文件的其余部分,跟踪打开和关闭大括号,当您到达函数体关闭大括号时,您就完成了。

      【讨论】:

      • 这是我的第一个想法,但是 cmets 让事情变得更复杂了。但是,如果我要写这样的脚本。我想我会发布它 - 它可能对其他人有用。
      • 我同意.. 您可能需要考虑 cmets,以防它们内部可能包含不匹配的花括号。不过,编码应该不会太难!
      • 我必须把它们去掉,得到函数结束的位置,然后用 cmets 提取代码。另一个问题是顶部的函数签名——它可能不止一行。正如我之前提到的,这没什么大不了的——但我宁愿专注于我的研究并使用现成的工具。如果那不可能,我会用 Python 解决问题!
      • 说真的,写这个脚本应该不到一个小时。您可能已经浪费了更多时间寻找工具而不是自己动手。
      • 您应该在解析源代码之前运行预处理器(例如,gcc -E)。预处理后应该很容易。
      猜你喜欢
      • 2015-02-10
      • 2023-03-10
      • 1970-01-01
      • 1970-01-01
      • 2021-12-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-28
      相关资源
      最近更新 更多