【Clang AST】基于 Clang 获取分析 AST

The Clang AST

AST(Abstract Syntax Tree)抽象语法树

  • AST是什么

抽象语法树(Abstract Syntax Tree, AST)是源代码的抽象表示,广泛用于编译器和分析工具中。 AST将源代码的语法结构转换为树形结构,其中每个节点表示代码中的一个语法元素。与源代码的文本表示相比,AST更关心代码的结构和语义。
在这里插入图片描述

词法分析(Lexical Analysis):将源代码分解为一系列词法单元(Tokens),如关键词、变量名、操作符等。

语法分析(Syntax Analysis): 根据语言的语法规则,将Token序列组织成语法树(Syntax Tree),也就是初步的结构化表示。

**抽象语法树(Abstract Syntax Tree):**在语法分析的基础上构建AST,这是一种高层次、结构化的代码表示方式。

代码生成(Code Generation): 将AST转化为中间表示(IR,Intermediate Representation),通常为LLVM IR

  • AST的特点

1. 抽象性:AST不包含源代码的所有信息,例如具体的空格、注释等,但它保留了语言的结构信息。

2. 层次结构:AST的每个节点代表源代码中的一个构造,例如表达式、语句、变量声明等。树的每个层次对应着不同的语法结构。

3. 语法语义结合:AST不仅体现代码的语法结构,还能结合上下文信息捕获部分语义内容(如变量作用域、类型信息等)。

4. 可扩展性:AST可以被修改和扩展,用于实现代码重构、代码生成以及语言特性的新增。

  • 简单实例

借助AST explorer,一个强大的在线工具,用于解析代码并展示其抽象语法树(AST)。它支持多种编程语言和解析器。

Python代码

def func(a, b):result = a + breturn result

获取对应的AST

在这里插入图片描述

AST 从顶层的 Program 节点开始,表示整个程序。其子节点为 FunctionDeclaration,表示定义了一个函数 func,包含两个参数 ab,函数体由一个 BlockStatement 表示。在函数体中,首先是一个 VariableDeclaration 节点,声明变量 result 并将 a + b 的结果赋值给它,该表达式由 BinaryExpression 节点表示,操作数为参数 ab。最后是一个 ReturnStatement 节点,返回变量 result

基于不同的工具可以获取到不同的 AST,获取到的 AST 的内容取决于工具的 LR 文法文件。例如 Clang 是 LLVM 提供的 C/C++/OC 的编译器前端,内部包含了成熟通用的文法文件,获取到的 AST 和编译过程中产生的 AST 相同。

  • 基于 AST 能做什么

AST 以树状的形式表现源代码的语法结构,非常有利于分析遍历,且包含了足够多的源代码信息,因此基于 AST 可以做很多语法分析相关的工作:

  1. 语法检查
  2. 自动修复编译错误
  3. 自动修改代码格式
  4. 代码高亮
  5. 语法折叠
  6. 代码结构分析

基于 Clang 获取分析 AST

  • Clang 介绍

Clang 是一个开源的编译器前端,主要用于 C、C++、Objective-C 和 Objective-C++ 的编译。它是 LLVM 项目的一部分,目标是提供一个高效、可移植、易于扩展且用户友好的编译器框架。Clang 不仅提供了编译器功能,还为静态分析、源代码工具、重构工具等提供了基础。

在这里插入图片描述

LLVM的三段式设计:Front-end、Middle-end、Back-end

Clang 是 OC、C++、C 语言的 Front-end,主要负责预处理、词法分析、语法分析、语义分析等,生成 AST、并把 AST 转换为 IR,作为 Middle-end 的输入。

Clang 的 AST 分析工具在生成 AST 之前需要预处理阶段,而预处理依赖于 完整的编译参数(如头文件路径、宏定义、目标架构等)和 编译环境配置

  • 基于 Clang 获取分析 AST
1、使用 Clang 命令行工具查看 AST

Clang 提供了命令行工具,可以快速查看源代码生成的抽象语法树(AST)。 这也是 Clang 最基础的用法。

