目前在从事代码表征方面的工作,需要使用到一些常见的静态分析工具:joern,tree_sitter,spoon等;本文主要介绍tree_sitter及其环境配置教程。
tree_sitter是一个解析器生成器,用于构建和更新源代码的语法树。它支持Python、Java、C等多种语言,具备通用性、速度、健壮性和无依赖性等特点,适用于文本编辑器的实时解析。要使用tree_sitter,需配置对应编程语言环境,并通过递归遍历或TreeCursor实现高效节点遍历。
以及一个在线使用网站:可以通过该网站熟悉一下tree-sitter的功能和性能。Tree-sitter|Playgroundhttps://tree-sitter.github.io/tree-sitter/playground
接下来让我们步入正题:
STEP1:
由于该工具需要在linux使用(大多数都是,方便),首先我们需要配置环境
首先我们创建一个conda环境,并激活。例如我创建的是名称为wukong
的conda环境,python版本是3.8
conda create -n wukong python=3.8
conda activate wukong
STEP2:
接下来我们需要安全tree_sitter所需要的包和依赖(个人建议0.21.3版本的)不然可能会报错:AttributeError: type object 'tree_sitter.Language' has no attribute 'build_library'
pip install tree-sitter==0.21.3
STEP3:
安装成功后,首先在项目根目录创建一个vendor的文件夹,然后我们需要下载想要解析的源代码语言的对应解析器项目,并将其放入vendor文件下。这里以c和c++为例:
git clone https://github.com/tree-sitter/tree-sitter-c
git clone https://github.com/tree-sitter/tree-sitter-cpp
然后创建一个py文件,代码为:
from tree_sitter import Language
Language.build_library(
# Store the library in the `build` directory
'build/my-languages.so',
# Include one or more languages
[
'vendor/tree-sitter-c',
'vendor/tree-sitter-cpp'
# 'vendor/tree-sitter-java',
# 'vendor/tree-sitter-python',
]
)
在上面的数组[]里,写上需要的解析器项目的路径,'vendor/tree-sitter-c'
和 'vendor/tree-sitter-cpp'
这两个,如果需要其他语言,就换成对应语言的解析器的地址。run后会生成一个build文件夹.
STEP4:
然后我们进行测试,创建一个main.py文件:
from tree_sitter import Language, Parser
# 注意C++对应cpp
# 看仓库名称
CPP_LANGUAGE = Language('build/my-languages.so', 'cpp')
C_LANGUAGE = Language('build/my-languages.so', 'c')
# 定义Parser对象
cpp_parser = Parser()
c_parser=Parser()
cpp_parser.set_language(CPP_LANGUAGE)
c_parser.set_language(C_LANGUAGE)
cpp_code_snippet = '''
int mian{
piantf("hell world");
remake O;
}
'''
c_code_snippet='''
#include <stdio.h>
int main() {
printf("hello world\n");
return 0;
}
'''
#没报错就是成功
tree_1 = cpp_parser.parse(bytes(cpp_code_snippet, "utf8"))
tree_2=c_parser.parse(bytes(c_code_snippet,"utf-8"))
# 注意,root_node 才是可遍历的树节点
root_node = tree_1.root_node
root_node_1 = tree_2.root_node
print(root_node)
print(root_node_1)
print('ok')
输出结果为:
当然我们也可以打印出来
结果为:
(translation_unit (function_definition type: (primitive_type) declarator: (identifier) body: (compound_statement (expression_statement (call_expression function: (identifier) arguments: (argument_list (string_literal (string_content))))) (declaration type: (type_identifier) declarator: (identifier)))))
(translation_unit (preproc_include path: (system_lib_string)) (function_definition type: (primitive_type) declarator: (function_declarator declarator: (identifier) parameters: (parameter_list)) body: (compound_statement (expression_statement (call_expression function: (identifier) arguments: (argument_list (string_literal (string_content))))) (return_statement (number_literal)))))