用纯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通过的所有测试:
一个纯通用的python c(pre-)预处理器实现,只对预处理头非常有用 C++库包括单个文件和其他这样的构建或打包阶段MARARKY。 该实现可以用作一个python模块( 请参阅api参考资料 ) 或者作为命令行工具 可以代替传统的C预处理器(即它将接受类似的参数)。
您的包括可以为重量基准,以提高您的建设时间!见 --时间 和 --文件时间 选项。
C预处理器的一个非常独特的功能是 部分预处理,因此您可以 通过编程控制pcpp完成的预处理量和 由C或C++编译器的预处理器完成。最终的控制是通过子类化 然而,python中的预处理器类 为了您的方便,pcpp命令行工具附带了以下功能 部分预处理算法:
< DL>
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
节中,使其通过执行,但不影响
否则预处理逻辑。