命令格式:

clang -Xclang -ast-dump -fsyntax-only <source_file>
  • -Xclang -ast-dump:打印抽象语法树。
  • -fsyntax-only:仅检查语法,不进行实际的编译。
  • <source_file>:输入的源代码文件。

ASTContext

ASTContext是 Clang 用于管理抽象语法树(AST)的核心类。它封装了一个翻译单元的所有 AST 相关信息。

它允许从 getTranslationUnitDeclTranslationUnitDecl 是 AST 的顶级节点,代表整个源文件)开始遍历整个翻译单元,或者对于已解析的翻译单元,访问 Clang 的标识符表(该表记录了源代码中所有的标识符及其对应的语法信息 )。

Clang AST节点

Clang 的 AST 节点是 Clang 抽象语法树的基础结构,每个节点表示源代码中的某种语法元素。

  • AST 节点的层次结构:Clang 的 AST 节点不是基于单一的祖先类,而是根据节点的语法和语义意义划分为多个主要类别
    • Decl(声明) :表示所有声明相关的语法元素,例如变量声明、函数声明、类声明等
    • Stmt(语句) :表示所有的语句,例如条件语句、循环语句、表达式语句等
    • Type(类型) :表示代码中的类型信息,例如 intfloatclass 类型等

简单示例

example.c

int main() {printf("Hello, world!\n");return 0;
}

运行指令:clang -Xclang -ast-dump -fsyntax-only example.c

输出(部分):

