用纯python编写的c99预处理器

pcpp的Python项目详细描述


用纯python编写的c99预处理器

(c)2018-2019年niall douglas http://www.nedproductions.biz/ 和(c)2007-2019年david beazley http://www.dabeaz.com/

pypi: https://pypi.python.org/pypi/pcpp github: https://github.com/ned14/pcpp api参考文档: https://ned14.github。IO/PCPP/

travis master branch python v2和v3通过的所有测试: travis

一个纯通用的python c(pre-)预处理器实现,只对预处理头非常有用 C++库包括单个文件和其他这样的构建或打包阶段MARARKY。 该实现可以用作一个python模块( 请参阅api参考资料 ) 或者作为命令行工具 可以代替传统的C预处理器(即它将接受类似的参数)。

您的包括可以为重量基准,以提高您的建设时间!见 --时间 --文件时间 选项。

C预处理器的一个非常独特的功能是 部分预处理,因此您可以 通过编程控制pcpp完成的预处理量和 由C或C++编译器的预处理器完成。最终的控制是通过子类化 然而,python中的预处理器类 为了您的方便,pcpp命令行工具附带了以下功能 部分预处理算法:

< DL>
passthru定义
传递但仍执行defines和undefs(如果不是总是由 预处理器逻辑。这样可以确保包含的输出集完全相同 宏,就好像你包含了原始的,加上包含保护工作。
直通未绑定包括
如果未找到 include ,请将其通过未修改的。这很有用 用于传递包括系统标题的内容。
直通未定义表达式
这是最强大的传递算法之一。如果表达式传递给 如果(或其brethern)包含未知宏,请使用 已知宏并通过未执行的 ,然后通过剩余的块。 依次计算每个elif,如果它不包含未知宏,则 立即执行。最后,任何 \else 子句总是通过未执行的 传递。 请注意,包含保护通常会击败此算法,因此这些是专门检测到的 忽略。
直通注释
pcpp的一个主要用例是作为doxygen的预处理器 其预处理器无法处理任何预处理的参考文档工具 任何复杂性。 pcpp 可以部分执行doxygen 无法,因此产生输出,从而产生良好的效果与强氧。 因此,传递包含doxygen标记的注释的能力非常有用。

标准(不合规)

pcpp 通过一个修改版的mcpp 测试套件。所做的修改是澄清带有额外括号的三元运算符, 加上那些测试表达式求值中不寻常的特殊特性(请参见详细信息 以下说明)。它还传递了"预处理器折磨"扩展片段的列表 在c11标准中,正确地扩展了一些非常复杂的递归宏扩展 其中展开导致形成新的宏展开。在这里面,它轻而易举地击败了 msvc预处理器,应该处理大多数c99预处理器元编程。 如果将其输出与gcc或clang的预处理器的输出并排进行比较,则 非常接近,空白行折叠是唯一的区别。

最不合格的部分是 \if 表达式 解析(为执行基于 欢迎访问http://www.dabeaz.com/ply/" rel="nofollow">http://www.dabeaz.com/ply/。实际上,在现实世界的大多数代码中,您 不会注意到离开,如果你注意到了,额外的括号应用到 将子表达式分组,这样python的eval就可以正确执行。

以下是已知不符合C99标准的完整详细清单。我们有 被告知 pcpp 不通过boost.wave预处理器测试套件,但是 大多数人被咬的几率很低。如果是的话,用错误拉请求 欢迎修复和新的修复单元测试。

注意,大多数预处理器最初是由david beazley编写的 从他优秀的python lex yacc库ply(http://www.dabeaz.com/ply/" rel="nofollow">http://www.dabeaz.com/ply/)中 隐藏在里面,没有明显的堆溢出 关于纯python c预处理器实现的问题。这个 实现修复了许多一致性错误(最初的目的不是 严格遵循c标准),并添加了一个基于c11预处理器的测试套件 酷刑样本加上mcpp预处理器测试套件。不过,这个项目 没有大卫的工作是不可能的,所以请摘下帽子向他鞠躬。

命令行工具

命令行工具的帮助

usage: pcpp [-h] [-o [path]] [-D macro[=val]] [-U macro] [-N macro] [-I path]
            [--passthru-defines] [--passthru-unfound-includes]
            [--passthru-unknown-exprs] [--passthru-comments]
            [--disable-auto-pragma-once] [--line-directive [form]] [--debug]
            [--time] [--filetimes [path]] [--version]
            [input [input ...]]

A pure universal Python C (pre-)preprocessor implementation very useful for
pre-preprocessing header only C++ libraries into single file includes and
other such build or packaging stage malarky.

positional arguments:
  input                 Files to preprocess

optional arguments:
  -h, --help            show this help message and exit
  -o [path]             Output to a file instead of stdout
  -D macro[=val]        Predefine name as a macro [with value]
  -U macro              Pre-undefine name as a macro
  -N macro              Never define name as a macro, even if defined during
                        the preprocessing.
  -I path               Path to search for unfound #include's
  --passthru-defines    Pass through but still execute #defines and #undefs if
                        not always removed by preprocessor logic
  --passthru-unfound-includes
                        Pass through #includes not found without execution
  --passthru-unknown-exprs
                        Unknown macros in expressions cause preprocessor logic
                        to be passed through instead of executed by treating
                        unknown macros as 0L
  --passthru-comments   Pass through comments unmodified
  --disable-auto-pragma-once
                        Disable the heuristics which auto apply #pragma once
                        to #include files wholly wrapped in an obvious include
                        guard macro
  --line-directive [form]
                        Form of line directive to use, defaults to #line,
                        specify nothing to disable output of line directives
  --debug               Generate a pcpp_debug.log file logging execution
  --time                Print the time it took to #include each file
  --filetimes [path]    Write CSV file with time spent inside each included
                        file, inclusive and exclusive
  --compress            Make output as small as possible
  --version             show program's version number and exit

Note that so pcpp can stand in for other preprocessor tooling, it ignores any
arguments it does not understand.

快速演示直通模式

让我们看一个直通模式的例子。这是原件:

#if !defined(__cpp_constexpr)
#if __cplusplus >= 201402L
#define __cpp_constexpr 201304  // relaxed constexpr
#else
#define __cpp_constexpr 190000
#endif
#endif
#ifndef BOOSTLITE_CONSTEXPR
#if __cpp_constexpr >= 201304
#define BOOSTLITE_CONSTEXPR constexpr
#endif
#endif
#ifndef BOOSTLITE_CONSTEXPR
#define BOOSTLITE_CONSTEXPR
#endif

pcpp测试。h --passthru定义 --passthru未知表达式 将输出:

#if !defined(__cpp_constexpr)
#if __cplusplus >= 201402
#define __cpp_constexpr 201304
#else
#define __cpp_constexpr 190000
#endif
#endif
#ifndef BOOSTLITE_CONSTEXPR
#if __cpp_constexpr >= 201304
#define BOOSTLITE_CONSTEXPR constexpr
#endif
#endif
#ifndef BOOSTLITE_CONSTEXPR
#define BOOSTLITE_CONSTEXPR
#endif

这是因为未定义constexpr,所以是因为 --passthru unknown expr标志 我们将遍历其中的所有内容,如果block unexecuted 即defines和undefs不是由 pcpp 。让我们定义constexpr

p cpp测试。h --passthru定义 --passthru未知表达式 -d

#line 8 "test.h"
#ifndef BOOSTLITE_CONSTEXPR
#endif
#ifndef BOOSTLITE_CONSTEXPR
#define BOOSTLITE_CONSTEXPR
#endif

所以,现在差别很大。我们首先执行整个if块,因为现在定义了 \cpp\u constexpr ,因此 留下空白。让我们尝试将constexpr设置得更高一点:

p cpp测试。h --passthru定义了 --passthru未知表达式 -d \uu cpp_constexpr=201304

#line 8 "test.h"
#ifndef BOOSTLITE_CONSTEXPR
#define BOOSTLITE_CONSTEXPR constexpr
#endif

如您所见,与已知的constexpr相关的行将被执行和删除,并通过 中包含未知宏的任何if块表达式。

如果希望宏已知但未定义,该怎么办?u(取消定义)标志在pass中有一个明显的含义 通过模式,使宏不再未知,而是已知未定义。

p cpp测试。h --passthru定义 --passthru未知表达式 -u

#if __cplusplus >= 201402
#define __cpp_constexpr 201304
#else
#define __cpp_constexpr 190000
#endif
#ifndef BOOSTLITE_CONSTEXPR
#endif
#ifndef BOOSTLITE_CONSTEXPR
#define BOOSTLITE_CONSTEXPR
#endif

这里,已知未定义constexpr,所以执行第一个子句,但是 未知,因此整个块都是未执行的。在下一个测试中比较 到201304,它仍然是未知的,所以0>;=201304是被测试的表达式,这是错误的, 因此,以下章节将被完全删除。

帮助使用源代码注释

在命令行上使用-d(define)、-u(undefine)和-n(never define)可以实现很多功能, 但是对于更复杂的预处理,如果没有源代码,很难通过正确的逻辑 注释。

pcpp 允许您注释由于使用未知宏而通过的if块的哪个部分 在传递之外也要执行。对于这种用法,pcpp总是错误的,或者 pcpp_always_u true_uu 它告诉 pcpp 临时开始执行传递 预处理器命令,例如

#if !defined(__cpp_constexpr)
#if __cplusplus >= 201402L
#define __cpp_constexpr 201304
#elif !__PCPP_ALWAYS_FALSE__     // pcpp please execute this next block
#define __cpp_constexpr 190000
#endif
#endif
#ifndef BOOSTLITE_CONSTEXPR
#if __cpp_constexpr >= 201304
#define BOOSTLITE_CONSTEXPR constexpr
#endif
#endif
#ifndef BOOSTLITE_CONSTEXPR
#define BOOSTLITE_CONSTEXPR
#endif

请注意,在任何其他预处理器中,pcpp始终为false,并且 在pcpp中为false。然而,它会导致p cpp执行 \cpp constexpr 到190000的定义:

pcpp测试。h --passthru定义 --passthru未知表达式

#if !defined(__cpp_constexpr)
#if __cplusplus >= 201402
#define __cpp_constexpr 201304
#elif 1
#define __cpp_constexpr 190000
#endif
#endif
#ifndef BOOSTLITE_CONSTEXPR
#endif
#ifndef BOOSTLITE_CONSTEXPR
#define BOOSTLITE_CONSTEXPR
#endif

这是标记 \else 子句的一种方法,因此它们总是在正常的预处理器中执行 也可以通过 pcpp 执行。当然,您也可以放置 u pcpp_always_u false_u 在任何 if 节中,使其通过执行,但不影响 否则预处理逻辑。

欢迎加入QQ群-->: 979659372 Python中文网_新手群

推荐PyPI第三方库


热门话题
gwt java。lang.UnsupportedClassVersionError:不受支持的专业。小版本51.0   java XML解析器trycatch不工作   java Jackson MRBean不工作,无法构造实例   javascript是检查参数的更好方法吗?   java在发生冲突时从ArrayList中删除对象   JavaSpringWebFlux和KeyClope JWTRESTAPI   java Selected选项在微调器中不可见   java在增加分区后,有没有办法在ApacheKafka中保持顺序?   java添加SourceRoot会导致spring启动应用程序出错   java Spring引导:任何bean都没有实现ReactiveCrudepository   java无法注册我的自定义AbstractAnnotationConfigDispatcherServletInitializer   TCP连接上的java Caesar密码   java树集排序不正确   java如何在自定义查询中加载@ElementCollection?