【问题标题】:Pycparser not working on preprocessed codePycparser 无法处理预处理代码
【发布时间】:2015-03-11 10:11:30
【问题描述】:

我需要在预处理的 C 代码上使用 pycparser(由 'gcc -E' 产生的结果)。但是我目前遇到了我无法理解或解决的问题。

我正在使用提供的示例 year2.c 和 func_defs.py,我对其进行了修改以使用各种预处理器和假库,但无济于事。也许你们中的一些人可以调查一下,看看是否可以重现/解决问题。我将附加所有必要的代码。

错误是使用 year2.c(常规示例文件)和 year2.i('gcc -E' 输出)生成的。后者没有可用的结果,而前者同时使用预处理器/fakelib 变体。

我创建了一个包含所有相关错误的 bitbucket 存储库、使用的脚本(尽管只是它的最后一个变体)以及 year2.c 和 year2.i 文件。

Error & Sample Repo

感谢您的宝贵时间。

【问题讨论】:

    标签: python-2.7 preprocessor pycparser


    【解决方案1】:

    你得到的错误是:

    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 编译器使用基于符号表的技术来解析类型名是很常见的,因为如果您无法将类型名与另一个标识符区分开来,语法中就会出现许多歧义。这样的解析器将假定未声明的标识符不是类型名,如果__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>,和 &lt;stdnoreturn.h&gt;(C11 标准,第 4 条,第 6 段)。这些必须由编译器实现,因为外部库无法充分了解编译代码的性质来正确定义它们。

    根据您对 pyparsed 输出的要求,您可以通过包含 __builtin_va_list 的定义为 pyparser 解决此问题,例如:

    typedef struct __builtin_va_list { } __builtin_va_list;
    

    __builtin_va_list 不是唯一的内置 gcc 数据类型,尽管您可能不会遇到其他数据类型。因此,您可能需要多次迭代此解决方案,直到实现您想要实现的目标。

    【讨论】:

    • 嗨,对不起,我花了这么长时间才回复你。我实施以更改您在给我错误的&lt;stdarg.h&gt; 文件中提出的建议,但错误保持不变。这是文件中的位置现在的样子。 #ifndef __GNUC_VA_LIST #define __GNUC_VA_LIST typedef struct __builtin_va_list {}; typedef __builtin_va_list __gnuc_va_list; #endif如果您有任何其他意见,我很乐意听到。
    • @Araiguma:糟糕,抱歉。这是一个明显的错误。我不知道我在想什么。应该是typedef struct __builtin_va_list {} __builtin_va_list;;我在答案中修复了它。
    【解决方案2】:

    @rici 已经解释了错误的原因。我会更多地关注如何解决它。我从 pycparser 作者的博客中得到了答案—— http://eli.thegreenplace.net/2015/on-parsing-c-type-declarations-and-fake-headers

    这个想法是 pycparser 需要知道 anyheader.h 包含的内容,以便它可以正确解析代码。由于实际解析 anyheader.h 和它传递包含的所有其他标头,可能非常耗时,并且您的任务可能不需要,因此可以使用 fakeheaders。伪造的 anyheader.h 将仅包含解析所需的原始部分 - #defines 和 typedefs。

    gcc -nostdinc -E -I/home/rg/pycparser-master/utils/fake_libc_include test.c &gt; testPP.c

    上面的命令使用 pycparser 包提供的假标头预处理包含&lt;stdio.h&gt; 的 test.c。 -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 &gt; testPP.c

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-21
      相关资源
      最近更新 更多