如何计算一组C文件中有多少个#ifdef子句至少具有#elif但没有#else?

Ira*_*ues 1 regex awk grep sed c-preprocessor

我有一堆C文件,我需要计算有多少#ifdef子句具有#elif子句,但在那些文件中没有#else子句,包括可能嵌套的#ifdef子句。例如,在第一个代码段中没有匹配项,而在第二个代码段中有两个匹配项:

1:没有匹配项(#ifdef包含#else子句)

#ifdef A
...
#elif B
...
#else
...
#endif
Run Code Online (Sandbox Code Playgroud)

2:两次匹配(有两个#ifdef子句带有#elif子句,但没有对应的#else)

#ifdef X1
...
#elif X2
...
#endif
...
#ifdef Y1
...
#elif Y2
...
#elif Y3
...
#endif
Run Code Online (Sandbox Code Playgroud)

我正在寻找一种使用某些命令行工具(例如grep,awk或sed)执行此操作的方法,但到目前为止还没有运气。因此,我仍然愿意寻求更简便的选择(如果有)。

我已经使用grep尝试过此正则表达式:('^(?=.*#elif)((?!#elif|#else).)(?=.*\#endif).)*$'一个#elif后面没有另一个#elif或#else并具有一个对应的#endif),但是它不起作用,因为子句位于不同的行。

Ed *_*ton 5

您需要编写一个递归下降解析器,该解析器在每次找到“ #ifdef”时下降,并在每次找到“ #endif”时返回。请参见如何在UNIX中比较和替换不同行中的字符串用awk编写的示例,。

您没有提供有用的样本输入或预期输出,因此我必须自己进行测试(因此可能不一定正是您所需要的),但是您将需要以下内容:

$ cat tst.awk
function descend(cond,    numElifs,numElses,gotEndif) {
    while ( !gotEndif && (getline > 0) ) {
        if      ( /#ifdef/ ) { descend($2) }
        else if ( /#elif/  ) { numElifs++  }
        else if ( /#else/  ) { numElses++  }
        else if ( /#endif/ ) { gotEndif++ }
    }
    print cond, numElses+0, numElifs+0, ((numElifs>0)&&(numElses==0) ? "UhOh" : "")
    return
}
/#ifdef/ { descend($2) }
Run Code Online (Sandbox Code Playgroud)

$ cat file
#ifdef A
#elif B
#else
  #ifdef C
  #elif D
  #endif

  #ifdef E
  #elif F
  #else
  #endif

  #ifdef G
  #elif H
    #ifdef I
    #else
    #endif
  #elif J
  #endif
#endif
Run Code Online (Sandbox Code Playgroud)

$ awk -f tst.awk file
C 0 1 UhOh
E 1 1
I 1 0
G 0 2 UhOh
A 1 1
Run Code Online (Sandbox Code Playgroud)

请注意,这是对getline的适当使用,但在其他地方使用它之前,请参阅http://awk.info/?tip/getline

所有关于确实需要语言解析器(例如处理注释或字符串中的#ifdef)而不是像这样的脚本的常见警告。