我有一个C文件(为了简单起见,假设它不包含任何内容(。这个C文件需要几个文字数字的定义才能正确编译,我想弄清楚这些定义是什么。
当然,人们可以尝试编译文件,但在某个时候我们会开始失败;通过一些故障恢复,我们可能会收到有关其他定义的故障通知。但是,这不是我想要的:
- 我对完成程序的编译不感兴趣。构建一个语法树(甚至是某种简化的语法树(就足够了
- 我可以假设,除了缺少宏之外,这个程序在语法上是正确的。对C来说,这意味着它在语法上是正确的,句号
- 我可以假设相关的宏都是大写的,即它们的形式为
[A-Z][A-Z_0-9]*
(
获取未定义宏列表的替代方案是什么?
动机:事实上,我正在向动态编译库中输入一些东西,我想事先检查是否已经定义了所有必要的宏,而不知道文件需要哪些宏(即,对于不同的输入文件,它可能是不同的宏(
丑陋的后备解决方案:
显然,您的后备方案是只编译程序。但是,要做到这一点,同时尽量减少不相关的信息和不相关的内容。这将依赖于编译器,但以GCC为例,您可以:
- 避免任何输出生成
- 取消显示警告
- 抑制注释
- 严格遵守标准,无GNU扩展
- 禁用GCC坚持使用的那些愚蠢的花哨引号
。。。使用各种命令行开关,并从标准输入流而不是文件中获取输入时(到目前为止,我找到的唯一方法是抑制一些注释(。看起来像:
cat your_program.c
| LC_CTYPE=C gcc -std=c99 -fsyntax-only -x c -fcompare-debug-second -
输出可能看起来像:
<stdin>: In function 'mult':
<stdin>:3:18: error: 'MY_CONSTANT' undeclared (first use in this function)
现在,如果您的程序除了未定义的宏(=未声明的标识符(之外是正确的,那么您可以通过一些shell脚本轻松地解析上面的内容:
cat your_program.c
| LC_CTYPE=C gcc -std=c99 -fsyntax-only -x c -fcompare-debug-second -
| sed -r '/error: /!d; s/^.*error: '"'//; s/'.*//;"
| sort -u
这还有一个缺点,即不能完全嵌入到程序中,即不能使用程序中的某个库调用部分编译,然后以编程方式解析输出。您需要一个system()
类型的调用。
注意:如果您的程序可能有其他错误,则sed
命令中的换行模式需要更具体一些
您可以围绕这样一个想法使用一些东西,即C文件中注释外的每个标识符(如非关键字(都必须在某个地方声明。(我想!对吗?(
其基本思想是生成一个此类标识符的列表,并搜索程序,然后搜索每个标识符的声明所包含的标头。虽然这可以手动和临时完成,但索引所有潜在的头文件并使用ctags之类的东西进行索引和查找可能是有意义的(正如我刚刚学到的,有一个libctags(。
我认为解决方案不一定是完美的——遗漏的案例只会导致编译失败——但您希望减少此类案例。在这种情况下,对标识符的源代码的解析不必是完美的(它可以忽略嵌套的注释等(;手动";付出了可以接受的努力。