编译原理初探一
环境:win7 64位+llvm11+mingw+python3.7+libclang11
LLVM编译一个源文件的过程:预处理 -> 词法分析 -> Token -> 语法分析 -> AST -> 代码生成 -> LLVM IR -> 优化 -> 生成汇编代码 -> Link -> 目标文件
main.c 源码:
//#include<stdio.h> //可以注释,不影响分析
int main(int argc,char*argv[])
{
puts("hello world");
return 0;
}
使用LLVM的对一门语言编译的简图如下所示:
Clang和LLVM关系:
Clang是一个C++编写、基于LLVM、发布于LLVM BSD许可证下的C/C++/Objective-C/Objective-C++编译器。那么为什么已经有了GCC还要开发Clang呢?Clang相比于GCC有什么优势呢? 其实,这也是Clang当初在设计开发的时候所主要考虑的原因。Clang是一个高度模块化开发的轻量级编译器,它的编译速度快、占用内存小、非常方便进行二次开发。
LVM和Clang的关系是怎样的呢。我们将它们对应于传统的编译器当中的几个独立的部分,这样能够更加方便明确生动的表述。

1、查看程序编译过程:
clang -ccc-print-phases main.c

2、查看preprocessor(预处理)的结果
clang -E main.c

3、词法分析,生成token
clang -Xclang -dump-tokens main.c

4、语法分析,生成语法树
clang -fsyntax-only -Xclang -ast-dump main.c

Clang AST介绍可以参考
https://www.cnblogs.com/jourluohua/p/14524955.html
配置python clang
现在的Clang,不仅仅是一个编译器前端,同时也可以作为一个库使用。作为一个库使用的时候,可以用它去分析C/C++/ObjectC语言代码,可以分析源码得到AST,也可以获取已经分析好的AST,也可以遍历AST,还可以获取AST中基本元素的物理源码位置。这就是libclang。libclang提供了一系列的C语言的接口,但是这些接口并不能完全提供存储在Clang C++ AST中的所有信息,只能提供部分基本信息,但是这些基本信息已经可以满足一般情况下的使用。主要目的是为了稳定,并且可以支持开发工具的基本功能。
libclang很方便就打印了词法分析结果和AST语法树
C语言测试代码
typedef unsigned int VOS_UINT32;
VOS_UINT32 add(VOS_UINT32 num1,VOS_UINT32 num2)
{
VOS_UINT32 result=num1+num2;
return result;
}生成的AST语法树:

python解析代码
功能:遍历tokens流和AST抽象语法树
from clang.cindex import Config #配置
from clang.cindex import TypeKind
from clang.cindex import CursorKind
from clang.cindex import Index #主要API
def GetTranslationUnit(filename):
index = Index.create()
tu = index.parse(filename)
print("tTranslation Unit=%s"%(tu.spelling))
return tu
def LoadLibClang(libclangPath):
if Config.loaded == True:
pass
else:
Config.set_library_file(libclangPath)
#主函数
if __name__ == '__main__':
filename='test.c' # C语言文件
libclangPath = r'C:\Program Files\LLVM\bin\libclang.dll' #libclang库路径
LoadLibClang(libclangPath) #加载libclang库
tu=GetTranslationUnit(filename)#解析main.c
ast_root_node=tu.cursor #获取cursor根节点
# 获取词法分析结果
print("Print all tokens:")
for token in ast_root_node.get_tokens():#遍历词法分析结果
print('%10s %s'%(token.spelling,token.kind))
print("Print all nodes in ast tree:")
for node in ast_root_node.walk_preorder(): # 遍历词法分析结果
print('%10s %s %s '%(node.spelling,node.location.line,node.kind))
#help(Token)
#help(Index)运行结果

0.0分
1 人评分
C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:
一点编程也不会写的:零基础C语言学练课程
解决困扰你多年的C语言疑难杂症特性的C语言进阶课程
从零到写出一个爬虫的Python编程课程
只会语法写不出代码?手把手带你写100个编程真题的编程百练课程
信息学奥赛或C++选手的 必学C++课程
蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程
手把手讲解近五年真题的蓝桥杯辅导课程
发表评论 取消回复