识别C项目中所有变量的类型

7 投票
5 回答
2986 浏览
提问于 2025-04-15 11:12

我正在尝试写一个程序,用来检查一些C语言源代码是否符合变量命名的规则。为了做到这一点,我需要分析源代码,并识别所有局部变量和全局变量的类型。

最终结果很可能是一个Python程序,但分析代码的工具可以是一个Python模块,或者是一个能生成易于解析报告的应用程序。或者(下面会详细说明)也可以是从编译器提取信息的一种方式(通过报告或类似的方式)。如果这有帮助的话,很可能会使用Keil的ARM编译器。

我一直在尝试使用ctags,这个工具对于找到所有的typedef和宏定义等非常有用,但它并不能直接找到变量的类型,特别是当定义跨越多行时(我希望这种情况不会发生!)。

举个例子:

static volatile u8 var1; // should be flagged as static and volatile and a u8 (typedef of unsigned 8-bit integer)
volatile   /* comments */   
    static /* inserted just to make life */
        u8 /* difficult! */   var2 =
        (u8) 72
           ; // likewise (nasty syntax, but technically valid C)
const uint_16t *pointer1;  // flagged as a pointer to a constant uint_16t
int * const pointer2; // flagged as a constant pointer to an int
const char * const pointer3; // flagged as a constant pointer to a constant char
static MyTypedefTYPE var3; // flagged as a MyTypedefTYPE variable
u8 var4, var5, var6 = 72;
int *array1[SOME_LENGTH]; // flagged as an array of pointers to integers
char array2[FIRST_DIM][72]; // flagged as an array of arrays of type char

等等等等

这个程序还需要识别变量是局部的还是全局的(ctags可以做到这一点),如果是局部变量,我希望能知道它们被声明在哪个函数里。

此外,我还想对函数做类似的事情:识别返回类型,是否是静态的,以及所有参数的类型和名称。

不幸的是,由于C语言的语法有一定的灵活性,比如参数的顺序和参数之间允许的空格数量,这让事情变得相当复杂。我尝试过用一些复杂的正则表达式来完成这项工作,但效果并不好,因为可以应用的情况太多,正则表达式很快就变得难以管理。我不禁想,编译器一定能做到这一点(为了正常工作!),所以我在想是否有可能提取这些信息。Keil编译器似乎会为每个编译的源文件生成一个“.crf”文件,这个文件似乎包含了该文件中声明的所有变量,但它是二进制格式的,我找不到任何关于如何解析这个文件的信息。或者从ctags中获取信息的方式也会很完美。

如果有人能提供帮助,我将非常感激。

谢谢,

Al

5 个回答

2

你想做的事情其实是一种轻量级的静态分析。你可以试着看看维基百科上提到的一些工具,或许会有帮助。

自己解析C代码听起来不是个好主意,这样做可能会让你陷入麻烦。如果你真的想这么做,那么[f]lex和yacc(bison)是编译器开发者常用的工具。

另外,如果ctags或cscope能帮你完成80%的工作,它们的源代码也是很容易找到的。剩下的20%就只是编程的小事了。:)

3

可以换个角度来考虑这个问题。你已经有一个能完全理解C语言类型系统的解析器,那就是编译器本身。所以,你可以开启完整的调试支持来编译项目,然后深入研究调试数据。

如果你的系统是基于binutils支持的格式,那么你需要的大部分细节都可以通过BFD库来了解。

微软的调试格式在MSDN的文档和库中(某种程度上)是有支持的,不过我今天的搜索能力不太强,找不到我知道的相关文章来链接给你。

Keil的8051编译器(我这里没有使用他们的ARM编译器)使用的是Intel OMF或OMF2格式,并且文档说明调试符号是为他们的调试器或“任何兼容Intel的模拟器”准备的。关于OMF的规格可以在Keil网站上找到,所以我想他们其他编译器的类似规格也应该是有的。

快速浏览一下Keil的网站似乎表明,他们放弃了自己的ARM编译器,转而授权使用ARM的RealView编译器,这个编译器似乎使用ELF对象和DWARF格式的调试信息。DWARF应该是被BFD支持的,应该能提供你需要知道的一切,以验证类型和名称是否匹配。

5

有很多Python的解析器包可以用来描述一种语法,然后它会生成Python代码来解析这种语法。

Ned Batchelder写了一篇非常不错的总结

在这些包中,Ply被用在一个叫pycparser的项目里,这个项目可以解析C语言的源代码。我建议你可以从这个开始。

其他一些解析器项目也可能有示例的C语言解析器。

编辑:我刚注意到,pycparser甚至有一个示例Python脚本,可以用来解析C语言的类型声明,就像以前的cdecl程序一样。

撰写回答