正则表达式以匹配多行上的C函数调用

时间:2012-08-03 11:24:13

标签: regex

我正在努力拼凑一个正则表达式以匹配函数调用,如下所示:

funcname (...(..
    ...)..(..(...
    )...)..)

因此该函数可以在多行上分布多个括号参数。

点可以是来自'('或')'的任何其他东西。

我会使用sed或grep的正则表达式。

谢谢, 瑞斯托

2 个答案:

答案 0 :(得分:0)

由于C是irregular language,您可能需要parser。当所有打开的括号再次关闭时,您将遇到的问题是解决问题。你可以用C做一些相当奇怪的事情。例如,你可以有一个参数,它本身就是一个函数定义。例如,在下面的程序中考虑如何区分a(),b(),c(),d(),e(),f()和g()?

#include <stdio.h>

#define f(c) c;

char a()
{
    return f('z');
}

/*
A function in a comment.
char b()
{
    return 'y';
}
*/

char c(char d()) 
{
    return d(); 
}

#if 0
This code is not included
char g()
{
    return 'v';
}
#endif

void main()
{
    printf ("A function in a string: char e() { return 'x'; }\n");
    printf ("The result from passing a to c: %c\n", c(a));
    printf ("Press enter to exit");
    getchar();
}

我已经看到许多尝试使用正则表达式执行此类操作,但大多数尝试最终会出现Catastrophic Backtracking个问题。

答案 1 :(得分:0)

所以,我继续用bash编写这个简单的解析器。它并不完美,但可以作为一个起点。例如,它无法区分函数调用是否被注释掉等等。

while read file; do
    linenum=0
    while IFS= read -r line; do
        (( linenum++ ))
        if [ $fmatch -eq 0 ]; then
            if [[ ! $line =~ $funcname ]]; then
                continue
            fi
            linenummatch=$linenum
            fmatch=1
            fstripped=0
            openbracket=0
            closebracket=0
            spacenum=0
        fi

        linelen=${#line}
        position=0
        while [ $position -lt $linelen ]; do
            if [ $fstripped -eq 0 ]; then
                subline=${line:$position}
                mlen=`expr "$subline" : "$funcname"`
                if [ $mlen -gt 0 ]; then
                    (( position+=mlen ))
                    resultstr=$funcname
                    fstripped=1
                    continue
                fi
                (( position++ ))
                continue
            fi
            ch=${line:$position:1}

            case $ch in
                '(' )
                    (( openbracket++ ))
                    spacenum=0
                    newresultstr="$resultstr$ch"
                    ;;

                ')' )
                    if [ $openbracket -eq 0 ]; then
                        fmatch=0
                        break
                    fi
                    (( closebracket++ ))
                    spacenum=0
                    newresultstr="$resultstr$ch"
                    if [ $closebracket -eq $openbracket ]; then
                        echo "$file $linenummatch $newresultstr"
                        fmatch=0
                        break
                    fi
                    ;;

                ' ' | '\t' )
                    if [ $spacenum -eq 0 ]; then
                        newresultstr=$resultstr' '
                    fi
                    (( spacenum++ ))
                    ;;

                '\n' )
                    # line feeds are skipped
                    ;;
                * )
                    if [ $openbracket -eq 0 ]; then
                        fmatch=0
                        break
                    fi
                    spacenum=0
                    newresultstr="$resultstr$ch"
                    ;;
            esac
            resultstr=$newresultstr
            (( position++ ))
        done
    done < $file
done < $filelist