【问题标题】:Making a preprocessor with Python用 Python 做一个预处理器
【发布时间】:2013-06-01 04:13:55
【问题描述】:

我基本上需要用 Python 编写一个 C 预处理器,我四处寻找,因为我需要完全自定义我的代码并对正在发生的事情有一个完美的理解,所以我最好自己编写。

这就是我所在的位置:我首先解析一些头文件 (.h) 以找到 #define 关键字并使用所有已建立的指令(它们的值都有一个)建立一个字典。然后我需要根据之前找到的指令解析源文件 (.c)。 我目前用来检查代码是否需要处理的机制如下:我获取所有定义的名称及其值并执行exec("define_name = define_value")(未指定时值为'1')。然后为了解决诸如#if defined DEFINE_1 || defined DEFINE_2 && (DEFINE_3 == 10) .... 之类的条件,我删除了 C 预处理器关键字,使它们成为 Python 风格,从而生成 DEFINE_1 or defined DEFINE_2 and (DEFINE_3 == 10)。

我终于在那个字符串上使用eval(...) 来找出结果。

问题是我想知道是否有必要使用 exec / eval 并且很多人不愿意使用它们,有没有更好的解决方案?

【问题讨论】:

  • 根据我使用基于 Python 的预处理器的经验,Python 速度太慢,无法实现。此外,例如标准库MSVC 不好预处理(尽管编译起来更糟)。你想解决什么问题?

标签: python c preprocessor c-preprocessor


【解决方案1】:

当然,exec() 不是必需的,也不应该使用。我什至不确定你期望它做什么,因为它会调用一个 shell 来设置一个只存在于子 shell 中的变量。

通常,您应该避免使用eval() 语句,因为这很少是正确的做法。

那么,你能做什么呢?

1) 首先,因为可以编写一个语句覆盖前一个语句的程序,所以您不能预处理 .h 文件(甚至假设您正在寻找的 #define 是仅在 .h 文件中)并让它工作。考虑一下:

#define foo 1
#if foo == 1
this line is true!
#endif
#define foo 0

如果您预处理所有内容,您会将“foo”设置为 1,然后设置为 0,然后再评估 #if。你不能那样做……

2) 更常见的做法是编写一个解析器,它可以逐行处理并一次处理每一行的内容。这样,您甚至可以编写一个递归函数来处理 #include 语句,这样您就可以只从 .c 文件开始,让它拉入它正在使用的正确标题,而不是要求以其他方式指定它们。

最后,你应该得到类似(在一个名为“read_file”的函数中):

# ... file opening not shown ...

for line in file:
    includematch = re.match("#include\\s+\\"(.*)\\"", line)
    if match:
        # deal with an include statement by calling a function to process it
        read_file(includematch.group(1), definedict)

    definematch = re.match("#define\\s+(\\w+)\\s+(.*)")
    if definematch:
        # deal with define statements by saving it in a dict
        definedict[match.group(1)] = definedict[match.group(2)]

    #....

显然,如果我向您展示了整个解决方案(上面的代码几乎不是漂亮的代码,但为了展示目的它很简洁),我会为您解决您的问题(家庭作业?)。但与您之前的路径相比,上述方法是构建整个事物的更好方法。

【讨论】:

  • 感谢您的回答,这不是家庭作业,而是工作;)。确切地说,我从事的项目非常严格,不允许人们将 #define 放在他们想要的位置(我只有 1 或 2 个文件,只是用 #define 填充,所以我只需要解析它),所以不会像你说的那样重新定义。我目前有一个工作代码,但有大量eval/exec,主要问题是我如何处理复杂的#if/#elif ...条件,而到目前为止已经解析了什么而不使用eval和exec?
  • 嗯,你必须要么做一个成熟的解析器(这更难但更安全)或评估。 eval 允许您跳过实现 paren 匹配、逻辑等,您可以专注于仅替换值,然后 eval 其余部分。您始终可以从 eval 开始,然后从那里开始工作,理想情况下在将来替换它。
  • 注意:仅仅因为您现在有一个结构化的严格环境并带有某些规则,并不意味着这些规则将来不会改变。您可能会考虑以正确的方式首先尽可能多地镜像 cpp,以帮助自己适应未来。
  • 是的,我已经尽可能多地从当前项目中抽象出来,但事情必须完成......一如既往,感谢您的回答和建议:)
  • 另请注意,您完全有可能在属于实现的头文件中找到定义和重新定义,如答案所示。因此,即使您的编码标准不允许,您仍然需要考虑它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-07-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-16
相关资源
最近更新 更多