我需要在预处理的C代码上使用pycparser(结果由' gcc -E'生成)。但是,我目前遇到的问题是我无法理解或解决。
我正在使用提供的示例year2.c和func_defs.py,我修改后使用各种预处理器和伪库无济于事。也许你们中的一些人可以调查一下,看看你是否可以重现/解决问题。我将附加所有必要的代码。
使用year2.c(常规样本文件)和year2.i(' gcc -E'输出)生成错误。后者没有可用的结果,而前者使用预处理器/ fakelib变体。
我创建了一个包含所有相关错误的bitbucket repo,使用的脚本(尽管只是它的最后一个变体)以及year2.c和year2.i文件。
感谢您的时间。
答案 0 :(得分:3)
您收到的错误是:
pycparser.plyparser.ParseError: /usr/lib/gcc/x86_64-linux-gnu/4.8/include/stdarg.h:40:27: before: __gnuc_va_list
表示导致错误的行(stdarg.h:40
):
typedef __builtin_va_list __gnuc_va_list;
在gcc中,正如其名称所示,__builtin_va_list
内置于编译器中。因此,不需要(或允许)声明该类型。
C编译器使用基于符号表的技术来解析类型名称是很常见的,因为如果你不能将typename与另一个标识符区分开来,语法中会有很多含糊之处。这样的解析器将假定未声明的标识符不是类型名称,如果__builtin_va_list
不是类型名称,则typedef
是语法错误。
所以我认为你使用的pyparser语法并不知道gcc内置类型(为什么要这样?)。
您的fakelib似乎包含相同的头文件。这并不奇怪,因为它很难伪造stdarg.h
;虽然从技术上讲是一个库头,但它是一小部分头文件的一部分,即使在独立(无标准库)实现中也必须由编译器提供:<float.h>, <iso646.h>, <limits.h>, <stdalign.h>,
<stdarg.h>, <stdbool.h>, <stddef.h>, <stdint.h>
,
<stdnoreturn.h>
(C11标准,第4条第6款)。这些必须由编译器实现,因为外部库无法充分了解已编译代码的性质以正确定义它们。
根据您对pyparsed输出的要求,您可以通过包含__builtin_va_list
的定义来解决此问题,例如:
typedef struct __builtin_va_list { } __builtin_va_list;
__builtin_va_list
不是唯一的内置gcc数据类型,尽管您可能不会遇到其他内容。因此,您可能需要迭代此解决方案几次,直到您实现您想要实现的任何目标。
答案 1 :(得分:0)
正如@rici解释了错误的原因。我更关注如何解决它。我从pycparser作者的博客中得到了我的回答 - http://eli.thegreenplace.net/2015/on-parsing-c-type-declarations-and-fake-headers
这个想法是pycparser需要知道anyheader.h包含什么,所以它可以正确地解析代码。实际上解析anyheader.h和它传递包含的所有其他头文件可能非常耗时,并且可能不需要你的任务,可以使用伪造的头文件。假的anyheader.h只包含解析所需的原始部分 - #define和typedef。
gcc -nostdinc -E -I/home/rg/pycparser-master/utils/fake_libc_include test.c > testPP.c
以上命令preprocess test.c,其中包含使用pycparser包提供的假标头的<stdio.h>
。 -nostdinc
标志用于阻止gcc自动包含的某些预设系统头目录。现在,使用例如解析预处理文件。下面的代码
import pycparser
pycparser.parse_file('testPP.c')
应该适用于大多数情况。如果它没有确保您提供预处理的所有依赖项。
如果某些标题没有提供伪造,你可以使用#defining伪造错误导致typedef,例如要解决由__builtin_va_list
引起的错误,您可以按照以下方式尝试伪造:
gcc -nostdinc -E -D'__builtin_va_list(x)=' -I/home/rg/pycparser-master/utils/fake_libc_include test.c > testPP.c