PyMacroParser 宏解析工具
PyMarcoParser宏解析工具
题目要求
题目描述
假定有CPP 源码文件(.cpp) 仅有如下内容
- 包含C/C++ 风格的注释: // 及 /**/
- 包含空白字符
- 只包含 #ifdef/#ifndef/#else/#endif/#define/#undef 这几个宏指令的应用
- #define 定义仅有如下定义情况:
#define identifier token-stringopt - 其中 token-stringopt 只有兼容如下几种C/C++指定基本类型常量表示内容:整型,浮点,布尔(true, false),字符(忽略宽字符),字符串,及各上述基本类型组成的聚合。
- 聚合:结构体 或者 数组初始化,均可用聚合初始化形式{}表示,聚合类型可以多维(嵌套).
- 除如上指定内容及适当的空格制表符换行等等等,不再有其他内容。不考虑字符映射及三元组序列, 不考虑行拼接
–
注释,空白字符,常量,和字符串的类型定义请参考如下相关描述文档
聚合初始化参考如下网址中关于聚合初始化的表述
预处理器相关参考如下文档,特别注意 “转换阶段” 与 “预处理器指令”
有如上特点的CPP源码文件,为了实现与Python脚本兼容对接,
请基于Python 2.7.X 封装实现一个可重用的类,要求如下:
- 该类能读取 .cpp文件中的宏定义,并接收可变化的预定义宏串, 并根据两者,解析出当前所有的可用的宏定义。全部字符串都是ANSI编码。
- 可用宏定义可转为Python字典模式输出。 其中宏名转为字符串作为字典key, 若有与宏对应的常量定义转为对应python数据类型后作为字典的value。 类型对应关系见附表。若无任何常量则value为None
- 可用宏定义可再次导出成为只含有当前宏定义的CPP源文件。
- 请遵循CPP宏及常量类型的定义标准,确保相同常量变换后数值上保持一致,类型上与Python保持兼容(由于python转换过程中可能会损失掉C的具体类型信息,比如char 可能最终变为 int,具体表示方法也会有所变化,比如16进制最终表示为10进制, 故多次转换后能保持最终常量的值相等即可。 类型转换标准见“注意”)
- 只允许使用Python内置模块(如sys、math)和string模块,不允许使用其他标准模块及任何第三方开发库(包括但不限于re),不要使用 evel/exec 懒人解析, 不要使用copy;deepcopy等懒人复制。
- 独立完成作业,并代码中给予必要的注释。
- 代码采用UTF-8编码
该类的类名要求为PyMacroParser,所提供的方法约定如下:
- load(self, f) 从指定文件中读取CPP宏定义,存为python内部数据,以备进一步解析使用。 f为文件路径,文件操作失败抛出异常;
无返回值。若在初步解析中遇到宏定义格式错误 或 常量类型数据定义错误应该抛出异常。 - preDefine(self, s) 输入一堆预定义宏名串,宏名与宏名之间以”;” 分割。
比如串"mcname1;mcname2"相当于把
#define mcname1
#define mcname2
加在了CPP宏数据的最前面。
而空串"" 表示没有任何预定义宏。 显然,预定义宏会影响对CPP文件数据内的可用宏解析。
preDefine函数可被反复调用,每次调用自动清理掉之前的预定义宏序列。 preDefine 与 load的CPP宏定义数据,一起决定最终可用的宏。 - dumpDict(self) 返回一个dict, 结合类中存储的CPP宏定义与预定义的宏序列,解析输出所有的可用宏到一个字典,其中宏名转为字符串后作为字典的key, 若有与宏名对应的常量转为python数据对象,无常量则存为None, 注意不要返回类中内置的对象的引用。 解析过程若遇到宏定义格式错误 或 常量类型数据定义错误应该抛出异常;
- dump(self, f) 结合类中的CPP宏定义数据与预定义宏序列,解析输出所有可用宏存储到新的CPP源文件,f为CPP文件路径,文件若存在则覆盖,文件操作失败抛出异常。 若遇到宏定义格式错误 或 常量类型数据定义错误应该抛出异常。 注意,转换后的常量数据表示应与Python对应类型兼容, 所以常量类型的长度存储信息可能丢失(例如 short 转为 int; float 转为 double 等), 允许特别表示方法信息丢失(例如原本16进制 统一变成10进制表示等)。 导出宏的顺序不做特别要求。
示例
Input
假设源文件 a.cpp 中有如下内容
#ifndef MCTEST
#define MCTEST
#ifdef MC1
#define data1 0x20
/*cmment start*/#define /*this is comment*/ data2 2.5f
#define data3 L"this is a data"
#define data4 true
#ifdef MC2
#define data5 'a'
#define data6 { {2.0, "abc"}, {1.5, "def"}, {5.6f, "7.2"}} // 浮点与字符串组成的结构体初始化聚合, 再进一步聚合组成了数组
#else
#define data5 {5.0, 7.5, 3.8}
#define data6 'c'
#endif //end MC2
#else
#define data1 1.0f /* this is float
may be changed
*/
#define data2 2
#define data3 false
#define data4 "this is a data"
#ifdef MC2
#define