python环境做C语⾔分析-pycparser的使⽤⽅法(2)
这篇⽂章根据上⼀篇的内容做补充:
这⾥介绍简单的pycparser使⽤⽅法,提供⼀种 遍历 抽象语法树AST 节点c_ast.py的⽅法,不⽤去对抽象语法树每⼀种节点的属性做条件判断,就能遍历成序列的形式,可以说是:
c语⾔代码->pycparser的AST节点类->AST遍历序列
c语⾔代码->AST节点
这⾥展⽰不使⽤gcc或llvm编译器处理#include或#define的⽅法,如果想处理这些语句可以看。
# 这⾥展⽰不⽤本地编译器的⽅法
# 但读取的⽂本序列,需去除#include #define这类语句才能⽣成AST
with open(filename, encoding='utf-8)as f:
txt = f.read()
ast = c_parser.CParser().parse(txt)
AST节点->遍历序列
细⼼观察的朋友会注意到,在pycparser的⽂件内,对于节点的声明是这样的(以ArrayDecl节点为例):
class ArrayDecl(Node):
__slots__ =('type','dim','dim_quals','coord','__weakref__')
def__init__(self,type, dim, dim_quals, coord=None):
self.dim = dim
self.dim_quals = dim_quals
def children(self):
nodelist =[]
pe is not None: nodelist.append(("type", pe))
if self.dim is not None: nodelist.append(("dim", self.dim))
return tuple(nodelist)
def__iter__(self):
pe is not None:
pe
if self.dim is not None:
yield self.dim
attr_names =('dim_quals',)
可以观察到,我们可以调⽤attr_names获取节点属性,调⽤节点的children()⽅法获取孩⼦节点。所以有了获取节点所有信息的思路:
# ast节点
node = ast
# ast节点名称
nodeName = node.__class__.__name__
# ast孩⼦节点
nodeChildren = node.children()
# ast节点属性
nodeAttributes = node.attr_names
缺点就是,children()会对孩⼦节点做筛查,如果不存在孩⼦节点,就不会返回对应的属性名称,要具体对每个节点类做分析还是不太友好。
据此,我们可以根据该操作写出所有的过程,代码如下:
from pycparser import parse_file, c_generator
from pycparser.plyparser import ParseError
from pycparser import c_parser
from pycparser.c_ast import*# ast节点类(所有节点类型都继承该⽂件中的Node类)
import os
def getAttribute(attr):
print(attr)
return''
def getAst(node):
nodeName = node.__class__.__name__
nodeChildren = node.children()
nodeAttributes = node.attr_names
nodeAttr =[nodeName]
for _, n in nodeChildren:
for attr in nodeAttributes:
attribute =getattr(node, attr)# 先获取属性
return nodeAttr
filePath ='test3.c'
try:
ast =None
# ast = parse_file(filePath)
with open(filePath)as f:
txtList = f.readlines()
txt =''
for each in txtList:
if each.find('#include')!=-1:
continue
elif each.find('//')!=-1:
txt += each[:each.find('//')]
else:编程先学c语言还是python
txt += each
txt +='\n'
ast = c_parser.CParser().parse(txt)
print(getAst(ast))
except ParseError as e:
print('代码有错:'+str(e))
except Exception as r:
print('错误:'+str(r))
到这⾥,就完成了所有ast节点的遍历操作,该代码还会对原有的#include和注释做删除。(没有删除#define)如果要对每⼀个节点的具体属性做分析,可以看看,会有帮助。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。