文章目录
优快云和中文互联网有不少tree-sitter的用法博客,但是由于tree-sitter更新速度较快,很多内容例如函数接口都迅速的过时且无法使用了;
所以笔者根据Tree-sitter官方document来梳理了自己入门tree-sitter的一些内容;欢迎大家一起讨论学习;
当然,最好的tree-sitter学习资料仍然是官方文档,更多的信息可以翻阅以下链接:
0. 介绍
tree-sitter是 解析器 生成器 工具
为源文件构建具体的语法树
- 通用:多语言转换AST
- 快速
- Robust:错误语法也能解析
- 无依赖:纯C11编写,可以无缝嵌入,也是性能高的原因
tree-sitter支持增量解析:
代码出现小范围修改时,解析器不会重新解析,只更新出现变更的部分
术语
-
编译 compile
将代码翻译为计算机执行的机器码;
会进行语法错误检查、优化代码、生成可执行文件 -
解析 parse
将代码拆解成计算机能理解的结构
代码->结构化表示(语法树)
解析器会检查语法 -
生成 generate
把中间处理好的代码转换为目标代码(机器码或者汇编) -
中间表示 IR Intermediate Representation
IR是编译器内部的通用格式;让优化和跨平台更容易;例如LLVM的IR -
AST 抽象语法树
树形结构来表示代码的逻辑
不包含括号分号等无关信息,只保留代码的核心语义;
不同的解析器生成的AST可能不同,但都是为了捕捉代码的语义 -
CFG 控制流图
表示执行流程,代码块与条件循环语句 -
LLVM
LLVM 是一个编译器框架,使用LLVM IR进行中间表示;LLVM IR显式表示了内存操作(load store)
Clang,基于LLVM的编译器
编译和解析
编译器阶段:
- 词法分析,源代码->tokens
- 语法分析,tokens->AST
- 语义分析,检查语义正确(变量声明与类型匹配等)
- IR生成 ,再优化
- 目标代码生成 Generate
解析器不会生成和执行代码,只进行分析
解析器主要是进行:
- 词法分析:输入字符串(源代码)->tokens
- 语法分析:tokens->语法树AST
1. Tree-sitter Parser的使用
提供了多语言的API
tree-sitter在2025年一月更新到了0.24
Language类中的build_library疑似被删除
from tree-sitter import Language
print(dir(Language))
# 查看输出中有哪些方法,如果没有build_library说明方法已经删除
# 亲测0.19.0有,而0.24.0没有
# 0.21.3 还有build_library方法
·PyPI — tree-sitter 0.21.3 · PyPI中的Build from source引用中提示:
build_library将于0.22.0删除
更为详细的使用可以参考tree-sitter0.24.0使用手册 · PyPI
最新版本tree-sitter使用
截至2025 1月0.24.0的更新,删除了build_library方法和parser的set_language方法
配置环境和准备解析器
pip install tree-sitter
# 根据需要的语言下载解析器
pip install tree-sitter-cpp
pip install tree-sitter-python
解析
import tree_sitter_python
import tree_sitter_cpp
from tree_sitter import Language, Parser
# 加载Language对象
PY_LANGAUGE = Language(tree_sitter_python.language())
CPP_LANGAUGE = Language(tree_sitter_cpp.language())
# 创建Parser并配置语言
cpp_parser = Parser(CPP_LANGUAGE)
# insdead of cpp_parser=Parser() cpp_parser.set_language(CPP_LANGUAGE)
# 准备用于解析的代码段
cpp_code_snippet = '''
// Your Code
'''
# 进行解析
tree = cpp_parser.parse(
bytes(
cpp_code_snippet, "utf-8"
)
)
# 获取AST的节点
root_node = tree.root_node
# 遍历AST
cursor = tree.walk()
解析后的节点访问
单个节点的访问可以通过TSNode这个API去访问;
节点
root_node = tree.root_node
root_node.type
# 类型,例如函数定义(function_definition),字符串(string)
节点有哪些属性
| 属性 | 说明 |
|---|---|
| type | 类型 |
| start_point | 节点在代码的开始位置,(row, column) |
| end_point | 节点在代码的结束位置 |
| start_byte | |
| end_byte | |
| children | 子节点列表 |
| sexp() | 返回S表达式,string |
cursor遍历
但是大量的访问还是使用光标tree cursor更加合适
cursor是一个带有状态的对象
tree = parser.parse(
bytes(code, 'utf-8')
)
cursor = tree.walk() # 创建了一个cursor对象
cursor的遍历
cursor.goto_first_child()
# 成功返回True,并移动到第一个子节点; 否则返回False
cursor.goto_next_sibling()
# 成功返回True,并移动到下一个兄弟节点; 否则返回False
cursor.goto_parent()
# 返回到父节点,返回True; 否则返回False
print(f"Node type: {
cursor.node.type}")
print(f"Text: {
code[cursor.node.start_byte:cursor.node.end_byte].decode('utf-8')}")
# 获取节点的源代码
递归进行遍历
# 递归进行遍历
def traverse(cursor):
node

最低0.47元/天 解锁文章
4023