TranslationUnitDecl 0x5608c0 <example.c:1:1, line:4:1>
|-FunctionDecl 0x560960 <line:1:1, line:4:1> line:1:5 main 'int ()'
| `-CompoundStmt 0x560b60 <line:2:1, line:4:1>
|   |-CallExpr 0x560aa8 <line:2:5, line:2:28> 'int'
|   | `-DeclRefExpr 0x560a90 <line:2:5> 'int (const char *)' Function 'printf'
|   `-ReturnStmt 0x560b40 <line:3:5, line:3:12>
......
  • TranslationUnitDecl:表示整个翻译单元(源文件)。
  • FunctionDecl:表示 main 函数的定义。
  • CompoundStmt:表示复合语句(函数体)。
  • CallExpr:表示函数调用(printf)。
  • ReturnStmt:表示返回语句。

优缺点分析

优点:简单易用

缺点:输出的信息难以阅读、无法直接操作AST、仅支持静态结构

2、使用编程接口查看分析 AST

Clang LibTooling 是 Clang 提供的一套强大的编程接口,用于构建自定义的编译器工具。这些工具可以解析源代码的抽象语法树(AST),并执行静态分析、代码重构、定制化的代码生成等任务。相比于通过命令行直接查看 AST 的方法,LibTooling 提供了更多的灵活性,允许开发者以编程方式操作 AST。

LibTooling 是 Clang 的 API,用于构建工具链程序。它可以直接访问 Clang 的编译器基础设施(如 AST、语义分析、诊断系统等),开发者可以通过它来实现以下功能:

  • 遍历和分析 AST。
  • 匹配特定的代码模式(使用 LibASTMatchers)。
  • 对源代码进行静态分析和诊断。
  • 修改和生成代码(代码重构工具)。

命令行方式存在固有的局限:(1)无法筛选或操作 AST;(2)难以自动化和扩展;(3)缺乏上下文信息,无法处理复杂的依赖关系或跨文件分析。

在 LibTooling 中,核心类包括:

  • ClangTool:管理工具的执行。
  • FrontendAction:定义工具的行为。
  • ASTConsumer:定义对 AST 的处理逻辑。
  • RecursiveASTVisitor:用于便利遍历 AST 节点。

简单示例

以下是一个使用 LibTooling 遍历 AST 并打印函数定义的代码示例:

#include "clang/AST/AST.h"  
// Clang 的 AST 核心头文件,用于访问 AST 节点的接口
#include "clang/AST/RecursiveASTVisitor.h"  
// 提供 RecursiveASTVisitor 类,用于遍历 AST 节点
#include "clang/Frontend/FrontendAction.h"  
// 定义 FrontendAction 类,作为工具的入口点
#include "clang/Frontend/CompilerInstance.h"  
// 提供 CompilerInstance 类,管理编译器的上下文
#include "clang/Tooling/Tooling.h"  // Clang 工具开发的核心接口
#include "clang/Tooling/CommonOptionsParser.h"  // 用于解析命令行参数和编译数据库
#include "clang/ASTMatchers/ASTMatchers.h"  // 提供 ASTMatchers 库,用于匹配 AST 节点
#include "clang/ASTMatchers/ASTMatchFinder.h"  
// 提供 ASTMatchFinder 类,用于查找 AST 节点
#include <iostream>  // 标准 C++ 输入输出库using namespace clang;  // 简化 Clang 命名空间的使用
using namespace clang::tooling;  // 简化 Clang 工具库命名空间的使用
using namespace clang::ast_matchers;  // 简化 ASTMatchers 库命名空间的使用// 自定义 AST 访问器,用于遍历 AST
class MyASTVisitor : public RecursiveASTVisitor<MyASTVisitor> {
public:// 构造函数,接受一个 ASTContext 指针,保存为成员变量explicit MyASTVisitor(ASTContext *Context) : Context(Context) {}// 钩子函数:访问函数声明节点 (FunctionDecl)bool VisitFunctionDecl(FunctionDecl *FD) {// 获取函数名称并打印到标准错误流llvm::errs() << "Function found: " << FD->getNameInfo().getName().getAsString() << "\n";return true;  // 返回 true 表示继续遍历其他节点}private:ASTContext *Context;  // 保存 AST 的上下文信息,供其他方法使用
};// 自定义 AST Consumer,用于处理 AST
class MyASTConsumer : public ASTConsumer {
public:// 构造函数,接受一个 ASTContext 指针,传递给自定义的 AST 访问器explicit MyASTConsumer(ASTContext *Context) : Visitor(Context) {}// 重写 HandleTranslationUnit 方法,当翻译单元解析完成后调用void HandleTranslationUnit(ASTContext &Context) override {// 调用访问器的 TraverseDecl 方法,遍历翻译单元的根节点 (TranslationUnitDecl)Visitor.TraverseDecl(Context.getTranslationUnitDecl());}private:MyASTVisitor Visitor;  // 自定义的 AST 访问器,用于遍历和分析 AST
};// 自定义 FrontendAction,定义工具的入口点
class MyFrontendAction : public ASTFrontendAction {
public:// 重写 CreateASTConsumer 方法,返回一个自定义的 ASTConsumer 实例std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, StringRef file) override {// 创建并返回 MyASTConsumer 对象,传递 AST 上下文return std::make_unique<MyASTConsumer>(&CI.getASTContext());}
};// 主函数,工具的入口
int main(int argc, const char **argv) {// 使用 CommonOptionsParser 解析命令行参数和编译数据库// 第一个参数:命令行参数数量 (argc)// 第二个参数:命令行参数内容 (argv)// 第三个参数:命令行选项的分类(这里使用默认分类)CommonOptionsParser OptionsParser(argc, argv, llvm::cl::GeneralCategory);// 创建 ClangTool 对象,用于管理工具的运行// 参数 1:编译数据库,包含编译参数 (compile_commands.json)// 参数 2:源文件路径列表ClangTool Tool(OptionsParser.getCompilations(), OptionsParser.getSourcePathList());// 运行工具,传递自定义的 FrontendAction 工厂return Tool.run(newFrontendActionFactory<MyFrontendAction>().get());
}

优缺点分析

优点:灵活性和可编程性、丰富的API支持

缺点:复杂性较高、依赖正确的头文件和编译参数

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/39478.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

onedav一为导航批量自动化导入网址(完整教程)

OneNav作为一个功能强大的导航工具,支持后台管理、加密链接、浏览器书签批量导入等功能,能够帮助用户轻松打造专属的导航页面。今天,我将为大家详细介绍如何实现OneNav导航站的批量自动化导入网址。 1、建立要批量导入的表格 格局需要创建表格,表格的要求是一定要有需要,…

文档处理控件Aspose.Words 教程:.NET版中增强的 AI 文档摘要功能

Aspose.Words是一个功能强大的 Word 文档处理库。它可以帮助开发人员自动编辑、转换和处理文档。 自 24.11 版以来&#xff0c;Aspose.Words for .NET 提供了 AI 驱动的文档摘要功能&#xff0c;使用户能够从冗长的文本中快速提取关键见解。在 25.2 版中&#xff0c;我们通过使…

AI本地部署之dify

快捷目录 Windows 系统一、环境准备:首先windows 需要准备docker 环1. 安装Docker desktop2. 安装Docker3. 配置Docker 镜像路径4. 配置Docker 下载镜像源5. 重启Docker服务二、Dify 下载和安装1. Dify下载2. Dify 配置3. Dify 安装附件知识:4. Dify创建账号三、下载Ollama d…

DDS协议(二)

一、DDS发布订阅机制 基于发布/订阅的数据分发服务为各种虚拟机载设备之间的通信提供了统一的底层支撑 其技术原理如图所示&#xff1a; 发布方应用程序和订阅方应用程序分别同发布/订阅中间件通信&#xff0c; 而数据的实际分发是由发布/订阅中间件来处理。 发布方将包含主题…

GitHub供应链攻击事件:Coinbase遭袭,218个仓库暴露,CI/CD密钥泄露

此次供应链攻击涉及GitHub Action "tj-actions/changed-files"&#xff0c;最初是针对Coinbase的一个开源项目的高度定向攻击&#xff0c;随后演变为范围更广的威胁。 攻击过程与影响 Palo Alto Networks Unit 42在一份报告中指出&#xff1a;“攻击载荷主要针对其…

transform

http://zhihu.com/question/445556653/answer/3254012065 西科技的文章 视频讲解 小白也能听懂的 transformer模型原理详解 self- attention 多头注意力机制 encoder decoder 机器翻译_哔哩哔哩_bilibili

Spring Boot 整合 Nacos 注册中心终极指南

在微服务架构中&#xff0c;配置管理和动态路由是核心需求。Nacos 作为阿里巴巴开源的动态服务发现、配置管理和服务管理平台&#xff0c;能够帮助开发者实现配置热更新、多环境共享配置以及动态路由管理。本文将结合 Spring Boot 和 Spring Cloud Gateway&#xff0c;手把手教…

网络基础梳理

为什么要有网络呢&#xff1f; 在一开始科学家们都是自己在计算机当中做实验但是难免需要共同进行科研。假设现在一个业务需要三个人共同完成&#xff0c;那么现在就有问题了&#xff1a; 由于第一个人完成工作前&#xff0c;其他两人无法开始&#xff0c;这导致工作流程是串行…

EMS小车技术特点与优势:高效灵活的自动化输送解决方案

北成新控伺服技术丨EMS小车调试视频 EMS小车是一种基于单轨运行的电动输送系统&#xff0c;通过电力驱动实现物料的高效搬运和输送&#xff0c;具有高效灵活、节能环保、多功能集成、行业适配性强等特性&#xff0c;广泛应用于汽车制造、工程机械、家电生产、仓储物流等行业自动…

Python实现deepseek接口的调用

简介&#xff1a;DeepSeek 是一个强大的大语言模型&#xff0c;提供 API 接口供开发者调用。在 Python 中&#xff0c;可以使用 requests 或 httpx 库向 DeepSeek API 发送请求&#xff0c;实现文本生成、代码补全&#xff0c;知识问答等功能。本文将介绍如何在 Python 中调用 …

2025清华大学:DeepSeek教程全集(PDF+视频精讲,共10份).zip

一、资料列表 第一课&#xff1a;Deepseek基础入门 第二课&#xff1a;DeepSeek赋能职场 第三课&#xff1a;普通人如何抓住DeepSeek红利 第四课&#xff1a;让科研像聊天一样简单 第五课&#xff1a;DeepSeek与AI幻觉 第六课&#xff1a;基于DeepSeek的AI音乐词曲的创造法 第…

“智改数转”新风口,物联网如何重构制造业竞争力?

一、政策背景 为深化制造业智能化改造、数字化转型、网络化联接&#xff0c;江苏省制定了《江苏省深化制造业智能化改造数字化转型网络化联接三年行动计划&#xff08;2025&#xff0d;2027年&#xff09;》&#xff0c;提出到2027年&#xff0c;全省制造业企业设备更新、工艺…

OpenHarmony 入门——ArkUI 跨页面数据同步和页面级UI状态存储LocalStorage小结(二)

文章大纲 引言一、在代码逻辑使用LocalStorage二、从UI内部使用LocalStorage三、LocalStorageProp和LocalStorage单向同步四、LocalStorageLink和LocalStorage双向同步五、兄弟组件之间同步状态变量七、将LocalStorage实例从UIAbility共享到一个或多个视图 引言 前面一篇文章主…

干货分享|DeepSeek技术革命、算力范式重构与场景落地洞察

本文为TsingtaoAI公司负责人汶生为某证券公司管理层和投资者教授的《DeepSeek技术革命、算力范式重构与场景落地洞察》主题培训内容&#xff0c;此次主题培训系统阐述了当前AI技术演进的核心趋势、算力需求的结构性变革&#xff0c;以及行业应用落地的关键路径。 现在我们将全…

从切图仔到鸿蒙开发01-文本样式

从切图仔到鸿蒙开发01-文本样式 本系列教程适合 HarmonyOS 初学者&#xff0c;为那些熟悉用 HTML 与 CSS 语法的 Web 前端开发者准备的。 本系列教程会将 HTML/CSS 代码片段替换为等价的 HarmonyOS/ArkUI 代码。 页面结构 HTML 与 ArkUI 在 Web 开发中&#xff0c;HTML 文档结…

零基础入门网络爬虫第5天:Scrapy框架

4周 Srapy爬虫框架 不是一个简单的函数功能库&#xff0c;而是一个爬虫框架 安装&#xff1a;pip install scrapy 检测&#xff1a;scrapy -h Scrapy爬虫框架结构 爬虫框架 爬虫框架是实现爬虫功能的一个软件结构和功能组件集合爬虫框架是一个半成品&#xff0c;能够帮助…

C语言:扫雷

在编程的世界里&#xff0c;扫雷游戏是一个经典的实践项目。它不仅能帮助我们巩固编程知识&#xff0c;还能锻炼逻辑思维和解决问题的能力。今天&#xff0c;就让我们一起用 C 语言来实现这个有趣的游戏&#xff0c;并且通过图文并茂的方式&#xff0c;让每一步都清晰易懂 1. 游…

同一个局域网的话 如何访问另一台电脑的ip

在局域网内访问另一台电脑&#xff0c;可以通过以下几种常见的方法来实现&#xff1a; ‌直接通过IP地址访问‌&#xff1a; 首先&#xff0c;确保两台电脑都连接在同一个局域网内。获取目标电脑的IP地址&#xff0c;这可以通过在目标电脑上打开命令提示符&#xff08;Windows系…

记录我的ICME2025论文之旅:困顿与收获

人生第一次中B会&#xff0c;还是在课业繁重的大三上&#xff08;有点说法~&#xff09; “在最黑暗的时刻&#xff0c;总有一束光为你指引前行。” ——记录这段难忘的历程 今年的ICME投稿量创下新高&#xff0c;录取率却跌至20多%&#xff0c;并且首次加入了rebuttal&#xf…

MySQL多表查询

这是两个表多表查询&#xff0c;需要一个连接条件customer_id。如果有n个表实现多表查询&#xff0c;至少需要n-1个连接条件。如果少于n-1个&#xff0c;就会出现笛卡尔积的错误。 SELECT orders.order_id, customers.customer_name FROM orders INNER JOIN customers ON orde…