c语言编程规范检查,使用Clang实现C语言编程规范检查

本文介绍了如何利用Clang进行C语言编程规范检查。Clang作为LLVM的前端,支持C语言等,其模块化设计允许进行语法检查和编程规范检查。通过RecursiveASTVisitor,可以访问和检查AST节点,实现对编程规范的定制化检查,例如限制逗号表达式、检查类型匹配等。此外,还讨论了处理宏、类型信息、符号表和错误诊断的方法。
摘要由CSDN通过智能技术生成

概述

Clang是LLVM编译器工具集的前端部分,也就是涵盖词法分析、语法语义分析的部分。而LLVM是Apple在Mac OS上用于替代GCC工具集的编译器软件集合。Clang支持类C语言的语言,例如C、C++、Objective C。Clang的与众不同在于其模块化的设计,使其不仅实现编译器前端部分,并且包装成库的形式提供给上层应用。使用Clang可以做诸如语法高亮、语法检查、编程规范检查方面的工作,当然也可以作为你自己的编译器前端。

编程规范一般包含编码格式和语义规范两部分。编码格式用于约定代码的排版、符号命名等;而语义规范则用于约定诸如类型匹配、表达式复杂度等,例如不允许对常数做逻辑运算、检查变量使用前是否被赋值等。本文描述的主要是基于语义方面的检查,其经验来自于最近做的一个检查工具,该工具实现了超过130条的规范。这份规范部分规则来自于MISRA C

编程模式

编译器前端部分主要是输出代码对应的抽象语法树(AST)。Clang提供给上层的接口也主要是围绕语法树来做操作。通过google一些Clang的资料,你可能会如我当初一样对该如何正确地使用Clang心存疑惑。我最后使用的方式是基于RecursiveASTVisitor。这是一种类似回调的使用机制,通过提供特定语法树节点的接口,Clang在遍历语法树的时候,在遇到该节点时,就会调用到上层代码。不能说这是最好的方式,但起码它可以工作。基于RecursiveASTVisitor使用Clang,程序主体框架大致为:

// 编写你感兴趣的语法树节点访问接口,例如该例子中提供了函数调用语句和goto语句的节点访问接口

class MyASTVisitor : public RecursiveASTVisitor {

public:

bool VisitCallExpr(CallExpr *expr);

bool VisitGotoStmt(GotoStmt *stmt);

...

};

class MyASTConsumer : public ASTConsumer {

public:

virtual bool HandleTopLevelDecl(DeclGroupRef DR) {

for (DeclGroupRef::iterator b = DR.begin(), e = DR.end(); b != e; ++b) {

Visitor.TraverseDecl(*b);

}

return true;

}

private:

MyASTVisitor Visitor;

};

int main(int argc, char **argv) {

CompilerInstance inst;

Rewriter writer;

inst.createFileManager();

inst.createSourceManager(inst.getFileManager());

inst.createPreprocessor();

inst.createASTContext();

writer.setSourceMgr(inst.getSourceManager(), inst.getLangOpts());

... // 其他初始化CompilerInstance的代码

const FileEntry *fileIn = fileMgr.getFile(argv[1]);

sourceMgr.createMainFileID(fileIn);

inst.getDiagnosticClient().BeginSourceFile(inst.getLangOpts(), &inst.getPreprocessor());

MyASTConsumer consumer(writer);

ParseAST(inst.getPreprocessor(), &consumer, inst.getASTContext());

inst.getDiagnosticClient().EndSourceFile();

return 0;

}

以上代码中,ParseAST为Clang开始分析代码的主入口,其中提供了一个ASTConsumer。每次分析到一个顶层定义时(Top level decl)就会回调MyASTConsumer::HandleTopLevelDecl,该函数的实现里调用MyASTVisitor开始递归访问该节点。这里的decl实际上包含定义。

语法树

Clang中视所有代码单元为语句(statement),Clang中使用类Stmt来代表statement。Clang构造出来的语法树,其节点类型就是Stmt。针对不同类型的语句,Clang有对应的Stmt子类,例如GotoStmt。Clang中的表达式也被视为语句,Clang使用Expr类来表示表达式

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值