Page 28 - 《软件学报》2024年第4期
P. 28
1606 软件学报 2024 年第 35 卷第 4 期
REcomp 是一种基于多模态对比学习的代码表征增强的编程语言预训练模型, 是基于 Transformer [23] 的,
能够以多种编程语言预训练模型(如 CodeBERT [29] , GraphCodeBERT [30] 和 UniXcoder [32] )为初始化标准. 下面将
依次介绍多模态特征提取、REcomp 的编码器、多模态对比学习的预训练任务(包含数据增强)和下游任务.
2.1 多模态特征提取
如图 2(a)多模态特征提取模块所示, 需要提取源代码 4 个层次的特征, 分别是文本级的代码注释、语义级
-结构级的融合特征序列和功能级的函数名. 下面将详细阐述需要提取源代码多个模态特征的原因以及获取
语义级-结构级融合的方法(见算法 1).
图 3 给出了一个带有注释和 AST 的 Python 代码示例. 注释“Return the sum of two numbers”高度概括了源
代码的功能, 提供了关键的语义信息. 函数名称“sum”简明扼要的描述了源代码主体函数的功能, 也是表征源
代码语义信息的另一重要而不可忽视的特征. 此外, 解析源代码后得到的 AST 包含丰富的句法相关的结构信
息,例如: 非叶结点(控制结点)“return_statement”控制了其叶结点“return”和“result”整体行为; 非叶结点
“parameters”指出来了“(x,y)”的类型是“参数”. 这里的“x”和“y”的结构是等价的. 这也是编程语言区别于自然
语言的特殊的点: 编程语言中字符的语义和结构信息共同决定了它的表征, 存在同一字符表示不同语义和不
同字符表示相同语义的现象. 因此, 不仅要关注语义级代码字符的信息, 也要关注隐藏的结构信息, 才能更加
准确地表示源代码.
图 3 一个 Python 的 AST 与代码字符的融合序列示例
算法 1 描述了代码的语义级-结构级特征的融合的过程. 算法的输入是编程语言的类型 Language∈{php,
java,python,ruby,go,javascript}, 以及程序 Code S=(s 1 ,s 2 ,…,s i ,…,s |S| ), 输出是所有语义级和结构级特征的集合
TokensAST. 将 Code S 相应的 AST 表示为六元组τ=(N,N leaf ,N nonleaf ,c(⋅),t(⋅),r), N 是 AST 所有结点的集合, N leaf =(l 1 ,
l 2 ,...,l |leaf| )⊂N 是叶子结点的集合, N nonleaf =(nol 1 ,nol 2 ,...,nol |nonleaf| )⊂N 是非叶子结点的集合, r∈N 是 AST 的根结点,
c(⋅)是 AST 的 N leaf 与代码 tokenss i ∈S 对齐的映射函数(第 18−27 行), t(⋅)是 AST 的 N nonleaf 与其结点的 type 属性映
射的函数(第 15 行).
算法 1 的核心是_SemanticsStructureFusion 函数(第 7−17 行), 它将 t(N nonleaf )与 c(N leaf )依次添加到集合
TokensAST, 即 ca(见公式(1))中. 整个算法自顶向下的遍历 AST, 融合了代码的语义信息和结构信息.
算法 1. 语义级-结构级特征融合(SemanticsStructureFusion).
输入: 编程语言 Language, 源代码 Code;
输出: 所有语义级和结构级特征的集合 TokensAST.
1. Function SemanticsStructureFusion(Langauge,Code)
2. TokensAST←∅
3. get the AST parser of Code depending on different Language
4. parse the Code to AST then get the root of the AST