使用Clang作为库 —— Clang AST


本文为译文,点击 此处查看原文。

本文档温和地介绍了Clang AST的神秘之处,主要针对那些希望为Clang做贡献的开发人员,或者使用基于Clang AST的工具(如AST matchers)的开发人员。

1. 介绍

Clang的AST不同于其他编译器生成的AST,因为它非常类似于编写的C++代码和C++标准。例如,括号表达式和编译时常量在AST中以未简化的形式可用,这使得Clang的 AST非常适合于重构工具。

所有Clang AST节点的文档都可以通过生成的Doxygen获得。doxygen在线文档也由您最喜欢的搜索引擎索引,该引擎将对clang进行搜索,AST节点的类名通常会显示您正在寻找的类的doxygen(例如,搜索:clang ParenExpr)。

2. 检查AST

熟悉Clang AST的一个好方法是在一些简单的示例代码中实际查看它。Clang具有一个内置的AST-dump模式,可以使用标记-ast-dump启用该模式。

让我们看一个简单的示例AST:

$ cat test.cc
int f(int x) {
  int result = (x / 42);
  return result;
}

# Clang by default is a frontend for many tools; -Xclang is used to pass
# options directly to the C++ frontend.
$ clang -Xclang -ast-dump -fsyntax-only test.cc
TranslationUnitDecl 0x5aea0d0 <<invalid sloc>>
... cutting out internal declarations of clang ...
`-FunctionDecl 0x5aeab50 <test.cc:1:1, line:4:1> f 'int (int)'
  |-ParmVarDecl 0x5aeaa90 <line:1:7, col:11> x 'int'
  `-CompoundStmt 0x5aead88 <col:14, line:4:1>
    |-DeclStmt 0x5aead10 <line:2:3, col:24>
    | `-VarDecl 0x5aeac10 <col:3, col:23> result 'int'
    |   `-ParenExpr 0x5aeacf0 <col:16, col:23> 'int'
    |     `-BinaryOperator 0x5aeacc8 <col:17, col:21> 'int' '/'
    |       |-ImplicitCastExpr 0x5aeacb0 <col:17> 'int' <LValueToRValue>
    |       | `-DeclRefExpr 0x5aeac68 <col:17> 'int' lvalue ParmVar 0x5aeaa90 'x' 'int'
    |       `-IntegerLiteral 0x5aeac90 <col:21> 'int' 42
    `-ReturnStmt 0x5aead68 <line:3:3, col:10>
      `-ImplicitCastExpr 0x5aead50 <col:10> 'int' <LValueToRValue>
        `-DeclRefExpr 0x5aead28 <col:10> 'int' lvalue Var 0x5aeac10 'result' 'int'

一个翻译单元中的顶层声明始终是 TranslationUnitDecl。在本例中,我们编写的第一个声明是“f”FunctionDecl“f”的 body 是一个复合语句(CompoundStmt),复合语句的子节点是一个 DeclStmt(声明我们的结果变量)和一个 ReturnStmt

3. AST Context

一个翻译单元的 AST 的所有信息都打包在类 ASTContext 中。它允许从 getTranslationUnitDecl 开始遍历整个翻译单元,或者对于已解析的翻译单元,访问 Clang 的标识符表

4. AST节点

Clang 的 AST 节点是基于没有公共祖先的类层次结构建模的。相反,对于像 DeclStmt 这样的基本节点类型,有多个更大的层次结构。许多重要的AST节点派生自 TypeDeclDeclContextStmt,有些类同时派生自 DeclDeclContext

AST 中还有许多节点不是更大层次结构的一部分,只能从特定的其他节点访问,比如 CXXBaseSpecifier

因此,要遍历整个 AST,首先从 TranslationUnitDecl 开始,然后递归遍历从该节点可以到达的所有内容 —— 必须为每个特定的节点类型编码此信息。这个算法是在 RecursiveASTVisitor 中编码的。请参阅 RecursiveASTVisitor 教程

Clang AST中最基本的两个节点是语句(Stmt)和声明(Decl)。注意:表达式(Expr)也是 Clang AST 中的语句。

  • 3
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值