用于C++的 Pythonic 预处理器
Pythonic pre-processor for C++
我经常发现自己在想"为什么C++预处理器这么弱?
传统的计数器似乎是"C++使用模板元编程代替"。但是,在很多情况下,模板不会破解它。
例如,我目前正在编写一个蹦床,它采用 C 结构函数指针表(属于我正在接口的库)并将函数映射到相应 C++ 类的方法上。每次对库的更新更改 C 结构时,都会创建一些维护地狱。我需要在四个不同的地方修改源代码。
撇开更新不谈,我的代码中存在大量无法绕过的重复项。
我真正需要的是代码来生成代码。
那么使用类似于Python的东西作为预处理器怎么样呢?
#[
funcpointers = []
for i in members(TheCStruct):
if i.name.beginswith("tp_"):
funcpointers.append(i)
def cxxsig(x):
//ToDo
def cxxname(x):
//ToDo
#]
因此,会立即创建一个存储所有函数指针的预处理器对象。
稍后我们可以使用此变量:
class CxxWrapper
{
#[
for i in funcpointers:
print 'virtual ' + cxxsig(i) + '{ std::cout << "' + cxxname(i) + '"ctorn"; }'
#]
等。因此,上面的示例将生成如下行:
virtual int my_fp(void*, int, float) { std::cout << "my_fp ctorn"; }
类似的循环将处理建造蹦床等。当底层 C 结构发生变化时,一切都保持同步。
可以单步执行预处理器。在预处理器级别调试与调试 Python 代码一样简单。
所以我的问题是:有没有尝试过这样的事情?如果没有,有充分的理由不这样做吗?如果是这样,结论是什么?
考虑编写一个代码生成器 - 它可能特定于此问题或更通用。它不必是预处理器,至少是初始版本。您可以稍后开发/扩展它。
代码生成器是常用的,包括像这样的情况。要记住的一件事是构建系统中的正确依赖项,以便重新生成生成的文件等。
可能还没有这样广泛的工具,因为它在大多数用例中都不需要,并且在许多其他用例中,它会使源代码更难理解和维护(未来计划得很远)。
仅供参考 这样的预处理器(pcpp
)可以非常简单:
#! /usr/bin/python
"""Python 2.x C and C++ preprocessor."""
import re, sys, textwrap
def ml_escape(msg):
return re.sub(
r'[^n-+./w:;<>]', lambda match: '\%03o' % ord(match.group(0)), msg)
output = []; oa = output.append
def lit(s):
if s.endswith('n'):
oa('__import__("sys").stdout.write("""%s\n""")n' % ml_escape(s[:-1]))
elif s:
oa('__import__("sys").stdout.write("""%s""")n' % ml_escape(s))
def cod(s): oa(textwrap.dedent(s))
f = open(sys.argv[1])
data, i = f.read(), 0
sc = re.compile(r'(?sm)^[ t]*#[[ t]*$(.*?n)[ t]*#][ t]*$').scanner(data)
for match in iter(sc.search, None):
j = match.start(0)
lit(data[i : match.start(0)])
cod(data[match.start(1) : match.end(1)])
i = match.end()
lit(data[i : len(data)])
exec compile(''.join(output), f.name, 'exec') in {}
示例输入 ( t.cp
):
#include <stdio.h>
#[
import re
def c_escape(msg):
return re.sub(
r'[^-+./w]', lambda match: '\%03o' % ord(match.group(0)), msg)
def repeat_msg(count, msg):
for i in xrange(count):
print 'puts("%s");' % c_escape(msg)
#]
int main() {
#[
repeat_msg(5, 'hi"')
#]
return 0;
}
示例命令:
$ ./pcpp t.cp >t.c
$ gcc -W -Wall -s -O2 t.c
$ ./a.out
hi"
hi"
hi"
hi"
hi"
示例输出:
#include <stdio.h>
int main() {
puts("hi 42");
puts("hi 42");
puts("hi 42");
puts("hi 42");
puts("hi 42");
return 0;
}
上面的pcpp
实现小心地保留换行符,因此如果您的 Python 代码中有错误,回溯将包含文件名t.cp
和正确的行号。通过添加 #line
指令的发出,也可以修复 C(++) 错误消息中的行号。
(请注意,c_escape
不能按预期处理二合字母和三合字母。
- 错误:无效的预处理指令 #i 的意思是 #if?
- C++预处理会生成变量成员、资源库和映射
- 使用预处理指令检查是否包含标头?
- 预处理的 C/C++ 文件是否特定于计算机?
- 使用 GCC 对 C 文件进行部分预处理(不删除 "define" 指令)
- 在 CPLEX 中求解线性规划,无需剪切和预处理
- CPP -D 选项,用于预处理 Fortran 代码
- 错误:粘贴"tmp_UINT"和"+"未提供有效的预处理令牌
- 任务计划程序库的预处理不起作用 - 多定义错误
- Eclipse 问题 - 编译期间不考虑 .c 和 .cpp 文件中定义的预处理
- 使用python预处理后,C++(opencv)中的垫子类型数据与image_to_array相同
- Howo 使用 cl 预处理为 masm 组装生成一个单独的文件
- 我有一个预处理的 C/C++ 源文件 (cacti.i).如何从这个 .i 文件生成可执行二进制文件,以便我可以像 ./
- 如何使用Visual Studio C/C++编译器(cl.exe)来预处理我的objective-C代码
- 是具有预处理前分支实现的结构违反ODR
- 与不完整的Cholesky预处理的共轭梯度返回特征库的意外错误
- Visual Studio C - 无法输出预处理文件
- 在海湾合作委员会中加快宏观预处理的任何方法
- Xmllint未设置,而在路径中找不到XMLLINT;跳过XML预处理
- 当头文件被预处理时是否有一个预处理器选项显示?