文章目录
- 安装 pycparser 模块
- 模块开发者网址
- 获取抽象语法树
- 1. 需要导入的模块
- 2. 获取 不关注预处理相关 c语言文件的抽象语法树ast
- 3. 获取 预处理后的c语言文件的抽象语法树ast
- 语法树组成
- 1. 数据类型定义 Typedef
- 2. 类型声明 TypeDecl
- 3. 标识符类型 IdentifierType
- 4. 变量声明 Decl
- 5. 常量 Constant
- 6. 函数定义 FuncDef
- 7. 函数声明 FuncDecl
- 8. 函数参数列表 ParamList
- 9. 代码块 Compound
- to do
感谢这两篇文章对于我学习之初的帮助
https://blog.csdn.net/u011079613/article/details/122462729
https://blog.csdn.net/qq_38808667/article/details/118059074
安装 pycparser 模块
pip install pycparser -i https://mirrors.aliyun.com/pypi/simple/
模块开发者网址
https://github.com/eliben/pycparser
获取抽象语法树
1. 需要导入的模块
# parser_file 用于处理c语言文件
from pycparser import parse_file
from pycparser import CParser
# c语言有错误时,会引出此错误
from pycparser.plyparser import ParseError
# c_ast.py 文件下包含了抽象语法树的节点类
from pycparser.c_ast import *
2. 获取 不关注预处理相关 c语言文件的抽象语法树ast
文件中需删除 #开头 预处理代码,不能有注释代码
- 方法1:
ast = parse_file(filename, use_cpp = False)
- 方法2:
with open(filename, encoding='utf-8',) as f:
txt = f.read()
ast = CParser().parse(txt) # 使用此方法需要 删除头文件
3. 获取 预处理后的c语言文件的抽象语法树ast
获取c语言文件的抽象语法树ast
,如果要处理 #include
等语句,需要下载fake_libc_include
文件夹,让编译器预处理常用的方法(添加其到代码的抽象语法树中)
点击此处下载 fake_libc_include
cpp_args必须加上 -E , 否则返回的抽象语法树是个空列表
ast = parse_file(filename, use_cpp = True, cpp_path=r'C:\MinGW\bin\gcc.exe', cpp_args=['-E', r'-Iutils/fake_libc_include'])
使用 parse_file
类获取 预处理后的c语言文件的抽象语法树ast
parse_file 参数 | 说明 |
---|---|
filename | 需要解析的 .c 文件名 |
use_cpp | 是否使用本地c语言编译器预处理代码,去掉其中的#命令(头文件、宏定义、pragma)值:False/True |
cpp_path | 本地c语言编译器路径 |
cpp_args | fake_libc_include 文件夹路径,需要在路径添加 -I 指明所包头文件路径; use_cpp=True 时使用 |
语法树组成
抽象语法树 ast
类型为 <class 'pycparser.c_ast.FileAST'>
其解析的具体内容通过 print(ast.ext)
查看,ext
数据类型为列表
FileAST
下级节点只有 3 种可能 :
Typedef
:typedef
数据类型定义Decl
:变量声明FuncDef
:函数声明
示例:
test.c
typedef int uint32;
int g =0;
int add(int a, int b)
{
int c = 0;
c = a + b;
return c;
}
int main(void)
{
printf("hello world");
return 0;
}
cparser.py
# parser_file 用于处理c语言文件
from pycparser import parse_file
from pycparser import CParser
# c语言有错误时,会引出此错误
from pycparser.plyparser import ParseError
# c_ast.py 文件下包含了抽象语法树的节点类
from pycparser.c_ast import *
filename = 'test.c'
ast = parse_file(filename, use_cpp = False)
print(type(ast))
for eachNode in ast.ext:
print(eachNode.__class__.__name__) # 打印节点类型名
#print(eachNode) # 打印节点内容
输出
1. 数据类型定义 Typedef
Typedef
数据结构类型 <class 'pycparser.c_ast.Typedef'>
数据类型定义 Typedef
属性如下:
Typedef.name = str
(Typedef
定义对象)Typedef.quals = [str]
(限定符号列表:const, volatile
)Typedef.storage = [str]
(存储说明符列表:extern, register, etc.
)Typedef.type = Node
(TypeDecl
节点)Typedef.coord= str
(定义对象所在行列)Typedef.coord.column= str
(定义对象所在列)Typedef.coord.line= str
(定义对象所在行)Typedef.coord.file= str
(定义对象所在文件)
示例:
test.c
typedef const int cuint32;
cparser.py
# parser_file 用于处理c语言文件
from pycparser import parse_file
from pycparser import CParser
# c语言有错误时,会引出此错误
from pycparser.plyparser import ParseError
# c_ast.py 文件下包含了抽象语法树的节点类
from pycparser.c_ast import *
filename = 'test.c'
ast = parse_file(filename, use_cpp = False)
print(type(ast.ext[0]))
print('name = ', ast.ext[0].name) # Typedef 定义对象
print('quals = ', ast.ext[0].quals)
print('storage = ', ast.ext[0].storage)
print('type = ', ast.ext[0].type)
print('coord = ', ast.ext[0].coord)
输出
2. 类型声明 TypeDecl
Typedef
的下一级 类型声明 TypeDecl
是以typedef
语句格式为中心
类型声明 TypeDecl
属性如下:
TypeDecl.declname= str
(typedef
定义对象)TypeDecl.quals = [str]
(限定符号列表:const, volatile
)TypeDecl.align= [str]
(暂不清楚)TypeDecl.type = Node
(IdentifierType
节点)TypeDecl.coord= str
(定义对象所在行列)TypeDecl.coord.column= str
(定义对象所在列)TypeDecl.coord.line= str
(定义对象所在行)TypeDecl.coord.file= str
(定义对象所在文件)
示例:
test.c
typedef const int cuint32;
cparser.py
# parser_file 用于处理c语言文件
from pycparser import parse_file
from pycparser import CParser
# c语言有错误时,会引出此错误
from pycparser.plyparser import ParseError
# c_ast.py 文件下包含了抽象语法树的节点类
from pycparser.c_ast import *
filename = 'test.c'
ast = parse_file(filename, use_cpp = False)
print(type(ast.ext[0].type))
my_typeDecl = ast.ext[0].type
print('name = ', my_typeDecl.declname) # Typedef 定义对象
print('quals = ', my_typeDecl.quals)
print('type = ', my_typeDecl.type)
print('storage = ', my_typeDecl.align)
print('coord = ', my_typeDecl.coord)
print('coord.column = ', my_typeDecl.coord.column) # (定义对象所在列)
print('coord.line = ', my_typeDecl.coord.line) # (定义对象所在行)
print('coord.file = ', my_typeDecl.coord.file) # (定义对象所在文件)
输出
3. 标识符类型 IdentifierType
TypeDecl
的下一级 标识符类型 IdentifierType
是简单标识符,比如 void, char
定义之类
原数据类型 : <class 'pycparser.c_ast.IdentifierType'>
标识符类型 IdentifierType
属性如下:
IdentifierType.name = [str]
(标识符字符串列表)IdentifierType.coord= str
(定义对象所在行列)IdentifierType.coord.column= str
(定义对象所在列)IdentifierType.coord.line= str
(定义对象所在行)IdentifierType.coord.file= str
(定义对象所在文件)
4. 变量声明 Decl
Decl
数据结构类型 <class 'pycparser.c_ast.Decl'>
变量声明 Decl
属性如下:
Decl.name = str
(被声明的变量名)Decl.quals = [str]
(限定符号列表: const, volatile)Decl.align= [str]
(暂不清楚)Decl.storage = [str]
(存储说明符列表: extern, register, static等)Decl.funcspec = [str]
(函数说明符列表: C99的inline)Decl.type = Node
(TypeDecl
节点)Decl.init = Node
(初始化值,Constant
节点)Decl.bitsize = Node
(位域bit field大小,或者为None)Decl.coord= str
(定义对象所在行列)Decl.coord.column= str
(定义对象所在列)Decl.coord.line= str
(定义对象所在行)Decl.coord.file= str
(定义对象所在文件)
示例:
test.c
typedef const int cuint32;
static const int g =0;
cparser.py
# parser_file 用于处理c语言文件
from pycparser import parse_file
from pycparser import CParser
# c语言有错误时,会引出此错误
from pycparser.plyparser import ParseError
# c_ast.py 文件下包含了抽象语法树的节点类
from pycparser.c_ast import *
filename = 'test.c'
ast = parse_file(filename, use_cpp = False)
print(type(ast.ext[1]))
my_ext = ast.ext[1]
print('name = ', ast.ext[1].name) # Typedef 定义对象
print('quals = ', ast.ext[1].quals)
print('align = ', ast.ext[1].align)
print('storage = ', ast.ext[1].storage)
print('funcspec = ', ast.ext[1].funcspec)
print('type = ', ast.ext[1].type)
print('init = ', ast.ext[1].init)
print('bitsize = ', ast.ext[1].bitsize)
print('coord = ', ast.ext[1].coord)
输出
5. 常量 Constant
常量 Constant
属性如下:
Constant.type= str
(基本数据类型,int等)Constant.value= str
(数值)Constant.coord= str
(定义对象所在行列)Constant.coord.column= str
(定义对象所在列)Constant.coord.line= str
(定义对象所在行)Constant.coord.file= str
(定义对象所在文件)
6. 函数定义 FuncDef
FuncDef
方法定义,不同于 FuncDecl
,有具体的函数实现过程
函数定义 FuncDef
属性如下:
FuncDef.decl = Node
(一般是包含Decl
的节点)param_decls=None
(暂不清楚)FuncDef.body = Node
(函数实现的代码块 一般是包含Compound
的节点)FuncDef.coord= str
(标识符字符串所在行列)FuncDef.coord.column= str
(定义对象所在列)FuncDef.coord.line= str
(定义对象所在行)FuncDef.coord.file= str
(定义对象所在文件)
7. 函数声明 FuncDecl
FuncDecl
既可以单独存在,也可以是函数定义的一部分
函数定义 FuncDecl
属性如下:
FuncDecl.args= Node
(一般是包含ParamList
的节点)FuncDecl.type= [str]
(一般是包含TypeDecl
的节点)
8. 函数参数列表 ParamList
以 list 形式,可遍历 参数
函数定义 ParamList
属性如下:
ParamList.params= [str]
(有哪些参数 ,一般是包含Decl
的节点)
9. 代码块 Compound
以 list 形式,可遍历 代码块内容
函数定义 Compound
属性如下:
Compound .block_items= [str]
(有哪些参数 ,一般是包含Decl Assignment 和 Return
的节点)
to do
解析任意编程语言 tree-sitter