CPP宏定义解析处理【python】

问题描述

c++宏定义文件中关键字有#define, #undef #ifndef, #ifdef, #else,#endif, 处理注释,//,/*,*/, 解析文件,输出其中的宏定义

分析思路

文本分析基础是字符串处理,宏定义文件的处理需要对遇到的关键字执行特殊的处理。

文件定义的中间数据结构用嵌套列表,宏定义主要是顺序结构和分支结构,顺序结构好理解,一个宏定义作为一个字典,字典作为列表的元素;对于分支结构,用子列表表示它,这个子列表的结构如下

[

{{'id': 1},{'parent': 0}, {'pos':0}},    # id给当前子列表编号,parent是子列表的父列表编号,pos是当前处理分支的左右分支,true是左,标记为1;false是右,标记为2.

{'macro_key': ''}, #macro_key是当前分支结构的条件

[], #表示左子列表

[],#表示右子列表

]

这样表示后,再定义当前分支子列表branch(这里利用了python的引用特征),当前列表编号node_id,父列表编号parent_id,左右分支位置pos,辅助对嵌套列表的遍历。

存储宏定义的格式是宏定义字典,键是宏名,值是宏定义值。还有一个辅助数据结构,预定义宏名列表,用于记录预定义的宏名。

下面对遇到的不同关键字作不同的分析:

1. 对注释的处理

注释有三种,//,/*,*/,其中/*和*/成对出现,用栈来表示顺序关系。采用逐个字符扫描的方法,对于每个字符,如果是//,后面的内容省略;对于/*,如果栈为空或/*,就入栈;对于*/,如果栈顶是/*, 就弹栈,游标向后一步;否则,如果栈顶不是/*,说明是有效字符,否则忽略。

2. 对关键字的统一处理

宏的定义一般是2个词,或3个词,中间空格分隔,常见的思路是split,这里有个小坑,如果定义的是字符串,字符串中间有空格,这样split会把第三个词割裂了。这里给split加个参数,maxsplit=2,意思是只分隔前两次遇到的空格,后面的作为整体。

2.1 遇到#ifndef: 

插入子列表

[{'id': node_id, 'parent': parent_id, 'pos': node_pos}, {key_name: ''}, [], []]

node_pos为2,表示右分支,branch分支指向字列表的第3个元素(空的子列表),其他字段定义见上面的说明。

2.2 遇到#ifdef:

插入子列表

[{'id': node_id, 'parent': parent_id, 'pos': node_pos}, {key_name: ''}, [], []]

node_pos为1,表示左分支,branch分支指向字列表的第2个元素(也是一个空的子列表),其他字段定义见上面的说明。

2.3 遇到#else:

需要切换分支,只需要修改pos值,1变成2,2变化成1;而且,当前branch是列表中的一个元素,需要找到它的父列表,我们就需要在整个嵌套列表上搜索父列表的id,找到这个列表,再根据pos调整到它的另外一个分支。如何搜索指定id的列表?这个单独设立一个函数,后面再详述。

2.4 遇到#define:

这是宏的一个定义,只需要在当前branch上append一个字典即可,如果只有宏名,值域留空。

2.5 遇到#endif:

这是一个分支退出的标记,需要变换当前的branch到父列表上,左右分支要求能恢复到父列表对应的左右分支才行。同样的,这里用到对整个树的搜索,和#else不同的地方,#endif不指定左右分支位置。

2.6 遇到#undef:

undef表示取消设定宏,

{'MC2': '', 'reverse': 1}

宏字典后面再加一个字段,reverse表示是取消宏的设定。

至此,所有的关键字处理完毕。

对于嵌套列表的搜索,用递归,算法思路如下:

输入参数3个,搜索的分支branch,待搜索的子列表号node_id,左右子列表类型(-1表示以搜索到pos为准,1表示左字列表,2表示右子列表)

输出结果2个,搜索结果0失败,1成功;[当前列表编号, 当前父列表编号, 当前左右分支位置, 当前分支branch]

如果当前分支为空,输出0,[0, 0, 0, []]

获取当前branch的字典类型元素的序列,找到包含id关键字的字典,比较id的值是不是node_id,如果是那就成功找到了,当要求的节点类型是1,2,分支取branch的子列表[1取左,2取右],输出当前结果;当要求的节点类型是-1,取id关键字字典的pos,分支取branch的子列表[pos对应的子列表]

如果左子树不空(子树长度>=1),搜索左子树,如果搜索结果字段不为0,左子树的输出结果就是最终的结果

如果右子数不空(子树长度==2),搜索右子树,如果搜索结果字段不为0,右子树的输出结果就是最终的结果

以上输出条件都不满足,输出0,[0,0,0[]]

其他

整个过程还是非常有挑战的,最后效果还好,复杂情况的处理还是火候不够,很多情况的处理可以更好。加油吧。

猜你喜欢

转载自blog.csdn.net/xiexie1357/article/details/86360435