【问题标题】:how to get the function declaration or definitions using regex如何使用正则表达式获取函数声明或定义
【发布时间】:2009-06-03 06:45:13
【问题描述】:

我只想得到类似的函数原型

int my_func(char, int, float)
void my_func1(void)
my_func2()

使用正则表达式和 python 从 C 文件中。

这是我的正则表达式格式:".*\(.*|[\r\n]\)\n"

【问题讨论】:

    标签: python regex


    【解决方案1】:

    这是我为此类任务编写的一个方便的脚本,但它不会给出函数类型。它仅适用于函数名称和参数列表。

    # Exctract routine signatures from a C++ module
    import re
    
    def loadtxt(filename):
        "Load text file into a string. I let FILE exceptions to pass."
        f = open(filename)
        txt = ''.join(f.readlines())
        f.close()
        return txt
    
    # regex group1, name group2, arguments group3
    rproc = r"((?<=[\s:~])(\w+)\s*\(([\w\s,<>\[\].=&':/*]*?)\)\s*(const)?\s*(?={))"
    code = loadtxt('your file name here')
    cppwords = ['if', 'while', 'do', 'for', 'switch']
    procs = [(i.group(2), i.group(3)) for i in re.finditer(rproc, code) \
     if i.group(2) not in cppwords]
    
    for i in procs: print i[0] + '(' + i[1] + ')'
    

    【讨论】:

    • @Michal,我相信我这样做是有原因的,但我现在不记得了 :)
    【解决方案2】:

    我在 Nick Dandoulakis 的 answer 的基础上构建了一个类似的用例。我想在 glibc 中找到socket 函数的定义。这会找到一堆名称中带有“socket”的函数,但没有找到socket,这突出了许多其他人所说的:可能有更好的方法来提取这些信息,比如编译器提供的工具。

    # find_functions.py
    #
    # Extract routine signatures from a C++ module
    import re
    import sys
    
    def loadtxt(filename):
        # Load text file into a string. Ignore FILE exceptions.
        f = open(filename)
        txt = ''.join(f.readlines())
        f.close()
        return txt
    
    # regex group1, name group2, arguments group3
    rproc = r"((?<=[\s:~])(\w+)\s*\(([\w\s,<>\[\].=&':/*]*?)\)\s*(const)?\s*(?={))"
    file = sys.argv[1]
    code = loadtxt(file)
    
    cppwords = ['if', 'while', 'do', 'for', 'switch']
    procs = [(i.group(1)) for i in re.finditer(rproc, code) \
     if i.group(2) not in cppwords]
    
    for i in procs: print file + ": " + i
    

    然后

    $ cd glibc
    $ find . -name "*.c" -print0 | xargs -0 -n 1 python find_functions.py | grep ':.*socket'
    ./hurd/hurdsock.c: _hurd_socket_server (int domain, int dead)
    ./manual/examples/mkfsock.c: make_named_socket (const char *filename)
    ./manual/examples/mkisock.c: make_socket (uint16_t port)
    ./nscd/connections.c: close_sockets (void)
    ./nscd/nscd.c: nscd_open_socket (void)
    ./nscd/nscd_helper.c: wait_on_socket (int sock, long int usectmo)
    ./nscd/nscd_helper.c: open_socket (request_type type, const char *key, size_t keylen)
    ./nscd/nscd_helper.c: __nscd_open_socket (const char *key, size_t keylen, request_type type,
    ./socket/socket.c: __socket (int domain, int type, int protocol)
    ./socket/socketpair.c: socketpair (int domain, int type, int protocol, int fds[2])
    ./sunrpc/key_call.c: key_call_socket (u_long proc, xdrproc_t xdr_arg, char *arg,
    ./sunrpc/pm_getport.c: __get_socket (struct sockaddr_in *saddr)
    ./sysdeps/mach/hurd/socket.c: __socket (int domain, int type, int protocol)
    ./sysdeps/mach/hurd/socketpair.c: __socketpair (int domain, int type, int protocol, int fds[2])
    ./sysdeps/unix/sysv/linux/socket.c: __socket (int fd, int type, int domain)
    ./sysdeps/unix/sysv/linux/socketpair.c: __socketpair (int domain, int type, int protocol, int sv[2])
    

    就我而言,thisthis 可能对我有帮助,但我似乎需要阅读汇编代码才能重用那里描述的策略。

    【讨论】:

      【解决方案3】:

      我认为正则表达式不是您的最佳解决方案。有很多陷阱,如 cmets、字符串中的文本等,但如果您的函数原型具有共同的风格:

      type fun_name(args);
      

      那么\w+ \w+\(.*\); 在大多数情况下应该可以工作:

      mn> egrep "\w+ \w+\(.*\);" *.h
      md5.h:extern bool md5_hash(const void *buff, size_t len, char *hexsum);
      md5file.h:int check_md5files(const char *filewithsums, const char *filemd5sum);
      

      【讨论】:

      • +1 表示这不是一个好主意。 C 源代码不是常规语言。
      【解决方案4】:

      看看你的 C 编译器是否有一个选项来输出一个只包含它正在编译的原型的文件。对于 gcc,它是 -aux-info FILENAME

      【讨论】:

        【解决方案5】:

        我认为这个应该做的工作:

        r"^\s*[\w_][\w\d_]*\s*.*\s*[\w_][\w\d_]*\s*\(.*\)\s*$"
        

        将扩展为:

        string begin:   
                ^
        any number of whitespaces (including none):
                \s*
        return type:
          - start with letter or _:
                [\w_]
          - continue with any letter, digit or _:
                [\w\d_]*
        any number of whitespaces:
                \s*
        any number of any characters 
          (for allow pointers, arrays and so on,
          could be replaced with more detailed checking):
                .*
        any number of whitespaces:
                \s*
        function name:
          - start with letter or _:
                [\w_]
          - continue with any letter, digit or _:
                [\w\d_]*
        any number of whitespaces:
                \s*
        open arguments list:
                \(
        arguments (allow none):
                .*
        close arguments list:
                \)
        any number of whitespaces:
                \s*
        string end:
                $
        

        匹配所有可能的组合并不完全正确,但应该适用于更多情况。如果您希望它更准确,请告诉我。

        编辑: 免责声明 - 我对 Python 和正则表达式都很陌生,所以请放纵 ;)

        【讨论】:

          【解决方案6】:

          尝试使用正则表达式“解析”C 代码(或至少提取一些信息)有很多陷阱,我肯定会为您最喜欢的解析器生成器借用 C(比如 Bison 或 Python 的任何替代方案,到处都有C语法示例)并在相应的规则中添加动作。

          另外,不要忘记在解析之前对文件运行 C 预处理器。

          【讨论】:

          • 没错。不管你的正则表达式有多好,它总是充其量是一个实际 C 解析器完成的处理的粗略近似。既然已经有为此目的量身定制的工具,为什么还要尝试重新发明轮子。
          【解决方案7】:

          下面的正则表达式也考虑了析构函数或常量函数的定义:

          ^\s*\~{0,1}[\w_][\w\d_]*\s*.*\s*[\w_][\w\d_]*\s*\(.*\)\s*(const){0,1}$
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2018-08-04
            • 2019-11-30
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2016-10-14
            • 1970-01-01
            相关资源
            最近更新 更多