llvm/clang编译器添加航天子集区域限制的制导#pragma as-check

一.实现效果

输入:添加制导的源程序*.c 输出:打印每个函数对应的是否在制导范围内,如果在制导范围内,对应的规则号 输出格式为 函数名:[0,1,2](1 表示有 as-check 制导 rule1,2 表示有制导 rule2, 0 表示没有) 每个函数一行 。

例如:

示例输入example.c

llvm/clang编译器添加航天子集区域限制的制导#pragma as-check

示例输出

llvm/clang编译器添加航天子集区域限制的制导#pragma as-check

二.算法流程: 

1、当 Lexer 认出”#pragma”时调用 PragmaNamespace::HandlePragma 函数,它会根据后 面的 Token 寻找合适的 Handler,因此我们定义并注册自己的 PragmaAsCheckHandler 来 实现语法分析。 2、当按照规定格式分析完一个”#Pragma asCheck …”后,会生成一个新的 Token,将相关 的 rule 信息填入其中,最后塞入到编译器处理的 Token 流中。 3、紧接着语法分析器会处理刚定义的 tok::annot_pragma_as_check 类型的 Token,根据 其内容修改 Sema 类中新成员 AsCheckRule 的状态。 4、从而,每当一个函数定义结束之后,会检查 Sema::AsCheckRule,根据它来修改该函 数的 FunctionDecl::AsCheckRule 状态。最后,遍历每个函数的状态打印对应的规则号。 
三.注意问题: 

1、实现 PragmaAsCheckHandler 时,首先需要判断紧跟“# pragma asCheck”后的标识符 是否是合法的规则。对于不合法情况,实现需要实现 3 种类型的 warning:一种是形 如”#pragma asCheck-haha”,这种类型已经被定义过,为 warn_pragma_expected_identifier, 使用时需要注意后面传参,否则会出现段错误!另一种是 asCheck 后不是 rule1/rule2, 这种情况我们在 DiagnosticParseKinds.td 中 定义的新 warning : warn_pragma_asCheck_invalid_option , 输出” unknown rule for ‘#pragma asCheck’ -Ignored”; 最后一种是 rule1/rule2 后还有其他内容, 该类型已经被定义过,为 warn_pragma_extra_tokens_at_eol; 2、Token 中取出属性值后要消耗掉当前的 Token,以便处理下一个 Token 3、设定 FD 的 AsCheckRule 状态后要清除 Sema 的 AsCheckRule 状态,因为一个 pragma 至多只能匹配一个函数定义。 4、最后注意需要 remove 我们使用过的 AsCheckHandler,否则在退出 clang 后会有段 错误

四.代码修改

1.ParsePragma.h 
定义 PragmaAsCheckHandler,告诉编译器这个 handler 要处理的是“#pragma asCheck” 
 llvm/clang编译器添加航天子集区域限制的制导#pragma as-check

2.Parser.h 定义 HandlePragmaAsCheck 

llvm/clang编译器添加航天子集区域限制的制导#pragma as-check

定义一个 handler 实例 

llvm/clang编译器添加航天子集区域限制的制导#pragma as-check

3.Parser.cpp 把定义的 handler 实例注册给预处理器,Parser 构造函数中 

llvm/clang编译器添加航天子集区域限制的制导#pragma as-check

在 Parser 析构函数中 

llvm/clang编译器添加航天子集区域限制的制导#pragma as-check

调用 HandlePragmaAsCheck 

llvm/clang编译器添加航天子集区域限制的制导#pragma as-check

4.TokenKinds.def 定义一个 asCheck 对应的 Token 

llvm/clang编译器添加航天子集区域限制的制导#pragma as-check

5.Sema.h 添加一个属性:AsCheckRule,以标明 asCheck 的状态 

llvm/clang编译器添加航天子集区域限制的制导#pragma as-check

定义 PragmaAsCheckKind 表示 Token 对应的语义信息是规则几 

llvm/clang编译器添加航天子集区域限制的制导#pragma as-check

定义 ActOnPragmaAsCheck 

llvm/clang编译器添加航天子集区域限制的制导#pragma as-check

 

6.ParsePragma.cpp 实现 PragmaAsCheckHandler 的 HandlePragma 

llvm/clang编译器添加航天子集区域限制的制导#pragma as-check

llvm/clang编译器添加航天子集区域限制的制导#pragma as-check

实现 HandlePragmaAsCheck 

llvm/clang编译器添加航天子集区域限制的制导#pragma as-check

7.Decl.h AsCheckRule 标明函数的定义的属性 

llvm/clang编译器添加航天子集区域限制的制导#pragma as-check

为实现对该属性的读取和置位,加入两个函数 

llvm/clang编译器添加航天子集区域限制的制导#pragma as-check

8.SemaAttr.cpp 实现 ActOnPragmaAsCheck 

llvm/clang编译器添加航天子集区域限制的制导#pragma as-check

9.Decl.cpp 实现 setAsCheckRule 

llvm/clang编译器添加航天子集区域限制的制导#pragma as-check

10.SemaDecl.cpp 根据当前 Sema 的 AsCheckRule 设定当前 FD 的 AsCheckRule 状态,注意清除状态 

llvm/clang编译器添加航天子集区域限制的制导#pragma as-check

截止到此函数的状态已经成功标记了,当你查看FD->getAsCheckrule()时会获取到函数的相应状态。

11.DiagnosticParseKinds.td 

llvm/clang编译器添加航天子集区域限制的制导#pragma as-check

12.笔者使用的llvm/clang是3.3版本后面的新版本可能有些不同,但都大同小异有些函数可能在3.3版本里在这个cpp里在其他版本就在另一个cpp里。